diff options
Diffstat (limited to 'drivers/media/video/cx23885')
31 files changed, 14134 insertions, 0 deletions
diff --git a/drivers/media/video/cx23885/Kconfig b/drivers/media/video/cx23885/Kconfig new file mode 100644 index 00000000000..caab1bfb79e --- /dev/null +++ b/drivers/media/video/cx23885/Kconfig | |||
@@ -0,0 +1,46 @@ | |||
1 | config VIDEO_CX23885 | ||
2 | tristate "Conexant cx23885 (2388x successor) support" | ||
3 | depends on DVB_CORE && VIDEO_DEV && PCI && I2C && INPUT && SND | ||
4 | select SND_PCM | ||
5 | select I2C_ALGOBIT | ||
6 | select VIDEO_BTCX | ||
7 | select VIDEO_TUNER | ||
8 | select VIDEO_TVEEPROM | ||
9 | depends on RC_CORE | ||
10 | select VIDEOBUF_DVB | ||
11 | select VIDEOBUF_DMA_SG | ||
12 | select VIDEO_CX25840 | ||
13 | select VIDEO_CX2341X | ||
14 | select DVB_DIB7000P if !DVB_FE_CUSTOMISE | ||
15 | select DVB_S5H1409 if !DVB_FE_CUSTOMISE | ||
16 | select DVB_S5H1411 if !DVB_FE_CUSTOMISE | ||
17 | select DVB_LGDT330X if !DVB_FE_CUSTOMISE | ||
18 | select DVB_ZL10353 if !DVB_FE_CUSTOMISE | ||
19 | select DVB_TDA10048 if !DVB_FE_CUSTOMISE | ||
20 | select DVB_LNBP21 if !DVB_FE_CUSTOMISE | ||
21 | select DVB_STV6110 if !DVB_FE_CUSTOMISE | ||
22 | select DVB_CX24116 if !DVB_FE_CUSTOMISE | ||
23 | select DVB_STV0900 if !DVB_FE_CUSTOMISE | ||
24 | select DVB_DS3000 if !DVB_FE_CUSTOMISE | ||
25 | select DVB_STV0367 if !DVB_FE_CUSTOMISE | ||
26 | select MEDIA_TUNER_MT2131 if !MEDIA_TUNER_CUSTOMISE | ||
27 | select MEDIA_TUNER_XC2028 if !MEDIA_TUNER_CUSTOMISE | ||
28 | select MEDIA_TUNER_TDA8290 if !MEDIA_TUNER_CUSTOMISE | ||
29 | select MEDIA_TUNER_TDA18271 if !MEDIA_TUNER_CUSTOMISE | ||
30 | select MEDIA_TUNER_XC5000 if !MEDIA_TUNER_CUSTOMISE | ||
31 | ---help--- | ||
32 | This is a video4linux driver for Conexant 23885 based | ||
33 | TV cards. | ||
34 | |||
35 | To compile this driver as a module, choose M here: the | ||
36 | module will be called cx23885 | ||
37 | |||
38 | config MEDIA_ALTERA_CI | ||
39 | tristate "Altera FPGA based CI module" | ||
40 | depends on VIDEO_CX23885 && DVB_CORE | ||
41 | select STAPL_ALTERA | ||
42 | ---help--- | ||
43 | An Altera FPGA CI module for NetUP Dual DVB-T/C RF CI card. | ||
44 | |||
45 | To compile this driver as a module, choose M here: the | ||
46 | module will be called altera-ci | ||
diff --git a/drivers/media/video/cx23885/Makefile b/drivers/media/video/cx23885/Makefile new file mode 100644 index 00000000000..23293c7b6ac --- /dev/null +++ b/drivers/media/video/cx23885/Makefile | |||
@@ -0,0 +1,15 @@ | |||
1 | cx23885-objs := cx23885-cards.o cx23885-video.o cx23885-vbi.o \ | ||
2 | cx23885-core.o cx23885-i2c.o cx23885-dvb.o cx23885-417.o \ | ||
3 | cx23885-ioctl.o cx23885-ir.o cx23885-av.o cx23885-input.o \ | ||
4 | cx23888-ir.o netup-init.o cimax2.o netup-eeprom.o \ | ||
5 | cx23885-f300.o | ||
6 | |||
7 | obj-$(CONFIG_VIDEO_CX23885) += cx23885.o | ||
8 | obj-$(CONFIG_MEDIA_ALTERA_CI) += altera-ci.o | ||
9 | |||
10 | EXTRA_CFLAGS += -Idrivers/media/video | ||
11 | EXTRA_CFLAGS += -Idrivers/media/common/tuners | ||
12 | EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core | ||
13 | EXTRA_CFLAGS += -Idrivers/media/dvb/frontends | ||
14 | |||
15 | EXTRA_CFLAGS += $(extra-cflags-y) $(extra-cflags-m) | ||
diff --git a/drivers/media/video/cx23885/altera-ci.c b/drivers/media/video/cx23885/altera-ci.c new file mode 100644 index 00000000000..1fa8927f0d3 --- /dev/null +++ b/drivers/media/video/cx23885/altera-ci.c | |||
@@ -0,0 +1,837 @@ | |||
1 | /* | ||
2 | * altera-ci.c | ||
3 | * | ||
4 | * CI driver in conjunction with NetUp Dual DVB-T/C RF CI card | ||
5 | * | ||
6 | * Copyright (C) 2010,2011 NetUP Inc. | ||
7 | * Copyright (C) 2010,2011 Igor M. Liplianin <liplianin@netup.ru> | ||
8 | * | ||
9 | * This program is free software; you can redistribute it and/or modify | ||
10 | * it under the terms of the GNU General Public License as published by | ||
11 | * the Free Software Foundation; either version 2 of the License, or | ||
12 | * (at your option) any later version. | ||
13 | * | ||
14 | * This program is distributed in the hope that it will be useful, | ||
15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
17 | * | ||
18 | * GNU General Public License for more details. | ||
19 | * | ||
20 | * You should have received a copy of the GNU General Public License | ||
21 | * along with this program; if not, write to the Free Software | ||
22 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
23 | */ | ||
24 | |||
25 | /* | ||
26 | * currently cx23885 GPIO's used. | ||
27 | * GPIO-0 ~INT in | ||
28 | * GPIO-1 TMS out | ||
29 | * GPIO-2 ~reset chips out | ||
30 | * GPIO-3 to GPIO-10 data/addr for CA in/out | ||
31 | * GPIO-11 ~CS out | ||
32 | * GPIO-12 AD_RG out | ||
33 | * GPIO-13 ~WR out | ||
34 | * GPIO-14 ~RD out | ||
35 | * GPIO-15 ~RDY in | ||
36 | * GPIO-16 TCK out | ||
37 | * GPIO-17 TDO in | ||
38 | * GPIO-18 TDI out | ||
39 | */ | ||
40 | /* | ||
41 | * Bit definitions for MC417_RWD and MC417_OEN registers | ||
42 | * bits 31-16 | ||
43 | * +-----------+ | ||
44 | * | Reserved | | ||
45 | * +-----------+ | ||
46 | * bit 15 bit 14 bit 13 bit 12 bit 11 bit 10 bit 9 bit 8 | ||
47 | * +-------+-------+-------+-------+-------+-------+-------+-------+ | ||
48 | * | TDI | TDO | TCK | RDY# | #RD | #WR | AD_RG | #CS | | ||
49 | * +-------+-------+-------+-------+-------+-------+-------+-------+ | ||
50 | * bit 7 bit 6 bit 5 bit 4 bit 3 bit 2 bit 1 bit 0 | ||
51 | * +-------+-------+-------+-------+-------+-------+-------+-------+ | ||
52 | * | DATA7| DATA6| DATA5| DATA4| DATA3| DATA2| DATA1| DATA0| | ||
53 | * +-------+-------+-------+-------+-------+-------+-------+-------+ | ||
54 | */ | ||
55 | #include <media/videobuf-dma-sg.h> | ||
56 | #include <media/videobuf-dvb.h> | ||
57 | #include "altera-ci.h" | ||
58 | #include "dvb_ca_en50221.h" | ||
59 | |||
60 | /* FPGA regs */ | ||
61 | #define NETUP_CI_INT_CTRL 0x00 | ||
62 | #define NETUP_CI_BUSCTRL2 0x01 | ||
63 | #define NETUP_CI_ADDR0 0x04 | ||
64 | #define NETUP_CI_ADDR1 0x05 | ||
65 | #define NETUP_CI_DATA 0x06 | ||
66 | #define NETUP_CI_BUSCTRL 0x07 | ||
67 | #define NETUP_CI_PID_ADDR0 0x08 | ||
68 | #define NETUP_CI_PID_ADDR1 0x09 | ||
69 | #define NETUP_CI_PID_DATA 0x0a | ||
70 | #define NETUP_CI_TSA_DIV 0x0c | ||
71 | #define NETUP_CI_TSB_DIV 0x0d | ||
72 | #define NETUP_CI_REVISION 0x0f | ||
73 | |||
74 | /* const for ci op */ | ||
75 | #define NETUP_CI_FLG_CTL 1 | ||
76 | #define NETUP_CI_FLG_RD 1 | ||
77 | #define NETUP_CI_FLG_AD 1 | ||
78 | |||
79 | static unsigned int ci_dbg; | ||
80 | module_param(ci_dbg, int, 0644); | ||
81 | MODULE_PARM_DESC(ci_dbg, "Enable CI debugging"); | ||
82 | |||
83 | static unsigned int pid_dbg; | ||
84 | module_param(pid_dbg, int, 0644); | ||
85 | MODULE_PARM_DESC(pid_dbg, "Enable PID filtering debugging"); | ||
86 | |||
87 | MODULE_DESCRIPTION("altera FPGA CI module"); | ||
88 | MODULE_AUTHOR("Igor M. Liplianin <liplianin@netup.ru>"); | ||
89 | MODULE_LICENSE("GPL"); | ||
90 | |||
91 | #define ci_dbg_print(args...) \ | ||
92 | do { \ | ||
93 | if (ci_dbg) \ | ||
94 | printk(KERN_DEBUG args); \ | ||
95 | } while (0) | ||
96 | |||
97 | #define pid_dbg_print(args...) \ | ||
98 | do { \ | ||
99 | if (pid_dbg) \ | ||
100 | printk(KERN_DEBUG args); \ | ||
101 | } while (0) | ||
102 | |||
103 | struct altera_ci_state; | ||
104 | struct netup_hw_pid_filter; | ||
105 | |||
106 | struct fpga_internal { | ||
107 | void *dev; | ||
108 | struct mutex fpga_mutex;/* two CI's on the same fpga */ | ||
109 | struct netup_hw_pid_filter *pid_filt[2]; | ||
110 | struct altera_ci_state *state[2]; | ||
111 | struct work_struct work; | ||
112 | int (*fpga_rw) (void *dev, int flag, int data, int rw); | ||
113 | int cis_used; | ||
114 | int filts_used; | ||
115 | int strt_wrk; | ||
116 | }; | ||
117 | |||
118 | /* stores all private variables for communication with CI */ | ||
119 | struct altera_ci_state { | ||
120 | struct fpga_internal *internal; | ||
121 | struct dvb_ca_en50221 ca; | ||
122 | int status; | ||
123 | int nr; | ||
124 | }; | ||
125 | |||
126 | /* stores all private variables for hardware pid filtering */ | ||
127 | struct netup_hw_pid_filter { | ||
128 | struct fpga_internal *internal; | ||
129 | struct dvb_demux *demux; | ||
130 | /* save old functions */ | ||
131 | int (*start_feed)(struct dvb_demux_feed *feed); | ||
132 | int (*stop_feed)(struct dvb_demux_feed *feed); | ||
133 | |||
134 | int status; | ||
135 | int nr; | ||
136 | }; | ||
137 | |||
138 | /* internal params node */ | ||
139 | struct fpga_inode { | ||
140 | /* pointer for internal params, one for each pair of CI's */ | ||
141 | struct fpga_internal *internal; | ||
142 | struct fpga_inode *next_inode; | ||
143 | }; | ||
144 | |||
145 | /* first internal params */ | ||
146 | static struct fpga_inode *fpga_first_inode; | ||
147 | |||
148 | /* find chip by dev */ | ||
149 | static struct fpga_inode *find_inode(void *dev) | ||
150 | { | ||
151 | struct fpga_inode *temp_chip = fpga_first_inode; | ||
152 | |||
153 | if (temp_chip == NULL) | ||
154 | return temp_chip; | ||
155 | |||
156 | /* | ||
157 | Search for the last fpga CI chip or | ||
158 | find it by dev */ | ||
159 | while ((temp_chip != NULL) && | ||
160 | (temp_chip->internal->dev != dev)) | ||
161 | temp_chip = temp_chip->next_inode; | ||
162 | |||
163 | return temp_chip; | ||
164 | } | ||
165 | /* check demux */ | ||
166 | static struct fpga_internal *check_filter(struct fpga_internal *temp_int, | ||
167 | void *demux_dev, int filt_nr) | ||
168 | { | ||
169 | if (temp_int == NULL) | ||
170 | return NULL; | ||
171 | |||
172 | if ((temp_int->pid_filt[filt_nr]) == NULL) | ||
173 | return NULL; | ||
174 | |||
175 | if (temp_int->pid_filt[filt_nr]->demux == demux_dev) | ||
176 | return temp_int; | ||
177 | |||
178 | return NULL; | ||
179 | } | ||
180 | |||
181 | /* find chip by demux */ | ||
182 | static struct fpga_inode *find_dinode(void *demux_dev) | ||
183 | { | ||
184 | struct fpga_inode *temp_chip = fpga_first_inode; | ||
185 | struct fpga_internal *temp_int; | ||
186 | |||
187 | /* | ||
188 | * Search of the last fpga CI chip or | ||
189 | * find it by demux | ||
190 | */ | ||
191 | while (temp_chip != NULL) { | ||
192 | if (temp_chip->internal != NULL) { | ||
193 | temp_int = temp_chip->internal; | ||
194 | if (check_filter(temp_int, demux_dev, 0)) | ||
195 | break; | ||
196 | if (check_filter(temp_int, demux_dev, 1)) | ||
197 | break; | ||
198 | } | ||
199 | |||
200 | temp_chip = temp_chip->next_inode; | ||
201 | } | ||
202 | |||
203 | return temp_chip; | ||
204 | } | ||
205 | |||
206 | /* deallocating chip */ | ||
207 | static void remove_inode(struct fpga_internal *internal) | ||
208 | { | ||
209 | struct fpga_inode *prev_node = fpga_first_inode; | ||
210 | struct fpga_inode *del_node = find_inode(internal->dev); | ||
211 | |||
212 | if (del_node != NULL) { | ||
213 | if (del_node == fpga_first_inode) { | ||
214 | fpga_first_inode = del_node->next_inode; | ||
215 | } else { | ||
216 | while (prev_node->next_inode != del_node) | ||
217 | prev_node = prev_node->next_inode; | ||
218 | |||
219 | if (del_node->next_inode == NULL) | ||
220 | prev_node->next_inode = NULL; | ||
221 | else | ||
222 | prev_node->next_inode = | ||
223 | prev_node->next_inode->next_inode; | ||
224 | } | ||
225 | |||
226 | kfree(del_node); | ||
227 | } | ||
228 | } | ||
229 | |||
230 | /* allocating new chip */ | ||
231 | static struct fpga_inode *append_internal(struct fpga_internal *internal) | ||
232 | { | ||
233 | struct fpga_inode *new_node = fpga_first_inode; | ||
234 | |||
235 | if (new_node == NULL) { | ||
236 | new_node = kmalloc(sizeof(struct fpga_inode), GFP_KERNEL); | ||
237 | fpga_first_inode = new_node; | ||
238 | } else { | ||
239 | while (new_node->next_inode != NULL) | ||
240 | new_node = new_node->next_inode; | ||
241 | |||
242 | new_node->next_inode = | ||
243 | kmalloc(sizeof(struct fpga_inode), GFP_KERNEL); | ||
244 | if (new_node->next_inode != NULL) | ||
245 | new_node = new_node->next_inode; | ||
246 | else | ||
247 | new_node = NULL; | ||
248 | } | ||
249 | |||
250 | if (new_node != NULL) { | ||
251 | new_node->internal = internal; | ||
252 | new_node->next_inode = NULL; | ||
253 | } | ||
254 | |||
255 | return new_node; | ||
256 | } | ||
257 | |||
258 | static int netup_fpga_op_rw(struct fpga_internal *inter, int addr, | ||
259 | u8 val, u8 read) | ||
260 | { | ||
261 | inter->fpga_rw(inter->dev, NETUP_CI_FLG_AD, addr, 0); | ||
262 | return inter->fpga_rw(inter->dev, 0, val, read); | ||
263 | } | ||
264 | |||
265 | /* flag - mem/io, read - read/write */ | ||
266 | int altera_ci_op_cam(struct dvb_ca_en50221 *en50221, int slot, | ||
267 | u8 flag, u8 read, int addr, u8 val) | ||
268 | { | ||
269 | |||
270 | struct altera_ci_state *state = en50221->data; | ||
271 | struct fpga_internal *inter = state->internal; | ||
272 | |||
273 | u8 store; | ||
274 | int mem = 0; | ||
275 | |||
276 | if (0 != slot) | ||
277 | return -EINVAL; | ||
278 | |||
279 | mutex_lock(&inter->fpga_mutex); | ||
280 | |||
281 | netup_fpga_op_rw(inter, NETUP_CI_ADDR0, ((addr << 1) & 0xfe), 0); | ||
282 | netup_fpga_op_rw(inter, NETUP_CI_ADDR1, ((addr >> 7) & 0x7f), 0); | ||
283 | store = netup_fpga_op_rw(inter, NETUP_CI_BUSCTRL, 0, NETUP_CI_FLG_RD); | ||
284 | |||
285 | store &= 0x0f; | ||
286 | store |= ((state->nr << 7) | (flag << 6)); | ||
287 | |||
288 | netup_fpga_op_rw(inter, NETUP_CI_BUSCTRL, store, 0); | ||
289 | mem = netup_fpga_op_rw(inter, NETUP_CI_DATA, val, read); | ||
290 | |||
291 | mutex_unlock(&inter->fpga_mutex); | ||
292 | |||
293 | ci_dbg_print("%s: %s: addr=[0x%02x], %s=%x\n", __func__, | ||
294 | (read) ? "read" : "write", addr, | ||
295 | (flag == NETUP_CI_FLG_CTL) ? "ctl" : "mem", | ||
296 | (read) ? mem : val); | ||
297 | |||
298 | return mem; | ||
299 | } | ||
300 | |||
301 | int altera_ci_read_attribute_mem(struct dvb_ca_en50221 *en50221, | ||
302 | int slot, int addr) | ||
303 | { | ||
304 | return altera_ci_op_cam(en50221, slot, 0, NETUP_CI_FLG_RD, addr, 0); | ||
305 | } | ||
306 | |||
307 | int altera_ci_write_attribute_mem(struct dvb_ca_en50221 *en50221, | ||
308 | int slot, int addr, u8 data) | ||
309 | { | ||
310 | return altera_ci_op_cam(en50221, slot, 0, 0, addr, data); | ||
311 | } | ||
312 | |||
313 | int altera_ci_read_cam_ctl(struct dvb_ca_en50221 *en50221, int slot, u8 addr) | ||
314 | { | ||
315 | return altera_ci_op_cam(en50221, slot, NETUP_CI_FLG_CTL, | ||
316 | NETUP_CI_FLG_RD, addr, 0); | ||
317 | } | ||
318 | |||
319 | int altera_ci_write_cam_ctl(struct dvb_ca_en50221 *en50221, int slot, | ||
320 | u8 addr, u8 data) | ||
321 | { | ||
322 | return altera_ci_op_cam(en50221, slot, NETUP_CI_FLG_CTL, 0, addr, data); | ||
323 | } | ||
324 | |||
325 | int altera_ci_slot_reset(struct dvb_ca_en50221 *en50221, int slot) | ||
326 | { | ||
327 | struct altera_ci_state *state = en50221->data; | ||
328 | struct fpga_internal *inter = state->internal; | ||
329 | /* reasonable timeout for CI reset is 10 seconds */ | ||
330 | unsigned long t_out = jiffies + msecs_to_jiffies(9999); | ||
331 | int ret; | ||
332 | |||
333 | ci_dbg_print("%s\n", __func__); | ||
334 | |||
335 | if (0 != slot) | ||
336 | return -EINVAL; | ||
337 | |||
338 | mutex_lock(&inter->fpga_mutex); | ||
339 | |||
340 | ret = netup_fpga_op_rw(inter, NETUP_CI_BUSCTRL, 0, NETUP_CI_FLG_RD); | ||
341 | netup_fpga_op_rw(inter, NETUP_CI_BUSCTRL, | ||
342 | (ret & 0xcf) | (1 << (5 - state->nr)), 0); | ||
343 | |||
344 | mutex_unlock(&inter->fpga_mutex); | ||
345 | |||
346 | for (;;) { | ||
347 | mdelay(50); | ||
348 | |||
349 | mutex_lock(&inter->fpga_mutex); | ||
350 | |||
351 | ret = netup_fpga_op_rw(inter, NETUP_CI_BUSCTRL, | ||
352 | 0, NETUP_CI_FLG_RD); | ||
353 | mutex_unlock(&inter->fpga_mutex); | ||
354 | |||
355 | if ((ret & (1 << (5 - state->nr))) == 0) | ||
356 | break; | ||
357 | if (time_after(jiffies, t_out)) | ||
358 | break; | ||
359 | } | ||
360 | |||
361 | |||
362 | ci_dbg_print("%s: %d msecs\n", __func__, | ||
363 | jiffies_to_msecs(jiffies + msecs_to_jiffies(9999) - t_out)); | ||
364 | |||
365 | return 0; | ||
366 | } | ||
367 | |||
368 | int altera_ci_slot_shutdown(struct dvb_ca_en50221 *en50221, int slot) | ||
369 | { | ||
370 | /* not implemented */ | ||
371 | return 0; | ||
372 | } | ||
373 | |||
374 | int altera_ci_slot_ts_ctl(struct dvb_ca_en50221 *en50221, int slot) | ||
375 | { | ||
376 | struct altera_ci_state *state = en50221->data; | ||
377 | struct fpga_internal *inter = state->internal; | ||
378 | int ret; | ||
379 | |||
380 | ci_dbg_print("%s\n", __func__); | ||
381 | |||
382 | if (0 != slot) | ||
383 | return -EINVAL; | ||
384 | |||
385 | mutex_lock(&inter->fpga_mutex); | ||
386 | |||
387 | ret = netup_fpga_op_rw(inter, NETUP_CI_BUSCTRL, 0, NETUP_CI_FLG_RD); | ||
388 | netup_fpga_op_rw(inter, NETUP_CI_BUSCTRL, | ||
389 | (ret & 0x0f) | (1 << (3 - state->nr)), 0); | ||
390 | |||
391 | mutex_unlock(&inter->fpga_mutex); | ||
392 | |||
393 | return 0; | ||
394 | } | ||
395 | |||
396 | /* work handler */ | ||
397 | static void netup_read_ci_status(struct work_struct *work) | ||
398 | { | ||
399 | struct fpga_internal *inter = | ||
400 | container_of(work, struct fpga_internal, work); | ||
401 | int ret; | ||
402 | |||
403 | ci_dbg_print("%s\n", __func__); | ||
404 | |||
405 | mutex_lock(&inter->fpga_mutex); | ||
406 | /* ack' irq */ | ||
407 | ret = netup_fpga_op_rw(inter, NETUP_CI_INT_CTRL, 0, NETUP_CI_FLG_RD); | ||
408 | ret = netup_fpga_op_rw(inter, NETUP_CI_BUSCTRL, 0, NETUP_CI_FLG_RD); | ||
409 | |||
410 | mutex_unlock(&inter->fpga_mutex); | ||
411 | |||
412 | if (inter->state[1] != NULL) { | ||
413 | inter->state[1]->status = | ||
414 | ((ret & 1) == 0 ? | ||
415 | DVB_CA_EN50221_POLL_CAM_PRESENT | | ||
416 | DVB_CA_EN50221_POLL_CAM_READY : 0); | ||
417 | ci_dbg_print("%s: setting CI[1] status = 0x%x\n", | ||
418 | __func__, inter->state[1]->status); | ||
419 | }; | ||
420 | |||
421 | if (inter->state[0] != NULL) { | ||
422 | inter->state[0]->status = | ||
423 | ((ret & 2) == 0 ? | ||
424 | DVB_CA_EN50221_POLL_CAM_PRESENT | | ||
425 | DVB_CA_EN50221_POLL_CAM_READY : 0); | ||
426 | ci_dbg_print("%s: setting CI[0] status = 0x%x\n", | ||
427 | __func__, inter->state[0]->status); | ||
428 | }; | ||
429 | } | ||
430 | |||
431 | /* CI irq handler */ | ||
432 | int altera_ci_irq(void *dev) | ||
433 | { | ||
434 | struct fpga_inode *temp_int = NULL; | ||
435 | struct fpga_internal *inter = NULL; | ||
436 | |||
437 | ci_dbg_print("%s\n", __func__); | ||
438 | |||
439 | if (dev != NULL) { | ||
440 | temp_int = find_inode(dev); | ||
441 | if (temp_int != NULL) { | ||
442 | inter = temp_int->internal; | ||
443 | schedule_work(&inter->work); | ||
444 | } | ||
445 | } | ||
446 | |||
447 | return 1; | ||
448 | } | ||
449 | EXPORT_SYMBOL(altera_ci_irq); | ||
450 | |||
451 | int altera_poll_ci_slot_status(struct dvb_ca_en50221 *en50221, int slot, | ||
452 | int open) | ||
453 | { | ||
454 | struct altera_ci_state *state = en50221->data; | ||
455 | |||
456 | if (0 != slot) | ||
457 | return -EINVAL; | ||
458 | |||
459 | return state->status; | ||
460 | } | ||
461 | |||
462 | void altera_hw_filt_release(void *main_dev, int filt_nr) | ||
463 | { | ||
464 | struct fpga_inode *temp_int = find_inode(main_dev); | ||
465 | struct netup_hw_pid_filter *pid_filt = NULL; | ||
466 | |||
467 | ci_dbg_print("%s\n", __func__); | ||
468 | |||
469 | if (temp_int != NULL) { | ||
470 | pid_filt = temp_int->internal->pid_filt[filt_nr - 1]; | ||
471 | /* stored old feed controls */ | ||
472 | pid_filt->demux->start_feed = pid_filt->start_feed; | ||
473 | pid_filt->demux->stop_feed = pid_filt->stop_feed; | ||
474 | |||
475 | if (((--(temp_int->internal->filts_used)) <= 0) && | ||
476 | ((temp_int->internal->cis_used) <= 0)) { | ||
477 | |||
478 | ci_dbg_print("%s: Actually removing\n", __func__); | ||
479 | |||
480 | remove_inode(temp_int->internal); | ||
481 | kfree(pid_filt->internal); | ||
482 | } | ||
483 | |||
484 | kfree(pid_filt); | ||
485 | |||
486 | } | ||
487 | |||
488 | } | ||
489 | EXPORT_SYMBOL(altera_hw_filt_release); | ||
490 | |||
491 | void altera_ci_release(void *dev, int ci_nr) | ||
492 | { | ||
493 | struct fpga_inode *temp_int = find_inode(dev); | ||
494 | struct altera_ci_state *state = NULL; | ||
495 | |||
496 | ci_dbg_print("%s\n", __func__); | ||
497 | |||
498 | if (temp_int != NULL) { | ||
499 | state = temp_int->internal->state[ci_nr - 1]; | ||
500 | altera_hw_filt_release(dev, ci_nr); | ||
501 | |||
502 | |||
503 | if (((temp_int->internal->filts_used) <= 0) && | ||
504 | ((--(temp_int->internal->cis_used)) <= 0)) { | ||
505 | |||
506 | ci_dbg_print("%s: Actually removing\n", __func__); | ||
507 | |||
508 | remove_inode(temp_int->internal); | ||
509 | kfree(state->internal); | ||
510 | } | ||
511 | |||
512 | if (state != NULL) { | ||
513 | if (state->ca.data != NULL) | ||
514 | dvb_ca_en50221_release(&state->ca); | ||
515 | |||
516 | kfree(state); | ||
517 | } | ||
518 | } | ||
519 | |||
520 | } | ||
521 | EXPORT_SYMBOL(altera_ci_release); | ||
522 | |||
523 | static void altera_pid_control(struct netup_hw_pid_filter *pid_filt, | ||
524 | u16 pid, int onoff) | ||
525 | { | ||
526 | struct fpga_internal *inter = pid_filt->internal; | ||
527 | u8 store = 0; | ||
528 | |||
529 | /* pid 0-0x1f always enabled, don't touch them */ | ||
530 | if ((pid == 0x2000) || (pid < 0x20)) | ||
531 | return; | ||
532 | |||
533 | mutex_lock(&inter->fpga_mutex); | ||
534 | |||
535 | netup_fpga_op_rw(inter, NETUP_CI_PID_ADDR0, (pid >> 3) & 0xff, 0); | ||
536 | netup_fpga_op_rw(inter, NETUP_CI_PID_ADDR1, | ||
537 | ((pid >> 11) & 0x03) | (pid_filt->nr << 2), 0); | ||
538 | |||
539 | store = netup_fpga_op_rw(inter, NETUP_CI_PID_DATA, 0, NETUP_CI_FLG_RD); | ||
540 | |||
541 | if (onoff)/* 0 - on, 1 - off */ | ||
542 | store |= (1 << (pid & 7)); | ||
543 | else | ||
544 | store &= ~(1 << (pid & 7)); | ||
545 | |||
546 | netup_fpga_op_rw(inter, NETUP_CI_PID_DATA, store, 0); | ||
547 | |||
548 | mutex_unlock(&inter->fpga_mutex); | ||
549 | |||
550 | pid_dbg_print("%s: (%d) set pid: %5d 0x%04x '%s'\n", __func__, | ||
551 | pid_filt->nr, pid, pid, onoff ? "off" : "on"); | ||
552 | } | ||
553 | |||
554 | static void altera_toggle_fullts_streaming(struct netup_hw_pid_filter *pid_filt, | ||
555 | int filt_nr, int onoff) | ||
556 | { | ||
557 | struct fpga_internal *inter = pid_filt->internal; | ||
558 | u8 store = 0; | ||
559 | int i; | ||
560 | |||
561 | pid_dbg_print("%s: pid_filt->nr[%d] now %s\n", __func__, pid_filt->nr, | ||
562 | onoff ? "off" : "on"); | ||
563 | |||
564 | if (onoff)/* 0 - on, 1 - off */ | ||
565 | store = 0xff;/* ignore pid */ | ||
566 | else | ||
567 | store = 0;/* enable pid */ | ||
568 | |||
569 | mutex_lock(&inter->fpga_mutex); | ||
570 | |||
571 | for (i = 0; i < 1024; i++) { | ||
572 | netup_fpga_op_rw(inter, NETUP_CI_PID_ADDR0, i & 0xff, 0); | ||
573 | |||
574 | netup_fpga_op_rw(inter, NETUP_CI_PID_ADDR1, | ||
575 | ((i >> 8) & 0x03) | (pid_filt->nr << 2), 0); | ||
576 | /* pid 0-0x1f always enabled */ | ||
577 | netup_fpga_op_rw(inter, NETUP_CI_PID_DATA, | ||
578 | (i > 3 ? store : 0), 0); | ||
579 | } | ||
580 | |||
581 | mutex_unlock(&inter->fpga_mutex); | ||
582 | } | ||
583 | |||
584 | int altera_pid_feed_control(void *demux_dev, int filt_nr, | ||
585 | struct dvb_demux_feed *feed, int onoff) | ||
586 | { | ||
587 | struct fpga_inode *temp_int = find_dinode(demux_dev); | ||
588 | struct fpga_internal *inter = temp_int->internal; | ||
589 | struct netup_hw_pid_filter *pid_filt = inter->pid_filt[filt_nr - 1]; | ||
590 | |||
591 | altera_pid_control(pid_filt, feed->pid, onoff ? 0 : 1); | ||
592 | /* call old feed proc's */ | ||
593 | if (onoff) | ||
594 | pid_filt->start_feed(feed); | ||
595 | else | ||
596 | pid_filt->stop_feed(feed); | ||
597 | |||
598 | if (feed->pid == 0x2000) | ||
599 | altera_toggle_fullts_streaming(pid_filt, filt_nr, | ||
600 | onoff ? 0 : 1); | ||
601 | |||
602 | return 0; | ||
603 | } | ||
604 | EXPORT_SYMBOL(altera_pid_feed_control); | ||
605 | |||
606 | int altera_ci_start_feed(struct dvb_demux_feed *feed, int num) | ||
607 | { | ||
608 | altera_pid_feed_control(feed->demux, num, feed, 1); | ||
609 | |||
610 | return 0; | ||
611 | } | ||
612 | |||
613 | int altera_ci_stop_feed(struct dvb_demux_feed *feed, int num) | ||
614 | { | ||
615 | altera_pid_feed_control(feed->demux, num, feed, 0); | ||
616 | |||
617 | return 0; | ||
618 | } | ||
619 | |||
620 | int altera_ci_start_feed_1(struct dvb_demux_feed *feed) | ||
621 | { | ||
622 | return altera_ci_start_feed(feed, 1); | ||
623 | } | ||
624 | |||
625 | int altera_ci_stop_feed_1(struct dvb_demux_feed *feed) | ||
626 | { | ||
627 | return altera_ci_stop_feed(feed, 1); | ||
628 | } | ||
629 | |||
630 | int altera_ci_start_feed_2(struct dvb_demux_feed *feed) | ||
631 | { | ||
632 | return altera_ci_start_feed(feed, 2); | ||
633 | } | ||
634 | |||
635 | int altera_ci_stop_feed_2(struct dvb_demux_feed *feed) | ||
636 | { | ||
637 | return altera_ci_stop_feed(feed, 2); | ||
638 | } | ||
639 | |||
640 | int altera_hw_filt_init(struct altera_ci_config *config, int hw_filt_nr) | ||
641 | { | ||
642 | struct netup_hw_pid_filter *pid_filt = NULL; | ||
643 | struct fpga_inode *temp_int = find_inode(config->dev); | ||
644 | struct fpga_internal *inter = NULL; | ||
645 | int ret = 0; | ||
646 | |||
647 | pid_filt = kzalloc(sizeof(struct netup_hw_pid_filter), GFP_KERNEL); | ||
648 | |||
649 | ci_dbg_print("%s\n", __func__); | ||
650 | |||
651 | if (!pid_filt) { | ||
652 | ret = -ENOMEM; | ||
653 | goto err; | ||
654 | } | ||
655 | |||
656 | if (temp_int != NULL) { | ||
657 | inter = temp_int->internal; | ||
658 | (inter->filts_used)++; | ||
659 | ci_dbg_print("%s: Find Internal Structure!\n", __func__); | ||
660 | } else { | ||
661 | inter = kzalloc(sizeof(struct fpga_internal), GFP_KERNEL); | ||
662 | if (!inter) { | ||
663 | ret = -ENOMEM; | ||
664 | goto err; | ||
665 | } | ||
666 | |||
667 | temp_int = append_internal(inter); | ||
668 | inter->filts_used = 1; | ||
669 | inter->dev = config->dev; | ||
670 | inter->fpga_rw = config->fpga_rw; | ||
671 | mutex_init(&inter->fpga_mutex); | ||
672 | inter->strt_wrk = 1; | ||
673 | ci_dbg_print("%s: Create New Internal Structure!\n", __func__); | ||
674 | } | ||
675 | |||
676 | ci_dbg_print("%s: setting hw pid filter = %p for ci = %d\n", __func__, | ||
677 | pid_filt, hw_filt_nr - 1); | ||
678 | inter->pid_filt[hw_filt_nr - 1] = pid_filt; | ||
679 | pid_filt->demux = config->demux; | ||
680 | pid_filt->internal = inter; | ||
681 | pid_filt->nr = hw_filt_nr - 1; | ||
682 | /* store old feed controls */ | ||
683 | pid_filt->start_feed = config->demux->start_feed; | ||
684 | pid_filt->stop_feed = config->demux->stop_feed; | ||
685 | /* replace with new feed controls */ | ||
686 | if (hw_filt_nr == 1) { | ||
687 | pid_filt->demux->start_feed = altera_ci_start_feed_1; | ||
688 | pid_filt->demux->stop_feed = altera_ci_stop_feed_1; | ||
689 | } else if (hw_filt_nr == 2) { | ||
690 | pid_filt->demux->start_feed = altera_ci_start_feed_2; | ||
691 | pid_filt->demux->stop_feed = altera_ci_stop_feed_2; | ||
692 | } | ||
693 | |||
694 | altera_toggle_fullts_streaming(pid_filt, 0, 1); | ||
695 | |||
696 | return 0; | ||
697 | err: | ||
698 | ci_dbg_print("%s: Can't init hardware filter: Error %d\n", | ||
699 | __func__, ret); | ||
700 | |||
701 | kfree(pid_filt); | ||
702 | |||
703 | return ret; | ||
704 | } | ||
705 | EXPORT_SYMBOL(altera_hw_filt_init); | ||
706 | |||
707 | int altera_ci_init(struct altera_ci_config *config, int ci_nr) | ||
708 | { | ||
709 | struct altera_ci_state *state; | ||
710 | struct fpga_inode *temp_int = find_inode(config->dev); | ||
711 | struct fpga_internal *inter = NULL; | ||
712 | int ret = 0; | ||
713 | u8 store = 0; | ||
714 | |||
715 | state = kzalloc(sizeof(struct altera_ci_state), GFP_KERNEL); | ||
716 | |||
717 | ci_dbg_print("%s\n", __func__); | ||
718 | |||
719 | if (!state) { | ||
720 | ret = -ENOMEM; | ||
721 | goto err; | ||
722 | } | ||
723 | |||
724 | if (temp_int != NULL) { | ||
725 | inter = temp_int->internal; | ||
726 | (inter->cis_used)++; | ||
727 | ci_dbg_print("%s: Find Internal Structure!\n", __func__); | ||
728 | } else { | ||
729 | inter = kzalloc(sizeof(struct fpga_internal), GFP_KERNEL); | ||
730 | if (!inter) { | ||
731 | ret = -ENOMEM; | ||
732 | goto err; | ||
733 | } | ||
734 | |||
735 | temp_int = append_internal(inter); | ||
736 | inter->cis_used = 1; | ||
737 | inter->dev = config->dev; | ||
738 | inter->fpga_rw = config->fpga_rw; | ||
739 | mutex_init(&inter->fpga_mutex); | ||
740 | inter->strt_wrk = 1; | ||
741 | ci_dbg_print("%s: Create New Internal Structure!\n", __func__); | ||
742 | } | ||
743 | |||
744 | ci_dbg_print("%s: setting state = %p for ci = %d\n", __func__, | ||
745 | state, ci_nr - 1); | ||
746 | inter->state[ci_nr - 1] = state; | ||
747 | state->internal = inter; | ||
748 | state->nr = ci_nr - 1; | ||
749 | |||
750 | state->ca.owner = THIS_MODULE; | ||
751 | state->ca.read_attribute_mem = altera_ci_read_attribute_mem; | ||
752 | state->ca.write_attribute_mem = altera_ci_write_attribute_mem; | ||
753 | state->ca.read_cam_control = altera_ci_read_cam_ctl; | ||
754 | state->ca.write_cam_control = altera_ci_write_cam_ctl; | ||
755 | state->ca.slot_reset = altera_ci_slot_reset; | ||
756 | state->ca.slot_shutdown = altera_ci_slot_shutdown; | ||
757 | state->ca.slot_ts_enable = altera_ci_slot_ts_ctl; | ||
758 | state->ca.poll_slot_status = altera_poll_ci_slot_status; | ||
759 | state->ca.data = state; | ||
760 | |||
761 | ret = dvb_ca_en50221_init(config->adapter, | ||
762 | &state->ca, | ||
763 | /* flags */ 0, | ||
764 | /* n_slots */ 1); | ||
765 | if (0 != ret) | ||
766 | goto err; | ||
767 | |||
768 | altera_hw_filt_init(config, ci_nr); | ||
769 | |||
770 | if (inter->strt_wrk) { | ||
771 | INIT_WORK(&inter->work, netup_read_ci_status); | ||
772 | inter->strt_wrk = 0; | ||
773 | } | ||
774 | |||
775 | ci_dbg_print("%s: CI initialized!\n", __func__); | ||
776 | |||
777 | mutex_lock(&inter->fpga_mutex); | ||
778 | |||
779 | /* Enable div */ | ||
780 | netup_fpga_op_rw(inter, NETUP_CI_TSA_DIV, 0x0, 0); | ||
781 | netup_fpga_op_rw(inter, NETUP_CI_TSB_DIV, 0x0, 0); | ||
782 | |||
783 | /* enable TS out */ | ||
784 | store = netup_fpga_op_rw(inter, NETUP_CI_BUSCTRL2, 0, NETUP_CI_FLG_RD); | ||
785 | store |= (3 << 4); | ||
786 | netup_fpga_op_rw(inter, NETUP_CI_BUSCTRL2, store, 0); | ||
787 | |||
788 | ret = netup_fpga_op_rw(inter, NETUP_CI_REVISION, 0, NETUP_CI_FLG_RD); | ||
789 | /* enable irq */ | ||
790 | netup_fpga_op_rw(inter, NETUP_CI_INT_CTRL, 0x44, 0); | ||
791 | |||
792 | mutex_unlock(&inter->fpga_mutex); | ||
793 | |||
794 | ci_dbg_print("%s: NetUP CI Revision = 0x%x\n", __func__, ret); | ||
795 | |||
796 | schedule_work(&inter->work); | ||
797 | |||
798 | return 0; | ||
799 | err: | ||
800 | ci_dbg_print("%s: Cannot initialize CI: Error %d.\n", __func__, ret); | ||
801 | |||
802 | kfree(state); | ||
803 | |||
804 | return ret; | ||
805 | } | ||
806 | EXPORT_SYMBOL(altera_ci_init); | ||
807 | |||
808 | int altera_ci_tuner_reset(void *dev, int ci_nr) | ||
809 | { | ||
810 | struct fpga_inode *temp_int = find_inode(dev); | ||
811 | struct fpga_internal *inter = NULL; | ||
812 | u8 store; | ||
813 | |||
814 | ci_dbg_print("%s\n", __func__); | ||
815 | |||
816 | if (temp_int == NULL) | ||
817 | return -1; | ||
818 | |||
819 | if (temp_int->internal == NULL) | ||
820 | return -1; | ||
821 | |||
822 | inter = temp_int->internal; | ||
823 | |||
824 | mutex_lock(&inter->fpga_mutex); | ||
825 | |||
826 | store = netup_fpga_op_rw(inter, NETUP_CI_BUSCTRL2, 0, NETUP_CI_FLG_RD); | ||
827 | store &= ~(4 << (2 - ci_nr)); | ||
828 | netup_fpga_op_rw(inter, NETUP_CI_BUSCTRL2, store, 0); | ||
829 | msleep(100); | ||
830 | store |= (4 << (2 - ci_nr)); | ||
831 | netup_fpga_op_rw(inter, NETUP_CI_BUSCTRL2, store, 0); | ||
832 | |||
833 | mutex_unlock(&inter->fpga_mutex); | ||
834 | |||
835 | return 0; | ||
836 | } | ||
837 | EXPORT_SYMBOL(altera_ci_tuner_reset); | ||
diff --git a/drivers/media/video/cx23885/altera-ci.h b/drivers/media/video/cx23885/altera-ci.h new file mode 100644 index 00000000000..70e4fd69ad9 --- /dev/null +++ b/drivers/media/video/cx23885/altera-ci.h | |||
@@ -0,0 +1,100 @@ | |||
1 | /* | ||
2 | * altera-ci.c | ||
3 | * | ||
4 | * CI driver in conjunction with NetUp Dual DVB-T/C RF CI card | ||
5 | * | ||
6 | * Copyright (C) 2010 NetUP Inc. | ||
7 | * Copyright (C) 2010 Igor M. Liplianin <liplianin@netup.ru> | ||
8 | * | ||
9 | * This program is free software; you can redistribute it and/or modify | ||
10 | * it under the terms of the GNU General Public License as published by | ||
11 | * the Free Software Foundation; either version 2 of the License, or | ||
12 | * (at your option) any later version. | ||
13 | * | ||
14 | * This program is distributed in the hope that it will be useful, | ||
15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
17 | * | ||
18 | * GNU General Public License for more details. | ||
19 | * | ||
20 | * You should have received a copy of the GNU General Public License | ||
21 | * along with this program; if not, write to the Free Software | ||
22 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
23 | */ | ||
24 | #ifndef __ALTERA_CI_H | ||
25 | #define __ALTERA_CI_H | ||
26 | |||
27 | #define ALT_DATA 0x000000ff | ||
28 | #define ALT_TDI 0x00008000 | ||
29 | #define ALT_TDO 0x00004000 | ||
30 | #define ALT_TCK 0x00002000 | ||
31 | #define ALT_RDY 0x00001000 | ||
32 | #define ALT_RD 0x00000800 | ||
33 | #define ALT_WR 0x00000400 | ||
34 | #define ALT_AD_RG 0x00000200 | ||
35 | #define ALT_CS 0x00000100 | ||
36 | |||
37 | struct altera_ci_config { | ||
38 | void *dev;/* main dev, for example cx23885_dev */ | ||
39 | void *adapter;/* for CI to connect to */ | ||
40 | struct dvb_demux *demux;/* for hardware PID filter to connect to */ | ||
41 | int (*fpga_rw) (void *dev, int ad_rg, int val, int rw); | ||
42 | }; | ||
43 | |||
44 | #if defined(CONFIG_MEDIA_ALTERA_CI) || (defined(CONFIG_MEDIA_ALTERA_CI_MODULE) \ | ||
45 | && defined(MODULE)) | ||
46 | |||
47 | extern int altera_ci_init(struct altera_ci_config *config, int ci_nr); | ||
48 | extern void altera_ci_release(void *dev, int ci_nr); | ||
49 | extern int altera_ci_irq(void *dev); | ||
50 | extern int altera_ci_tuner_reset(void *dev, int ci_nr); | ||
51 | |||
52 | #else | ||
53 | |||
54 | static inline int altera_ci_init(struct altera_ci_config *config, int ci_nr) | ||
55 | { | ||
56 | printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); | ||
57 | return 0; | ||
58 | } | ||
59 | |||
60 | static inline void altera_ci_release(void *dev, int ci_nr) | ||
61 | { | ||
62 | printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); | ||
63 | } | ||
64 | |||
65 | static inline int altera_ci_irq(void *dev) | ||
66 | { | ||
67 | printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); | ||
68 | return 0; | ||
69 | } | ||
70 | |||
71 | static inline int altera_ci_tuner_reset(void *dev, int ci_nr) | ||
72 | { | ||
73 | printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); | ||
74 | return 0; | ||
75 | } | ||
76 | |||
77 | #endif | ||
78 | #if 0 | ||
79 | static inline int altera_hw_filt_init(struct altera_ci_config *config, | ||
80 | int hw_filt_nr) | ||
81 | { | ||
82 | printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); | ||
83 | return 0; | ||
84 | } | ||
85 | |||
86 | static inline void altera_hw_filt_release(void *dev, int filt_nr) | ||
87 | { | ||
88 | printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); | ||
89 | } | ||
90 | |||
91 | static inline int altera_pid_feed_control(void *dev, int filt_nr, | ||
92 | struct dvb_demux_feed *dvbdmxfeed, int onoff) | ||
93 | { | ||
94 | printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); | ||
95 | return 0; | ||
96 | } | ||
97 | |||
98 | #endif /* CONFIG_MEDIA_ALTERA_CI */ | ||
99 | |||
100 | #endif /* __ALTERA_CI_H */ | ||
diff --git a/drivers/media/video/cx23885/cimax2.c b/drivers/media/video/cx23885/cimax2.c new file mode 100644 index 00000000000..c9f15d6dec4 --- /dev/null +++ b/drivers/media/video/cx23885/cimax2.c | |||
@@ -0,0 +1,536 @@ | |||
1 | /* | ||
2 | * cimax2.c | ||
3 | * | ||
4 | * CIMax2(R) SP2 driver in conjunction with NetUp Dual DVB-S2 CI card | ||
5 | * | ||
6 | * Copyright (C) 2009 NetUP Inc. | ||
7 | * Copyright (C) 2009 Igor M. Liplianin <liplianin@netup.ru> | ||
8 | * Copyright (C) 2009 Abylay Ospan <aospan@netup.ru> | ||
9 | * | ||
10 | * This program is free software; you can redistribute it and/or modify | ||
11 | * it under the terms of the GNU General Public License as published by | ||
12 | * the Free Software Foundation; either version 2 of the License, or | ||
13 | * (at your option) any later version. | ||
14 | * | ||
15 | * This program is distributed in the hope that it will be useful, | ||
16 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
17 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
18 | * | ||
19 | * GNU General Public License for more details. | ||
20 | * | ||
21 | * You should have received a copy of the GNU General Public License | ||
22 | * along with this program; if not, write to the Free Software | ||
23 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
24 | */ | ||
25 | |||
26 | #include "cx23885.h" | ||
27 | #include "dvb_ca_en50221.h" | ||
28 | /**** Bit definitions for MC417_RWD and MC417_OEN registers *** | ||
29 | bits 31-16 | ||
30 | +-----------+ | ||
31 | | Reserved | | ||
32 | +-----------+ | ||
33 | bit 15 bit 14 bit 13 bit 12 bit 11 bit 10 bit 9 bit 8 | ||
34 | +-------+-------+-------+-------+-------+-------+-------+-------+ | ||
35 | | WR# | RD# | | ACK# | ADHI | ADLO | CS1# | CS0# | | ||
36 | +-------+-------+-------+-------+-------+-------+-------+-------+ | ||
37 | bit 7 bit 6 bit 5 bit 4 bit 3 bit 2 bit 1 bit 0 | ||
38 | +-------+-------+-------+-------+-------+-------+-------+-------+ | ||
39 | | DATA7| DATA6| DATA5| DATA4| DATA3| DATA2| DATA1| DATA0| | ||
40 | +-------+-------+-------+-------+-------+-------+-------+-------+ | ||
41 | ***/ | ||
42 | /* MC417 */ | ||
43 | #define NETUP_DATA 0x000000ff | ||
44 | #define NETUP_WR 0x00008000 | ||
45 | #define NETUP_RD 0x00004000 | ||
46 | #define NETUP_ACK 0x00001000 | ||
47 | #define NETUP_ADHI 0x00000800 | ||
48 | #define NETUP_ADLO 0x00000400 | ||
49 | #define NETUP_CS1 0x00000200 | ||
50 | #define NETUP_CS0 0x00000100 | ||
51 | #define NETUP_EN_ALL 0x00001000 | ||
52 | #define NETUP_CTRL_OFF (NETUP_CS1 | NETUP_CS0 | NETUP_WR | NETUP_RD) | ||
53 | #define NETUP_CI_CTL 0x04 | ||
54 | #define NETUP_CI_RD 1 | ||
55 | |||
56 | #define NETUP_IRQ_DETAM 0x1 | ||
57 | #define NETUP_IRQ_IRQAM 0x4 | ||
58 | |||
59 | static unsigned int ci_dbg; | ||
60 | module_param(ci_dbg, int, 0644); | ||
61 | MODULE_PARM_DESC(ci_dbg, "Enable CI debugging"); | ||
62 | |||
63 | static unsigned int ci_irq_enable; | ||
64 | module_param(ci_irq_enable, int, 0644); | ||
65 | MODULE_PARM_DESC(ci_irq_enable, "Enable IRQ from CAM"); | ||
66 | |||
67 | #define ci_dbg_print(args...) \ | ||
68 | do { \ | ||
69 | if (ci_dbg) \ | ||
70 | printk(KERN_DEBUG args); \ | ||
71 | } while (0) | ||
72 | |||
73 | #define ci_irq_flags() (ci_irq_enable ? NETUP_IRQ_IRQAM : 0) | ||
74 | |||
75 | /* stores all private variables for communication with CI */ | ||
76 | struct netup_ci_state { | ||
77 | struct dvb_ca_en50221 ca; | ||
78 | struct mutex ca_mutex; | ||
79 | struct i2c_adapter *i2c_adap; | ||
80 | u8 ci_i2c_addr; | ||
81 | int status; | ||
82 | struct work_struct work; | ||
83 | void *priv; | ||
84 | u8 current_irq_mode; | ||
85 | int current_ci_flag; | ||
86 | unsigned long next_status_checked_time; | ||
87 | }; | ||
88 | |||
89 | |||
90 | int netup_read_i2c(struct i2c_adapter *i2c_adap, u8 addr, u8 reg, | ||
91 | u8 *buf, int len) | ||
92 | { | ||
93 | int ret; | ||
94 | struct i2c_msg msg[] = { | ||
95 | { | ||
96 | .addr = addr, | ||
97 | .flags = 0, | ||
98 | .buf = ®, | ||
99 | .len = 1 | ||
100 | }, { | ||
101 | .addr = addr, | ||
102 | .flags = I2C_M_RD, | ||
103 | .buf = buf, | ||
104 | .len = len | ||
105 | } | ||
106 | }; | ||
107 | |||
108 | ret = i2c_transfer(i2c_adap, msg, 2); | ||
109 | |||
110 | if (ret != 2) { | ||
111 | ci_dbg_print("%s: i2c read error, Reg = 0x%02x, Status = %d\n", | ||
112 | __func__, reg, ret); | ||
113 | |||
114 | return -1; | ||
115 | } | ||
116 | |||
117 | ci_dbg_print("%s: i2c read Addr=0x%04x, Reg = 0x%02x, data = %02x\n", | ||
118 | __func__, addr, reg, buf[0]); | ||
119 | |||
120 | return 0; | ||
121 | } | ||
122 | |||
123 | int netup_write_i2c(struct i2c_adapter *i2c_adap, u8 addr, u8 reg, | ||
124 | u8 *buf, int len) | ||
125 | { | ||
126 | int ret; | ||
127 | u8 buffer[len + 1]; | ||
128 | |||
129 | struct i2c_msg msg = { | ||
130 | .addr = addr, | ||
131 | .flags = 0, | ||
132 | .buf = &buffer[0], | ||
133 | .len = len + 1 | ||
134 | }; | ||
135 | |||
136 | buffer[0] = reg; | ||
137 | memcpy(&buffer[1], buf, len); | ||
138 | |||
139 | ret = i2c_transfer(i2c_adap, &msg, 1); | ||
140 | |||
141 | if (ret != 1) { | ||
142 | ci_dbg_print("%s: i2c write error, Reg=[0x%02x], Status=%d\n", | ||
143 | __func__, reg, ret); | ||
144 | return -1; | ||
145 | } | ||
146 | |||
147 | return 0; | ||
148 | } | ||
149 | |||
150 | int netup_ci_get_mem(struct cx23885_dev *dev) | ||
151 | { | ||
152 | int mem; | ||
153 | unsigned long timeout = jiffies + msecs_to_jiffies(1); | ||
154 | |||
155 | for (;;) { | ||
156 | mem = cx_read(MC417_RWD); | ||
157 | if ((mem & NETUP_ACK) == 0) | ||
158 | break; | ||
159 | if (time_after(jiffies, timeout)) | ||
160 | break; | ||
161 | udelay(1); | ||
162 | } | ||
163 | |||
164 | cx_set(MC417_RWD, NETUP_CTRL_OFF); | ||
165 | |||
166 | return mem & 0xff; | ||
167 | } | ||
168 | |||
169 | int netup_ci_op_cam(struct dvb_ca_en50221 *en50221, int slot, | ||
170 | u8 flag, u8 read, int addr, u8 data) | ||
171 | { | ||
172 | struct netup_ci_state *state = en50221->data; | ||
173 | struct cx23885_tsport *port = state->priv; | ||
174 | struct cx23885_dev *dev = port->dev; | ||
175 | |||
176 | u8 store; | ||
177 | int mem; | ||
178 | int ret; | ||
179 | |||
180 | if (0 != slot) | ||
181 | return -EINVAL; | ||
182 | |||
183 | if (state->current_ci_flag != flag) { | ||
184 | ret = netup_read_i2c(state->i2c_adap, state->ci_i2c_addr, | ||
185 | 0, &store, 1); | ||
186 | if (ret != 0) | ||
187 | return ret; | ||
188 | |||
189 | store &= ~0x0c; | ||
190 | store |= flag; | ||
191 | |||
192 | ret = netup_write_i2c(state->i2c_adap, state->ci_i2c_addr, | ||
193 | 0, &store, 1); | ||
194 | if (ret != 0) | ||
195 | return ret; | ||
196 | }; | ||
197 | state->current_ci_flag = flag; | ||
198 | |||
199 | mutex_lock(&dev->gpio_lock); | ||
200 | |||
201 | /* write addr */ | ||
202 | cx_write(MC417_OEN, NETUP_EN_ALL); | ||
203 | cx_write(MC417_RWD, NETUP_CTRL_OFF | | ||
204 | NETUP_ADLO | (0xff & addr)); | ||
205 | cx_clear(MC417_RWD, NETUP_ADLO); | ||
206 | cx_write(MC417_RWD, NETUP_CTRL_OFF | | ||
207 | NETUP_ADHI | (0xff & (addr >> 8))); | ||
208 | cx_clear(MC417_RWD, NETUP_ADHI); | ||
209 | |||
210 | if (read) { /* data in */ | ||
211 | cx_write(MC417_OEN, NETUP_EN_ALL | NETUP_DATA); | ||
212 | } else /* data out */ | ||
213 | cx_write(MC417_RWD, NETUP_CTRL_OFF | data); | ||
214 | |||
215 | /* choose chip */ | ||
216 | cx_clear(MC417_RWD, | ||
217 | (state->ci_i2c_addr == 0x40) ? NETUP_CS0 : NETUP_CS1); | ||
218 | /* read/write */ | ||
219 | cx_clear(MC417_RWD, (read) ? NETUP_RD : NETUP_WR); | ||
220 | mem = netup_ci_get_mem(dev); | ||
221 | |||
222 | mutex_unlock(&dev->gpio_lock); | ||
223 | |||
224 | if (!read) | ||
225 | if (mem < 0) | ||
226 | return -EREMOTEIO; | ||
227 | |||
228 | ci_dbg_print("%s: %s: chipaddr=[0x%x] addr=[0x%02x], %s=%x\n", __func__, | ||
229 | (read) ? "read" : "write", state->ci_i2c_addr, addr, | ||
230 | (flag == NETUP_CI_CTL) ? "ctl" : "mem", | ||
231 | (read) ? mem : data); | ||
232 | |||
233 | if (read) | ||
234 | return mem; | ||
235 | |||
236 | return 0; | ||
237 | } | ||
238 | |||
239 | int netup_ci_read_attribute_mem(struct dvb_ca_en50221 *en50221, | ||
240 | int slot, int addr) | ||
241 | { | ||
242 | return netup_ci_op_cam(en50221, slot, 0, NETUP_CI_RD, addr, 0); | ||
243 | } | ||
244 | |||
245 | int netup_ci_write_attribute_mem(struct dvb_ca_en50221 *en50221, | ||
246 | int slot, int addr, u8 data) | ||
247 | { | ||
248 | return netup_ci_op_cam(en50221, slot, 0, 0, addr, data); | ||
249 | } | ||
250 | |||
251 | int netup_ci_read_cam_ctl(struct dvb_ca_en50221 *en50221, int slot, u8 addr) | ||
252 | { | ||
253 | return netup_ci_op_cam(en50221, slot, NETUP_CI_CTL, | ||
254 | NETUP_CI_RD, addr, 0); | ||
255 | } | ||
256 | |||
257 | int netup_ci_write_cam_ctl(struct dvb_ca_en50221 *en50221, int slot, | ||
258 | u8 addr, u8 data) | ||
259 | { | ||
260 | return netup_ci_op_cam(en50221, slot, NETUP_CI_CTL, 0, addr, data); | ||
261 | } | ||
262 | |||
263 | int netup_ci_slot_reset(struct dvb_ca_en50221 *en50221, int slot) | ||
264 | { | ||
265 | struct netup_ci_state *state = en50221->data; | ||
266 | u8 buf = 0x80; | ||
267 | int ret; | ||
268 | |||
269 | if (0 != slot) | ||
270 | return -EINVAL; | ||
271 | |||
272 | udelay(500); | ||
273 | ret = netup_write_i2c(state->i2c_adap, state->ci_i2c_addr, | ||
274 | 0, &buf, 1); | ||
275 | |||
276 | if (ret != 0) | ||
277 | return ret; | ||
278 | |||
279 | udelay(500); | ||
280 | |||
281 | buf = 0x00; | ||
282 | ret = netup_write_i2c(state->i2c_adap, state->ci_i2c_addr, | ||
283 | 0, &buf, 1); | ||
284 | |||
285 | msleep(1000); | ||
286 | dvb_ca_en50221_camready_irq(&state->ca, 0); | ||
287 | |||
288 | return 0; | ||
289 | |||
290 | } | ||
291 | |||
292 | int netup_ci_slot_shutdown(struct dvb_ca_en50221 *en50221, int slot) | ||
293 | { | ||
294 | /* not implemented */ | ||
295 | return 0; | ||
296 | } | ||
297 | |||
298 | int netup_ci_set_irq(struct dvb_ca_en50221 *en50221, u8 irq_mode) | ||
299 | { | ||
300 | struct netup_ci_state *state = en50221->data; | ||
301 | int ret; | ||
302 | |||
303 | if (irq_mode == state->current_irq_mode) | ||
304 | return 0; | ||
305 | |||
306 | ci_dbg_print("%s: chipaddr=[0x%x] setting ci IRQ to [0x%x] \n", | ||
307 | __func__, state->ci_i2c_addr, irq_mode); | ||
308 | ret = netup_write_i2c(state->i2c_adap, state->ci_i2c_addr, | ||
309 | 0x1b, &irq_mode, 1); | ||
310 | |||
311 | if (ret != 0) | ||
312 | return ret; | ||
313 | |||
314 | state->current_irq_mode = irq_mode; | ||
315 | |||
316 | return 0; | ||
317 | } | ||
318 | |||
319 | int netup_ci_slot_ts_ctl(struct dvb_ca_en50221 *en50221, int slot) | ||
320 | { | ||
321 | struct netup_ci_state *state = en50221->data; | ||
322 | u8 buf; | ||
323 | |||
324 | if (0 != slot) | ||
325 | return -EINVAL; | ||
326 | |||
327 | netup_read_i2c(state->i2c_adap, state->ci_i2c_addr, | ||
328 | 0, &buf, 1); | ||
329 | buf |= 0x60; | ||
330 | |||
331 | return netup_write_i2c(state->i2c_adap, state->ci_i2c_addr, | ||
332 | 0, &buf, 1); | ||
333 | } | ||
334 | |||
335 | /* work handler */ | ||
336 | static void netup_read_ci_status(struct work_struct *work) | ||
337 | { | ||
338 | struct netup_ci_state *state = | ||
339 | container_of(work, struct netup_ci_state, work); | ||
340 | u8 buf[33]; | ||
341 | int ret; | ||
342 | |||
343 | /* CAM module IRQ processing. fast operation */ | ||
344 | dvb_ca_en50221_frda_irq(&state->ca, 0); | ||
345 | |||
346 | /* CAM module INSERT/REMOVE processing. slow operation because of i2c | ||
347 | * transfers */ | ||
348 | if (time_after(jiffies, state->next_status_checked_time) | ||
349 | || !state->status) { | ||
350 | ret = netup_read_i2c(state->i2c_adap, state->ci_i2c_addr, | ||
351 | 0, &buf[0], 33); | ||
352 | |||
353 | state->next_status_checked_time = jiffies | ||
354 | + msecs_to_jiffies(1000); | ||
355 | |||
356 | if (ret != 0) | ||
357 | return; | ||
358 | |||
359 | ci_dbg_print("%s: Slot Status Addr=[0x%04x], " | ||
360 | "Reg=[0x%02x], data=%02x, " | ||
361 | "TS config = %02x\n", __func__, | ||
362 | state->ci_i2c_addr, 0, buf[0], | ||
363 | buf[0]); | ||
364 | |||
365 | |||
366 | if (buf[0] & 1) | ||
367 | state->status = DVB_CA_EN50221_POLL_CAM_PRESENT | | ||
368 | DVB_CA_EN50221_POLL_CAM_READY; | ||
369 | else | ||
370 | state->status = 0; | ||
371 | } | ||
372 | } | ||
373 | |||
374 | /* CI irq handler */ | ||
375 | int netup_ci_slot_status(struct cx23885_dev *dev, u32 pci_status) | ||
376 | { | ||
377 | struct cx23885_tsport *port = NULL; | ||
378 | struct netup_ci_state *state = NULL; | ||
379 | |||
380 | ci_dbg_print("%s:\n", __func__); | ||
381 | |||
382 | if (0 == (pci_status & (PCI_MSK_GPIO0 | PCI_MSK_GPIO1))) | ||
383 | return 0; | ||
384 | |||
385 | if (pci_status & PCI_MSK_GPIO0) { | ||
386 | port = &dev->ts1; | ||
387 | state = port->port_priv; | ||
388 | schedule_work(&state->work); | ||
389 | ci_dbg_print("%s: Wakeup CI0\n", __func__); | ||
390 | } | ||
391 | |||
392 | if (pci_status & PCI_MSK_GPIO1) { | ||
393 | port = &dev->ts2; | ||
394 | state = port->port_priv; | ||
395 | schedule_work(&state->work); | ||
396 | ci_dbg_print("%s: Wakeup CI1\n", __func__); | ||
397 | } | ||
398 | |||
399 | return 1; | ||
400 | } | ||
401 | |||
402 | int netup_poll_ci_slot_status(struct dvb_ca_en50221 *en50221, int slot, int open) | ||
403 | { | ||
404 | struct netup_ci_state *state = en50221->data; | ||
405 | |||
406 | if (0 != slot) | ||
407 | return -EINVAL; | ||
408 | |||
409 | netup_ci_set_irq(en50221, open ? (NETUP_IRQ_DETAM | ci_irq_flags()) | ||
410 | : NETUP_IRQ_DETAM); | ||
411 | |||
412 | return state->status; | ||
413 | } | ||
414 | |||
415 | int netup_ci_init(struct cx23885_tsport *port) | ||
416 | { | ||
417 | struct netup_ci_state *state; | ||
418 | u8 cimax_init[34] = { | ||
419 | 0x00, /* module A control*/ | ||
420 | 0x00, /* auto select mask high A */ | ||
421 | 0x00, /* auto select mask low A */ | ||
422 | 0x00, /* auto select pattern high A */ | ||
423 | 0x00, /* auto select pattern low A */ | ||
424 | 0x44, /* memory access time A */ | ||
425 | 0x00, /* invert input A */ | ||
426 | 0x00, /* RFU */ | ||
427 | 0x00, /* RFU */ | ||
428 | 0x00, /* module B control*/ | ||
429 | 0x00, /* auto select mask high B */ | ||
430 | 0x00, /* auto select mask low B */ | ||
431 | 0x00, /* auto select pattern high B */ | ||
432 | 0x00, /* auto select pattern low B */ | ||
433 | 0x44, /* memory access time B */ | ||
434 | 0x00, /* invert input B */ | ||
435 | 0x00, /* RFU */ | ||
436 | 0x00, /* RFU */ | ||
437 | 0x00, /* auto select mask high Ext */ | ||
438 | 0x00, /* auto select mask low Ext */ | ||
439 | 0x00, /* auto select pattern high Ext */ | ||
440 | 0x00, /* auto select pattern low Ext */ | ||
441 | 0x00, /* RFU */ | ||
442 | 0x02, /* destination - module A */ | ||
443 | 0x01, /* power on (use it like store place) */ | ||
444 | 0x00, /* RFU */ | ||
445 | 0x00, /* int status read only */ | ||
446 | ci_irq_flags() | NETUP_IRQ_DETAM, /* DETAM, IRQAM unmasked */ | ||
447 | 0x05, /* EXTINT=active-high, INT=push-pull */ | ||
448 | 0x00, /* USCG1 */ | ||
449 | 0x04, /* ack active low */ | ||
450 | 0x00, /* LOCK = 0 */ | ||
451 | 0x33, /* serial mode, rising in, rising out, MSB first*/ | ||
452 | 0x31, /* synchronization */ | ||
453 | }; | ||
454 | int ret; | ||
455 | |||
456 | ci_dbg_print("%s\n", __func__); | ||
457 | state = kzalloc(sizeof(struct netup_ci_state), GFP_KERNEL); | ||
458 | if (!state) { | ||
459 | ci_dbg_print("%s: Unable create CI structure!\n", __func__); | ||
460 | ret = -ENOMEM; | ||
461 | goto err; | ||
462 | } | ||
463 | |||
464 | port->port_priv = state; | ||
465 | |||
466 | switch (port->nr) { | ||
467 | case 1: | ||
468 | state->ci_i2c_addr = 0x40; | ||
469 | break; | ||
470 | case 2: | ||
471 | state->ci_i2c_addr = 0x41; | ||
472 | break; | ||
473 | } | ||
474 | |||
475 | state->i2c_adap = &port->dev->i2c_bus[0].i2c_adap; | ||
476 | state->ca.owner = THIS_MODULE; | ||
477 | state->ca.read_attribute_mem = netup_ci_read_attribute_mem; | ||
478 | state->ca.write_attribute_mem = netup_ci_write_attribute_mem; | ||
479 | state->ca.read_cam_control = netup_ci_read_cam_ctl; | ||
480 | state->ca.write_cam_control = netup_ci_write_cam_ctl; | ||
481 | state->ca.slot_reset = netup_ci_slot_reset; | ||
482 | state->ca.slot_shutdown = netup_ci_slot_shutdown; | ||
483 | state->ca.slot_ts_enable = netup_ci_slot_ts_ctl; | ||
484 | state->ca.poll_slot_status = netup_poll_ci_slot_status; | ||
485 | state->ca.data = state; | ||
486 | state->priv = port; | ||
487 | state->current_irq_mode = ci_irq_flags() | NETUP_IRQ_DETAM; | ||
488 | |||
489 | ret = netup_write_i2c(state->i2c_adap, state->ci_i2c_addr, | ||
490 | 0, &cimax_init[0], 34); | ||
491 | /* lock registers */ | ||
492 | ret |= netup_write_i2c(state->i2c_adap, state->ci_i2c_addr, | ||
493 | 0x1f, &cimax_init[0x18], 1); | ||
494 | /* power on slots */ | ||
495 | ret |= netup_write_i2c(state->i2c_adap, state->ci_i2c_addr, | ||
496 | 0x18, &cimax_init[0x18], 1); | ||
497 | |||
498 | if (0 != ret) | ||
499 | goto err; | ||
500 | |||
501 | ret = dvb_ca_en50221_init(&port->frontends.adapter, | ||
502 | &state->ca, | ||
503 | /* flags */ 0, | ||
504 | /* n_slots */ 1); | ||
505 | if (0 != ret) | ||
506 | goto err; | ||
507 | |||
508 | INIT_WORK(&state->work, netup_read_ci_status); | ||
509 | schedule_work(&state->work); | ||
510 | |||
511 | ci_dbg_print("%s: CI initialized!\n", __func__); | ||
512 | |||
513 | return 0; | ||
514 | err: | ||
515 | ci_dbg_print("%s: Cannot initialize CI: Error %d.\n", __func__, ret); | ||
516 | kfree(state); | ||
517 | return ret; | ||
518 | } | ||
519 | |||
520 | void netup_ci_exit(struct cx23885_tsport *port) | ||
521 | { | ||
522 | struct netup_ci_state *state; | ||
523 | |||
524 | if (NULL == port) | ||
525 | return; | ||
526 | |||
527 | state = (struct netup_ci_state *)port->port_priv; | ||
528 | if (NULL == state) | ||
529 | return; | ||
530 | |||
531 | if (NULL == state->ca.data) | ||
532 | return; | ||
533 | |||
534 | dvb_ca_en50221_release(&state->ca); | ||
535 | kfree(state); | ||
536 | } | ||
diff --git a/drivers/media/video/cx23885/cimax2.h b/drivers/media/video/cx23885/cimax2.h new file mode 100644 index 00000000000..518744a4c8a --- /dev/null +++ b/drivers/media/video/cx23885/cimax2.h | |||
@@ -0,0 +1,47 @@ | |||
1 | /* | ||
2 | * cimax2.h | ||
3 | * | ||
4 | * CIMax(R) SP2 driver in conjunction with NetUp Dual DVB-S2 CI card | ||
5 | * | ||
6 | * Copyright (C) 2009 NetUP Inc. | ||
7 | * Copyright (C) 2009 Igor M. Liplianin <liplianin@netup.ru> | ||
8 | * Copyright (C) 2009 Abylay Ospan <aospan@netup.ru> | ||
9 | * | ||
10 | * This program is free software; you can redistribute it and/or modify | ||
11 | * it under the terms of the GNU General Public License as published by | ||
12 | * the Free Software Foundation; either version 2 of the License, or | ||
13 | * (at your option) any later version. | ||
14 | * | ||
15 | * This program is distributed in the hope that it will be useful, | ||
16 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
17 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
18 | * | ||
19 | * GNU General Public License for more details. | ||
20 | * | ||
21 | * You should have received a copy of the GNU General Public License | ||
22 | * along with this program; if not, write to the Free Software | ||
23 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
24 | */ | ||
25 | |||
26 | #ifndef CIMAX2_H | ||
27 | #define CIMAX2_H | ||
28 | #include "dvb_ca_en50221.h" | ||
29 | |||
30 | extern int netup_ci_read_attribute_mem(struct dvb_ca_en50221 *en50221, | ||
31 | int slot, int addr); | ||
32 | extern int netup_ci_write_attribute_mem(struct dvb_ca_en50221 *en50221, | ||
33 | int slot, int addr, u8 data); | ||
34 | extern int netup_ci_read_cam_ctl(struct dvb_ca_en50221 *en50221, | ||
35 | int slot, u8 addr); | ||
36 | extern int netup_ci_write_cam_ctl(struct dvb_ca_en50221 *en50221, | ||
37 | int slot, u8 addr, u8 data); | ||
38 | extern int netup_ci_slot_reset(struct dvb_ca_en50221 *en50221, int slot); | ||
39 | extern int netup_ci_slot_shutdown(struct dvb_ca_en50221 *en50221, int slot); | ||
40 | extern int netup_ci_slot_ts_ctl(struct dvb_ca_en50221 *en50221, int slot); | ||
41 | extern int netup_ci_slot_status(struct cx23885_dev *dev, u32 pci_status); | ||
42 | extern int netup_poll_ci_slot_status(struct dvb_ca_en50221 *en50221, | ||
43 | int slot, int open); | ||
44 | extern int netup_ci_init(struct cx23885_tsport *port); | ||
45 | extern void netup_ci_exit(struct cx23885_tsport *port); | ||
46 | |||
47 | #endif | ||
diff --git a/drivers/media/video/cx23885/cx23885-417.c b/drivers/media/video/cx23885/cx23885-417.c new file mode 100644 index 00000000000..67c4a59bd88 --- /dev/null +++ b/drivers/media/video/cx23885/cx23885-417.c | |||
@@ -0,0 +1,1795 @@ | |||
1 | /* | ||
2 | * | ||
3 | * Support for a cx23417 mpeg encoder via cx23885 host port. | ||
4 | * | ||
5 | * (c) 2004 Jelle Foks <jelle@foks.us> | ||
6 | * (c) 2004 Gerd Knorr <kraxel@bytesex.org> | ||
7 | * (c) 2008 Steven Toth <stoth@linuxtv.org> | ||
8 | * - CX23885/7/8 support | ||
9 | * | ||
10 | * Includes parts from the ivtv driver <http://sourceforge.net/projects/ivtv/> | ||
11 | * | ||
12 | * This program is free software; you can redistribute it and/or modify | ||
13 | * it under the terms of the GNU General Public License as published by | ||
14 | * the Free Software Foundation; either version 2 of the License, or | ||
15 | * (at your option) any later version. | ||
16 | * | ||
17 | * This program is distributed in the hope that it will be useful, | ||
18 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
19 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
20 | * GNU General Public License for more details. | ||
21 | * | ||
22 | * You should have received a copy of the GNU General Public License | ||
23 | * along with this program; if not, write to the Free Software | ||
24 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
25 | */ | ||
26 | |||
27 | #include <linux/module.h> | ||
28 | #include <linux/moduleparam.h> | ||
29 | #include <linux/init.h> | ||
30 | #include <linux/fs.h> | ||
31 | #include <linux/delay.h> | ||
32 | #include <linux/device.h> | ||
33 | #include <linux/firmware.h> | ||
34 | #include <linux/slab.h> | ||
35 | #include <media/v4l2-common.h> | ||
36 | #include <media/v4l2-ioctl.h> | ||
37 | #include <media/cx2341x.h> | ||
38 | |||
39 | #include "cx23885.h" | ||
40 | #include "cx23885-ioctl.h" | ||
41 | |||
42 | #define CX23885_FIRM_IMAGE_SIZE 376836 | ||
43 | #define CX23885_FIRM_IMAGE_NAME "v4l-cx23885-enc.fw" | ||
44 | |||
45 | static unsigned int mpegbufs = 32; | ||
46 | module_param(mpegbufs, int, 0644); | ||
47 | MODULE_PARM_DESC(mpegbufs, "number of mpeg buffers, range 2-32"); | ||
48 | static unsigned int mpeglines = 32; | ||
49 | module_param(mpeglines, int, 0644); | ||
50 | MODULE_PARM_DESC(mpeglines, "number of lines in an MPEG buffer, range 2-32"); | ||
51 | static unsigned int mpeglinesize = 512; | ||
52 | module_param(mpeglinesize, int, 0644); | ||
53 | MODULE_PARM_DESC(mpeglinesize, | ||
54 | "number of bytes in each line of an MPEG buffer, range 512-1024"); | ||
55 | |||
56 | static unsigned int v4l_debug; | ||
57 | module_param(v4l_debug, int, 0644); | ||
58 | MODULE_PARM_DESC(v4l_debug, "enable V4L debug messages"); | ||
59 | |||
60 | #define dprintk(level, fmt, arg...)\ | ||
61 | do { if (v4l_debug >= level) \ | ||
62 | printk(KERN_DEBUG "%s: " fmt, \ | ||
63 | (dev) ? dev->name : "cx23885[?]", ## arg); \ | ||
64 | } while (0) | ||
65 | |||
66 | static struct cx23885_tvnorm cx23885_tvnorms[] = { | ||
67 | { | ||
68 | .name = "NTSC-M", | ||
69 | .id = V4L2_STD_NTSC_M, | ||
70 | }, { | ||
71 | .name = "NTSC-JP", | ||
72 | .id = V4L2_STD_NTSC_M_JP, | ||
73 | }, { | ||
74 | .name = "PAL-BG", | ||
75 | .id = V4L2_STD_PAL_BG, | ||
76 | }, { | ||
77 | .name = "PAL-DK", | ||
78 | .id = V4L2_STD_PAL_DK, | ||
79 | }, { | ||
80 | .name = "PAL-I", | ||
81 | .id = V4L2_STD_PAL_I, | ||
82 | }, { | ||
83 | .name = "PAL-M", | ||
84 | .id = V4L2_STD_PAL_M, | ||
85 | }, { | ||
86 | .name = "PAL-N", | ||
87 | .id = V4L2_STD_PAL_N, | ||
88 | }, { | ||
89 | .name = "PAL-Nc", | ||
90 | .id = V4L2_STD_PAL_Nc, | ||
91 | }, { | ||
92 | .name = "PAL-60", | ||
93 | .id = V4L2_STD_PAL_60, | ||
94 | }, { | ||
95 | .name = "SECAM-L", | ||
96 | .id = V4L2_STD_SECAM_L, | ||
97 | }, { | ||
98 | .name = "SECAM-DK", | ||
99 | .id = V4L2_STD_SECAM_DK, | ||
100 | } | ||
101 | }; | ||
102 | |||
103 | /* ------------------------------------------------------------------ */ | ||
104 | enum cx23885_capture_type { | ||
105 | CX23885_MPEG_CAPTURE, | ||
106 | CX23885_RAW_CAPTURE, | ||
107 | CX23885_RAW_PASSTHRU_CAPTURE | ||
108 | }; | ||
109 | enum cx23885_capture_bits { | ||
110 | CX23885_RAW_BITS_NONE = 0x00, | ||
111 | CX23885_RAW_BITS_YUV_CAPTURE = 0x01, | ||
112 | CX23885_RAW_BITS_PCM_CAPTURE = 0x02, | ||
113 | CX23885_RAW_BITS_VBI_CAPTURE = 0x04, | ||
114 | CX23885_RAW_BITS_PASSTHRU_CAPTURE = 0x08, | ||
115 | CX23885_RAW_BITS_TO_HOST_CAPTURE = 0x10 | ||
116 | }; | ||
117 | enum cx23885_capture_end { | ||
118 | CX23885_END_AT_GOP, /* stop at the end of gop, generate irq */ | ||
119 | CX23885_END_NOW, /* stop immediately, no irq */ | ||
120 | }; | ||
121 | enum cx23885_framerate { | ||
122 | CX23885_FRAMERATE_NTSC_30, /* NTSC: 30fps */ | ||
123 | CX23885_FRAMERATE_PAL_25 /* PAL: 25fps */ | ||
124 | }; | ||
125 | enum cx23885_stream_port { | ||
126 | CX23885_OUTPUT_PORT_MEMORY, | ||
127 | CX23885_OUTPUT_PORT_STREAMING, | ||
128 | CX23885_OUTPUT_PORT_SERIAL | ||
129 | }; | ||
130 | enum cx23885_data_xfer_status { | ||
131 | CX23885_MORE_BUFFERS_FOLLOW, | ||
132 | CX23885_LAST_BUFFER, | ||
133 | }; | ||
134 | enum cx23885_picture_mask { | ||
135 | CX23885_PICTURE_MASK_NONE, | ||
136 | CX23885_PICTURE_MASK_I_FRAMES, | ||
137 | CX23885_PICTURE_MASK_I_P_FRAMES = 0x3, | ||
138 | CX23885_PICTURE_MASK_ALL_FRAMES = 0x7, | ||
139 | }; | ||
140 | enum cx23885_vbi_mode_bits { | ||
141 | CX23885_VBI_BITS_SLICED, | ||
142 | CX23885_VBI_BITS_RAW, | ||
143 | }; | ||
144 | enum cx23885_vbi_insertion_bits { | ||
145 | CX23885_VBI_BITS_INSERT_IN_XTENSION_USR_DATA, | ||
146 | CX23885_VBI_BITS_INSERT_IN_PRIVATE_PACKETS = 0x1 << 1, | ||
147 | CX23885_VBI_BITS_SEPARATE_STREAM = 0x2 << 1, | ||
148 | CX23885_VBI_BITS_SEPARATE_STREAM_USR_DATA = 0x4 << 1, | ||
149 | CX23885_VBI_BITS_SEPARATE_STREAM_PRV_DATA = 0x5 << 1, | ||
150 | }; | ||
151 | enum cx23885_dma_unit { | ||
152 | CX23885_DMA_BYTES, | ||
153 | CX23885_DMA_FRAMES, | ||
154 | }; | ||
155 | enum cx23885_dma_transfer_status_bits { | ||
156 | CX23885_DMA_TRANSFER_BITS_DONE = 0x01, | ||
157 | CX23885_DMA_TRANSFER_BITS_ERROR = 0x04, | ||
158 | CX23885_DMA_TRANSFER_BITS_LL_ERROR = 0x10, | ||
159 | }; | ||
160 | enum cx23885_pause { | ||
161 | CX23885_PAUSE_ENCODING, | ||
162 | CX23885_RESUME_ENCODING, | ||
163 | }; | ||
164 | enum cx23885_copyright { | ||
165 | CX23885_COPYRIGHT_OFF, | ||
166 | CX23885_COPYRIGHT_ON, | ||
167 | }; | ||
168 | enum cx23885_notification_type { | ||
169 | CX23885_NOTIFICATION_REFRESH, | ||
170 | }; | ||
171 | enum cx23885_notification_status { | ||
172 | CX23885_NOTIFICATION_OFF, | ||
173 | CX23885_NOTIFICATION_ON, | ||
174 | }; | ||
175 | enum cx23885_notification_mailbox { | ||
176 | CX23885_NOTIFICATION_NO_MAILBOX = -1, | ||
177 | }; | ||
178 | enum cx23885_field1_lines { | ||
179 | CX23885_FIELD1_SAA7114 = 0x00EF, /* 239 */ | ||
180 | CX23885_FIELD1_SAA7115 = 0x00F0, /* 240 */ | ||
181 | CX23885_FIELD1_MICRONAS = 0x0105, /* 261 */ | ||
182 | }; | ||
183 | enum cx23885_field2_lines { | ||
184 | CX23885_FIELD2_SAA7114 = 0x00EF, /* 239 */ | ||
185 | CX23885_FIELD2_SAA7115 = 0x00F0, /* 240 */ | ||
186 | CX23885_FIELD2_MICRONAS = 0x0106, /* 262 */ | ||
187 | }; | ||
188 | enum cx23885_custom_data_type { | ||
189 | CX23885_CUSTOM_EXTENSION_USR_DATA, | ||
190 | CX23885_CUSTOM_PRIVATE_PACKET, | ||
191 | }; | ||
192 | enum cx23885_mute { | ||
193 | CX23885_UNMUTE, | ||
194 | CX23885_MUTE, | ||
195 | }; | ||
196 | enum cx23885_mute_video_mask { | ||
197 | CX23885_MUTE_VIDEO_V_MASK = 0x0000FF00, | ||
198 | CX23885_MUTE_VIDEO_U_MASK = 0x00FF0000, | ||
199 | CX23885_MUTE_VIDEO_Y_MASK = 0xFF000000, | ||
200 | }; | ||
201 | enum cx23885_mute_video_shift { | ||
202 | CX23885_MUTE_VIDEO_V_SHIFT = 8, | ||
203 | CX23885_MUTE_VIDEO_U_SHIFT = 16, | ||
204 | CX23885_MUTE_VIDEO_Y_SHIFT = 24, | ||
205 | }; | ||
206 | |||
207 | /* defines below are from ivtv-driver.h */ | ||
208 | #define IVTV_CMD_HW_BLOCKS_RST 0xFFFFFFFF | ||
209 | |||
210 | /* Firmware API commands */ | ||
211 | #define IVTV_API_STD_TIMEOUT 500 | ||
212 | |||
213 | /* Registers */ | ||
214 | /* IVTV_REG_OFFSET */ | ||
215 | #define IVTV_REG_ENC_SDRAM_REFRESH (0x07F8) | ||
216 | #define IVTV_REG_ENC_SDRAM_PRECHARGE (0x07FC) | ||
217 | #define IVTV_REG_SPU (0x9050) | ||
218 | #define IVTV_REG_HW_BLOCKS (0x9054) | ||
219 | #define IVTV_REG_VPU (0x9058) | ||
220 | #define IVTV_REG_APU (0xA064) | ||
221 | |||
222 | /**** Bit definitions for MC417_RWD and MC417_OEN registers *** | ||
223 | bits 31-16 | ||
224 | +-----------+ | ||
225 | | Reserved | | ||
226 | +-----------+ | ||
227 | bit 15 bit 14 bit 13 bit 12 bit 11 bit 10 bit 9 bit 8 | ||
228 | +-------+-------+-------+-------+-------+-------+-------+-------+ | ||
229 | | MIWR# | MIRD# | MICS# |MIRDY# |MIADDR3|MIADDR2|MIADDR1|MIADDR0| | ||
230 | +-------+-------+-------+-------+-------+-------+-------+-------+ | ||
231 | bit 7 bit 6 bit 5 bit 4 bit 3 bit 2 bit 1 bit 0 | ||
232 | +-------+-------+-------+-------+-------+-------+-------+-------+ | ||
233 | |MIDATA7|MIDATA6|MIDATA5|MIDATA4|MIDATA3|MIDATA2|MIDATA1|MIDATA0| | ||
234 | +-------+-------+-------+-------+-------+-------+-------+-------+ | ||
235 | ***/ | ||
236 | #define MC417_MIWR 0x8000 | ||
237 | #define MC417_MIRD 0x4000 | ||
238 | #define MC417_MICS 0x2000 | ||
239 | #define MC417_MIRDY 0x1000 | ||
240 | #define MC417_MIADDR 0x0F00 | ||
241 | #define MC417_MIDATA 0x00FF | ||
242 | |||
243 | /* MIADDR* nibble definitions */ | ||
244 | #define MCI_MEMORY_DATA_BYTE0 0x000 | ||
245 | #define MCI_MEMORY_DATA_BYTE1 0x100 | ||
246 | #define MCI_MEMORY_DATA_BYTE2 0x200 | ||
247 | #define MCI_MEMORY_DATA_BYTE3 0x300 | ||
248 | #define MCI_MEMORY_ADDRESS_BYTE2 0x400 | ||
249 | #define MCI_MEMORY_ADDRESS_BYTE1 0x500 | ||
250 | #define MCI_MEMORY_ADDRESS_BYTE0 0x600 | ||
251 | #define MCI_REGISTER_DATA_BYTE0 0x800 | ||
252 | #define MCI_REGISTER_DATA_BYTE1 0x900 | ||
253 | #define MCI_REGISTER_DATA_BYTE2 0xA00 | ||
254 | #define MCI_REGISTER_DATA_BYTE3 0xB00 | ||
255 | #define MCI_REGISTER_ADDRESS_BYTE0 0xC00 | ||
256 | #define MCI_REGISTER_ADDRESS_BYTE1 0xD00 | ||
257 | #define MCI_REGISTER_MODE 0xE00 | ||
258 | |||
259 | /* Read and write modes */ | ||
260 | #define MCI_MODE_REGISTER_READ 0 | ||
261 | #define MCI_MODE_REGISTER_WRITE 1 | ||
262 | #define MCI_MODE_MEMORY_READ 0 | ||
263 | #define MCI_MODE_MEMORY_WRITE 0x40 | ||
264 | |||
265 | /*** Bit definitions for MC417_CTL register **** | ||
266 | bits 31-6 bits 5-4 bit 3 bits 2-1 Bit 0 | ||
267 | +--------+-------------+--------+--------------+------------+ | ||
268 | |Reserved|MC417_SPD_CTL|Reserved|MC417_GPIO_SEL|UART_GPIO_EN| | ||
269 | +--------+-------------+--------+--------------+------------+ | ||
270 | ***/ | ||
271 | #define MC417_SPD_CTL(x) (((x) << 4) & 0x00000030) | ||
272 | #define MC417_GPIO_SEL(x) (((x) << 1) & 0x00000006) | ||
273 | #define MC417_UART_GPIO_EN 0x00000001 | ||
274 | |||
275 | /* Values for speed control */ | ||
276 | #define MC417_SPD_CTL_SLOW 0x1 | ||
277 | #define MC417_SPD_CTL_MEDIUM 0x0 | ||
278 | #define MC417_SPD_CTL_FAST 0x3 /* b'1x, but we use b'11 */ | ||
279 | |||
280 | /* Values for GPIO select */ | ||
281 | #define MC417_GPIO_SEL_GPIO3 0x3 | ||
282 | #define MC417_GPIO_SEL_GPIO2 0x2 | ||
283 | #define MC417_GPIO_SEL_GPIO1 0x1 | ||
284 | #define MC417_GPIO_SEL_GPIO0 0x0 | ||
285 | |||
286 | void cx23885_mc417_init(struct cx23885_dev *dev) | ||
287 | { | ||
288 | u32 regval; | ||
289 | |||
290 | dprintk(2, "%s()\n", __func__); | ||
291 | |||
292 | /* Configure MC417_CTL register to defaults. */ | ||
293 | regval = MC417_SPD_CTL(MC417_SPD_CTL_FAST) | | ||
294 | MC417_GPIO_SEL(MC417_GPIO_SEL_GPIO3) | | ||
295 | MC417_UART_GPIO_EN; | ||
296 | cx_write(MC417_CTL, regval); | ||
297 | |||
298 | /* Configure MC417_OEN to defaults. */ | ||
299 | regval = MC417_MIRDY; | ||
300 | cx_write(MC417_OEN, regval); | ||
301 | |||
302 | /* Configure MC417_RWD to defaults. */ | ||
303 | regval = MC417_MIWR | MC417_MIRD | MC417_MICS; | ||
304 | cx_write(MC417_RWD, regval); | ||
305 | } | ||
306 | |||
307 | static int mc417_wait_ready(struct cx23885_dev *dev) | ||
308 | { | ||
309 | u32 mi_ready; | ||
310 | unsigned long timeout = jiffies + msecs_to_jiffies(1); | ||
311 | |||
312 | for (;;) { | ||
313 | mi_ready = cx_read(MC417_RWD) & MC417_MIRDY; | ||
314 | if (mi_ready != 0) | ||
315 | return 0; | ||
316 | if (time_after(jiffies, timeout)) | ||
317 | return -1; | ||
318 | udelay(1); | ||
319 | } | ||
320 | } | ||
321 | |||
322 | int mc417_register_write(struct cx23885_dev *dev, u16 address, u32 value) | ||
323 | { | ||
324 | u32 regval; | ||
325 | |||
326 | /* Enable MC417 GPIO outputs except for MC417_MIRDY, | ||
327 | * which is an input. | ||
328 | */ | ||
329 | cx_write(MC417_OEN, MC417_MIRDY); | ||
330 | |||
331 | /* Write data byte 0 */ | ||
332 | regval = MC417_MIRD | MC417_MIRDY | MCI_REGISTER_DATA_BYTE0 | | ||
333 | (value & 0x000000FF); | ||
334 | cx_write(MC417_RWD, regval); | ||
335 | |||
336 | /* Transition CS/WR to effect write transaction across bus. */ | ||
337 | regval |= MC417_MICS | MC417_MIWR; | ||
338 | cx_write(MC417_RWD, regval); | ||
339 | |||
340 | /* Write data byte 1 */ | ||
341 | regval = MC417_MIRD | MC417_MIRDY | MCI_REGISTER_DATA_BYTE1 | | ||
342 | ((value >> 8) & 0x000000FF); | ||
343 | cx_write(MC417_RWD, regval); | ||
344 | regval |= MC417_MICS | MC417_MIWR; | ||
345 | cx_write(MC417_RWD, regval); | ||
346 | |||
347 | /* Write data byte 2 */ | ||
348 | regval = MC417_MIRD | MC417_MIRDY | MCI_REGISTER_DATA_BYTE2 | | ||
349 | ((value >> 16) & 0x000000FF); | ||
350 | cx_write(MC417_RWD, regval); | ||
351 | regval |= MC417_MICS | MC417_MIWR; | ||
352 | cx_write(MC417_RWD, regval); | ||
353 | |||
354 | /* Write data byte 3 */ | ||
355 | regval = MC417_MIRD | MC417_MIRDY | MCI_REGISTER_DATA_BYTE3 | | ||
356 | ((value >> 24) & 0x000000FF); | ||
357 | cx_write(MC417_RWD, regval); | ||
358 | regval |= MC417_MICS | MC417_MIWR; | ||
359 | cx_write(MC417_RWD, regval); | ||
360 | |||
361 | /* Write address byte 0 */ | ||
362 | regval = MC417_MIRD | MC417_MIRDY | MCI_REGISTER_ADDRESS_BYTE0 | | ||
363 | (address & 0xFF); | ||
364 | cx_write(MC417_RWD, regval); | ||
365 | regval |= MC417_MICS | MC417_MIWR; | ||
366 | cx_write(MC417_RWD, regval); | ||
367 | |||
368 | /* Write address byte 1 */ | ||
369 | regval = MC417_MIRD | MC417_MIRDY | MCI_REGISTER_ADDRESS_BYTE1 | | ||
370 | ((address >> 8) & 0xFF); | ||
371 | cx_write(MC417_RWD, regval); | ||
372 | regval |= MC417_MICS | MC417_MIWR; | ||
373 | cx_write(MC417_RWD, regval); | ||
374 | |||
375 | /* Indicate that this is a write. */ | ||
376 | regval = MC417_MIRD | MC417_MIRDY | MCI_REGISTER_MODE | | ||
377 | MCI_MODE_REGISTER_WRITE; | ||
378 | cx_write(MC417_RWD, regval); | ||
379 | regval |= MC417_MICS | MC417_MIWR; | ||
380 | cx_write(MC417_RWD, regval); | ||
381 | |||
382 | /* Wait for the trans to complete (MC417_MIRDY asserted). */ | ||
383 | return mc417_wait_ready(dev); | ||
384 | } | ||
385 | |||
386 | int mc417_register_read(struct cx23885_dev *dev, u16 address, u32 *value) | ||
387 | { | ||
388 | int retval; | ||
389 | u32 regval; | ||
390 | u32 tempval; | ||
391 | u32 dataval; | ||
392 | |||
393 | /* Enable MC417 GPIO outputs except for MC417_MIRDY, | ||
394 | * which is an input. | ||
395 | */ | ||
396 | cx_write(MC417_OEN, MC417_MIRDY); | ||
397 | |||
398 | /* Write address byte 0 */ | ||
399 | regval = MC417_MIRD | MC417_MIRDY | MCI_REGISTER_ADDRESS_BYTE0 | | ||
400 | ((address & 0x00FF)); | ||
401 | cx_write(MC417_RWD, regval); | ||
402 | regval |= MC417_MICS | MC417_MIWR; | ||
403 | cx_write(MC417_RWD, regval); | ||
404 | |||
405 | /* Write address byte 1 */ | ||
406 | regval = MC417_MIRD | MC417_MIRDY | MCI_REGISTER_ADDRESS_BYTE1 | | ||
407 | ((address >> 8) & 0xFF); | ||
408 | cx_write(MC417_RWD, regval); | ||
409 | regval |= MC417_MICS | MC417_MIWR; | ||
410 | cx_write(MC417_RWD, regval); | ||
411 | |||
412 | /* Indicate that this is a register read. */ | ||
413 | regval = MC417_MIRD | MC417_MIRDY | MCI_REGISTER_MODE | | ||
414 | MCI_MODE_REGISTER_READ; | ||
415 | cx_write(MC417_RWD, regval); | ||
416 | regval |= MC417_MICS | MC417_MIWR; | ||
417 | cx_write(MC417_RWD, regval); | ||
418 | |||
419 | /* Wait for the trans to complete (MC417_MIRDY asserted). */ | ||
420 | retval = mc417_wait_ready(dev); | ||
421 | |||
422 | /* switch the DAT0-7 GPIO[10:3] to input mode */ | ||
423 | cx_write(MC417_OEN, MC417_MIRDY | MC417_MIDATA); | ||
424 | |||
425 | /* Read data byte 0 */ | ||
426 | regval = MC417_MIRD | MC417_MIRDY | MCI_REGISTER_DATA_BYTE0; | ||
427 | cx_write(MC417_RWD, regval); | ||
428 | |||
429 | /* Transition RD to effect read transaction across bus. | ||
430 | * Transtion 0x5000 -> 0x9000 correct (RD/RDY -> WR/RDY)? | ||
431 | * Should it be 0x9000 -> 0xF000 (also why is RDY being set, its | ||
432 | * input only...) | ||
433 | */ | ||
434 | regval = MC417_MIWR | MC417_MIRDY | MCI_REGISTER_DATA_BYTE0; | ||
435 | cx_write(MC417_RWD, regval); | ||
436 | |||
437 | /* Collect byte */ | ||
438 | tempval = cx_read(MC417_RWD); | ||
439 | dataval = tempval & 0x000000FF; | ||
440 | |||
441 | /* Bring CS and RD high. */ | ||
442 | regval = MC417_MIWR | MC417_MIRD | MC417_MICS | MC417_MIRDY; | ||
443 | cx_write(MC417_RWD, regval); | ||
444 | |||
445 | /* Read data byte 1 */ | ||
446 | regval = MC417_MIRD | MC417_MIRDY | MCI_REGISTER_DATA_BYTE1; | ||
447 | cx_write(MC417_RWD, regval); | ||
448 | regval = MC417_MIWR | MC417_MIRDY | MCI_REGISTER_DATA_BYTE1; | ||
449 | cx_write(MC417_RWD, regval); | ||
450 | tempval = cx_read(MC417_RWD); | ||
451 | dataval |= ((tempval & 0x000000FF) << 8); | ||
452 | regval = MC417_MIWR | MC417_MIRD | MC417_MICS | MC417_MIRDY; | ||
453 | cx_write(MC417_RWD, regval); | ||
454 | |||
455 | /* Read data byte 2 */ | ||
456 | regval = MC417_MIRD | MC417_MIRDY | MCI_REGISTER_DATA_BYTE2; | ||
457 | cx_write(MC417_RWD, regval); | ||
458 | regval = MC417_MIWR | MC417_MIRDY | MCI_REGISTER_DATA_BYTE2; | ||
459 | cx_write(MC417_RWD, regval); | ||
460 | tempval = cx_read(MC417_RWD); | ||
461 | dataval |= ((tempval & 0x000000FF) << 16); | ||
462 | regval = MC417_MIWR | MC417_MIRD | MC417_MICS | MC417_MIRDY; | ||
463 | cx_write(MC417_RWD, regval); | ||
464 | |||
465 | /* Read data byte 3 */ | ||
466 | regval = MC417_MIRD | MC417_MIRDY | MCI_REGISTER_DATA_BYTE3; | ||
467 | cx_write(MC417_RWD, regval); | ||
468 | regval = MC417_MIWR | MC417_MIRDY | MCI_REGISTER_DATA_BYTE3; | ||
469 | cx_write(MC417_RWD, regval); | ||
470 | tempval = cx_read(MC417_RWD); | ||
471 | dataval |= ((tempval & 0x000000FF) << 24); | ||
472 | regval = MC417_MIWR | MC417_MIRD | MC417_MICS | MC417_MIRDY; | ||
473 | cx_write(MC417_RWD, regval); | ||
474 | |||
475 | *value = dataval; | ||
476 | |||
477 | return retval; | ||
478 | } | ||
479 | |||
480 | int mc417_memory_write(struct cx23885_dev *dev, u32 address, u32 value) | ||
481 | { | ||
482 | u32 regval; | ||
483 | |||
484 | /* Enable MC417 GPIO outputs except for MC417_MIRDY, | ||
485 | * which is an input. | ||
486 | */ | ||
487 | cx_write(MC417_OEN, MC417_MIRDY); | ||
488 | |||
489 | /* Write data byte 0 */ | ||
490 | regval = MC417_MIRD | MC417_MIRDY | MCI_MEMORY_DATA_BYTE0 | | ||
491 | (value & 0x000000FF); | ||
492 | cx_write(MC417_RWD, regval); | ||
493 | |||
494 | /* Transition CS/WR to effect write transaction across bus. */ | ||
495 | regval |= MC417_MICS | MC417_MIWR; | ||
496 | cx_write(MC417_RWD, regval); | ||
497 | |||
498 | /* Write data byte 1 */ | ||
499 | regval = MC417_MIRD | MC417_MIRDY | MCI_MEMORY_DATA_BYTE1 | | ||
500 | ((value >> 8) & 0x000000FF); | ||
501 | cx_write(MC417_RWD, regval); | ||
502 | regval |= MC417_MICS | MC417_MIWR; | ||
503 | cx_write(MC417_RWD, regval); | ||
504 | |||
505 | /* Write data byte 2 */ | ||
506 | regval = MC417_MIRD | MC417_MIRDY | MCI_MEMORY_DATA_BYTE2 | | ||
507 | ((value >> 16) & 0x000000FF); | ||
508 | cx_write(MC417_RWD, regval); | ||
509 | regval |= MC417_MICS | MC417_MIWR; | ||
510 | cx_write(MC417_RWD, regval); | ||
511 | |||
512 | /* Write data byte 3 */ | ||
513 | regval = MC417_MIRD | MC417_MIRDY | MCI_MEMORY_DATA_BYTE3 | | ||
514 | ((value >> 24) & 0x000000FF); | ||
515 | cx_write(MC417_RWD, regval); | ||
516 | regval |= MC417_MICS | MC417_MIWR; | ||
517 | cx_write(MC417_RWD, regval); | ||
518 | |||
519 | /* Write address byte 2 */ | ||
520 | regval = MC417_MIRD | MC417_MIRDY | MCI_MEMORY_ADDRESS_BYTE2 | | ||
521 | MCI_MODE_MEMORY_WRITE | ((address >> 16) & 0x3F); | ||
522 | cx_write(MC417_RWD, regval); | ||
523 | regval |= MC417_MICS | MC417_MIWR; | ||
524 | cx_write(MC417_RWD, regval); | ||
525 | |||
526 | /* Write address byte 1 */ | ||
527 | regval = MC417_MIRD | MC417_MIRDY | MCI_MEMORY_ADDRESS_BYTE1 | | ||
528 | ((address >> 8) & 0xFF); | ||
529 | cx_write(MC417_RWD, regval); | ||
530 | regval |= MC417_MICS | MC417_MIWR; | ||
531 | cx_write(MC417_RWD, regval); | ||
532 | |||
533 | /* Write address byte 0 */ | ||
534 | regval = MC417_MIRD | MC417_MIRDY | MCI_MEMORY_ADDRESS_BYTE0 | | ||
535 | (address & 0xFF); | ||
536 | cx_write(MC417_RWD, regval); | ||
537 | regval |= MC417_MICS | MC417_MIWR; | ||
538 | cx_write(MC417_RWD, regval); | ||
539 | |||
540 | /* Wait for the trans to complete (MC417_MIRDY asserted). */ | ||
541 | return mc417_wait_ready(dev); | ||
542 | } | ||
543 | |||
544 | int mc417_memory_read(struct cx23885_dev *dev, u32 address, u32 *value) | ||
545 | { | ||
546 | int retval; | ||
547 | u32 regval; | ||
548 | u32 tempval; | ||
549 | u32 dataval; | ||
550 | |||
551 | /* Enable MC417 GPIO outputs except for MC417_MIRDY, | ||
552 | * which is an input. | ||
553 | */ | ||
554 | cx_write(MC417_OEN, MC417_MIRDY); | ||
555 | |||
556 | /* Write address byte 2 */ | ||
557 | regval = MC417_MIRD | MC417_MIRDY | MCI_MEMORY_ADDRESS_BYTE2 | | ||
558 | MCI_MODE_MEMORY_READ | ((address >> 16) & 0x3F); | ||
559 | cx_write(MC417_RWD, regval); | ||
560 | regval |= MC417_MICS | MC417_MIWR; | ||
561 | cx_write(MC417_RWD, regval); | ||
562 | |||
563 | /* Write address byte 1 */ | ||
564 | regval = MC417_MIRD | MC417_MIRDY | MCI_MEMORY_ADDRESS_BYTE1 | | ||
565 | ((address >> 8) & 0xFF); | ||
566 | cx_write(MC417_RWD, regval); | ||
567 | regval |= MC417_MICS | MC417_MIWR; | ||
568 | cx_write(MC417_RWD, regval); | ||
569 | |||
570 | /* Write address byte 0 */ | ||
571 | regval = MC417_MIRD | MC417_MIRDY | MCI_MEMORY_ADDRESS_BYTE0 | | ||
572 | (address & 0xFF); | ||
573 | cx_write(MC417_RWD, regval); | ||
574 | regval |= MC417_MICS | MC417_MIWR; | ||
575 | cx_write(MC417_RWD, regval); | ||
576 | |||
577 | /* Wait for the trans to complete (MC417_MIRDY asserted). */ | ||
578 | retval = mc417_wait_ready(dev); | ||
579 | |||
580 | /* switch the DAT0-7 GPIO[10:3] to input mode */ | ||
581 | cx_write(MC417_OEN, MC417_MIRDY | MC417_MIDATA); | ||
582 | |||
583 | /* Read data byte 3 */ | ||
584 | regval = MC417_MIRD | MC417_MIRDY | MCI_MEMORY_DATA_BYTE3; | ||
585 | cx_write(MC417_RWD, regval); | ||
586 | |||
587 | /* Transition RD to effect read transaction across bus. */ | ||
588 | regval = MC417_MIWR | MC417_MIRDY | MCI_MEMORY_DATA_BYTE3; | ||
589 | cx_write(MC417_RWD, regval); | ||
590 | |||
591 | /* Collect byte */ | ||
592 | tempval = cx_read(MC417_RWD); | ||
593 | dataval = ((tempval & 0x000000FF) << 24); | ||
594 | |||
595 | /* Bring CS and RD high. */ | ||
596 | regval = MC417_MIWR | MC417_MIRD | MC417_MICS | MC417_MIRDY; | ||
597 | cx_write(MC417_RWD, regval); | ||
598 | |||
599 | /* Read data byte 2 */ | ||
600 | regval = MC417_MIRD | MC417_MIRDY | MCI_MEMORY_DATA_BYTE2; | ||
601 | cx_write(MC417_RWD, regval); | ||
602 | regval = MC417_MIWR | MC417_MIRDY | MCI_MEMORY_DATA_BYTE2; | ||
603 | cx_write(MC417_RWD, regval); | ||
604 | tempval = cx_read(MC417_RWD); | ||
605 | dataval |= ((tempval & 0x000000FF) << 16); | ||
606 | regval = MC417_MIWR | MC417_MIRD | MC417_MICS | MC417_MIRDY; | ||
607 | cx_write(MC417_RWD, regval); | ||
608 | |||
609 | /* Read data byte 1 */ | ||
610 | regval = MC417_MIRD | MC417_MIRDY | MCI_MEMORY_DATA_BYTE1; | ||
611 | cx_write(MC417_RWD, regval); | ||
612 | regval = MC417_MIWR | MC417_MIRDY | MCI_MEMORY_DATA_BYTE1; | ||
613 | cx_write(MC417_RWD, regval); | ||
614 | tempval = cx_read(MC417_RWD); | ||
615 | dataval |= ((tempval & 0x000000FF) << 8); | ||
616 | regval = MC417_MIWR | MC417_MIRD | MC417_MICS | MC417_MIRDY; | ||
617 | cx_write(MC417_RWD, regval); | ||
618 | |||
619 | /* Read data byte 0 */ | ||
620 | regval = MC417_MIRD | MC417_MIRDY | MCI_MEMORY_DATA_BYTE0; | ||
621 | cx_write(MC417_RWD, regval); | ||
622 | regval = MC417_MIWR | MC417_MIRDY | MCI_MEMORY_DATA_BYTE0; | ||
623 | cx_write(MC417_RWD, regval); | ||
624 | tempval = cx_read(MC417_RWD); | ||
625 | dataval |= (tempval & 0x000000FF); | ||
626 | regval = MC417_MIWR | MC417_MIRD | MC417_MICS | MC417_MIRDY; | ||
627 | cx_write(MC417_RWD, regval); | ||
628 | |||
629 | *value = dataval; | ||
630 | |||
631 | return retval; | ||
632 | } | ||
633 | |||
634 | void mc417_gpio_set(struct cx23885_dev *dev, u32 mask) | ||
635 | { | ||
636 | u32 val; | ||
637 | |||
638 | /* Set the gpio value */ | ||
639 | mc417_register_read(dev, 0x900C, &val); | ||
640 | val |= (mask & 0x000ffff); | ||
641 | mc417_register_write(dev, 0x900C, val); | ||
642 | } | ||
643 | |||
644 | void mc417_gpio_clear(struct cx23885_dev *dev, u32 mask) | ||
645 | { | ||
646 | u32 val; | ||
647 | |||
648 | /* Clear the gpio value */ | ||
649 | mc417_register_read(dev, 0x900C, &val); | ||
650 | val &= ~(mask & 0x0000ffff); | ||
651 | mc417_register_write(dev, 0x900C, val); | ||
652 | } | ||
653 | |||
654 | void mc417_gpio_enable(struct cx23885_dev *dev, u32 mask, int asoutput) | ||
655 | { | ||
656 | u32 val; | ||
657 | |||
658 | /* Enable GPIO direction bits */ | ||
659 | mc417_register_read(dev, 0x9020, &val); | ||
660 | if (asoutput) | ||
661 | val |= (mask & 0x0000ffff); | ||
662 | else | ||
663 | val &= ~(mask & 0x0000ffff); | ||
664 | |||
665 | mc417_register_write(dev, 0x9020, val); | ||
666 | } | ||
667 | /* ------------------------------------------------------------------ */ | ||
668 | |||
669 | /* MPEG encoder API */ | ||
670 | static char *cmd_to_str(int cmd) | ||
671 | { | ||
672 | switch (cmd) { | ||
673 | case CX2341X_ENC_PING_FW: | ||
674 | return "PING_FW"; | ||
675 | case CX2341X_ENC_START_CAPTURE: | ||
676 | return "START_CAPTURE"; | ||
677 | case CX2341X_ENC_STOP_CAPTURE: | ||
678 | return "STOP_CAPTURE"; | ||
679 | case CX2341X_ENC_SET_AUDIO_ID: | ||
680 | return "SET_AUDIO_ID"; | ||
681 | case CX2341X_ENC_SET_VIDEO_ID: | ||
682 | return "SET_VIDEO_ID"; | ||
683 | case CX2341X_ENC_SET_PCR_ID: | ||
684 | return "SET_PCR_ID"; | ||
685 | case CX2341X_ENC_SET_FRAME_RATE: | ||
686 | return "SET_FRAME_RATE"; | ||
687 | case CX2341X_ENC_SET_FRAME_SIZE: | ||
688 | return "SET_FRAME_SIZE"; | ||
689 | case CX2341X_ENC_SET_BIT_RATE: | ||
690 | return "SET_BIT_RATE"; | ||
691 | case CX2341X_ENC_SET_GOP_PROPERTIES: | ||
692 | return "SET_GOP_PROPERTIES"; | ||
693 | case CX2341X_ENC_SET_ASPECT_RATIO: | ||
694 | return "SET_ASPECT_RATIO"; | ||
695 | case CX2341X_ENC_SET_DNR_FILTER_MODE: | ||
696 | return "SET_DNR_FILTER_MODE"; | ||
697 | case CX2341X_ENC_SET_DNR_FILTER_PROPS: | ||
698 | return "SET_DNR_FILTER_PROPS"; | ||
699 | case CX2341X_ENC_SET_CORING_LEVELS: | ||
700 | return "SET_CORING_LEVELS"; | ||
701 | case CX2341X_ENC_SET_SPATIAL_FILTER_TYPE: | ||
702 | return "SET_SPATIAL_FILTER_TYPE"; | ||
703 | case CX2341X_ENC_SET_VBI_LINE: | ||
704 | return "SET_VBI_LINE"; | ||
705 | case CX2341X_ENC_SET_STREAM_TYPE: | ||
706 | return "SET_STREAM_TYPE"; | ||
707 | case CX2341X_ENC_SET_OUTPUT_PORT: | ||
708 | return "SET_OUTPUT_PORT"; | ||
709 | case CX2341X_ENC_SET_AUDIO_PROPERTIES: | ||
710 | return "SET_AUDIO_PROPERTIES"; | ||
711 | case CX2341X_ENC_HALT_FW: | ||
712 | return "HALT_FW"; | ||
713 | case CX2341X_ENC_GET_VERSION: | ||
714 | return "GET_VERSION"; | ||
715 | case CX2341X_ENC_SET_GOP_CLOSURE: | ||
716 | return "SET_GOP_CLOSURE"; | ||
717 | case CX2341X_ENC_GET_SEQ_END: | ||
718 | return "GET_SEQ_END"; | ||
719 | case CX2341X_ENC_SET_PGM_INDEX_INFO: | ||
720 | return "SET_PGM_INDEX_INFO"; | ||
721 | case CX2341X_ENC_SET_VBI_CONFIG: | ||
722 | return "SET_VBI_CONFIG"; | ||
723 | case CX2341X_ENC_SET_DMA_BLOCK_SIZE: | ||
724 | return "SET_DMA_BLOCK_SIZE"; | ||
725 | case CX2341X_ENC_GET_PREV_DMA_INFO_MB_10: | ||
726 | return "GET_PREV_DMA_INFO_MB_10"; | ||
727 | case CX2341X_ENC_GET_PREV_DMA_INFO_MB_9: | ||
728 | return "GET_PREV_DMA_INFO_MB_9"; | ||
729 | case CX2341X_ENC_SCHED_DMA_TO_HOST: | ||
730 | return "SCHED_DMA_TO_HOST"; | ||
731 | case CX2341X_ENC_INITIALIZE_INPUT: | ||
732 | return "INITIALIZE_INPUT"; | ||
733 | case CX2341X_ENC_SET_FRAME_DROP_RATE: | ||
734 | return "SET_FRAME_DROP_RATE"; | ||
735 | case CX2341X_ENC_PAUSE_ENCODER: | ||
736 | return "PAUSE_ENCODER"; | ||
737 | case CX2341X_ENC_REFRESH_INPUT: | ||
738 | return "REFRESH_INPUT"; | ||
739 | case CX2341X_ENC_SET_COPYRIGHT: | ||
740 | return "SET_COPYRIGHT"; | ||
741 | case CX2341X_ENC_SET_EVENT_NOTIFICATION: | ||
742 | return "SET_EVENT_NOTIFICATION"; | ||
743 | case CX2341X_ENC_SET_NUM_VSYNC_LINES: | ||
744 | return "SET_NUM_VSYNC_LINES"; | ||
745 | case CX2341X_ENC_SET_PLACEHOLDER: | ||
746 | return "SET_PLACEHOLDER"; | ||
747 | case CX2341X_ENC_MUTE_VIDEO: | ||
748 | return "MUTE_VIDEO"; | ||
749 | case CX2341X_ENC_MUTE_AUDIO: | ||
750 | return "MUTE_AUDIO"; | ||
751 | case CX2341X_ENC_MISC: | ||
752 | return "MISC"; | ||
753 | default: | ||
754 | return "UNKNOWN"; | ||
755 | } | ||
756 | } | ||
757 | |||
758 | static int cx23885_mbox_func(void *priv, | ||
759 | u32 command, | ||
760 | int in, | ||
761 | int out, | ||
762 | u32 data[CX2341X_MBOX_MAX_DATA]) | ||
763 | { | ||
764 | struct cx23885_dev *dev = priv; | ||
765 | unsigned long timeout; | ||
766 | u32 value, flag, retval = 0; | ||
767 | int i; | ||
768 | |||
769 | dprintk(3, "%s: command(0x%X) = %s\n", __func__, command, | ||
770 | cmd_to_str(command)); | ||
771 | |||
772 | /* this may not be 100% safe if we can't read any memory location | ||
773 | without side effects */ | ||
774 | mc417_memory_read(dev, dev->cx23417_mailbox - 4, &value); | ||
775 | if (value != 0x12345678) { | ||
776 | printk(KERN_ERR | ||
777 | "Firmware and/or mailbox pointer not initialized " | ||
778 | "or corrupted, signature = 0x%x, cmd = %s\n", value, | ||
779 | cmd_to_str(command)); | ||
780 | return -1; | ||
781 | } | ||
782 | |||
783 | /* This read looks at 32 bits, but flag is only 8 bits. | ||
784 | * Seems we also bail if CMD or TIMEOUT bytes are set??? | ||
785 | */ | ||
786 | mc417_memory_read(dev, dev->cx23417_mailbox, &flag); | ||
787 | if (flag) { | ||
788 | printk(KERN_ERR "ERROR: Mailbox appears to be in use " | ||
789 | "(%x), cmd = %s\n", flag, cmd_to_str(command)); | ||
790 | return -1; | ||
791 | } | ||
792 | |||
793 | flag |= 1; /* tell 'em we're working on it */ | ||
794 | mc417_memory_write(dev, dev->cx23417_mailbox, flag); | ||
795 | |||
796 | /* write command + args + fill remaining with zeros */ | ||
797 | /* command code */ | ||
798 | mc417_memory_write(dev, dev->cx23417_mailbox + 1, command); | ||
799 | mc417_memory_write(dev, dev->cx23417_mailbox + 3, | ||
800 | IVTV_API_STD_TIMEOUT); /* timeout */ | ||
801 | for (i = 0; i < in; i++) { | ||
802 | mc417_memory_write(dev, dev->cx23417_mailbox + 4 + i, data[i]); | ||
803 | dprintk(3, "API Input %d = %d\n", i, data[i]); | ||
804 | } | ||
805 | for (; i < CX2341X_MBOX_MAX_DATA; i++) | ||
806 | mc417_memory_write(dev, dev->cx23417_mailbox + 4 + i, 0); | ||
807 | |||
808 | flag |= 3; /* tell 'em we're done writing */ | ||
809 | mc417_memory_write(dev, dev->cx23417_mailbox, flag); | ||
810 | |||
811 | /* wait for firmware to handle the API command */ | ||
812 | timeout = jiffies + msecs_to_jiffies(10); | ||
813 | for (;;) { | ||
814 | mc417_memory_read(dev, dev->cx23417_mailbox, &flag); | ||
815 | if (0 != (flag & 4)) | ||
816 | break; | ||
817 | if (time_after(jiffies, timeout)) { | ||
818 | printk(KERN_ERR "ERROR: API Mailbox timeout\n"); | ||
819 | return -1; | ||
820 | } | ||
821 | udelay(10); | ||
822 | } | ||
823 | |||
824 | /* read output values */ | ||
825 | for (i = 0; i < out; i++) { | ||
826 | mc417_memory_read(dev, dev->cx23417_mailbox + 4 + i, data + i); | ||
827 | dprintk(3, "API Output %d = %d\n", i, data[i]); | ||
828 | } | ||
829 | |||
830 | mc417_memory_read(dev, dev->cx23417_mailbox + 2, &retval); | ||
831 | dprintk(3, "API result = %d\n", retval); | ||
832 | |||
833 | flag = 0; | ||
834 | mc417_memory_write(dev, dev->cx23417_mailbox, flag); | ||
835 | |||
836 | return retval; | ||
837 | } | ||
838 | |||
839 | /* We don't need to call the API often, so using just one | ||
840 | * mailbox will probably suffice | ||
841 | */ | ||
842 | static int cx23885_api_cmd(struct cx23885_dev *dev, | ||
843 | u32 command, | ||
844 | u32 inputcnt, | ||
845 | u32 outputcnt, | ||
846 | ...) | ||
847 | { | ||
848 | u32 data[CX2341X_MBOX_MAX_DATA]; | ||
849 | va_list vargs; | ||
850 | int i, err; | ||
851 | |||
852 | dprintk(3, "%s() cmds = 0x%08x\n", __func__, command); | ||
853 | |||
854 | va_start(vargs, outputcnt); | ||
855 | for (i = 0; i < inputcnt; i++) | ||
856 | data[i] = va_arg(vargs, int); | ||
857 | |||
858 | err = cx23885_mbox_func(dev, command, inputcnt, outputcnt, data); | ||
859 | for (i = 0; i < outputcnt; i++) { | ||
860 | int *vptr = va_arg(vargs, int *); | ||
861 | *vptr = data[i]; | ||
862 | } | ||
863 | va_end(vargs); | ||
864 | |||
865 | return err; | ||
866 | } | ||
867 | |||
868 | static int cx23885_find_mailbox(struct cx23885_dev *dev) | ||
869 | { | ||
870 | u32 signature[4] = { | ||
871 | 0x12345678, 0x34567812, 0x56781234, 0x78123456 | ||
872 | }; | ||
873 | int signaturecnt = 0; | ||
874 | u32 value; | ||
875 | int i; | ||
876 | |||
877 | dprintk(2, "%s()\n", __func__); | ||
878 | |||
879 | for (i = 0; i < CX23885_FIRM_IMAGE_SIZE; i++) { | ||
880 | mc417_memory_read(dev, i, &value); | ||
881 | if (value == signature[signaturecnt]) | ||
882 | signaturecnt++; | ||
883 | else | ||
884 | signaturecnt = 0; | ||
885 | if (4 == signaturecnt) { | ||
886 | dprintk(1, "Mailbox signature found at 0x%x\n", i+1); | ||
887 | return i+1; | ||
888 | } | ||
889 | } | ||
890 | printk(KERN_ERR "Mailbox signature values not found!\n"); | ||
891 | return -1; | ||
892 | } | ||
893 | |||
894 | static int cx23885_load_firmware(struct cx23885_dev *dev) | ||
895 | { | ||
896 | static const unsigned char magic[8] = { | ||
897 | 0xa7, 0x0d, 0x00, 0x00, 0x66, 0xbb, 0x55, 0xaa | ||
898 | }; | ||
899 | const struct firmware *firmware; | ||
900 | int i, retval = 0; | ||
901 | u32 value = 0; | ||
902 | u32 gpio_output = 0; | ||
903 | u32 checksum = 0; | ||
904 | u32 *dataptr; | ||
905 | |||
906 | dprintk(2, "%s()\n", __func__); | ||
907 | |||
908 | /* Save GPIO settings before reset of APU */ | ||
909 | retval |= mc417_memory_read(dev, 0x9020, &gpio_output); | ||
910 | retval |= mc417_memory_read(dev, 0x900C, &value); | ||
911 | |||
912 | retval = mc417_register_write(dev, | ||
913 | IVTV_REG_VPU, 0xFFFFFFED); | ||
914 | retval |= mc417_register_write(dev, | ||
915 | IVTV_REG_HW_BLOCKS, IVTV_CMD_HW_BLOCKS_RST); | ||
916 | retval |= mc417_register_write(dev, | ||
917 | IVTV_REG_ENC_SDRAM_REFRESH, 0x80000800); | ||
918 | retval |= mc417_register_write(dev, | ||
919 | IVTV_REG_ENC_SDRAM_PRECHARGE, 0x1A); | ||
920 | retval |= mc417_register_write(dev, | ||
921 | IVTV_REG_APU, 0); | ||
922 | |||
923 | if (retval != 0) { | ||
924 | printk(KERN_ERR "%s: Error with mc417_register_write\n", | ||
925 | __func__); | ||
926 | return -1; | ||
927 | } | ||
928 | |||
929 | retval = request_firmware(&firmware, CX23885_FIRM_IMAGE_NAME, | ||
930 | &dev->pci->dev); | ||
931 | |||
932 | if (retval != 0) { | ||
933 | printk(KERN_ERR | ||
934 | "ERROR: Hotplug firmware request failed (%s).\n", | ||
935 | CX23885_FIRM_IMAGE_NAME); | ||
936 | printk(KERN_ERR "Please fix your hotplug setup, the board will " | ||
937 | "not work without firmware loaded!\n"); | ||
938 | return -1; | ||
939 | } | ||
940 | |||
941 | if (firmware->size != CX23885_FIRM_IMAGE_SIZE) { | ||
942 | printk(KERN_ERR "ERROR: Firmware size mismatch " | ||
943 | "(have %zd, expected %d)\n", | ||
944 | firmware->size, CX23885_FIRM_IMAGE_SIZE); | ||
945 | release_firmware(firmware); | ||
946 | return -1; | ||
947 | } | ||
948 | |||
949 | if (0 != memcmp(firmware->data, magic, 8)) { | ||
950 | printk(KERN_ERR | ||
951 | "ERROR: Firmware magic mismatch, wrong file?\n"); | ||
952 | release_firmware(firmware); | ||
953 | return -1; | ||
954 | } | ||
955 | |||
956 | /* transfer to the chip */ | ||
957 | dprintk(2, "Loading firmware ...\n"); | ||
958 | dataptr = (u32 *)firmware->data; | ||
959 | for (i = 0; i < (firmware->size >> 2); i++) { | ||
960 | value = *dataptr; | ||
961 | checksum += ~value; | ||
962 | if (mc417_memory_write(dev, i, value) != 0) { | ||
963 | printk(KERN_ERR "ERROR: Loading firmware failed!\n"); | ||
964 | release_firmware(firmware); | ||
965 | return -1; | ||
966 | } | ||
967 | dataptr++; | ||
968 | } | ||
969 | |||
970 | /* read back to verify with the checksum */ | ||
971 | dprintk(1, "Verifying firmware ...\n"); | ||
972 | for (i--; i >= 0; i--) { | ||
973 | if (mc417_memory_read(dev, i, &value) != 0) { | ||
974 | printk(KERN_ERR "ERROR: Reading firmware failed!\n"); | ||
975 | release_firmware(firmware); | ||
976 | return -1; | ||
977 | } | ||
978 | checksum -= ~value; | ||
979 | } | ||
980 | if (checksum) { | ||
981 | printk(KERN_ERR | ||
982 | "ERROR: Firmware load failed (checksum mismatch).\n"); | ||
983 | release_firmware(firmware); | ||
984 | return -1; | ||
985 | } | ||
986 | release_firmware(firmware); | ||
987 | dprintk(1, "Firmware upload successful.\n"); | ||
988 | |||
989 | retval |= mc417_register_write(dev, IVTV_REG_HW_BLOCKS, | ||
990 | IVTV_CMD_HW_BLOCKS_RST); | ||
991 | |||
992 | /* F/W power up disturbs the GPIOs, restore state */ | ||
993 | retval |= mc417_register_write(dev, 0x9020, gpio_output); | ||
994 | retval |= mc417_register_write(dev, 0x900C, value); | ||
995 | |||
996 | retval |= mc417_register_read(dev, IVTV_REG_VPU, &value); | ||
997 | retval |= mc417_register_write(dev, IVTV_REG_VPU, value & 0xFFFFFFE8); | ||
998 | |||
999 | if (retval < 0) | ||
1000 | printk(KERN_ERR "%s: Error with mc417_register_write\n", | ||
1001 | __func__); | ||
1002 | return 0; | ||
1003 | } | ||
1004 | |||
1005 | void cx23885_417_check_encoder(struct cx23885_dev *dev) | ||
1006 | { | ||
1007 | u32 status, seq; | ||
1008 | |||
1009 | status = seq = 0; | ||
1010 | cx23885_api_cmd(dev, CX2341X_ENC_GET_SEQ_END, 0, 2, &status, &seq); | ||
1011 | dprintk(1, "%s() status = %d, seq = %d\n", __func__, status, seq); | ||
1012 | } | ||
1013 | |||
1014 | static void cx23885_codec_settings(struct cx23885_dev *dev) | ||
1015 | { | ||
1016 | dprintk(1, "%s()\n", __func__); | ||
1017 | |||
1018 | /* assign frame size */ | ||
1019 | cx23885_api_cmd(dev, CX2341X_ENC_SET_FRAME_SIZE, 2, 0, | ||
1020 | dev->ts1.height, dev->ts1.width); | ||
1021 | |||
1022 | dev->mpeg_params.width = dev->ts1.width; | ||
1023 | dev->mpeg_params.height = dev->ts1.height; | ||
1024 | dev->mpeg_params.is_50hz = | ||
1025 | (dev->encodernorm.id & V4L2_STD_625_50) != 0; | ||
1026 | |||
1027 | cx2341x_update(dev, cx23885_mbox_func, NULL, &dev->mpeg_params); | ||
1028 | |||
1029 | cx23885_api_cmd(dev, CX2341X_ENC_MISC, 2, 0, 3, 1); | ||
1030 | cx23885_api_cmd(dev, CX2341X_ENC_MISC, 2, 0, 4, 1); | ||
1031 | } | ||
1032 | |||
1033 | static int cx23885_initialize_codec(struct cx23885_dev *dev) | ||
1034 | { | ||
1035 | int version; | ||
1036 | int retval; | ||
1037 | u32 i, data[7]; | ||
1038 | |||
1039 | dprintk(1, "%s()\n", __func__); | ||
1040 | |||
1041 | retval = cx23885_api_cmd(dev, CX2341X_ENC_PING_FW, 0, 0); /* ping */ | ||
1042 | if (retval < 0) { | ||
1043 | dprintk(2, "%s() PING OK\n", __func__); | ||
1044 | retval = cx23885_load_firmware(dev); | ||
1045 | if (retval < 0) { | ||
1046 | printk(KERN_ERR "%s() f/w load failed\n", __func__); | ||
1047 | return retval; | ||
1048 | } | ||
1049 | retval = cx23885_find_mailbox(dev); | ||
1050 | if (retval < 0) { | ||
1051 | printk(KERN_ERR "%s() mailbox < 0, error\n", | ||
1052 | __func__); | ||
1053 | return -1; | ||
1054 | } | ||
1055 | dev->cx23417_mailbox = retval; | ||
1056 | retval = cx23885_api_cmd(dev, CX2341X_ENC_PING_FW, 0, 0); | ||
1057 | if (retval < 0) { | ||
1058 | printk(KERN_ERR | ||
1059 | "ERROR: cx23417 firmware ping failed!\n"); | ||
1060 | return -1; | ||
1061 | } | ||
1062 | retval = cx23885_api_cmd(dev, CX2341X_ENC_GET_VERSION, 0, 1, | ||
1063 | &version); | ||
1064 | if (retval < 0) { | ||
1065 | printk(KERN_ERR "ERROR: cx23417 firmware get encoder :" | ||
1066 | "version failed!\n"); | ||
1067 | return -1; | ||
1068 | } | ||
1069 | dprintk(1, "cx23417 firmware version is 0x%08x\n", version); | ||
1070 | msleep(200); | ||
1071 | } | ||
1072 | |||
1073 | cx23885_codec_settings(dev); | ||
1074 | msleep(60); | ||
1075 | |||
1076 | cx23885_api_cmd(dev, CX2341X_ENC_SET_NUM_VSYNC_LINES, 2, 0, | ||
1077 | CX23885_FIELD1_SAA7115, CX23885_FIELD2_SAA7115); | ||
1078 | cx23885_api_cmd(dev, CX2341X_ENC_SET_PLACEHOLDER, 12, 0, | ||
1079 | CX23885_CUSTOM_EXTENSION_USR_DATA, 0, 0, 0, 0, 0, 0, 0, 0, 0, | ||
1080 | 0, 0); | ||
1081 | |||
1082 | /* Setup to capture VBI */ | ||
1083 | data[0] = 0x0001BD00; | ||
1084 | data[1] = 1; /* frames per interrupt */ | ||
1085 | data[2] = 4; /* total bufs */ | ||
1086 | data[3] = 0x91559155; /* start codes */ | ||
1087 | data[4] = 0x206080C0; /* stop codes */ | ||
1088 | data[5] = 6; /* lines */ | ||
1089 | data[6] = 64; /* BPL */ | ||
1090 | |||
1091 | cx23885_api_cmd(dev, CX2341X_ENC_SET_VBI_CONFIG, 7, 0, data[0], data[1], | ||
1092 | data[2], data[3], data[4], data[5], data[6]); | ||
1093 | |||
1094 | for (i = 2; i <= 24; i++) { | ||
1095 | int valid; | ||
1096 | |||
1097 | valid = ((i >= 19) && (i <= 21)); | ||
1098 | cx23885_api_cmd(dev, CX2341X_ENC_SET_VBI_LINE, 5, 0, i, | ||
1099 | valid, 0 , 0, 0); | ||
1100 | cx23885_api_cmd(dev, CX2341X_ENC_SET_VBI_LINE, 5, 0, | ||
1101 | i | 0x80000000, valid, 0, 0, 0); | ||
1102 | } | ||
1103 | |||
1104 | cx23885_api_cmd(dev, CX2341X_ENC_MUTE_AUDIO, 1, 0, CX23885_UNMUTE); | ||
1105 | msleep(60); | ||
1106 | |||
1107 | /* initialize the video input */ | ||
1108 | cx23885_api_cmd(dev, CX2341X_ENC_INITIALIZE_INPUT, 0, 0); | ||
1109 | msleep(60); | ||
1110 | |||
1111 | /* Enable VIP style pixel invalidation so we work with scaled mode */ | ||
1112 | mc417_memory_write(dev, 2120, 0x00000080); | ||
1113 | |||
1114 | /* start capturing to the host interface */ | ||
1115 | cx23885_api_cmd(dev, CX2341X_ENC_START_CAPTURE, 2, 0, | ||
1116 | CX23885_MPEG_CAPTURE, CX23885_RAW_BITS_NONE); | ||
1117 | msleep(10); | ||
1118 | |||
1119 | return 0; | ||
1120 | } | ||
1121 | |||
1122 | /* ------------------------------------------------------------------ */ | ||
1123 | |||
1124 | static int bb_buf_setup(struct videobuf_queue *q, | ||
1125 | unsigned int *count, unsigned int *size) | ||
1126 | { | ||
1127 | struct cx23885_fh *fh = q->priv_data; | ||
1128 | |||
1129 | fh->dev->ts1.ts_packet_size = mpeglinesize; | ||
1130 | fh->dev->ts1.ts_packet_count = mpeglines; | ||
1131 | |||
1132 | *size = fh->dev->ts1.ts_packet_size * fh->dev->ts1.ts_packet_count; | ||
1133 | *count = mpegbufs; | ||
1134 | |||
1135 | return 0; | ||
1136 | } | ||
1137 | |||
1138 | static int bb_buf_prepare(struct videobuf_queue *q, | ||
1139 | struct videobuf_buffer *vb, enum v4l2_field field) | ||
1140 | { | ||
1141 | struct cx23885_fh *fh = q->priv_data; | ||
1142 | return cx23885_buf_prepare(q, &fh->dev->ts1, | ||
1143 | (struct cx23885_buffer *)vb, | ||
1144 | field); | ||
1145 | } | ||
1146 | |||
1147 | static void bb_buf_queue(struct videobuf_queue *q, | ||
1148 | struct videobuf_buffer *vb) | ||
1149 | { | ||
1150 | struct cx23885_fh *fh = q->priv_data; | ||
1151 | cx23885_buf_queue(&fh->dev->ts1, (struct cx23885_buffer *)vb); | ||
1152 | } | ||
1153 | |||
1154 | static void bb_buf_release(struct videobuf_queue *q, | ||
1155 | struct videobuf_buffer *vb) | ||
1156 | { | ||
1157 | cx23885_free_buffer(q, (struct cx23885_buffer *)vb); | ||
1158 | } | ||
1159 | |||
1160 | static struct videobuf_queue_ops cx23885_qops = { | ||
1161 | .buf_setup = bb_buf_setup, | ||
1162 | .buf_prepare = bb_buf_prepare, | ||
1163 | .buf_queue = bb_buf_queue, | ||
1164 | .buf_release = bb_buf_release, | ||
1165 | }; | ||
1166 | |||
1167 | /* ------------------------------------------------------------------ */ | ||
1168 | |||
1169 | static const u32 *ctrl_classes[] = { | ||
1170 | cx2341x_mpeg_ctrls, | ||
1171 | NULL | ||
1172 | }; | ||
1173 | |||
1174 | static int cx23885_queryctrl(struct cx23885_dev *dev, | ||
1175 | struct v4l2_queryctrl *qctrl) | ||
1176 | { | ||
1177 | qctrl->id = v4l2_ctrl_next(ctrl_classes, qctrl->id); | ||
1178 | if (qctrl->id == 0) | ||
1179 | return -EINVAL; | ||
1180 | |||
1181 | /* MPEG V4L2 controls */ | ||
1182 | if (cx2341x_ctrl_query(&dev->mpeg_params, qctrl)) | ||
1183 | qctrl->flags |= V4L2_CTRL_FLAG_DISABLED; | ||
1184 | |||
1185 | return 0; | ||
1186 | } | ||
1187 | |||
1188 | static int cx23885_querymenu(struct cx23885_dev *dev, | ||
1189 | struct v4l2_querymenu *qmenu) | ||
1190 | { | ||
1191 | struct v4l2_queryctrl qctrl; | ||
1192 | |||
1193 | qctrl.id = qmenu->id; | ||
1194 | cx23885_queryctrl(dev, &qctrl); | ||
1195 | return v4l2_ctrl_query_menu(qmenu, &qctrl, | ||
1196 | cx2341x_ctrl_get_menu(&dev->mpeg_params, qmenu->id)); | ||
1197 | } | ||
1198 | |||
1199 | static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id *id) | ||
1200 | { | ||
1201 | struct cx23885_fh *fh = file->private_data; | ||
1202 | struct cx23885_dev *dev = fh->dev; | ||
1203 | unsigned int i; | ||
1204 | |||
1205 | for (i = 0; i < ARRAY_SIZE(cx23885_tvnorms); i++) | ||
1206 | if (*id & cx23885_tvnorms[i].id) | ||
1207 | break; | ||
1208 | if (i == ARRAY_SIZE(cx23885_tvnorms)) | ||
1209 | return -EINVAL; | ||
1210 | dev->encodernorm = cx23885_tvnorms[i]; | ||
1211 | return 0; | ||
1212 | } | ||
1213 | |||
1214 | static int vidioc_enum_input(struct file *file, void *priv, | ||
1215 | struct v4l2_input *i) | ||
1216 | { | ||
1217 | struct cx23885_fh *fh = file->private_data; | ||
1218 | struct cx23885_dev *dev = fh->dev; | ||
1219 | struct cx23885_input *input; | ||
1220 | int n; | ||
1221 | |||
1222 | if (i->index >= 4) | ||
1223 | return -EINVAL; | ||
1224 | |||
1225 | input = &cx23885_boards[dev->board].input[i->index]; | ||
1226 | |||
1227 | if (input->type == 0) | ||
1228 | return -EINVAL; | ||
1229 | |||
1230 | /* FIXME | ||
1231 | * strcpy(i->name, input->name); */ | ||
1232 | strcpy(i->name, "unset"); | ||
1233 | |||
1234 | if (input->type == CX23885_VMUX_TELEVISION || | ||
1235 | input->type == CX23885_VMUX_CABLE) | ||
1236 | i->type = V4L2_INPUT_TYPE_TUNER; | ||
1237 | else | ||
1238 | i->type = V4L2_INPUT_TYPE_CAMERA; | ||
1239 | |||
1240 | for (n = 0; n < ARRAY_SIZE(cx23885_tvnorms); n++) | ||
1241 | i->std |= cx23885_tvnorms[n].id; | ||
1242 | return 0; | ||
1243 | } | ||
1244 | |||
1245 | static int vidioc_g_input(struct file *file, void *priv, unsigned int *i) | ||
1246 | { | ||
1247 | struct cx23885_fh *fh = file->private_data; | ||
1248 | struct cx23885_dev *dev = fh->dev; | ||
1249 | |||
1250 | *i = dev->input; | ||
1251 | return 0; | ||
1252 | } | ||
1253 | |||
1254 | static int vidioc_s_input(struct file *file, void *priv, unsigned int i) | ||
1255 | { | ||
1256 | if (i >= 4) | ||
1257 | return -EINVAL; | ||
1258 | |||
1259 | return 0; | ||
1260 | } | ||
1261 | |||
1262 | static int vidioc_g_tuner(struct file *file, void *priv, | ||
1263 | struct v4l2_tuner *t) | ||
1264 | { | ||
1265 | struct cx23885_fh *fh = file->private_data; | ||
1266 | struct cx23885_dev *dev = fh->dev; | ||
1267 | |||
1268 | if (UNSET == dev->tuner_type) | ||
1269 | return -EINVAL; | ||
1270 | if (0 != t->index) | ||
1271 | return -EINVAL; | ||
1272 | strcpy(t->name, "Television"); | ||
1273 | call_all(dev, tuner, g_tuner, t); | ||
1274 | |||
1275 | dprintk(1, "VIDIOC_G_TUNER: tuner type %d\n", t->type); | ||
1276 | |||
1277 | return 0; | ||
1278 | } | ||
1279 | |||
1280 | static int vidioc_s_tuner(struct file *file, void *priv, | ||
1281 | struct v4l2_tuner *t) | ||
1282 | { | ||
1283 | struct cx23885_fh *fh = file->private_data; | ||
1284 | struct cx23885_dev *dev = fh->dev; | ||
1285 | |||
1286 | if (UNSET == dev->tuner_type) | ||
1287 | return -EINVAL; | ||
1288 | |||
1289 | /* Update the A/V core */ | ||
1290 | call_all(dev, tuner, s_tuner, t); | ||
1291 | |||
1292 | return 0; | ||
1293 | } | ||
1294 | |||
1295 | static int vidioc_g_frequency(struct file *file, void *priv, | ||
1296 | struct v4l2_frequency *f) | ||
1297 | { | ||
1298 | struct cx23885_fh *fh = file->private_data; | ||
1299 | struct cx23885_dev *dev = fh->dev; | ||
1300 | |||
1301 | if (UNSET == dev->tuner_type) | ||
1302 | return -EINVAL; | ||
1303 | f->type = V4L2_TUNER_ANALOG_TV; | ||
1304 | f->frequency = dev->freq; | ||
1305 | |||
1306 | call_all(dev, tuner, g_frequency, f); | ||
1307 | |||
1308 | return 0; | ||
1309 | } | ||
1310 | |||
1311 | static int vidioc_s_frequency(struct file *file, void *priv, | ||
1312 | struct v4l2_frequency *f) | ||
1313 | { | ||
1314 | struct cx23885_fh *fh = file->private_data; | ||
1315 | struct cx23885_dev *dev = fh->dev; | ||
1316 | |||
1317 | cx23885_api_cmd(fh->dev, CX2341X_ENC_STOP_CAPTURE, 3, 0, | ||
1318 | CX23885_END_NOW, CX23885_MPEG_CAPTURE, | ||
1319 | CX23885_RAW_BITS_NONE); | ||
1320 | |||
1321 | dprintk(1, "VIDIOC_S_FREQUENCY: dev type %d, f\n", | ||
1322 | dev->tuner_type); | ||
1323 | dprintk(1, "VIDIOC_S_FREQUENCY: f tuner %d, f type %d\n", | ||
1324 | f->tuner, f->type); | ||
1325 | if (UNSET == dev->tuner_type) | ||
1326 | return -EINVAL; | ||
1327 | if (f->tuner != 0) | ||
1328 | return -EINVAL; | ||
1329 | if (f->type != V4L2_TUNER_ANALOG_TV) | ||
1330 | return -EINVAL; | ||
1331 | dev->freq = f->frequency; | ||
1332 | |||
1333 | call_all(dev, tuner, s_frequency, f); | ||
1334 | |||
1335 | cx23885_initialize_codec(dev); | ||
1336 | |||
1337 | return 0; | ||
1338 | } | ||
1339 | |||
1340 | static int vidioc_s_ctrl(struct file *file, void *priv, | ||
1341 | struct v4l2_control *ctl) | ||
1342 | { | ||
1343 | struct cx23885_fh *fh = file->private_data; | ||
1344 | struct cx23885_dev *dev = fh->dev; | ||
1345 | |||
1346 | /* Update the A/V core */ | ||
1347 | call_all(dev, core, s_ctrl, ctl); | ||
1348 | return 0; | ||
1349 | } | ||
1350 | |||
1351 | static int vidioc_querycap(struct file *file, void *priv, | ||
1352 | struct v4l2_capability *cap) | ||
1353 | { | ||
1354 | struct cx23885_fh *fh = file->private_data; | ||
1355 | struct cx23885_dev *dev = fh->dev; | ||
1356 | struct cx23885_tsport *tsport = &dev->ts1; | ||
1357 | |||
1358 | strlcpy(cap->driver, dev->name, sizeof(cap->driver)); | ||
1359 | strlcpy(cap->card, cx23885_boards[tsport->dev->board].name, | ||
1360 | sizeof(cap->card)); | ||
1361 | sprintf(cap->bus_info, "PCI:%s", pci_name(dev->pci)); | ||
1362 | cap->capabilities = | ||
1363 | V4L2_CAP_VIDEO_CAPTURE | | ||
1364 | V4L2_CAP_READWRITE | | ||
1365 | V4L2_CAP_STREAMING | | ||
1366 | 0; | ||
1367 | if (UNSET != dev->tuner_type) | ||
1368 | cap->capabilities |= V4L2_CAP_TUNER; | ||
1369 | |||
1370 | return 0; | ||
1371 | } | ||
1372 | |||
1373 | static int vidioc_enum_fmt_vid_cap(struct file *file, void *priv, | ||
1374 | struct v4l2_fmtdesc *f) | ||
1375 | { | ||
1376 | if (f->index != 0) | ||
1377 | return -EINVAL; | ||
1378 | |||
1379 | strlcpy(f->description, "MPEG", sizeof(f->description)); | ||
1380 | f->pixelformat = V4L2_PIX_FMT_MPEG; | ||
1381 | |||
1382 | return 0; | ||
1383 | } | ||
1384 | |||
1385 | static int vidioc_g_fmt_vid_cap(struct file *file, void *priv, | ||
1386 | struct v4l2_format *f) | ||
1387 | { | ||
1388 | struct cx23885_fh *fh = file->private_data; | ||
1389 | struct cx23885_dev *dev = fh->dev; | ||
1390 | |||
1391 | f->fmt.pix.pixelformat = V4L2_PIX_FMT_MPEG; | ||
1392 | f->fmt.pix.bytesperline = 0; | ||
1393 | f->fmt.pix.sizeimage = | ||
1394 | dev->ts1.ts_packet_size * dev->ts1.ts_packet_count; | ||
1395 | f->fmt.pix.colorspace = 0; | ||
1396 | f->fmt.pix.width = dev->ts1.width; | ||
1397 | f->fmt.pix.height = dev->ts1.height; | ||
1398 | f->fmt.pix.field = fh->mpegq.field; | ||
1399 | dprintk(1, "VIDIOC_G_FMT: w: %d, h: %d, f: %d\n", | ||
1400 | dev->ts1.width, dev->ts1.height, fh->mpegq.field); | ||
1401 | return 0; | ||
1402 | } | ||
1403 | |||
1404 | static int vidioc_try_fmt_vid_cap(struct file *file, void *priv, | ||
1405 | struct v4l2_format *f) | ||
1406 | { | ||
1407 | struct cx23885_fh *fh = file->private_data; | ||
1408 | struct cx23885_dev *dev = fh->dev; | ||
1409 | |||
1410 | f->fmt.pix.pixelformat = V4L2_PIX_FMT_MPEG; | ||
1411 | f->fmt.pix.bytesperline = 0; | ||
1412 | f->fmt.pix.sizeimage = | ||
1413 | dev->ts1.ts_packet_size * dev->ts1.ts_packet_count; | ||
1414 | f->fmt.pix.colorspace = 0; | ||
1415 | dprintk(1, "VIDIOC_TRY_FMT: w: %d, h: %d, f: %d\n", | ||
1416 | dev->ts1.width, dev->ts1.height, fh->mpegq.field); | ||
1417 | return 0; | ||
1418 | } | ||
1419 | |||
1420 | static int vidioc_s_fmt_vid_cap(struct file *file, void *priv, | ||
1421 | struct v4l2_format *f) | ||
1422 | { | ||
1423 | struct cx23885_fh *fh = file->private_data; | ||
1424 | struct cx23885_dev *dev = fh->dev; | ||
1425 | |||
1426 | f->fmt.pix.pixelformat = V4L2_PIX_FMT_MPEG; | ||
1427 | f->fmt.pix.bytesperline = 0; | ||
1428 | f->fmt.pix.sizeimage = | ||
1429 | dev->ts1.ts_packet_size * dev->ts1.ts_packet_count; | ||
1430 | f->fmt.pix.colorspace = 0; | ||
1431 | dprintk(1, "VIDIOC_S_FMT: w: %d, h: %d, f: %d\n", | ||
1432 | f->fmt.pix.width, f->fmt.pix.height, f->fmt.pix.field); | ||
1433 | return 0; | ||
1434 | } | ||
1435 | |||
1436 | static int vidioc_reqbufs(struct file *file, void *priv, | ||
1437 | struct v4l2_requestbuffers *p) | ||
1438 | { | ||
1439 | struct cx23885_fh *fh = file->private_data; | ||
1440 | |||
1441 | return videobuf_reqbufs(&fh->mpegq, p); | ||
1442 | } | ||
1443 | |||
1444 | static int vidioc_querybuf(struct file *file, void *priv, | ||
1445 | struct v4l2_buffer *p) | ||
1446 | { | ||
1447 | struct cx23885_fh *fh = file->private_data; | ||
1448 | |||
1449 | return videobuf_querybuf(&fh->mpegq, p); | ||
1450 | } | ||
1451 | |||
1452 | static int vidioc_qbuf(struct file *file, void *priv, | ||
1453 | struct v4l2_buffer *p) | ||
1454 | { | ||
1455 | struct cx23885_fh *fh = file->private_data; | ||
1456 | |||
1457 | return videobuf_qbuf(&fh->mpegq, p); | ||
1458 | } | ||
1459 | |||
1460 | static int vidioc_dqbuf(struct file *file, void *priv, struct v4l2_buffer *b) | ||
1461 | { | ||
1462 | struct cx23885_fh *fh = priv; | ||
1463 | |||
1464 | return videobuf_dqbuf(&fh->mpegq, b, file->f_flags & O_NONBLOCK); | ||
1465 | } | ||
1466 | |||
1467 | |||
1468 | static int vidioc_streamon(struct file *file, void *priv, | ||
1469 | enum v4l2_buf_type i) | ||
1470 | { | ||
1471 | struct cx23885_fh *fh = file->private_data; | ||
1472 | |||
1473 | return videobuf_streamon(&fh->mpegq); | ||
1474 | } | ||
1475 | |||
1476 | static int vidioc_streamoff(struct file *file, void *priv, enum v4l2_buf_type i) | ||
1477 | { | ||
1478 | struct cx23885_fh *fh = file->private_data; | ||
1479 | |||
1480 | return videobuf_streamoff(&fh->mpegq); | ||
1481 | } | ||
1482 | |||
1483 | static int vidioc_g_ext_ctrls(struct file *file, void *priv, | ||
1484 | struct v4l2_ext_controls *f) | ||
1485 | { | ||
1486 | struct cx23885_fh *fh = priv; | ||
1487 | struct cx23885_dev *dev = fh->dev; | ||
1488 | |||
1489 | if (f->ctrl_class != V4L2_CTRL_CLASS_MPEG) | ||
1490 | return -EINVAL; | ||
1491 | return cx2341x_ext_ctrls(&dev->mpeg_params, 0, f, VIDIOC_G_EXT_CTRLS); | ||
1492 | } | ||
1493 | |||
1494 | static int vidioc_s_ext_ctrls(struct file *file, void *priv, | ||
1495 | struct v4l2_ext_controls *f) | ||
1496 | { | ||
1497 | struct cx23885_fh *fh = priv; | ||
1498 | struct cx23885_dev *dev = fh->dev; | ||
1499 | struct cx2341x_mpeg_params p; | ||
1500 | int err; | ||
1501 | |||
1502 | if (f->ctrl_class != V4L2_CTRL_CLASS_MPEG) | ||
1503 | return -EINVAL; | ||
1504 | |||
1505 | p = dev->mpeg_params; | ||
1506 | err = cx2341x_ext_ctrls(&p, 0, f, VIDIOC_S_EXT_CTRLS); | ||
1507 | |||
1508 | if (err == 0) { | ||
1509 | err = cx2341x_update(dev, cx23885_mbox_func, | ||
1510 | &dev->mpeg_params, &p); | ||
1511 | dev->mpeg_params = p; | ||
1512 | } | ||
1513 | return err; | ||
1514 | } | ||
1515 | |||
1516 | static int vidioc_try_ext_ctrls(struct file *file, void *priv, | ||
1517 | struct v4l2_ext_controls *f) | ||
1518 | { | ||
1519 | struct cx23885_fh *fh = priv; | ||
1520 | struct cx23885_dev *dev = fh->dev; | ||
1521 | struct cx2341x_mpeg_params p; | ||
1522 | int err; | ||
1523 | |||
1524 | if (f->ctrl_class != V4L2_CTRL_CLASS_MPEG) | ||
1525 | return -EINVAL; | ||
1526 | |||
1527 | p = dev->mpeg_params; | ||
1528 | err = cx2341x_ext_ctrls(&p, 0, f, VIDIOC_TRY_EXT_CTRLS); | ||
1529 | return err; | ||
1530 | } | ||
1531 | |||
1532 | static int vidioc_log_status(struct file *file, void *priv) | ||
1533 | { | ||
1534 | struct cx23885_fh *fh = priv; | ||
1535 | struct cx23885_dev *dev = fh->dev; | ||
1536 | char name[32 + 2]; | ||
1537 | |||
1538 | snprintf(name, sizeof(name), "%s/2", dev->name); | ||
1539 | printk(KERN_INFO | ||
1540 | "%s/2: ============ START LOG STATUS ============\n", | ||
1541 | dev->name); | ||
1542 | call_all(dev, core, log_status); | ||
1543 | cx2341x_log_status(&dev->mpeg_params, name); | ||
1544 | printk(KERN_INFO | ||
1545 | "%s/2: ============= END LOG STATUS =============\n", | ||
1546 | dev->name); | ||
1547 | return 0; | ||
1548 | } | ||
1549 | |||
1550 | static int vidioc_querymenu(struct file *file, void *priv, | ||
1551 | struct v4l2_querymenu *a) | ||
1552 | { | ||
1553 | struct cx23885_fh *fh = priv; | ||
1554 | struct cx23885_dev *dev = fh->dev; | ||
1555 | |||
1556 | return cx23885_querymenu(dev, a); | ||
1557 | } | ||
1558 | |||
1559 | static int vidioc_queryctrl(struct file *file, void *priv, | ||
1560 | struct v4l2_queryctrl *c) | ||
1561 | { | ||
1562 | struct cx23885_fh *fh = priv; | ||
1563 | struct cx23885_dev *dev = fh->dev; | ||
1564 | |||
1565 | return cx23885_queryctrl(dev, c); | ||
1566 | } | ||
1567 | |||
1568 | static int mpeg_open(struct file *file) | ||
1569 | { | ||
1570 | struct cx23885_dev *dev = video_drvdata(file); | ||
1571 | struct cx23885_fh *fh; | ||
1572 | |||
1573 | dprintk(2, "%s()\n", __func__); | ||
1574 | |||
1575 | /* allocate + initialize per filehandle data */ | ||
1576 | fh = kzalloc(sizeof(*fh), GFP_KERNEL); | ||
1577 | if (!fh) | ||
1578 | return -ENOMEM; | ||
1579 | |||
1580 | file->private_data = fh; | ||
1581 | fh->dev = dev; | ||
1582 | |||
1583 | videobuf_queue_sg_init(&fh->mpegq, &cx23885_qops, | ||
1584 | &dev->pci->dev, &dev->ts1.slock, | ||
1585 | V4L2_BUF_TYPE_VIDEO_CAPTURE, | ||
1586 | V4L2_FIELD_INTERLACED, | ||
1587 | sizeof(struct cx23885_buffer), | ||
1588 | fh, NULL); | ||
1589 | return 0; | ||
1590 | } | ||
1591 | |||
1592 | static int mpeg_release(struct file *file) | ||
1593 | { | ||
1594 | struct cx23885_fh *fh = file->private_data; | ||
1595 | struct cx23885_dev *dev = fh->dev; | ||
1596 | |||
1597 | dprintk(2, "%s()\n", __func__); | ||
1598 | |||
1599 | /* FIXME: Review this crap */ | ||
1600 | /* Shut device down on last close */ | ||
1601 | if (atomic_cmpxchg(&fh->v4l_reading, 1, 0) == 1) { | ||
1602 | if (atomic_dec_return(&dev->v4l_reader_count) == 0) { | ||
1603 | /* stop mpeg capture */ | ||
1604 | cx23885_api_cmd(fh->dev, CX2341X_ENC_STOP_CAPTURE, 3, 0, | ||
1605 | CX23885_END_NOW, CX23885_MPEG_CAPTURE, | ||
1606 | CX23885_RAW_BITS_NONE); | ||
1607 | |||
1608 | msleep(500); | ||
1609 | cx23885_417_check_encoder(dev); | ||
1610 | |||
1611 | cx23885_cancel_buffers(&fh->dev->ts1); | ||
1612 | } | ||
1613 | } | ||
1614 | |||
1615 | if (fh->mpegq.streaming) | ||
1616 | videobuf_streamoff(&fh->mpegq); | ||
1617 | if (fh->mpegq.reading) | ||
1618 | videobuf_read_stop(&fh->mpegq); | ||
1619 | |||
1620 | videobuf_mmap_free(&fh->mpegq); | ||
1621 | file->private_data = NULL; | ||
1622 | kfree(fh); | ||
1623 | |||
1624 | return 0; | ||
1625 | } | ||
1626 | |||
1627 | static ssize_t mpeg_read(struct file *file, char __user *data, | ||
1628 | size_t count, loff_t *ppos) | ||
1629 | { | ||
1630 | struct cx23885_fh *fh = file->private_data; | ||
1631 | struct cx23885_dev *dev = fh->dev; | ||
1632 | |||
1633 | dprintk(2, "%s()\n", __func__); | ||
1634 | |||
1635 | /* Deal w/ A/V decoder * and mpeg encoder sync issues. */ | ||
1636 | /* Start mpeg encoder on first read. */ | ||
1637 | if (atomic_cmpxchg(&fh->v4l_reading, 0, 1) == 0) { | ||
1638 | if (atomic_inc_return(&dev->v4l_reader_count) == 1) { | ||
1639 | if (cx23885_initialize_codec(dev) < 0) | ||
1640 | return -EINVAL; | ||
1641 | } | ||
1642 | } | ||
1643 | |||
1644 | return videobuf_read_stream(&fh->mpegq, data, count, ppos, 0, | ||
1645 | file->f_flags & O_NONBLOCK); | ||
1646 | } | ||
1647 | |||
1648 | static unsigned int mpeg_poll(struct file *file, | ||
1649 | struct poll_table_struct *wait) | ||
1650 | { | ||
1651 | struct cx23885_fh *fh = file->private_data; | ||
1652 | struct cx23885_dev *dev = fh->dev; | ||
1653 | |||
1654 | dprintk(2, "%s\n", __func__); | ||
1655 | |||
1656 | return videobuf_poll_stream(file, &fh->mpegq, wait); | ||
1657 | } | ||
1658 | |||
1659 | static int mpeg_mmap(struct file *file, struct vm_area_struct *vma) | ||
1660 | { | ||
1661 | struct cx23885_fh *fh = file->private_data; | ||
1662 | struct cx23885_dev *dev = fh->dev; | ||
1663 | |||
1664 | dprintk(2, "%s()\n", __func__); | ||
1665 | |||
1666 | return videobuf_mmap_mapper(&fh->mpegq, vma); | ||
1667 | } | ||
1668 | |||
1669 | static struct v4l2_file_operations mpeg_fops = { | ||
1670 | .owner = THIS_MODULE, | ||
1671 | .open = mpeg_open, | ||
1672 | .release = mpeg_release, | ||
1673 | .read = mpeg_read, | ||
1674 | .poll = mpeg_poll, | ||
1675 | .mmap = mpeg_mmap, | ||
1676 | .ioctl = video_ioctl2, | ||
1677 | }; | ||
1678 | |||
1679 | static const struct v4l2_ioctl_ops mpeg_ioctl_ops = { | ||
1680 | .vidioc_s_std = vidioc_s_std, | ||
1681 | .vidioc_enum_input = vidioc_enum_input, | ||
1682 | .vidioc_g_input = vidioc_g_input, | ||
1683 | .vidioc_s_input = vidioc_s_input, | ||
1684 | .vidioc_g_tuner = vidioc_g_tuner, | ||
1685 | .vidioc_s_tuner = vidioc_s_tuner, | ||
1686 | .vidioc_g_frequency = vidioc_g_frequency, | ||
1687 | .vidioc_s_frequency = vidioc_s_frequency, | ||
1688 | .vidioc_s_ctrl = vidioc_s_ctrl, | ||
1689 | .vidioc_querycap = vidioc_querycap, | ||
1690 | .vidioc_enum_fmt_vid_cap = vidioc_enum_fmt_vid_cap, | ||
1691 | .vidioc_g_fmt_vid_cap = vidioc_g_fmt_vid_cap, | ||
1692 | .vidioc_try_fmt_vid_cap = vidioc_try_fmt_vid_cap, | ||
1693 | .vidioc_s_fmt_vid_cap = vidioc_s_fmt_vid_cap, | ||
1694 | .vidioc_reqbufs = vidioc_reqbufs, | ||
1695 | .vidioc_querybuf = vidioc_querybuf, | ||
1696 | .vidioc_qbuf = vidioc_qbuf, | ||
1697 | .vidioc_dqbuf = vidioc_dqbuf, | ||
1698 | .vidioc_streamon = vidioc_streamon, | ||
1699 | .vidioc_streamoff = vidioc_streamoff, | ||
1700 | .vidioc_g_ext_ctrls = vidioc_g_ext_ctrls, | ||
1701 | .vidioc_s_ext_ctrls = vidioc_s_ext_ctrls, | ||
1702 | .vidioc_try_ext_ctrls = vidioc_try_ext_ctrls, | ||
1703 | .vidioc_log_status = vidioc_log_status, | ||
1704 | .vidioc_querymenu = vidioc_querymenu, | ||
1705 | .vidioc_queryctrl = vidioc_queryctrl, | ||
1706 | .vidioc_g_chip_ident = cx23885_g_chip_ident, | ||
1707 | #ifdef CONFIG_VIDEO_ADV_DEBUG | ||
1708 | .vidioc_g_register = cx23885_g_register, | ||
1709 | .vidioc_s_register = cx23885_s_register, | ||
1710 | #endif | ||
1711 | }; | ||
1712 | |||
1713 | static struct video_device cx23885_mpeg_template = { | ||
1714 | .name = "cx23885", | ||
1715 | .fops = &mpeg_fops, | ||
1716 | .ioctl_ops = &mpeg_ioctl_ops, | ||
1717 | .tvnorms = CX23885_NORMS, | ||
1718 | .current_norm = V4L2_STD_NTSC_M, | ||
1719 | }; | ||
1720 | |||
1721 | void cx23885_417_unregister(struct cx23885_dev *dev) | ||
1722 | { | ||
1723 | dprintk(1, "%s()\n", __func__); | ||
1724 | |||
1725 | if (dev->v4l_device) { | ||
1726 | if (video_is_registered(dev->v4l_device)) | ||
1727 | video_unregister_device(dev->v4l_device); | ||
1728 | else | ||
1729 | video_device_release(dev->v4l_device); | ||
1730 | dev->v4l_device = NULL; | ||
1731 | } | ||
1732 | } | ||
1733 | |||
1734 | static struct video_device *cx23885_video_dev_alloc( | ||
1735 | struct cx23885_tsport *tsport, | ||
1736 | struct pci_dev *pci, | ||
1737 | struct video_device *template, | ||
1738 | char *type) | ||
1739 | { | ||
1740 | struct video_device *vfd; | ||
1741 | struct cx23885_dev *dev = tsport->dev; | ||
1742 | |||
1743 | dprintk(1, "%s()\n", __func__); | ||
1744 | |||
1745 | vfd = video_device_alloc(); | ||
1746 | if (NULL == vfd) | ||
1747 | return NULL; | ||
1748 | *vfd = *template; | ||
1749 | snprintf(vfd->name, sizeof(vfd->name), "%s %s (%s)", dev->name, | ||
1750 | type, cx23885_boards[tsport->dev->board].name); | ||
1751 | vfd->parent = &pci->dev; | ||
1752 | vfd->release = video_device_release; | ||
1753 | return vfd; | ||
1754 | } | ||
1755 | |||
1756 | int cx23885_417_register(struct cx23885_dev *dev) | ||
1757 | { | ||
1758 | /* FIXME: Port1 hardcoded here */ | ||
1759 | int err = -ENODEV; | ||
1760 | struct cx23885_tsport *tsport = &dev->ts1; | ||
1761 | |||
1762 | dprintk(1, "%s()\n", __func__); | ||
1763 | |||
1764 | if (cx23885_boards[dev->board].portb != CX23885_MPEG_ENCODER) | ||
1765 | return err; | ||
1766 | |||
1767 | /* Set default TV standard */ | ||
1768 | dev->encodernorm = cx23885_tvnorms[0]; | ||
1769 | |||
1770 | if (dev->encodernorm.id & V4L2_STD_525_60) | ||
1771 | tsport->height = 480; | ||
1772 | else | ||
1773 | tsport->height = 576; | ||
1774 | |||
1775 | tsport->width = 720; | ||
1776 | cx2341x_fill_defaults(&dev->mpeg_params); | ||
1777 | |||
1778 | dev->mpeg_params.port = CX2341X_PORT_SERIAL; | ||
1779 | |||
1780 | /* Allocate and initialize V4L video device */ | ||
1781 | dev->v4l_device = cx23885_video_dev_alloc(tsport, | ||
1782 | dev->pci, &cx23885_mpeg_template, "mpeg"); | ||
1783 | video_set_drvdata(dev->v4l_device, dev); | ||
1784 | err = video_register_device(dev->v4l_device, | ||
1785 | VFL_TYPE_GRABBER, -1); | ||
1786 | if (err < 0) { | ||
1787 | printk(KERN_INFO "%s: can't register mpeg device\n", dev->name); | ||
1788 | return err; | ||
1789 | } | ||
1790 | |||
1791 | printk(KERN_INFO "%s: registered device %s [mpeg]\n", | ||
1792 | dev->name, video_device_node_name(dev->v4l_device)); | ||
1793 | |||
1794 | return 0; | ||
1795 | } | ||
diff --git a/drivers/media/video/cx23885/cx23885-av.c b/drivers/media/video/cx23885/cx23885-av.c new file mode 100644 index 00000000000..134ebddd860 --- /dev/null +++ b/drivers/media/video/cx23885/cx23885-av.c | |||
@@ -0,0 +1,35 @@ | |||
1 | /* | ||
2 | * Driver for the Conexant CX23885/7/8 PCIe bridge | ||
3 | * | ||
4 | * AV device support routines - non-input, non-vl42_subdev routines | ||
5 | * | ||
6 | * Copyright (C) 2010 Andy Walls <awalls@md.metrocast.net> | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or | ||
9 | * modify it under the terms of the GNU General Public License | ||
10 | * as published by the Free Software Foundation; either version 2 | ||
11 | * of the License, or (at your option) any later version. | ||
12 | * | ||
13 | * This program is distributed in the hope that it will be useful, | ||
14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
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., 51 Franklin Street, Fifth Floor, Boston, MA | ||
21 | * 02110-1301, USA. | ||
22 | */ | ||
23 | |||
24 | #include "cx23885.h" | ||
25 | |||
26 | void cx23885_av_work_handler(struct work_struct *work) | ||
27 | { | ||
28 | struct cx23885_dev *dev = | ||
29 | container_of(work, struct cx23885_dev, cx25840_work); | ||
30 | bool handled; | ||
31 | |||
32 | v4l2_subdev_call(dev->sd_cx25840, core, interrupt_service_routine, | ||
33 | PCI_MSK_AV_CORE, &handled); | ||
34 | cx23885_irq_enable(dev, PCI_MSK_AV_CORE); | ||
35 | } | ||
diff --git a/drivers/media/video/cx23885/cx23885-av.h b/drivers/media/video/cx23885/cx23885-av.h new file mode 100644 index 00000000000..d2915c3e53a --- /dev/null +++ b/drivers/media/video/cx23885/cx23885-av.h | |||
@@ -0,0 +1,27 @@ | |||
1 | /* | ||
2 | * Driver for the Conexant CX23885/7/8 PCIe bridge | ||
3 | * | ||
4 | * AV device support routines - non-input, non-vl42_subdev routines | ||
5 | * | ||
6 | * Copyright (C) 2010 Andy Walls <awalls@md.metrocast.net> | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or | ||
9 | * modify it under the terms of the GNU General Public License | ||
10 | * as published by the Free Software Foundation; either version 2 | ||
11 | * of the License, or (at your option) any later version. | ||
12 | * | ||
13 | * This program is distributed in the hope that it will be useful, | ||
14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
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., 51 Franklin Street, Fifth Floor, Boston, MA | ||
21 | * 02110-1301, USA. | ||
22 | */ | ||
23 | |||
24 | #ifndef _CX23885_AV_H_ | ||
25 | #define _CX23885_AV_H_ | ||
26 | void cx23885_av_work_handler(struct work_struct *work); | ||
27 | #endif | ||
diff --git a/drivers/media/video/cx23885/cx23885-cards.c b/drivers/media/video/cx23885/cx23885-cards.c new file mode 100644 index 00000000000..76b7563de39 --- /dev/null +++ b/drivers/media/video/cx23885/cx23885-cards.c | |||
@@ -0,0 +1,1476 @@ | |||
1 | /* | ||
2 | * Driver for the Conexant CX23885 PCIe bridge | ||
3 | * | ||
4 | * Copyright (c) 2006 Steven Toth <stoth@linuxtv.org> | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify | ||
7 | * it under the terms of the GNU General Public License as published by | ||
8 | * the Free Software Foundation; either version 2 of the License, or | ||
9 | * (at your option) any later version. | ||
10 | * | ||
11 | * This program is distributed in the hope that it will be useful, | ||
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
14 | * | ||
15 | * GNU General Public License for more details. | ||
16 | * | ||
17 | * You should have received a copy of the GNU General Public License | ||
18 | * along with this program; if not, write to the Free Software | ||
19 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
20 | */ | ||
21 | |||
22 | #include <linux/init.h> | ||
23 | #include <linux/module.h> | ||
24 | #include <linux/pci.h> | ||
25 | #include <linux/delay.h> | ||
26 | #include <media/cx25840.h> | ||
27 | #include <linux/firmware.h> | ||
28 | |||
29 | #include "../../../staging/altera-stapl/altera.h" | ||
30 | #include "cx23885.h" | ||
31 | #include "tuner-xc2028.h" | ||
32 | #include "netup-eeprom.h" | ||
33 | #include "netup-init.h" | ||
34 | #include "altera-ci.h" | ||
35 | #include "xc4000.h" | ||
36 | #include "xc5000.h" | ||
37 | #include "cx23888-ir.h" | ||
38 | |||
39 | static unsigned int netup_card_rev = 1; | ||
40 | module_param(netup_card_rev, int, 0644); | ||
41 | MODULE_PARM_DESC(netup_card_rev, | ||
42 | "NetUP Dual DVB-T/C CI card revision"); | ||
43 | static unsigned int enable_885_ir; | ||
44 | module_param(enable_885_ir, int, 0644); | ||
45 | MODULE_PARM_DESC(enable_885_ir, | ||
46 | "Enable integrated IR controller for supported\n" | ||
47 | "\t\t CX2388[57] boards that are wired for it:\n" | ||
48 | "\t\t\tHVR-1250 (reported safe)\n" | ||
49 | "\t\t\tTeVii S470 (reported unsafe)\n" | ||
50 | "\t\t This can cause an interrupt storm with some cards.\n" | ||
51 | "\t\t Default: 0 [Disabled]"); | ||
52 | |||
53 | /* ------------------------------------------------------------------ */ | ||
54 | /* board config info */ | ||
55 | |||
56 | struct cx23885_board cx23885_boards[] = { | ||
57 | [CX23885_BOARD_UNKNOWN] = { | ||
58 | .name = "UNKNOWN/GENERIC", | ||
59 | /* Ensure safe default for unknown boards */ | ||
60 | .clk_freq = 0, | ||
61 | .input = {{ | ||
62 | .type = CX23885_VMUX_COMPOSITE1, | ||
63 | .vmux = 0, | ||
64 | }, { | ||
65 | .type = CX23885_VMUX_COMPOSITE2, | ||
66 | .vmux = 1, | ||
67 | }, { | ||
68 | .type = CX23885_VMUX_COMPOSITE3, | ||
69 | .vmux = 2, | ||
70 | }, { | ||
71 | .type = CX23885_VMUX_COMPOSITE4, | ||
72 | .vmux = 3, | ||
73 | } }, | ||
74 | }, | ||
75 | [CX23885_BOARD_HAUPPAUGE_HVR1800lp] = { | ||
76 | .name = "Hauppauge WinTV-HVR1800lp", | ||
77 | .portc = CX23885_MPEG_DVB, | ||
78 | .input = {{ | ||
79 | .type = CX23885_VMUX_TELEVISION, | ||
80 | .vmux = 0, | ||
81 | .gpio0 = 0xff00, | ||
82 | }, { | ||
83 | .type = CX23885_VMUX_DEBUG, | ||
84 | .vmux = 0, | ||
85 | .gpio0 = 0xff01, | ||
86 | }, { | ||
87 | .type = CX23885_VMUX_COMPOSITE1, | ||
88 | .vmux = 1, | ||
89 | .gpio0 = 0xff02, | ||
90 | }, { | ||
91 | .type = CX23885_VMUX_SVIDEO, | ||
92 | .vmux = 2, | ||
93 | .gpio0 = 0xff02, | ||
94 | } }, | ||
95 | }, | ||
96 | [CX23885_BOARD_HAUPPAUGE_HVR1800] = { | ||
97 | .name = "Hauppauge WinTV-HVR1800", | ||
98 | .porta = CX23885_ANALOG_VIDEO, | ||
99 | .portb = CX23885_MPEG_ENCODER, | ||
100 | .portc = CX23885_MPEG_DVB, | ||
101 | .tuner_type = TUNER_PHILIPS_TDA8290, | ||
102 | .tuner_addr = 0x42, /* 0x84 >> 1 */ | ||
103 | .tuner_bus = 1, | ||
104 | .input = {{ | ||
105 | .type = CX23885_VMUX_TELEVISION, | ||
106 | .vmux = CX25840_VIN7_CH3 | | ||
107 | CX25840_VIN5_CH2 | | ||
108 | CX25840_VIN2_CH1, | ||
109 | .gpio0 = 0, | ||
110 | }, { | ||
111 | .type = CX23885_VMUX_COMPOSITE1, | ||
112 | .vmux = CX25840_VIN7_CH3 | | ||
113 | CX25840_VIN4_CH2 | | ||
114 | CX25840_VIN6_CH1, | ||
115 | .gpio0 = 0, | ||
116 | }, { | ||
117 | .type = CX23885_VMUX_SVIDEO, | ||
118 | .vmux = CX25840_VIN7_CH3 | | ||
119 | CX25840_VIN4_CH2 | | ||
120 | CX25840_VIN8_CH1 | | ||
121 | CX25840_SVIDEO_ON, | ||
122 | .gpio0 = 0, | ||
123 | } }, | ||
124 | }, | ||
125 | [CX23885_BOARD_HAUPPAUGE_HVR1250] = { | ||
126 | .name = "Hauppauge WinTV-HVR1250", | ||
127 | .portc = CX23885_MPEG_DVB, | ||
128 | .input = {{ | ||
129 | .type = CX23885_VMUX_TELEVISION, | ||
130 | .vmux = 0, | ||
131 | .gpio0 = 0xff00, | ||
132 | }, { | ||
133 | .type = CX23885_VMUX_DEBUG, | ||
134 | .vmux = 0, | ||
135 | .gpio0 = 0xff01, | ||
136 | }, { | ||
137 | .type = CX23885_VMUX_COMPOSITE1, | ||
138 | .vmux = 1, | ||
139 | .gpio0 = 0xff02, | ||
140 | }, { | ||
141 | .type = CX23885_VMUX_SVIDEO, | ||
142 | .vmux = 2, | ||
143 | .gpio0 = 0xff02, | ||
144 | } }, | ||
145 | }, | ||
146 | [CX23885_BOARD_DVICO_FUSIONHDTV_5_EXP] = { | ||
147 | .name = "DViCO FusionHDTV5 Express", | ||
148 | .portb = CX23885_MPEG_DVB, | ||
149 | }, | ||
150 | [CX23885_BOARD_HAUPPAUGE_HVR1500Q] = { | ||
151 | .name = "Hauppauge WinTV-HVR1500Q", | ||
152 | .portc = CX23885_MPEG_DVB, | ||
153 | }, | ||
154 | [CX23885_BOARD_HAUPPAUGE_HVR1500] = { | ||
155 | .name = "Hauppauge WinTV-HVR1500", | ||
156 | .portc = CX23885_MPEG_DVB, | ||
157 | }, | ||
158 | [CX23885_BOARD_HAUPPAUGE_HVR1200] = { | ||
159 | .name = "Hauppauge WinTV-HVR1200", | ||
160 | .portc = CX23885_MPEG_DVB, | ||
161 | }, | ||
162 | [CX23885_BOARD_HAUPPAUGE_HVR1700] = { | ||
163 | .name = "Hauppauge WinTV-HVR1700", | ||
164 | .portc = CX23885_MPEG_DVB, | ||
165 | }, | ||
166 | [CX23885_BOARD_HAUPPAUGE_HVR1400] = { | ||
167 | .name = "Hauppauge WinTV-HVR1400", | ||
168 | .portc = CX23885_MPEG_DVB, | ||
169 | }, | ||
170 | [CX23885_BOARD_DVICO_FUSIONHDTV_7_DUAL_EXP] = { | ||
171 | .name = "DViCO FusionHDTV7 Dual Express", | ||
172 | .portb = CX23885_MPEG_DVB, | ||
173 | .portc = CX23885_MPEG_DVB, | ||
174 | }, | ||
175 | [CX23885_BOARD_DVICO_FUSIONHDTV_DVB_T_DUAL_EXP] = { | ||
176 | .name = "DViCO FusionHDTV DVB-T Dual Express", | ||
177 | .portb = CX23885_MPEG_DVB, | ||
178 | .portc = CX23885_MPEG_DVB, | ||
179 | }, | ||
180 | [CX23885_BOARD_LEADTEK_WINFAST_PXDVR3200_H] = { | ||
181 | .name = "Leadtek Winfast PxDVR3200 H", | ||
182 | .portc = CX23885_MPEG_DVB, | ||
183 | }, | ||
184 | [CX23885_BOARD_LEADTEK_WINFAST_PXDVR3200_H_XC4000] = { | ||
185 | .name = "Leadtek Winfast PxDVR3200 H XC4000", | ||
186 | .porta = CX23885_ANALOG_VIDEO, | ||
187 | .portc = CX23885_MPEG_DVB, | ||
188 | .tuner_type = TUNER_XC4000, | ||
189 | .tuner_addr = 0x61, | ||
190 | .radio_type = TUNER_XC4000, | ||
191 | .radio_addr = 0x61, | ||
192 | .input = {{ | ||
193 | .type = CX23885_VMUX_TELEVISION, | ||
194 | .vmux = CX25840_VIN2_CH1 | | ||
195 | CX25840_VIN5_CH2 | | ||
196 | CX25840_NONE0_CH3, | ||
197 | }, { | ||
198 | .type = CX23885_VMUX_COMPOSITE1, | ||
199 | .vmux = CX25840_COMPOSITE1, | ||
200 | }, { | ||
201 | .type = CX23885_VMUX_SVIDEO, | ||
202 | .vmux = CX25840_SVIDEO_LUMA3 | | ||
203 | CX25840_SVIDEO_CHROMA4, | ||
204 | }, { | ||
205 | .type = CX23885_VMUX_COMPONENT, | ||
206 | .vmux = CX25840_VIN7_CH1 | | ||
207 | CX25840_VIN6_CH2 | | ||
208 | CX25840_VIN8_CH3 | | ||
209 | CX25840_COMPONENT_ON, | ||
210 | } }, | ||
211 | }, | ||
212 | [CX23885_BOARD_COMPRO_VIDEOMATE_E650F] = { | ||
213 | .name = "Compro VideoMate E650F", | ||
214 | .portc = CX23885_MPEG_DVB, | ||
215 | }, | ||
216 | [CX23885_BOARD_TBS_6920] = { | ||
217 | .name = "TurboSight TBS 6920", | ||
218 | .portb = CX23885_MPEG_DVB, | ||
219 | }, | ||
220 | [CX23885_BOARD_TEVII_S470] = { | ||
221 | .name = "TeVii S470", | ||
222 | .portb = CX23885_MPEG_DVB, | ||
223 | }, | ||
224 | [CX23885_BOARD_DVBWORLD_2005] = { | ||
225 | .name = "DVBWorld DVB-S2 2005", | ||
226 | .portb = CX23885_MPEG_DVB, | ||
227 | }, | ||
228 | [CX23885_BOARD_NETUP_DUAL_DVBS2_CI] = { | ||
229 | .ci_type = 1, | ||
230 | .name = "NetUP Dual DVB-S2 CI", | ||
231 | .portb = CX23885_MPEG_DVB, | ||
232 | .portc = CX23885_MPEG_DVB, | ||
233 | }, | ||
234 | [CX23885_BOARD_HAUPPAUGE_HVR1270] = { | ||
235 | .name = "Hauppauge WinTV-HVR1270", | ||
236 | .portc = CX23885_MPEG_DVB, | ||
237 | }, | ||
238 | [CX23885_BOARD_HAUPPAUGE_HVR1275] = { | ||
239 | .name = "Hauppauge WinTV-HVR1275", | ||
240 | .portc = CX23885_MPEG_DVB, | ||
241 | }, | ||
242 | [CX23885_BOARD_HAUPPAUGE_HVR1255] = { | ||
243 | .name = "Hauppauge WinTV-HVR1255", | ||
244 | .portc = CX23885_MPEG_DVB, | ||
245 | }, | ||
246 | [CX23885_BOARD_HAUPPAUGE_HVR1210] = { | ||
247 | .name = "Hauppauge WinTV-HVR1210", | ||
248 | .portc = CX23885_MPEG_DVB, | ||
249 | }, | ||
250 | [CX23885_BOARD_MYGICA_X8506] = { | ||
251 | .name = "Mygica X8506 DMB-TH", | ||
252 | .tuner_type = TUNER_XC5000, | ||
253 | .tuner_addr = 0x61, | ||
254 | .tuner_bus = 1, | ||
255 | .porta = CX23885_ANALOG_VIDEO, | ||
256 | .portb = CX23885_MPEG_DVB, | ||
257 | .input = { | ||
258 | { | ||
259 | .type = CX23885_VMUX_TELEVISION, | ||
260 | .vmux = CX25840_COMPOSITE2, | ||
261 | }, | ||
262 | { | ||
263 | .type = CX23885_VMUX_COMPOSITE1, | ||
264 | .vmux = CX25840_COMPOSITE8, | ||
265 | }, | ||
266 | { | ||
267 | .type = CX23885_VMUX_SVIDEO, | ||
268 | .vmux = CX25840_SVIDEO_LUMA3 | | ||
269 | CX25840_SVIDEO_CHROMA4, | ||
270 | }, | ||
271 | { | ||
272 | .type = CX23885_VMUX_COMPONENT, | ||
273 | .vmux = CX25840_COMPONENT_ON | | ||
274 | CX25840_VIN1_CH1 | | ||
275 | CX25840_VIN6_CH2 | | ||
276 | CX25840_VIN7_CH3, | ||
277 | }, | ||
278 | }, | ||
279 | }, | ||
280 | [CX23885_BOARD_MAGICPRO_PROHDTVE2] = { | ||
281 | .name = "Magic-Pro ProHDTV Extreme 2", | ||
282 | .tuner_type = TUNER_XC5000, | ||
283 | .tuner_addr = 0x61, | ||
284 | .tuner_bus = 1, | ||
285 | .porta = CX23885_ANALOG_VIDEO, | ||
286 | .portb = CX23885_MPEG_DVB, | ||
287 | .input = { | ||
288 | { | ||
289 | .type = CX23885_VMUX_TELEVISION, | ||
290 | .vmux = CX25840_COMPOSITE2, | ||
291 | }, | ||
292 | { | ||
293 | .type = CX23885_VMUX_COMPOSITE1, | ||
294 | .vmux = CX25840_COMPOSITE8, | ||
295 | }, | ||
296 | { | ||
297 | .type = CX23885_VMUX_SVIDEO, | ||
298 | .vmux = CX25840_SVIDEO_LUMA3 | | ||
299 | CX25840_SVIDEO_CHROMA4, | ||
300 | }, | ||
301 | { | ||
302 | .type = CX23885_VMUX_COMPONENT, | ||
303 | .vmux = CX25840_COMPONENT_ON | | ||
304 | CX25840_VIN1_CH1 | | ||
305 | CX25840_VIN6_CH2 | | ||
306 | CX25840_VIN7_CH3, | ||
307 | }, | ||
308 | }, | ||
309 | }, | ||
310 | [CX23885_BOARD_HAUPPAUGE_HVR1850] = { | ||
311 | .name = "Hauppauge WinTV-HVR1850", | ||
312 | .portb = CX23885_MPEG_ENCODER, | ||
313 | .portc = CX23885_MPEG_DVB, | ||
314 | }, | ||
315 | [CX23885_BOARD_COMPRO_VIDEOMATE_E800] = { | ||
316 | .name = "Compro VideoMate E800", | ||
317 | .portc = CX23885_MPEG_DVB, | ||
318 | }, | ||
319 | [CX23885_BOARD_HAUPPAUGE_HVR1290] = { | ||
320 | .name = "Hauppauge WinTV-HVR1290", | ||
321 | .portc = CX23885_MPEG_DVB, | ||
322 | }, | ||
323 | [CX23885_BOARD_MYGICA_X8558PRO] = { | ||
324 | .name = "Mygica X8558 PRO DMB-TH", | ||
325 | .portb = CX23885_MPEG_DVB, | ||
326 | .portc = CX23885_MPEG_DVB, | ||
327 | }, | ||
328 | [CX23885_BOARD_LEADTEK_WINFAST_PXTV1200] = { | ||
329 | .name = "LEADTEK WinFast PxTV1200", | ||
330 | .porta = CX23885_ANALOG_VIDEO, | ||
331 | .tuner_type = TUNER_XC2028, | ||
332 | .tuner_addr = 0x61, | ||
333 | .tuner_bus = 1, | ||
334 | .input = {{ | ||
335 | .type = CX23885_VMUX_TELEVISION, | ||
336 | .vmux = CX25840_VIN2_CH1 | | ||
337 | CX25840_VIN5_CH2 | | ||
338 | CX25840_NONE0_CH3, | ||
339 | }, { | ||
340 | .type = CX23885_VMUX_COMPOSITE1, | ||
341 | .vmux = CX25840_COMPOSITE1, | ||
342 | }, { | ||
343 | .type = CX23885_VMUX_SVIDEO, | ||
344 | .vmux = CX25840_SVIDEO_LUMA3 | | ||
345 | CX25840_SVIDEO_CHROMA4, | ||
346 | }, { | ||
347 | .type = CX23885_VMUX_COMPONENT, | ||
348 | .vmux = CX25840_VIN7_CH1 | | ||
349 | CX25840_VIN6_CH2 | | ||
350 | CX25840_VIN8_CH3 | | ||
351 | CX25840_COMPONENT_ON, | ||
352 | } }, | ||
353 | }, | ||
354 | [CX23885_BOARD_GOTVIEW_X5_3D_HYBRID] = { | ||
355 | .name = "GoTView X5 3D Hybrid", | ||
356 | .tuner_type = TUNER_XC5000, | ||
357 | .tuner_addr = 0x64, | ||
358 | .tuner_bus = 1, | ||
359 | .porta = CX23885_ANALOG_VIDEO, | ||
360 | .portb = CX23885_MPEG_DVB, | ||
361 | .input = {{ | ||
362 | .type = CX23885_VMUX_TELEVISION, | ||
363 | .vmux = CX25840_VIN2_CH1 | | ||
364 | CX25840_VIN5_CH2, | ||
365 | .gpio0 = 0x02, | ||
366 | }, { | ||
367 | .type = CX23885_VMUX_COMPOSITE1, | ||
368 | .vmux = CX23885_VMUX_COMPOSITE1, | ||
369 | }, { | ||
370 | .type = CX23885_VMUX_SVIDEO, | ||
371 | .vmux = CX25840_SVIDEO_LUMA3 | | ||
372 | CX25840_SVIDEO_CHROMA4, | ||
373 | } }, | ||
374 | }, | ||
375 | [CX23885_BOARD_NETUP_DUAL_DVB_T_C_CI_RF] = { | ||
376 | .ci_type = 2, | ||
377 | .name = "NetUP Dual DVB-T/C-CI RF", | ||
378 | .porta = CX23885_ANALOG_VIDEO, | ||
379 | .portb = CX23885_MPEG_DVB, | ||
380 | .portc = CX23885_MPEG_DVB, | ||
381 | .num_fds_portb = 2, | ||
382 | .num_fds_portc = 2, | ||
383 | .tuner_type = TUNER_XC5000, | ||
384 | .tuner_addr = 0x64, | ||
385 | .input = { { | ||
386 | .type = CX23885_VMUX_TELEVISION, | ||
387 | .vmux = CX25840_COMPOSITE1, | ||
388 | } }, | ||
389 | }, | ||
390 | }; | ||
391 | const unsigned int cx23885_bcount = ARRAY_SIZE(cx23885_boards); | ||
392 | |||
393 | /* ------------------------------------------------------------------ */ | ||
394 | /* PCI subsystem IDs */ | ||
395 | |||
396 | struct cx23885_subid cx23885_subids[] = { | ||
397 | { | ||
398 | .subvendor = 0x0070, | ||
399 | .subdevice = 0x3400, | ||
400 | .card = CX23885_BOARD_UNKNOWN, | ||
401 | }, { | ||
402 | .subvendor = 0x0070, | ||
403 | .subdevice = 0x7600, | ||
404 | .card = CX23885_BOARD_HAUPPAUGE_HVR1800lp, | ||
405 | }, { | ||
406 | .subvendor = 0x0070, | ||
407 | .subdevice = 0x7800, | ||
408 | .card = CX23885_BOARD_HAUPPAUGE_HVR1800, | ||
409 | }, { | ||
410 | .subvendor = 0x0070, | ||
411 | .subdevice = 0x7801, | ||
412 | .card = CX23885_BOARD_HAUPPAUGE_HVR1800, | ||
413 | }, { | ||
414 | .subvendor = 0x0070, | ||
415 | .subdevice = 0x7809, | ||
416 | .card = CX23885_BOARD_HAUPPAUGE_HVR1800, | ||
417 | }, { | ||
418 | .subvendor = 0x0070, | ||
419 | .subdevice = 0x7911, | ||
420 | .card = CX23885_BOARD_HAUPPAUGE_HVR1250, | ||
421 | }, { | ||
422 | .subvendor = 0x18ac, | ||
423 | .subdevice = 0xd500, | ||
424 | .card = CX23885_BOARD_DVICO_FUSIONHDTV_5_EXP, | ||
425 | }, { | ||
426 | .subvendor = 0x0070, | ||
427 | .subdevice = 0x7790, | ||
428 | .card = CX23885_BOARD_HAUPPAUGE_HVR1500Q, | ||
429 | }, { | ||
430 | .subvendor = 0x0070, | ||
431 | .subdevice = 0x7797, | ||
432 | .card = CX23885_BOARD_HAUPPAUGE_HVR1500Q, | ||
433 | }, { | ||
434 | .subvendor = 0x0070, | ||
435 | .subdevice = 0x7710, | ||
436 | .card = CX23885_BOARD_HAUPPAUGE_HVR1500, | ||
437 | }, { | ||
438 | .subvendor = 0x0070, | ||
439 | .subdevice = 0x7717, | ||
440 | .card = CX23885_BOARD_HAUPPAUGE_HVR1500, | ||
441 | }, { | ||
442 | .subvendor = 0x0070, | ||
443 | .subdevice = 0x71d1, | ||
444 | .card = CX23885_BOARD_HAUPPAUGE_HVR1200, | ||
445 | }, { | ||
446 | .subvendor = 0x0070, | ||
447 | .subdevice = 0x71d3, | ||
448 | .card = CX23885_BOARD_HAUPPAUGE_HVR1200, | ||
449 | }, { | ||
450 | .subvendor = 0x0070, | ||
451 | .subdevice = 0x8101, | ||
452 | .card = CX23885_BOARD_HAUPPAUGE_HVR1700, | ||
453 | }, { | ||
454 | .subvendor = 0x0070, | ||
455 | .subdevice = 0x8010, | ||
456 | .card = CX23885_BOARD_HAUPPAUGE_HVR1400, | ||
457 | }, { | ||
458 | .subvendor = 0x18ac, | ||
459 | .subdevice = 0xd618, | ||
460 | .card = CX23885_BOARD_DVICO_FUSIONHDTV_7_DUAL_EXP, | ||
461 | }, { | ||
462 | .subvendor = 0x18ac, | ||
463 | .subdevice = 0xdb78, | ||
464 | .card = CX23885_BOARD_DVICO_FUSIONHDTV_DVB_T_DUAL_EXP, | ||
465 | }, { | ||
466 | .subvendor = 0x107d, | ||
467 | .subdevice = 0x6681, | ||
468 | .card = CX23885_BOARD_LEADTEK_WINFAST_PXDVR3200_H, | ||
469 | }, { | ||
470 | .subvendor = 0x107d, | ||
471 | .subdevice = 0x6f39, | ||
472 | .card = CX23885_BOARD_LEADTEK_WINFAST_PXDVR3200_H_XC4000, | ||
473 | }, { | ||
474 | .subvendor = 0x185b, | ||
475 | .subdevice = 0xe800, | ||
476 | .card = CX23885_BOARD_COMPRO_VIDEOMATE_E650F, | ||
477 | }, { | ||
478 | .subvendor = 0x6920, | ||
479 | .subdevice = 0x8888, | ||
480 | .card = CX23885_BOARD_TBS_6920, | ||
481 | }, { | ||
482 | .subvendor = 0xd470, | ||
483 | .subdevice = 0x9022, | ||
484 | .card = CX23885_BOARD_TEVII_S470, | ||
485 | }, { | ||
486 | .subvendor = 0x0001, | ||
487 | .subdevice = 0x2005, | ||
488 | .card = CX23885_BOARD_DVBWORLD_2005, | ||
489 | }, { | ||
490 | .subvendor = 0x1b55, | ||
491 | .subdevice = 0x2a2c, | ||
492 | .card = CX23885_BOARD_NETUP_DUAL_DVBS2_CI, | ||
493 | }, { | ||
494 | .subvendor = 0x0070, | ||
495 | .subdevice = 0x2211, | ||
496 | .card = CX23885_BOARD_HAUPPAUGE_HVR1270, | ||
497 | }, { | ||
498 | .subvendor = 0x0070, | ||
499 | .subdevice = 0x2215, | ||
500 | .card = CX23885_BOARD_HAUPPAUGE_HVR1275, | ||
501 | }, { | ||
502 | .subvendor = 0x0070, | ||
503 | .subdevice = 0x221d, | ||
504 | .card = CX23885_BOARD_HAUPPAUGE_HVR1275, | ||
505 | }, { | ||
506 | .subvendor = 0x0070, | ||
507 | .subdevice = 0x2251, | ||
508 | .card = CX23885_BOARD_HAUPPAUGE_HVR1255, | ||
509 | }, { | ||
510 | .subvendor = 0x0070, | ||
511 | .subdevice = 0x2259, | ||
512 | .card = CX23885_BOARD_HAUPPAUGE_HVR1255, | ||
513 | }, { | ||
514 | .subvendor = 0x0070, | ||
515 | .subdevice = 0x2291, | ||
516 | .card = CX23885_BOARD_HAUPPAUGE_HVR1210, | ||
517 | }, { | ||
518 | .subvendor = 0x0070, | ||
519 | .subdevice = 0x2295, | ||
520 | .card = CX23885_BOARD_HAUPPAUGE_HVR1210, | ||
521 | }, { | ||
522 | .subvendor = 0x0070, | ||
523 | .subdevice = 0x2299, | ||
524 | .card = CX23885_BOARD_HAUPPAUGE_HVR1210, | ||
525 | }, { | ||
526 | .subvendor = 0x0070, | ||
527 | .subdevice = 0x229d, | ||
528 | .card = CX23885_BOARD_HAUPPAUGE_HVR1210, /* HVR1215 */ | ||
529 | }, { | ||
530 | .subvendor = 0x0070, | ||
531 | .subdevice = 0x22f0, | ||
532 | .card = CX23885_BOARD_HAUPPAUGE_HVR1210, | ||
533 | }, { | ||
534 | .subvendor = 0x0070, | ||
535 | .subdevice = 0x22f1, | ||
536 | .card = CX23885_BOARD_HAUPPAUGE_HVR1255, | ||
537 | }, { | ||
538 | .subvendor = 0x0070, | ||
539 | .subdevice = 0x22f2, | ||
540 | .card = CX23885_BOARD_HAUPPAUGE_HVR1275, | ||
541 | }, { | ||
542 | .subvendor = 0x0070, | ||
543 | .subdevice = 0x22f3, | ||
544 | .card = CX23885_BOARD_HAUPPAUGE_HVR1210, /* HVR1215 */ | ||
545 | }, { | ||
546 | .subvendor = 0x0070, | ||
547 | .subdevice = 0x22f4, | ||
548 | .card = CX23885_BOARD_HAUPPAUGE_HVR1210, | ||
549 | }, { | ||
550 | .subvendor = 0x0070, | ||
551 | .subdevice = 0x22f5, | ||
552 | .card = CX23885_BOARD_HAUPPAUGE_HVR1210, /* HVR1215 */ | ||
553 | }, { | ||
554 | .subvendor = 0x14f1, | ||
555 | .subdevice = 0x8651, | ||
556 | .card = CX23885_BOARD_MYGICA_X8506, | ||
557 | }, { | ||
558 | .subvendor = 0x14f1, | ||
559 | .subdevice = 0x8657, | ||
560 | .card = CX23885_BOARD_MAGICPRO_PROHDTVE2, | ||
561 | }, { | ||
562 | .subvendor = 0x0070, | ||
563 | .subdevice = 0x8541, | ||
564 | .card = CX23885_BOARD_HAUPPAUGE_HVR1850, | ||
565 | }, { | ||
566 | .subvendor = 0x1858, | ||
567 | .subdevice = 0xe800, | ||
568 | .card = CX23885_BOARD_COMPRO_VIDEOMATE_E800, | ||
569 | }, { | ||
570 | .subvendor = 0x0070, | ||
571 | .subdevice = 0x8551, | ||
572 | .card = CX23885_BOARD_HAUPPAUGE_HVR1290, | ||
573 | }, { | ||
574 | .subvendor = 0x14f1, | ||
575 | .subdevice = 0x8578, | ||
576 | .card = CX23885_BOARD_MYGICA_X8558PRO, | ||
577 | }, { | ||
578 | .subvendor = 0x107d, | ||
579 | .subdevice = 0x6f22, | ||
580 | .card = CX23885_BOARD_LEADTEK_WINFAST_PXTV1200, | ||
581 | }, { | ||
582 | .subvendor = 0x5654, | ||
583 | .subdevice = 0x2390, | ||
584 | .card = CX23885_BOARD_GOTVIEW_X5_3D_HYBRID, | ||
585 | }, { | ||
586 | .subvendor = 0x1b55, | ||
587 | .subdevice = 0xe2e4, | ||
588 | .card = CX23885_BOARD_NETUP_DUAL_DVB_T_C_CI_RF, | ||
589 | }, | ||
590 | }; | ||
591 | const unsigned int cx23885_idcount = ARRAY_SIZE(cx23885_subids); | ||
592 | |||
593 | void cx23885_card_list(struct cx23885_dev *dev) | ||
594 | { | ||
595 | int i; | ||
596 | |||
597 | if (0 == dev->pci->subsystem_vendor && | ||
598 | 0 == dev->pci->subsystem_device) { | ||
599 | printk(KERN_INFO | ||
600 | "%s: Board has no valid PCIe Subsystem ID and can't\n" | ||
601 | "%s: be autodetected. Pass card=<n> insmod option\n" | ||
602 | "%s: to workaround that. Redirect complaints to the\n" | ||
603 | "%s: vendor of the TV card. Best regards,\n" | ||
604 | "%s: -- tux\n", | ||
605 | dev->name, dev->name, dev->name, dev->name, dev->name); | ||
606 | } else { | ||
607 | printk(KERN_INFO | ||
608 | "%s: Your board isn't known (yet) to the driver.\n" | ||
609 | "%s: Try to pick one of the existing card configs via\n" | ||
610 | "%s: card=<n> insmod option. Updating to the latest\n" | ||
611 | "%s: version might help as well.\n", | ||
612 | dev->name, dev->name, dev->name, dev->name); | ||
613 | } | ||
614 | printk(KERN_INFO "%s: Here is a list of valid choices for the card=<n> insmod option:\n", | ||
615 | dev->name); | ||
616 | for (i = 0; i < cx23885_bcount; i++) | ||
617 | printk(KERN_INFO "%s: card=%d -> %s\n", | ||
618 | dev->name, i, cx23885_boards[i].name); | ||
619 | } | ||
620 | |||
621 | static void hauppauge_eeprom(struct cx23885_dev *dev, u8 *eeprom_data) | ||
622 | { | ||
623 | struct tveeprom tv; | ||
624 | |||
625 | tveeprom_hauppauge_analog(&dev->i2c_bus[0].i2c_client, &tv, | ||
626 | eeprom_data); | ||
627 | |||
628 | /* Make sure we support the board model */ | ||
629 | switch (tv.model) { | ||
630 | case 22001: | ||
631 | /* WinTV-HVR1270 (PCIe, Retail, half height) | ||
632 | * ATSC/QAM and basic analog, IR Blast */ | ||
633 | case 22009: | ||
634 | /* WinTV-HVR1210 (PCIe, Retail, half height) | ||
635 | * DVB-T and basic analog, IR Blast */ | ||
636 | case 22011: | ||
637 | /* WinTV-HVR1270 (PCIe, Retail, half height) | ||
638 | * ATSC/QAM and basic analog, IR Recv */ | ||
639 | case 22019: | ||
640 | /* WinTV-HVR1210 (PCIe, Retail, half height) | ||
641 | * DVB-T and basic analog, IR Recv */ | ||
642 | case 22021: | ||
643 | /* WinTV-HVR1275 (PCIe, Retail, half height) | ||
644 | * ATSC/QAM and basic analog, IR Recv */ | ||
645 | case 22029: | ||
646 | /* WinTV-HVR1210 (PCIe, Retail, half height) | ||
647 | * DVB-T and basic analog, IR Recv */ | ||
648 | case 22101: | ||
649 | /* WinTV-HVR1270 (PCIe, Retail, full height) | ||
650 | * ATSC/QAM and basic analog, IR Blast */ | ||
651 | case 22109: | ||
652 | /* WinTV-HVR1210 (PCIe, Retail, full height) | ||
653 | * DVB-T and basic analog, IR Blast */ | ||
654 | case 22111: | ||
655 | /* WinTV-HVR1270 (PCIe, Retail, full height) | ||
656 | * ATSC/QAM and basic analog, IR Recv */ | ||
657 | case 22119: | ||
658 | /* WinTV-HVR1210 (PCIe, Retail, full height) | ||
659 | * DVB-T and basic analog, IR Recv */ | ||
660 | case 22121: | ||
661 | /* WinTV-HVR1275 (PCIe, Retail, full height) | ||
662 | * ATSC/QAM and basic analog, IR Recv */ | ||
663 | case 22129: | ||
664 | /* WinTV-HVR1210 (PCIe, Retail, full height) | ||
665 | * DVB-T and basic analog, IR Recv */ | ||
666 | case 71009: | ||
667 | /* WinTV-HVR1200 (PCIe, Retail, full height) | ||
668 | * DVB-T and basic analog */ | ||
669 | case 71359: | ||
670 | /* WinTV-HVR1200 (PCIe, OEM, half height) | ||
671 | * DVB-T and basic analog */ | ||
672 | case 71439: | ||
673 | /* WinTV-HVR1200 (PCIe, OEM, half height) | ||
674 | * DVB-T and basic analog */ | ||
675 | case 71449: | ||
676 | /* WinTV-HVR1200 (PCIe, OEM, full height) | ||
677 | * DVB-T and basic analog */ | ||
678 | case 71939: | ||
679 | /* WinTV-HVR1200 (PCIe, OEM, half height) | ||
680 | * DVB-T and basic analog */ | ||
681 | case 71949: | ||
682 | /* WinTV-HVR1200 (PCIe, OEM, full height) | ||
683 | * DVB-T and basic analog */ | ||
684 | case 71959: | ||
685 | /* WinTV-HVR1200 (PCIe, OEM, full height) | ||
686 | * DVB-T and basic analog */ | ||
687 | case 71979: | ||
688 | /* WinTV-HVR1200 (PCIe, OEM, half height) | ||
689 | * DVB-T and basic analog */ | ||
690 | case 71999: | ||
691 | /* WinTV-HVR1200 (PCIe, OEM, full height) | ||
692 | * DVB-T and basic analog */ | ||
693 | case 76601: | ||
694 | /* WinTV-HVR1800lp (PCIe, Retail, No IR, Dual | ||
695 | channel ATSC and MPEG2 HW Encoder */ | ||
696 | case 77001: | ||
697 | /* WinTV-HVR1500 (Express Card, OEM, No IR, ATSC | ||
698 | and Basic analog */ | ||
699 | case 77011: | ||
700 | /* WinTV-HVR1500 (Express Card, Retail, No IR, ATSC | ||
701 | and Basic analog */ | ||
702 | case 77041: | ||
703 | /* WinTV-HVR1500Q (Express Card, OEM, No IR, ATSC/QAM | ||
704 | and Basic analog */ | ||
705 | case 77051: | ||
706 | /* WinTV-HVR1500Q (Express Card, Retail, No IR, ATSC/QAM | ||
707 | and Basic analog */ | ||
708 | case 78011: | ||
709 | /* WinTV-HVR1800 (PCIe, Retail, 3.5mm in, IR, No FM, | ||
710 | Dual channel ATSC and MPEG2 HW Encoder */ | ||
711 | case 78501: | ||
712 | /* WinTV-HVR1800 (PCIe, OEM, RCA in, No IR, FM, | ||
713 | Dual channel ATSC and MPEG2 HW Encoder */ | ||
714 | case 78521: | ||
715 | /* WinTV-HVR1800 (PCIe, OEM, RCA in, No IR, FM, | ||
716 | Dual channel ATSC and MPEG2 HW Encoder */ | ||
717 | case 78531: | ||
718 | /* WinTV-HVR1800 (PCIe, OEM, RCA in, No IR, No FM, | ||
719 | Dual channel ATSC and MPEG2 HW Encoder */ | ||
720 | case 78631: | ||
721 | /* WinTV-HVR1800 (PCIe, OEM, No IR, No FM, | ||
722 | Dual channel ATSC and MPEG2 HW Encoder */ | ||
723 | case 79001: | ||
724 | /* WinTV-HVR1250 (PCIe, Retail, IR, full height, | ||
725 | ATSC and Basic analog */ | ||
726 | case 79101: | ||
727 | /* WinTV-HVR1250 (PCIe, Retail, IR, half height, | ||
728 | ATSC and Basic analog */ | ||
729 | case 79501: | ||
730 | /* WinTV-HVR1250 (PCIe, No IR, half height, | ||
731 | ATSC [at least] and Basic analog) */ | ||
732 | case 79561: | ||
733 | /* WinTV-HVR1250 (PCIe, OEM, No IR, half height, | ||
734 | ATSC and Basic analog */ | ||
735 | case 79571: | ||
736 | /* WinTV-HVR1250 (PCIe, OEM, No IR, full height, | ||
737 | ATSC and Basic analog */ | ||
738 | case 79671: | ||
739 | /* WinTV-HVR1250 (PCIe, OEM, No IR, half height, | ||
740 | ATSC and Basic analog */ | ||
741 | case 80019: | ||
742 | /* WinTV-HVR1400 (Express Card, Retail, IR, | ||
743 | * DVB-T and Basic analog */ | ||
744 | case 81509: | ||
745 | /* WinTV-HVR1700 (PCIe, OEM, No IR, half height) | ||
746 | * DVB-T and MPEG2 HW Encoder */ | ||
747 | case 81519: | ||
748 | /* WinTV-HVR1700 (PCIe, OEM, No IR, full height) | ||
749 | * DVB-T and MPEG2 HW Encoder */ | ||
750 | break; | ||
751 | case 85021: | ||
752 | /* WinTV-HVR1850 (PCIe, Retail, 3.5mm in, IR, FM, | ||
753 | Dual channel ATSC and MPEG2 HW Encoder */ | ||
754 | break; | ||
755 | case 85721: | ||
756 | /* WinTV-HVR1290 (PCIe, OEM, RCA in, IR, | ||
757 | Dual channel ATSC and Basic analog */ | ||
758 | break; | ||
759 | default: | ||
760 | printk(KERN_WARNING "%s: warning: " | ||
761 | "unknown hauppauge model #%d\n", | ||
762 | dev->name, tv.model); | ||
763 | break; | ||
764 | } | ||
765 | |||
766 | printk(KERN_INFO "%s: hauppauge eeprom: model=%d\n", | ||
767 | dev->name, tv.model); | ||
768 | } | ||
769 | |||
770 | int cx23885_tuner_callback(void *priv, int component, int command, int arg) | ||
771 | { | ||
772 | struct cx23885_tsport *port = priv; | ||
773 | struct cx23885_dev *dev = port->dev; | ||
774 | u32 bitmask = 0; | ||
775 | |||
776 | if (command == XC2028_RESET_CLK) | ||
777 | return 0; | ||
778 | |||
779 | if (command != 0) { | ||
780 | printk(KERN_ERR "%s(): Unknown command 0x%x.\n", | ||
781 | __func__, command); | ||
782 | return -EINVAL; | ||
783 | } | ||
784 | |||
785 | switch (dev->board) { | ||
786 | case CX23885_BOARD_HAUPPAUGE_HVR1400: | ||
787 | case CX23885_BOARD_HAUPPAUGE_HVR1500: | ||
788 | case CX23885_BOARD_HAUPPAUGE_HVR1500Q: | ||
789 | case CX23885_BOARD_LEADTEK_WINFAST_PXDVR3200_H: | ||
790 | case CX23885_BOARD_LEADTEK_WINFAST_PXDVR3200_H_XC4000: | ||
791 | case CX23885_BOARD_COMPRO_VIDEOMATE_E650F: | ||
792 | case CX23885_BOARD_COMPRO_VIDEOMATE_E800: | ||
793 | case CX23885_BOARD_LEADTEK_WINFAST_PXTV1200: | ||
794 | /* Tuner Reset Command */ | ||
795 | bitmask = 0x04; | ||
796 | break; | ||
797 | case CX23885_BOARD_DVICO_FUSIONHDTV_7_DUAL_EXP: | ||
798 | case CX23885_BOARD_DVICO_FUSIONHDTV_DVB_T_DUAL_EXP: | ||
799 | /* Two identical tuners on two different i2c buses, | ||
800 | * we need to reset the correct gpio. */ | ||
801 | if (port->nr == 1) | ||
802 | bitmask = 0x01; | ||
803 | else if (port->nr == 2) | ||
804 | bitmask = 0x04; | ||
805 | break; | ||
806 | case CX23885_BOARD_GOTVIEW_X5_3D_HYBRID: | ||
807 | /* Tuner Reset Command */ | ||
808 | bitmask = 0x02; | ||
809 | break; | ||
810 | case CX23885_BOARD_NETUP_DUAL_DVB_T_C_CI_RF: | ||
811 | altera_ci_tuner_reset(dev, port->nr); | ||
812 | break; | ||
813 | } | ||
814 | |||
815 | if (bitmask) { | ||
816 | /* Drive the tuner into reset and back out */ | ||
817 | cx_clear(GP0_IO, bitmask); | ||
818 | mdelay(200); | ||
819 | cx_set(GP0_IO, bitmask); | ||
820 | } | ||
821 | |||
822 | return 0; | ||
823 | } | ||
824 | |||
825 | void cx23885_gpio_setup(struct cx23885_dev *dev) | ||
826 | { | ||
827 | switch (dev->board) { | ||
828 | case CX23885_BOARD_HAUPPAUGE_HVR1250: | ||
829 | /* GPIO-0 cx24227 demodulator reset */ | ||
830 | cx_set(GP0_IO, 0x00010001); /* Bring the part out of reset */ | ||
831 | break; | ||
832 | case CX23885_BOARD_HAUPPAUGE_HVR1500: | ||
833 | /* GPIO-0 cx24227 demodulator */ | ||
834 | /* GPIO-2 xc3028 tuner */ | ||
835 | |||
836 | /* Put the parts into reset */ | ||
837 | cx_set(GP0_IO, 0x00050000); | ||
838 | cx_clear(GP0_IO, 0x00000005); | ||
839 | msleep(5); | ||
840 | |||
841 | /* Bring the parts out of reset */ | ||
842 | cx_set(GP0_IO, 0x00050005); | ||
843 | break; | ||
844 | case CX23885_BOARD_HAUPPAUGE_HVR1500Q: | ||
845 | /* GPIO-0 cx24227 demodulator reset */ | ||
846 | /* GPIO-2 xc5000 tuner reset */ | ||
847 | cx_set(GP0_IO, 0x00050005); /* Bring the part out of reset */ | ||
848 | break; | ||
849 | case CX23885_BOARD_HAUPPAUGE_HVR1800: | ||
850 | /* GPIO-0 656_CLK */ | ||
851 | /* GPIO-1 656_D0 */ | ||
852 | /* GPIO-2 8295A Reset */ | ||
853 | /* GPIO-3-10 cx23417 data0-7 */ | ||
854 | /* GPIO-11-14 cx23417 addr0-3 */ | ||
855 | /* GPIO-15-18 cx23417 READY, CS, RD, WR */ | ||
856 | /* GPIO-19 IR_RX */ | ||
857 | |||
858 | /* CX23417 GPIO's */ | ||
859 | /* EIO15 Zilog Reset */ | ||
860 | /* EIO14 S5H1409/CX24227 Reset */ | ||
861 | mc417_gpio_enable(dev, GPIO_15 | GPIO_14, 1); | ||
862 | |||
863 | /* Put the demod into reset and protect the eeprom */ | ||
864 | mc417_gpio_clear(dev, GPIO_15 | GPIO_14); | ||
865 | mdelay(100); | ||
866 | |||
867 | /* Bring the demod and blaster out of reset */ | ||
868 | mc417_gpio_set(dev, GPIO_15 | GPIO_14); | ||
869 | mdelay(100); | ||
870 | |||
871 | /* Force the TDA8295A into reset and back */ | ||
872 | cx23885_gpio_enable(dev, GPIO_2, 1); | ||
873 | cx23885_gpio_set(dev, GPIO_2); | ||
874 | mdelay(20); | ||
875 | cx23885_gpio_clear(dev, GPIO_2); | ||
876 | mdelay(20); | ||
877 | cx23885_gpio_set(dev, GPIO_2); | ||
878 | mdelay(20); | ||
879 | break; | ||
880 | case CX23885_BOARD_HAUPPAUGE_HVR1200: | ||
881 | /* GPIO-0 tda10048 demodulator reset */ | ||
882 | /* GPIO-2 tda18271 tuner reset */ | ||
883 | |||
884 | /* Put the parts into reset and back */ | ||
885 | cx_set(GP0_IO, 0x00050000); | ||
886 | mdelay(20); | ||
887 | cx_clear(GP0_IO, 0x00000005); | ||
888 | mdelay(20); | ||
889 | cx_set(GP0_IO, 0x00050005); | ||
890 | break; | ||
891 | case CX23885_BOARD_HAUPPAUGE_HVR1700: | ||
892 | /* GPIO-0 TDA10048 demodulator reset */ | ||
893 | /* GPIO-2 TDA8295A Reset */ | ||
894 | /* GPIO-3-10 cx23417 data0-7 */ | ||
895 | /* GPIO-11-14 cx23417 addr0-3 */ | ||
896 | /* GPIO-15-18 cx23417 READY, CS, RD, WR */ | ||
897 | |||
898 | /* The following GPIO's are on the interna AVCore (cx25840) */ | ||
899 | /* GPIO-19 IR_RX */ | ||
900 | /* GPIO-20 IR_TX 416/DVBT Select */ | ||
901 | /* GPIO-21 IIS DAT */ | ||
902 | /* GPIO-22 IIS WCLK */ | ||
903 | /* GPIO-23 IIS BCLK */ | ||
904 | |||
905 | /* Put the parts into reset and back */ | ||
906 | cx_set(GP0_IO, 0x00050000); | ||
907 | mdelay(20); | ||
908 | cx_clear(GP0_IO, 0x00000005); | ||
909 | mdelay(20); | ||
910 | cx_set(GP0_IO, 0x00050005); | ||
911 | break; | ||
912 | case CX23885_BOARD_HAUPPAUGE_HVR1400: | ||
913 | /* GPIO-0 Dibcom7000p demodulator reset */ | ||
914 | /* GPIO-2 xc3028L tuner reset */ | ||
915 | /* GPIO-13 LED */ | ||
916 | |||
917 | /* Put the parts into reset and back */ | ||
918 | cx_set(GP0_IO, 0x00050000); | ||
919 | mdelay(20); | ||
920 | cx_clear(GP0_IO, 0x00000005); | ||
921 | mdelay(20); | ||
922 | cx_set(GP0_IO, 0x00050005); | ||
923 | break; | ||
924 | case CX23885_BOARD_DVICO_FUSIONHDTV_7_DUAL_EXP: | ||
925 | /* GPIO-0 xc5000 tuner reset i2c bus 0 */ | ||
926 | /* GPIO-1 s5h1409 demod reset i2c bus 0 */ | ||
927 | /* GPIO-2 xc5000 tuner reset i2c bus 1 */ | ||
928 | /* GPIO-3 s5h1409 demod reset i2c bus 0 */ | ||
929 | |||
930 | /* Put the parts into reset and back */ | ||
931 | cx_set(GP0_IO, 0x000f0000); | ||
932 | mdelay(20); | ||
933 | cx_clear(GP0_IO, 0x0000000f); | ||
934 | mdelay(20); | ||
935 | cx_set(GP0_IO, 0x000f000f); | ||
936 | break; | ||
937 | case CX23885_BOARD_DVICO_FUSIONHDTV_DVB_T_DUAL_EXP: | ||
938 | /* GPIO-0 portb xc3028 reset */ | ||
939 | /* GPIO-1 portb zl10353 reset */ | ||
940 | /* GPIO-2 portc xc3028 reset */ | ||
941 | /* GPIO-3 portc zl10353 reset */ | ||
942 | |||
943 | /* Put the parts into reset and back */ | ||
944 | cx_set(GP0_IO, 0x000f0000); | ||
945 | mdelay(20); | ||
946 | cx_clear(GP0_IO, 0x0000000f); | ||
947 | mdelay(20); | ||
948 | cx_set(GP0_IO, 0x000f000f); | ||
949 | break; | ||
950 | case CX23885_BOARD_LEADTEK_WINFAST_PXDVR3200_H: | ||
951 | case CX23885_BOARD_LEADTEK_WINFAST_PXDVR3200_H_XC4000: | ||
952 | case CX23885_BOARD_COMPRO_VIDEOMATE_E650F: | ||
953 | case CX23885_BOARD_COMPRO_VIDEOMATE_E800: | ||
954 | case CX23885_BOARD_LEADTEK_WINFAST_PXTV1200: | ||
955 | /* GPIO-2 xc3028 tuner reset */ | ||
956 | |||
957 | /* The following GPIO's are on the internal AVCore (cx25840) */ | ||
958 | /* GPIO-? zl10353 demod reset */ | ||
959 | |||
960 | /* Put the parts into reset and back */ | ||
961 | cx_set(GP0_IO, 0x00040000); | ||
962 | mdelay(20); | ||
963 | cx_clear(GP0_IO, 0x00000004); | ||
964 | mdelay(20); | ||
965 | cx_set(GP0_IO, 0x00040004); | ||
966 | break; | ||
967 | case CX23885_BOARD_TBS_6920: | ||
968 | cx_write(MC417_CTL, 0x00000036); | ||
969 | cx_write(MC417_OEN, 0x00001000); | ||
970 | cx_set(MC417_RWD, 0x00000002); | ||
971 | mdelay(200); | ||
972 | cx_clear(MC417_RWD, 0x00000800); | ||
973 | mdelay(200); | ||
974 | cx_set(MC417_RWD, 0x00000800); | ||
975 | mdelay(200); | ||
976 | break; | ||
977 | case CX23885_BOARD_NETUP_DUAL_DVBS2_CI: | ||
978 | /* GPIO-0 INTA from CiMax1 | ||
979 | GPIO-1 INTB from CiMax2 | ||
980 | GPIO-2 reset chips | ||
981 | GPIO-3 to GPIO-10 data/addr for CA | ||
982 | GPIO-11 ~CS0 to CiMax1 | ||
983 | GPIO-12 ~CS1 to CiMax2 | ||
984 | GPIO-13 ADL0 load LSB addr | ||
985 | GPIO-14 ADL1 load MSB addr | ||
986 | GPIO-15 ~RDY from CiMax | ||
987 | GPIO-17 ~RD to CiMax | ||
988 | GPIO-18 ~WR to CiMax | ||
989 | */ | ||
990 | cx_set(GP0_IO, 0x00040000); /* GPIO as out */ | ||
991 | /* GPIO1 and GPIO2 as INTA and INTB from CiMaxes, reset low */ | ||
992 | cx_clear(GP0_IO, 0x00030004); | ||
993 | mdelay(100);/* reset delay */ | ||
994 | cx_set(GP0_IO, 0x00040004); /* GPIO as out, reset high */ | ||
995 | cx_write(MC417_CTL, 0x00000037);/* enable GPIO3-18 pins */ | ||
996 | /* GPIO-15 IN as ~ACK, rest as OUT */ | ||
997 | cx_write(MC417_OEN, 0x00001000); | ||
998 | /* ~RD, ~WR high; ADL0, ADL1 low; ~CS0, ~CS1 high */ | ||
999 | cx_write(MC417_RWD, 0x0000c300); | ||
1000 | /* enable irq */ | ||
1001 | cx_write(GPIO_ISM, 0x00000000);/* INTERRUPTS active low*/ | ||
1002 | break; | ||
1003 | case CX23885_BOARD_HAUPPAUGE_HVR1270: | ||
1004 | case CX23885_BOARD_HAUPPAUGE_HVR1275: | ||
1005 | case CX23885_BOARD_HAUPPAUGE_HVR1255: | ||
1006 | case CX23885_BOARD_HAUPPAUGE_HVR1210: | ||
1007 | /* GPIO-5 RF Control: 0 = RF1 Terrestrial, 1 = RF2 Cable */ | ||
1008 | /* GPIO-6 I2C Gate which can isolate the demod from the bus */ | ||
1009 | /* GPIO-9 Demod reset */ | ||
1010 | |||
1011 | /* Put the parts into reset and back */ | ||
1012 | cx23885_gpio_enable(dev, GPIO_9 | GPIO_6 | GPIO_5, 1); | ||
1013 | cx23885_gpio_set(dev, GPIO_9 | GPIO_6 | GPIO_5); | ||
1014 | cx23885_gpio_clear(dev, GPIO_9); | ||
1015 | mdelay(20); | ||
1016 | cx23885_gpio_set(dev, GPIO_9); | ||
1017 | break; | ||
1018 | case CX23885_BOARD_MYGICA_X8506: | ||
1019 | case CX23885_BOARD_MAGICPRO_PROHDTVE2: | ||
1020 | /* GPIO-0 (0)Analog / (1)Digital TV */ | ||
1021 | /* GPIO-1 reset XC5000 */ | ||
1022 | /* GPIO-2 reset LGS8GL5 / LGS8G75 */ | ||
1023 | cx23885_gpio_enable(dev, GPIO_0 | GPIO_1 | GPIO_2, 1); | ||
1024 | cx23885_gpio_clear(dev, GPIO_1 | GPIO_2); | ||
1025 | mdelay(100); | ||
1026 | cx23885_gpio_set(dev, GPIO_0 | GPIO_1 | GPIO_2); | ||
1027 | mdelay(100); | ||
1028 | break; | ||
1029 | case CX23885_BOARD_MYGICA_X8558PRO: | ||
1030 | /* GPIO-0 reset first ATBM8830 */ | ||
1031 | /* GPIO-1 reset second ATBM8830 */ | ||
1032 | cx23885_gpio_enable(dev, GPIO_0 | GPIO_1, 1); | ||
1033 | cx23885_gpio_clear(dev, GPIO_0 | GPIO_1); | ||
1034 | mdelay(100); | ||
1035 | cx23885_gpio_set(dev, GPIO_0 | GPIO_1); | ||
1036 | mdelay(100); | ||
1037 | break; | ||
1038 | case CX23885_BOARD_HAUPPAUGE_HVR1850: | ||
1039 | case CX23885_BOARD_HAUPPAUGE_HVR1290: | ||
1040 | /* GPIO-0 656_CLK */ | ||
1041 | /* GPIO-1 656_D0 */ | ||
1042 | /* GPIO-2 Wake# */ | ||
1043 | /* GPIO-3-10 cx23417 data0-7 */ | ||
1044 | /* GPIO-11-14 cx23417 addr0-3 */ | ||
1045 | /* GPIO-15-18 cx23417 READY, CS, RD, WR */ | ||
1046 | /* GPIO-19 IR_RX */ | ||
1047 | /* GPIO-20 C_IR_TX */ | ||
1048 | /* GPIO-21 I2S DAT */ | ||
1049 | /* GPIO-22 I2S WCLK */ | ||
1050 | /* GPIO-23 I2S BCLK */ | ||
1051 | /* ALT GPIO: EXP GPIO LATCH */ | ||
1052 | |||
1053 | /* CX23417 GPIO's */ | ||
1054 | /* GPIO-14 S5H1411/CX24228 Reset */ | ||
1055 | /* GPIO-13 EEPROM write protect */ | ||
1056 | mc417_gpio_enable(dev, GPIO_14 | GPIO_13, 1); | ||
1057 | |||
1058 | /* Put the demod into reset and protect the eeprom */ | ||
1059 | mc417_gpio_clear(dev, GPIO_14 | GPIO_13); | ||
1060 | mdelay(100); | ||
1061 | |||
1062 | /* Bring the demod out of reset */ | ||
1063 | mc417_gpio_set(dev, GPIO_14); | ||
1064 | mdelay(100); | ||
1065 | |||
1066 | /* CX24228 GPIO */ | ||
1067 | /* Connected to IF / Mux */ | ||
1068 | break; | ||
1069 | case CX23885_BOARD_GOTVIEW_X5_3D_HYBRID: | ||
1070 | cx_set(GP0_IO, 0x00010001); /* Bring the part out of reset */ | ||
1071 | break; | ||
1072 | case CX23885_BOARD_NETUP_DUAL_DVB_T_C_CI_RF: | ||
1073 | /* GPIO-0 ~INT in | ||
1074 | GPIO-1 TMS out | ||
1075 | GPIO-2 ~reset chips out | ||
1076 | GPIO-3 to GPIO-10 data/addr for CA in/out | ||
1077 | GPIO-11 ~CS out | ||
1078 | GPIO-12 ADDR out | ||
1079 | GPIO-13 ~WR out | ||
1080 | GPIO-14 ~RD out | ||
1081 | GPIO-15 ~RDY in | ||
1082 | GPIO-16 TCK out | ||
1083 | GPIO-17 TDO in | ||
1084 | GPIO-18 TDI out | ||
1085 | */ | ||
1086 | cx_set(GP0_IO, 0x00060000); /* GPIO-1,2 as out */ | ||
1087 | /* GPIO-0 as INT, reset & TMS low */ | ||
1088 | cx_clear(GP0_IO, 0x00010006); | ||
1089 | mdelay(100);/* reset delay */ | ||
1090 | cx_set(GP0_IO, 0x00000004); /* reset high */ | ||
1091 | cx_write(MC417_CTL, 0x00000037);/* enable GPIO-3..18 pins */ | ||
1092 | /* GPIO-17 is TDO in, GPIO-15 is ~RDY in, rest is out */ | ||
1093 | cx_write(MC417_OEN, 0x00005000); | ||
1094 | /* ~RD, ~WR high; ADDR low; ~CS high */ | ||
1095 | cx_write(MC417_RWD, 0x00000d00); | ||
1096 | /* enable irq */ | ||
1097 | cx_write(GPIO_ISM, 0x00000000);/* INTERRUPTS active low*/ | ||
1098 | break; | ||
1099 | } | ||
1100 | } | ||
1101 | |||
1102 | int cx23885_ir_init(struct cx23885_dev *dev) | ||
1103 | { | ||
1104 | static struct v4l2_subdev_io_pin_config ir_rxtx_pin_cfg[] = { | ||
1105 | { | ||
1106 | .flags = V4L2_SUBDEV_IO_PIN_INPUT, | ||
1107 | .pin = CX23885_PIN_IR_RX_GPIO19, | ||
1108 | .function = CX23885_PAD_IR_RX, | ||
1109 | .value = 0, | ||
1110 | .strength = CX25840_PIN_DRIVE_MEDIUM, | ||
1111 | }, { | ||
1112 | .flags = V4L2_SUBDEV_IO_PIN_OUTPUT, | ||
1113 | .pin = CX23885_PIN_IR_TX_GPIO20, | ||
1114 | .function = CX23885_PAD_IR_TX, | ||
1115 | .value = 0, | ||
1116 | .strength = CX25840_PIN_DRIVE_MEDIUM, | ||
1117 | } | ||
1118 | }; | ||
1119 | const size_t ir_rxtx_pin_cfg_count = ARRAY_SIZE(ir_rxtx_pin_cfg); | ||
1120 | |||
1121 | static struct v4l2_subdev_io_pin_config ir_rx_pin_cfg[] = { | ||
1122 | { | ||
1123 | .flags = V4L2_SUBDEV_IO_PIN_INPUT, | ||
1124 | .pin = CX23885_PIN_IR_RX_GPIO19, | ||
1125 | .function = CX23885_PAD_IR_RX, | ||
1126 | .value = 0, | ||
1127 | .strength = CX25840_PIN_DRIVE_MEDIUM, | ||
1128 | } | ||
1129 | }; | ||
1130 | const size_t ir_rx_pin_cfg_count = ARRAY_SIZE(ir_rx_pin_cfg); | ||
1131 | |||
1132 | struct v4l2_subdev_ir_parameters params; | ||
1133 | int ret = 0; | ||
1134 | switch (dev->board) { | ||
1135 | case CX23885_BOARD_HAUPPAUGE_HVR1500: | ||
1136 | case CX23885_BOARD_HAUPPAUGE_HVR1500Q: | ||
1137 | case CX23885_BOARD_HAUPPAUGE_HVR1800: | ||
1138 | case CX23885_BOARD_HAUPPAUGE_HVR1200: | ||
1139 | case CX23885_BOARD_HAUPPAUGE_HVR1400: | ||
1140 | case CX23885_BOARD_HAUPPAUGE_HVR1275: | ||
1141 | case CX23885_BOARD_HAUPPAUGE_HVR1255: | ||
1142 | case CX23885_BOARD_HAUPPAUGE_HVR1210: | ||
1143 | /* FIXME: Implement me */ | ||
1144 | break; | ||
1145 | case CX23885_BOARD_HAUPPAUGE_HVR1270: | ||
1146 | ret = cx23888_ir_probe(dev); | ||
1147 | if (ret) | ||
1148 | break; | ||
1149 | dev->sd_ir = cx23885_find_hw(dev, CX23885_HW_888_IR); | ||
1150 | v4l2_subdev_call(dev->sd_cx25840, core, s_io_pin_config, | ||
1151 | ir_rx_pin_cfg_count, ir_rx_pin_cfg); | ||
1152 | break; | ||
1153 | case CX23885_BOARD_HAUPPAUGE_HVR1850: | ||
1154 | case CX23885_BOARD_HAUPPAUGE_HVR1290: | ||
1155 | ret = cx23888_ir_probe(dev); | ||
1156 | if (ret) | ||
1157 | break; | ||
1158 | dev->sd_ir = cx23885_find_hw(dev, CX23885_HW_888_IR); | ||
1159 | v4l2_subdev_call(dev->sd_cx25840, core, s_io_pin_config, | ||
1160 | ir_rxtx_pin_cfg_count, ir_rxtx_pin_cfg); | ||
1161 | /* | ||
1162 | * For these boards we need to invert the Tx output via the | ||
1163 | * IR controller to have the LED off while idle | ||
1164 | */ | ||
1165 | v4l2_subdev_call(dev->sd_ir, ir, tx_g_parameters, ¶ms); | ||
1166 | params.enable = false; | ||
1167 | params.shutdown = false; | ||
1168 | params.invert_level = true; | ||
1169 | v4l2_subdev_call(dev->sd_ir, ir, tx_s_parameters, ¶ms); | ||
1170 | params.shutdown = true; | ||
1171 | v4l2_subdev_call(dev->sd_ir, ir, tx_s_parameters, ¶ms); | ||
1172 | break; | ||
1173 | case CX23885_BOARD_TEVII_S470: | ||
1174 | if (!enable_885_ir) | ||
1175 | break; | ||
1176 | dev->sd_ir = cx23885_find_hw(dev, CX23885_HW_AV_CORE); | ||
1177 | if (dev->sd_ir == NULL) { | ||
1178 | ret = -ENODEV; | ||
1179 | break; | ||
1180 | } | ||
1181 | v4l2_subdev_call(dev->sd_cx25840, core, s_io_pin_config, | ||
1182 | ir_rx_pin_cfg_count, ir_rx_pin_cfg); | ||
1183 | break; | ||
1184 | case CX23885_BOARD_HAUPPAUGE_HVR1250: | ||
1185 | if (!enable_885_ir) | ||
1186 | break; | ||
1187 | dev->sd_ir = cx23885_find_hw(dev, CX23885_HW_AV_CORE); | ||
1188 | if (dev->sd_ir == NULL) { | ||
1189 | ret = -ENODEV; | ||
1190 | break; | ||
1191 | } | ||
1192 | v4l2_subdev_call(dev->sd_cx25840, core, s_io_pin_config, | ||
1193 | ir_rxtx_pin_cfg_count, ir_rxtx_pin_cfg); | ||
1194 | break; | ||
1195 | case CX23885_BOARD_DVICO_FUSIONHDTV_DVB_T_DUAL_EXP: | ||
1196 | request_module("ir-kbd-i2c"); | ||
1197 | break; | ||
1198 | } | ||
1199 | |||
1200 | return ret; | ||
1201 | } | ||
1202 | |||
1203 | void cx23885_ir_fini(struct cx23885_dev *dev) | ||
1204 | { | ||
1205 | switch (dev->board) { | ||
1206 | case CX23885_BOARD_HAUPPAUGE_HVR1270: | ||
1207 | case CX23885_BOARD_HAUPPAUGE_HVR1850: | ||
1208 | case CX23885_BOARD_HAUPPAUGE_HVR1290: | ||
1209 | cx23885_irq_remove(dev, PCI_MSK_IR); | ||
1210 | cx23888_ir_remove(dev); | ||
1211 | dev->sd_ir = NULL; | ||
1212 | break; | ||
1213 | case CX23885_BOARD_TEVII_S470: | ||
1214 | case CX23885_BOARD_HAUPPAUGE_HVR1250: | ||
1215 | cx23885_irq_remove(dev, PCI_MSK_AV_CORE); | ||
1216 | /* sd_ir is a duplicate pointer to the AV Core, just clear it */ | ||
1217 | dev->sd_ir = NULL; | ||
1218 | break; | ||
1219 | } | ||
1220 | } | ||
1221 | |||
1222 | int netup_jtag_io(void *device, int tms, int tdi, int read_tdo) | ||
1223 | { | ||
1224 | int data; | ||
1225 | int tdo = 0; | ||
1226 | struct cx23885_dev *dev = (struct cx23885_dev *)device; | ||
1227 | /*TMS*/ | ||
1228 | data = ((cx_read(GP0_IO)) & (~0x00000002)); | ||
1229 | data |= (tms ? 0x00020002 : 0x00020000); | ||
1230 | cx_write(GP0_IO, data); | ||
1231 | |||
1232 | /*TDI*/ | ||
1233 | data = ((cx_read(MC417_RWD)) & (~0x0000a000)); | ||
1234 | data |= (tdi ? 0x00008000 : 0); | ||
1235 | cx_write(MC417_RWD, data); | ||
1236 | if (read_tdo) | ||
1237 | tdo = (data & 0x00004000) ? 1 : 0; /*TDO*/ | ||
1238 | |||
1239 | cx_write(MC417_RWD, data | 0x00002000); | ||
1240 | udelay(1); | ||
1241 | /*TCK*/ | ||
1242 | cx_write(MC417_RWD, data); | ||
1243 | |||
1244 | return tdo; | ||
1245 | } | ||
1246 | |||
1247 | void cx23885_ir_pci_int_enable(struct cx23885_dev *dev) | ||
1248 | { | ||
1249 | switch (dev->board) { | ||
1250 | case CX23885_BOARD_HAUPPAUGE_HVR1270: | ||
1251 | case CX23885_BOARD_HAUPPAUGE_HVR1850: | ||
1252 | case CX23885_BOARD_HAUPPAUGE_HVR1290: | ||
1253 | if (dev->sd_ir) | ||
1254 | cx23885_irq_add_enable(dev, PCI_MSK_IR); | ||
1255 | break; | ||
1256 | case CX23885_BOARD_TEVII_S470: | ||
1257 | case CX23885_BOARD_HAUPPAUGE_HVR1250: | ||
1258 | if (dev->sd_ir) | ||
1259 | cx23885_irq_add_enable(dev, PCI_MSK_AV_CORE); | ||
1260 | break; | ||
1261 | } | ||
1262 | } | ||
1263 | |||
1264 | void cx23885_card_setup(struct cx23885_dev *dev) | ||
1265 | { | ||
1266 | struct cx23885_tsport *ts1 = &dev->ts1; | ||
1267 | struct cx23885_tsport *ts2 = &dev->ts2; | ||
1268 | |||
1269 | static u8 eeprom[256]; | ||
1270 | |||
1271 | if (dev->i2c_bus[0].i2c_rc == 0) { | ||
1272 | dev->i2c_bus[0].i2c_client.addr = 0xa0 >> 1; | ||
1273 | tveeprom_read(&dev->i2c_bus[0].i2c_client, | ||
1274 | eeprom, sizeof(eeprom)); | ||
1275 | } | ||
1276 | |||
1277 | switch (dev->board) { | ||
1278 | case CX23885_BOARD_HAUPPAUGE_HVR1250: | ||
1279 | if (dev->i2c_bus[0].i2c_rc == 0) { | ||
1280 | if (eeprom[0x80] != 0x84) | ||
1281 | hauppauge_eeprom(dev, eeprom+0xc0); | ||
1282 | else | ||
1283 | hauppauge_eeprom(dev, eeprom+0x80); | ||
1284 | } | ||
1285 | break; | ||
1286 | case CX23885_BOARD_HAUPPAUGE_HVR1500: | ||
1287 | case CX23885_BOARD_HAUPPAUGE_HVR1500Q: | ||
1288 | case CX23885_BOARD_HAUPPAUGE_HVR1400: | ||
1289 | if (dev->i2c_bus[0].i2c_rc == 0) | ||
1290 | hauppauge_eeprom(dev, eeprom+0x80); | ||
1291 | break; | ||
1292 | case CX23885_BOARD_HAUPPAUGE_HVR1800: | ||
1293 | case CX23885_BOARD_HAUPPAUGE_HVR1800lp: | ||
1294 | case CX23885_BOARD_HAUPPAUGE_HVR1200: | ||
1295 | case CX23885_BOARD_HAUPPAUGE_HVR1700: | ||
1296 | case CX23885_BOARD_HAUPPAUGE_HVR1270: | ||
1297 | case CX23885_BOARD_HAUPPAUGE_HVR1275: | ||
1298 | case CX23885_BOARD_HAUPPAUGE_HVR1255: | ||
1299 | case CX23885_BOARD_HAUPPAUGE_HVR1210: | ||
1300 | case CX23885_BOARD_HAUPPAUGE_HVR1850: | ||
1301 | case CX23885_BOARD_HAUPPAUGE_HVR1290: | ||
1302 | if (dev->i2c_bus[0].i2c_rc == 0) | ||
1303 | hauppauge_eeprom(dev, eeprom+0xc0); | ||
1304 | break; | ||
1305 | } | ||
1306 | |||
1307 | switch (dev->board) { | ||
1308 | case CX23885_BOARD_DVICO_FUSIONHDTV_7_DUAL_EXP: | ||
1309 | case CX23885_BOARD_DVICO_FUSIONHDTV_DVB_T_DUAL_EXP: | ||
1310 | ts2->gen_ctrl_val = 0xc; /* Serial bus + punctured clock */ | ||
1311 | ts2->ts_clk_en_val = 0x1; /* Enable TS_CLK */ | ||
1312 | ts2->src_sel_val = CX23885_SRC_SEL_PARALLEL_MPEG_VIDEO; | ||
1313 | /* break omitted intentionally */ | ||
1314 | case CX23885_BOARD_DVICO_FUSIONHDTV_5_EXP: | ||
1315 | ts1->gen_ctrl_val = 0xc; /* Serial bus + punctured clock */ | ||
1316 | ts1->ts_clk_en_val = 0x1; /* Enable TS_CLK */ | ||
1317 | ts1->src_sel_val = CX23885_SRC_SEL_PARALLEL_MPEG_VIDEO; | ||
1318 | break; | ||
1319 | case CX23885_BOARD_HAUPPAUGE_HVR1800: | ||
1320 | /* Defaults for VID B - Analog encoder */ | ||
1321 | /* DREQ_POL, SMODE, PUNC_CLK, MCLK_POL Serial bus + punc clk */ | ||
1322 | ts1->gen_ctrl_val = 0x10e; | ||
1323 | ts1->ts_clk_en_val = 0x1; /* Enable TS_CLK */ | ||
1324 | ts1->src_sel_val = CX23885_SRC_SEL_PARALLEL_MPEG_VIDEO; | ||
1325 | |||
1326 | /* APB_TSVALERR_POL (active low)*/ | ||
1327 | ts1->vld_misc_val = 0x2000; | ||
1328 | ts1->hw_sop_ctrl_val = (0x47 << 16 | 188 << 4 | 0xc); | ||
1329 | |||
1330 | /* Defaults for VID C */ | ||
1331 | ts2->gen_ctrl_val = 0xc; /* Serial bus + punctured clock */ | ||
1332 | ts2->ts_clk_en_val = 0x1; /* Enable TS_CLK */ | ||
1333 | ts2->src_sel_val = CX23885_SRC_SEL_PARALLEL_MPEG_VIDEO; | ||
1334 | break; | ||
1335 | case CX23885_BOARD_TBS_6920: | ||
1336 | ts1->gen_ctrl_val = 0x4; /* Parallel */ | ||
1337 | ts1->ts_clk_en_val = 0x1; /* Enable TS_CLK */ | ||
1338 | ts1->src_sel_val = CX23885_SRC_SEL_PARALLEL_MPEG_VIDEO; | ||
1339 | break; | ||
1340 | case CX23885_BOARD_TEVII_S470: | ||
1341 | case CX23885_BOARD_DVBWORLD_2005: | ||
1342 | ts1->gen_ctrl_val = 0x5; /* Parallel */ | ||
1343 | ts1->ts_clk_en_val = 0x1; /* Enable TS_CLK */ | ||
1344 | ts1->src_sel_val = CX23885_SRC_SEL_PARALLEL_MPEG_VIDEO; | ||
1345 | break; | ||
1346 | case CX23885_BOARD_NETUP_DUAL_DVBS2_CI: | ||
1347 | case CX23885_BOARD_NETUP_DUAL_DVB_T_C_CI_RF: | ||
1348 | ts1->gen_ctrl_val = 0xc; /* Serial bus + punctured clock */ | ||
1349 | ts1->ts_clk_en_val = 0x1; /* Enable TS_CLK */ | ||
1350 | ts1->src_sel_val = CX23885_SRC_SEL_PARALLEL_MPEG_VIDEO; | ||
1351 | ts2->gen_ctrl_val = 0xc; /* Serial bus + punctured clock */ | ||
1352 | ts2->ts_clk_en_val = 0x1; /* Enable TS_CLK */ | ||
1353 | ts2->src_sel_val = CX23885_SRC_SEL_PARALLEL_MPEG_VIDEO; | ||
1354 | break; | ||
1355 | case CX23885_BOARD_MYGICA_X8506: | ||
1356 | case CX23885_BOARD_MAGICPRO_PROHDTVE2: | ||
1357 | ts1->gen_ctrl_val = 0x5; /* Parallel */ | ||
1358 | ts1->ts_clk_en_val = 0x1; /* Enable TS_CLK */ | ||
1359 | ts1->src_sel_val = CX23885_SRC_SEL_PARALLEL_MPEG_VIDEO; | ||
1360 | break; | ||
1361 | case CX23885_BOARD_MYGICA_X8558PRO: | ||
1362 | ts1->gen_ctrl_val = 0x5; /* Parallel */ | ||
1363 | ts1->ts_clk_en_val = 0x1; /* Enable TS_CLK */ | ||
1364 | ts1->src_sel_val = CX23885_SRC_SEL_PARALLEL_MPEG_VIDEO; | ||
1365 | ts2->gen_ctrl_val = 0xc; /* Serial bus + punctured clock */ | ||
1366 | ts2->ts_clk_en_val = 0x1; /* Enable TS_CLK */ | ||
1367 | ts2->src_sel_val = CX23885_SRC_SEL_PARALLEL_MPEG_VIDEO; | ||
1368 | break; | ||
1369 | case CX23885_BOARD_HAUPPAUGE_HVR1250: | ||
1370 | case CX23885_BOARD_HAUPPAUGE_HVR1500: | ||
1371 | case CX23885_BOARD_HAUPPAUGE_HVR1500Q: | ||
1372 | case CX23885_BOARD_HAUPPAUGE_HVR1800lp: | ||
1373 | case CX23885_BOARD_HAUPPAUGE_HVR1200: | ||
1374 | case CX23885_BOARD_HAUPPAUGE_HVR1700: | ||
1375 | case CX23885_BOARD_HAUPPAUGE_HVR1400: | ||
1376 | case CX23885_BOARD_LEADTEK_WINFAST_PXDVR3200_H: | ||
1377 | case CX23885_BOARD_LEADTEK_WINFAST_PXDVR3200_H_XC4000: | ||
1378 | case CX23885_BOARD_COMPRO_VIDEOMATE_E650F: | ||
1379 | case CX23885_BOARD_HAUPPAUGE_HVR1270: | ||
1380 | case CX23885_BOARD_HAUPPAUGE_HVR1275: | ||
1381 | case CX23885_BOARD_HAUPPAUGE_HVR1255: | ||
1382 | case CX23885_BOARD_HAUPPAUGE_HVR1210: | ||
1383 | case CX23885_BOARD_HAUPPAUGE_HVR1850: | ||
1384 | case CX23885_BOARD_COMPRO_VIDEOMATE_E800: | ||
1385 | case CX23885_BOARD_HAUPPAUGE_HVR1290: | ||
1386 | case CX23885_BOARD_GOTVIEW_X5_3D_HYBRID: | ||
1387 | default: | ||
1388 | ts2->gen_ctrl_val = 0xc; /* Serial bus + punctured clock */ | ||
1389 | ts2->ts_clk_en_val = 0x1; /* Enable TS_CLK */ | ||
1390 | ts2->src_sel_val = CX23885_SRC_SEL_PARALLEL_MPEG_VIDEO; | ||
1391 | } | ||
1392 | |||
1393 | /* Certain boards support analog, or require the avcore to be | ||
1394 | * loaded, ensure this happens. | ||
1395 | */ | ||
1396 | switch (dev->board) { | ||
1397 | case CX23885_BOARD_TEVII_S470: | ||
1398 | case CX23885_BOARD_HAUPPAUGE_HVR1250: | ||
1399 | /* Currently only enabled for the integrated IR controller */ | ||
1400 | if (!enable_885_ir) | ||
1401 | break; | ||
1402 | case CX23885_BOARD_HAUPPAUGE_HVR1800: | ||
1403 | case CX23885_BOARD_HAUPPAUGE_HVR1800lp: | ||
1404 | case CX23885_BOARD_HAUPPAUGE_HVR1700: | ||
1405 | case CX23885_BOARD_LEADTEK_WINFAST_PXDVR3200_H: | ||
1406 | case CX23885_BOARD_LEADTEK_WINFAST_PXDVR3200_H_XC4000: | ||
1407 | case CX23885_BOARD_COMPRO_VIDEOMATE_E650F: | ||
1408 | case CX23885_BOARD_NETUP_DUAL_DVBS2_CI: | ||
1409 | case CX23885_BOARD_NETUP_DUAL_DVB_T_C_CI_RF: | ||
1410 | case CX23885_BOARD_COMPRO_VIDEOMATE_E800: | ||
1411 | case CX23885_BOARD_HAUPPAUGE_HVR1270: | ||
1412 | case CX23885_BOARD_HAUPPAUGE_HVR1850: | ||
1413 | case CX23885_BOARD_MYGICA_X8506: | ||
1414 | case CX23885_BOARD_MAGICPRO_PROHDTVE2: | ||
1415 | case CX23885_BOARD_HAUPPAUGE_HVR1290: | ||
1416 | case CX23885_BOARD_LEADTEK_WINFAST_PXTV1200: | ||
1417 | case CX23885_BOARD_GOTVIEW_X5_3D_HYBRID: | ||
1418 | dev->sd_cx25840 = v4l2_i2c_new_subdev(&dev->v4l2_dev, | ||
1419 | &dev->i2c_bus[2].i2c_adap, | ||
1420 | "cx25840", 0x88 >> 1, NULL); | ||
1421 | if (dev->sd_cx25840) { | ||
1422 | dev->sd_cx25840->grp_id = CX23885_HW_AV_CORE; | ||
1423 | v4l2_subdev_call(dev->sd_cx25840, core, load_fw); | ||
1424 | } | ||
1425 | break; | ||
1426 | } | ||
1427 | |||
1428 | /* AUX-PLL 27MHz CLK */ | ||
1429 | switch (dev->board) { | ||
1430 | case CX23885_BOARD_NETUP_DUAL_DVBS2_CI: | ||
1431 | netup_initialize(dev); | ||
1432 | break; | ||
1433 | case CX23885_BOARD_NETUP_DUAL_DVB_T_C_CI_RF: { | ||
1434 | int ret; | ||
1435 | const struct firmware *fw; | ||
1436 | const char *filename = "dvb-netup-altera-01.fw"; | ||
1437 | char *action = "configure"; | ||
1438 | static struct netup_card_info cinfo; | ||
1439 | struct altera_config netup_config = { | ||
1440 | .dev = dev, | ||
1441 | .action = action, | ||
1442 | .jtag_io = netup_jtag_io, | ||
1443 | }; | ||
1444 | |||
1445 | netup_initialize(dev); | ||
1446 | |||
1447 | netup_get_card_info(&dev->i2c_bus[0].i2c_adap, &cinfo); | ||
1448 | if (netup_card_rev) | ||
1449 | cinfo.rev = netup_card_rev; | ||
1450 | |||
1451 | switch (cinfo.rev) { | ||
1452 | case 0x4: | ||
1453 | filename = "dvb-netup-altera-04.fw"; | ||
1454 | break; | ||
1455 | default: | ||
1456 | filename = "dvb-netup-altera-01.fw"; | ||
1457 | break; | ||
1458 | } | ||
1459 | printk(KERN_INFO "NetUP card rev=0x%x fw_filename=%s\n", | ||
1460 | cinfo.rev, filename); | ||
1461 | |||
1462 | ret = request_firmware(&fw, filename, &dev->pci->dev); | ||
1463 | if (ret != 0) | ||
1464 | printk(KERN_ERR "did not find the firmware file. (%s) " | ||
1465 | "Please see linux/Documentation/dvb/ for more details " | ||
1466 | "on firmware-problems.", filename); | ||
1467 | else | ||
1468 | altera_init(&netup_config, fw); | ||
1469 | |||
1470 | release_firmware(fw); | ||
1471 | break; | ||
1472 | } | ||
1473 | } | ||
1474 | } | ||
1475 | |||
1476 | /* ------------------------------------------------------------------ */ | ||
diff --git a/drivers/media/video/cx23885/cx23885-core.c b/drivers/media/video/cx23885/cx23885-core.c new file mode 100644 index 00000000000..ee41a8882f5 --- /dev/null +++ b/drivers/media/video/cx23885/cx23885-core.c | |||
@@ -0,0 +1,2162 @@ | |||
1 | /* | ||
2 | * Driver for the Conexant CX23885 PCIe bridge | ||
3 | * | ||
4 | * Copyright (c) 2006 Steven Toth <stoth@linuxtv.org> | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify | ||
7 | * it under the terms of the GNU General Public License as published by | ||
8 | * the Free Software Foundation; either version 2 of the License, or | ||
9 | * (at your option) any later version. | ||
10 | * | ||
11 | * This program is distributed in the hope that it will be useful, | ||
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
14 | * | ||
15 | * GNU General Public License for more details. | ||
16 | * | ||
17 | * You should have received a copy of the GNU General Public License | ||
18 | * along with this program; if not, write to the Free Software | ||
19 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
20 | */ | ||
21 | |||
22 | #include <linux/init.h> | ||
23 | #include <linux/list.h> | ||
24 | #include <linux/module.h> | ||
25 | #include <linux/moduleparam.h> | ||
26 | #include <linux/kmod.h> | ||
27 | #include <linux/kernel.h> | ||
28 | #include <linux/slab.h> | ||
29 | #include <linux/interrupt.h> | ||
30 | #include <linux/delay.h> | ||
31 | #include <asm/div64.h> | ||
32 | #include <linux/firmware.h> | ||
33 | |||
34 | #include "cx23885.h" | ||
35 | #include "cimax2.h" | ||
36 | #include "altera-ci.h" | ||
37 | #include "cx23888-ir.h" | ||
38 | #include "cx23885-ir.h" | ||
39 | #include "cx23885-av.h" | ||
40 | #include "cx23885-input.h" | ||
41 | |||
42 | MODULE_DESCRIPTION("Driver for cx23885 based TV cards"); | ||
43 | MODULE_AUTHOR("Steven Toth <stoth@linuxtv.org>"); | ||
44 | MODULE_LICENSE("GPL"); | ||
45 | MODULE_VERSION(CX23885_VERSION); | ||
46 | |||
47 | static unsigned int debug; | ||
48 | module_param(debug, int, 0644); | ||
49 | MODULE_PARM_DESC(debug, "enable debug messages"); | ||
50 | |||
51 | static unsigned int card[] = {[0 ... (CX23885_MAXBOARDS - 1)] = UNSET }; | ||
52 | module_param_array(card, int, NULL, 0444); | ||
53 | MODULE_PARM_DESC(card, "card type"); | ||
54 | |||
55 | #define dprintk(level, fmt, arg...)\ | ||
56 | do { if (debug >= level)\ | ||
57 | printk(KERN_DEBUG "%s/0: " fmt, dev->name, ## arg);\ | ||
58 | } while (0) | ||
59 | |||
60 | static unsigned int cx23885_devcount; | ||
61 | |||
62 | #define NO_SYNC_LINE (-1U) | ||
63 | |||
64 | /* FIXME, these allocations will change when | ||
65 | * analog arrives. The be reviewed. | ||
66 | * CX23887 Assumptions | ||
67 | * 1 line = 16 bytes of CDT | ||
68 | * cmds size = 80 | ||
69 | * cdt size = 16 * linesize | ||
70 | * iqsize = 64 | ||
71 | * maxlines = 6 | ||
72 | * | ||
73 | * Address Space: | ||
74 | * 0x00000000 0x00008fff FIFO clusters | ||
75 | * 0x00010000 0x000104af Channel Management Data Structures | ||
76 | * 0x000104b0 0x000104ff Free | ||
77 | * 0x00010500 0x000108bf 15 channels * iqsize | ||
78 | * 0x000108c0 0x000108ff Free | ||
79 | * 0x00010900 0x00010e9f IQ's + Cluster Descriptor Tables | ||
80 | * 15 channels * (iqsize + (maxlines * linesize)) | ||
81 | * 0x00010ea0 0x00010xxx Free | ||
82 | */ | ||
83 | |||
84 | static struct sram_channel cx23885_sram_channels[] = { | ||
85 | [SRAM_CH01] = { | ||
86 | .name = "VID A", | ||
87 | .cmds_start = 0x10000, | ||
88 | .ctrl_start = 0x10380, | ||
89 | .cdt = 0x104c0, | ||
90 | .fifo_start = 0x40, | ||
91 | .fifo_size = 0x2800, | ||
92 | .ptr1_reg = DMA1_PTR1, | ||
93 | .ptr2_reg = DMA1_PTR2, | ||
94 | .cnt1_reg = DMA1_CNT1, | ||
95 | .cnt2_reg = DMA1_CNT2, | ||
96 | }, | ||
97 | [SRAM_CH02] = { | ||
98 | .name = "ch2", | ||
99 | .cmds_start = 0x0, | ||
100 | .ctrl_start = 0x0, | ||
101 | .cdt = 0x0, | ||
102 | .fifo_start = 0x0, | ||
103 | .fifo_size = 0x0, | ||
104 | .ptr1_reg = DMA2_PTR1, | ||
105 | .ptr2_reg = DMA2_PTR2, | ||
106 | .cnt1_reg = DMA2_CNT1, | ||
107 | .cnt2_reg = DMA2_CNT2, | ||
108 | }, | ||
109 | [SRAM_CH03] = { | ||
110 | .name = "TS1 B", | ||
111 | .cmds_start = 0x100A0, | ||
112 | .ctrl_start = 0x10400, | ||
113 | .cdt = 0x10580, | ||
114 | .fifo_start = 0x5000, | ||
115 | .fifo_size = 0x1000, | ||
116 | .ptr1_reg = DMA3_PTR1, | ||
117 | .ptr2_reg = DMA3_PTR2, | ||
118 | .cnt1_reg = DMA3_CNT1, | ||
119 | .cnt2_reg = DMA3_CNT2, | ||
120 | }, | ||
121 | [SRAM_CH04] = { | ||
122 | .name = "ch4", | ||
123 | .cmds_start = 0x0, | ||
124 | .ctrl_start = 0x0, | ||
125 | .cdt = 0x0, | ||
126 | .fifo_start = 0x0, | ||
127 | .fifo_size = 0x0, | ||
128 | .ptr1_reg = DMA4_PTR1, | ||
129 | .ptr2_reg = DMA4_PTR2, | ||
130 | .cnt1_reg = DMA4_CNT1, | ||
131 | .cnt2_reg = DMA4_CNT2, | ||
132 | }, | ||
133 | [SRAM_CH05] = { | ||
134 | .name = "ch5", | ||
135 | .cmds_start = 0x0, | ||
136 | .ctrl_start = 0x0, | ||
137 | .cdt = 0x0, | ||
138 | .fifo_start = 0x0, | ||
139 | .fifo_size = 0x0, | ||
140 | .ptr1_reg = DMA5_PTR1, | ||
141 | .ptr2_reg = DMA5_PTR2, | ||
142 | .cnt1_reg = DMA5_CNT1, | ||
143 | .cnt2_reg = DMA5_CNT2, | ||
144 | }, | ||
145 | [SRAM_CH06] = { | ||
146 | .name = "TS2 C", | ||
147 | .cmds_start = 0x10140, | ||
148 | .ctrl_start = 0x10440, | ||
149 | .cdt = 0x105e0, | ||
150 | .fifo_start = 0x6000, | ||
151 | .fifo_size = 0x1000, | ||
152 | .ptr1_reg = DMA5_PTR1, | ||
153 | .ptr2_reg = DMA5_PTR2, | ||
154 | .cnt1_reg = DMA5_CNT1, | ||
155 | .cnt2_reg = DMA5_CNT2, | ||
156 | }, | ||
157 | [SRAM_CH07] = { | ||
158 | .name = "ch7", | ||
159 | .cmds_start = 0x0, | ||
160 | .ctrl_start = 0x0, | ||
161 | .cdt = 0x0, | ||
162 | .fifo_start = 0x0, | ||
163 | .fifo_size = 0x0, | ||
164 | .ptr1_reg = DMA6_PTR1, | ||
165 | .ptr2_reg = DMA6_PTR2, | ||
166 | .cnt1_reg = DMA6_CNT1, | ||
167 | .cnt2_reg = DMA6_CNT2, | ||
168 | }, | ||
169 | [SRAM_CH08] = { | ||
170 | .name = "ch8", | ||
171 | .cmds_start = 0x0, | ||
172 | .ctrl_start = 0x0, | ||
173 | .cdt = 0x0, | ||
174 | .fifo_start = 0x0, | ||
175 | .fifo_size = 0x0, | ||
176 | .ptr1_reg = DMA7_PTR1, | ||
177 | .ptr2_reg = DMA7_PTR2, | ||
178 | .cnt1_reg = DMA7_CNT1, | ||
179 | .cnt2_reg = DMA7_CNT2, | ||
180 | }, | ||
181 | [SRAM_CH09] = { | ||
182 | .name = "ch9", | ||
183 | .cmds_start = 0x0, | ||
184 | .ctrl_start = 0x0, | ||
185 | .cdt = 0x0, | ||
186 | .fifo_start = 0x0, | ||
187 | .fifo_size = 0x0, | ||
188 | .ptr1_reg = DMA8_PTR1, | ||
189 | .ptr2_reg = DMA8_PTR2, | ||
190 | .cnt1_reg = DMA8_CNT1, | ||
191 | .cnt2_reg = DMA8_CNT2, | ||
192 | }, | ||
193 | }; | ||
194 | |||
195 | static struct sram_channel cx23887_sram_channels[] = { | ||
196 | [SRAM_CH01] = { | ||
197 | .name = "VID A", | ||
198 | .cmds_start = 0x10000, | ||
199 | .ctrl_start = 0x105b0, | ||
200 | .cdt = 0x107b0, | ||
201 | .fifo_start = 0x40, | ||
202 | .fifo_size = 0x2800, | ||
203 | .ptr1_reg = DMA1_PTR1, | ||
204 | .ptr2_reg = DMA1_PTR2, | ||
205 | .cnt1_reg = DMA1_CNT1, | ||
206 | .cnt2_reg = DMA1_CNT2, | ||
207 | }, | ||
208 | [SRAM_CH02] = { | ||
209 | .name = "ch2", | ||
210 | .cmds_start = 0x0, | ||
211 | .ctrl_start = 0x0, | ||
212 | .cdt = 0x0, | ||
213 | .fifo_start = 0x0, | ||
214 | .fifo_size = 0x0, | ||
215 | .ptr1_reg = DMA2_PTR1, | ||
216 | .ptr2_reg = DMA2_PTR2, | ||
217 | .cnt1_reg = DMA2_CNT1, | ||
218 | .cnt2_reg = DMA2_CNT2, | ||
219 | }, | ||
220 | [SRAM_CH03] = { | ||
221 | .name = "TS1 B", | ||
222 | .cmds_start = 0x100A0, | ||
223 | .ctrl_start = 0x10630, | ||
224 | .cdt = 0x10870, | ||
225 | .fifo_start = 0x5000, | ||
226 | .fifo_size = 0x1000, | ||
227 | .ptr1_reg = DMA3_PTR1, | ||
228 | .ptr2_reg = DMA3_PTR2, | ||
229 | .cnt1_reg = DMA3_CNT1, | ||
230 | .cnt2_reg = DMA3_CNT2, | ||
231 | }, | ||
232 | [SRAM_CH04] = { | ||
233 | .name = "ch4", | ||
234 | .cmds_start = 0x0, | ||
235 | .ctrl_start = 0x0, | ||
236 | .cdt = 0x0, | ||
237 | .fifo_start = 0x0, | ||
238 | .fifo_size = 0x0, | ||
239 | .ptr1_reg = DMA4_PTR1, | ||
240 | .ptr2_reg = DMA4_PTR2, | ||
241 | .cnt1_reg = DMA4_CNT1, | ||
242 | .cnt2_reg = DMA4_CNT2, | ||
243 | }, | ||
244 | [SRAM_CH05] = { | ||
245 | .name = "ch5", | ||
246 | .cmds_start = 0x0, | ||
247 | .ctrl_start = 0x0, | ||
248 | .cdt = 0x0, | ||
249 | .fifo_start = 0x0, | ||
250 | .fifo_size = 0x0, | ||
251 | .ptr1_reg = DMA5_PTR1, | ||
252 | .ptr2_reg = DMA5_PTR2, | ||
253 | .cnt1_reg = DMA5_CNT1, | ||
254 | .cnt2_reg = DMA5_CNT2, | ||
255 | }, | ||
256 | [SRAM_CH06] = { | ||
257 | .name = "TS2 C", | ||
258 | .cmds_start = 0x10140, | ||
259 | .ctrl_start = 0x10670, | ||
260 | .cdt = 0x108d0, | ||
261 | .fifo_start = 0x6000, | ||
262 | .fifo_size = 0x1000, | ||
263 | .ptr1_reg = DMA5_PTR1, | ||
264 | .ptr2_reg = DMA5_PTR2, | ||
265 | .cnt1_reg = DMA5_CNT1, | ||
266 | .cnt2_reg = DMA5_CNT2, | ||
267 | }, | ||
268 | [SRAM_CH07] = { | ||
269 | .name = "ch7", | ||
270 | .cmds_start = 0x0, | ||
271 | .ctrl_start = 0x0, | ||
272 | .cdt = 0x0, | ||
273 | .fifo_start = 0x0, | ||
274 | .fifo_size = 0x0, | ||
275 | .ptr1_reg = DMA6_PTR1, | ||
276 | .ptr2_reg = DMA6_PTR2, | ||
277 | .cnt1_reg = DMA6_CNT1, | ||
278 | .cnt2_reg = DMA6_CNT2, | ||
279 | }, | ||
280 | [SRAM_CH08] = { | ||
281 | .name = "ch8", | ||
282 | .cmds_start = 0x0, | ||
283 | .ctrl_start = 0x0, | ||
284 | .cdt = 0x0, | ||
285 | .fifo_start = 0x0, | ||
286 | .fifo_size = 0x0, | ||
287 | .ptr1_reg = DMA7_PTR1, | ||
288 | .ptr2_reg = DMA7_PTR2, | ||
289 | .cnt1_reg = DMA7_CNT1, | ||
290 | .cnt2_reg = DMA7_CNT2, | ||
291 | }, | ||
292 | [SRAM_CH09] = { | ||
293 | .name = "ch9", | ||
294 | .cmds_start = 0x0, | ||
295 | .ctrl_start = 0x0, | ||
296 | .cdt = 0x0, | ||
297 | .fifo_start = 0x0, | ||
298 | .fifo_size = 0x0, | ||
299 | .ptr1_reg = DMA8_PTR1, | ||
300 | .ptr2_reg = DMA8_PTR2, | ||
301 | .cnt1_reg = DMA8_CNT1, | ||
302 | .cnt2_reg = DMA8_CNT2, | ||
303 | }, | ||
304 | }; | ||
305 | |||
306 | void cx23885_irq_add(struct cx23885_dev *dev, u32 mask) | ||
307 | { | ||
308 | unsigned long flags; | ||
309 | spin_lock_irqsave(&dev->pci_irqmask_lock, flags); | ||
310 | |||
311 | dev->pci_irqmask |= mask; | ||
312 | |||
313 | spin_unlock_irqrestore(&dev->pci_irqmask_lock, flags); | ||
314 | } | ||
315 | |||
316 | void cx23885_irq_add_enable(struct cx23885_dev *dev, u32 mask) | ||
317 | { | ||
318 | unsigned long flags; | ||
319 | spin_lock_irqsave(&dev->pci_irqmask_lock, flags); | ||
320 | |||
321 | dev->pci_irqmask |= mask; | ||
322 | cx_set(PCI_INT_MSK, mask); | ||
323 | |||
324 | spin_unlock_irqrestore(&dev->pci_irqmask_lock, flags); | ||
325 | } | ||
326 | |||
327 | void cx23885_irq_enable(struct cx23885_dev *dev, u32 mask) | ||
328 | { | ||
329 | u32 v; | ||
330 | unsigned long flags; | ||
331 | spin_lock_irqsave(&dev->pci_irqmask_lock, flags); | ||
332 | |||
333 | v = mask & dev->pci_irqmask; | ||
334 | if (v) | ||
335 | cx_set(PCI_INT_MSK, v); | ||
336 | |||
337 | spin_unlock_irqrestore(&dev->pci_irqmask_lock, flags); | ||
338 | } | ||
339 | |||
340 | static inline void cx23885_irq_enable_all(struct cx23885_dev *dev) | ||
341 | { | ||
342 | cx23885_irq_enable(dev, 0xffffffff); | ||
343 | } | ||
344 | |||
345 | void cx23885_irq_disable(struct cx23885_dev *dev, u32 mask) | ||
346 | { | ||
347 | unsigned long flags; | ||
348 | spin_lock_irqsave(&dev->pci_irqmask_lock, flags); | ||
349 | |||
350 | cx_clear(PCI_INT_MSK, mask); | ||
351 | |||
352 | spin_unlock_irqrestore(&dev->pci_irqmask_lock, flags); | ||
353 | } | ||
354 | |||
355 | static inline void cx23885_irq_disable_all(struct cx23885_dev *dev) | ||
356 | { | ||
357 | cx23885_irq_disable(dev, 0xffffffff); | ||
358 | } | ||
359 | |||
360 | void cx23885_irq_remove(struct cx23885_dev *dev, u32 mask) | ||
361 | { | ||
362 | unsigned long flags; | ||
363 | spin_lock_irqsave(&dev->pci_irqmask_lock, flags); | ||
364 | |||
365 | dev->pci_irqmask &= ~mask; | ||
366 | cx_clear(PCI_INT_MSK, mask); | ||
367 | |||
368 | spin_unlock_irqrestore(&dev->pci_irqmask_lock, flags); | ||
369 | } | ||
370 | |||
371 | static u32 cx23885_irq_get_mask(struct cx23885_dev *dev) | ||
372 | { | ||
373 | u32 v; | ||
374 | unsigned long flags; | ||
375 | spin_lock_irqsave(&dev->pci_irqmask_lock, flags); | ||
376 | |||
377 | v = cx_read(PCI_INT_MSK); | ||
378 | |||
379 | spin_unlock_irqrestore(&dev->pci_irqmask_lock, flags); | ||
380 | return v; | ||
381 | } | ||
382 | |||
383 | static int cx23885_risc_decode(u32 risc) | ||
384 | { | ||
385 | static char *instr[16] = { | ||
386 | [RISC_SYNC >> 28] = "sync", | ||
387 | [RISC_WRITE >> 28] = "write", | ||
388 | [RISC_WRITEC >> 28] = "writec", | ||
389 | [RISC_READ >> 28] = "read", | ||
390 | [RISC_READC >> 28] = "readc", | ||
391 | [RISC_JUMP >> 28] = "jump", | ||
392 | [RISC_SKIP >> 28] = "skip", | ||
393 | [RISC_WRITERM >> 28] = "writerm", | ||
394 | [RISC_WRITECM >> 28] = "writecm", | ||
395 | [RISC_WRITECR >> 28] = "writecr", | ||
396 | }; | ||
397 | static int incr[16] = { | ||
398 | [RISC_WRITE >> 28] = 3, | ||
399 | [RISC_JUMP >> 28] = 3, | ||
400 | [RISC_SKIP >> 28] = 1, | ||
401 | [RISC_SYNC >> 28] = 1, | ||
402 | [RISC_WRITERM >> 28] = 3, | ||
403 | [RISC_WRITECM >> 28] = 3, | ||
404 | [RISC_WRITECR >> 28] = 4, | ||
405 | }; | ||
406 | static char *bits[] = { | ||
407 | "12", "13", "14", "resync", | ||
408 | "cnt0", "cnt1", "18", "19", | ||
409 | "20", "21", "22", "23", | ||
410 | "irq1", "irq2", "eol", "sol", | ||
411 | }; | ||
412 | int i; | ||
413 | |||
414 | printk("0x%08x [ %s", risc, | ||
415 | instr[risc >> 28] ? instr[risc >> 28] : "INVALID"); | ||
416 | for (i = ARRAY_SIZE(bits) - 1; i >= 0; i--) | ||
417 | if (risc & (1 << (i + 12))) | ||
418 | printk(" %s", bits[i]); | ||
419 | printk(" count=%d ]\n", risc & 0xfff); | ||
420 | return incr[risc >> 28] ? incr[risc >> 28] : 1; | ||
421 | } | ||
422 | |||
423 | void cx23885_wakeup(struct cx23885_tsport *port, | ||
424 | struct cx23885_dmaqueue *q, u32 count) | ||
425 | { | ||
426 | struct cx23885_dev *dev = port->dev; | ||
427 | struct cx23885_buffer *buf; | ||
428 | int bc; | ||
429 | |||
430 | for (bc = 0;; bc++) { | ||
431 | if (list_empty(&q->active)) | ||
432 | break; | ||
433 | buf = list_entry(q->active.next, | ||
434 | struct cx23885_buffer, vb.queue); | ||
435 | |||
436 | /* count comes from the hw and is is 16bit wide -- | ||
437 | * this trick handles wrap-arounds correctly for | ||
438 | * up to 32767 buffers in flight... */ | ||
439 | if ((s16) (count - buf->count) < 0) | ||
440 | break; | ||
441 | |||
442 | do_gettimeofday(&buf->vb.ts); | ||
443 | dprintk(2, "[%p/%d] wakeup reg=%d buf=%d\n", buf, buf->vb.i, | ||
444 | count, buf->count); | ||
445 | buf->vb.state = VIDEOBUF_DONE; | ||
446 | list_del(&buf->vb.queue); | ||
447 | wake_up(&buf->vb.done); | ||
448 | } | ||
449 | if (list_empty(&q->active)) | ||
450 | del_timer(&q->timeout); | ||
451 | else | ||
452 | mod_timer(&q->timeout, jiffies + BUFFER_TIMEOUT); | ||
453 | if (bc != 1) | ||
454 | printk(KERN_WARNING "%s: %d buffers handled (should be 1)\n", | ||
455 | __func__, bc); | ||
456 | } | ||
457 | |||
458 | int cx23885_sram_channel_setup(struct cx23885_dev *dev, | ||
459 | struct sram_channel *ch, | ||
460 | unsigned int bpl, u32 risc) | ||
461 | { | ||
462 | unsigned int i, lines; | ||
463 | u32 cdt; | ||
464 | |||
465 | if (ch->cmds_start == 0) { | ||
466 | dprintk(1, "%s() Erasing channel [%s]\n", __func__, | ||
467 | ch->name); | ||
468 | cx_write(ch->ptr1_reg, 0); | ||
469 | cx_write(ch->ptr2_reg, 0); | ||
470 | cx_write(ch->cnt2_reg, 0); | ||
471 | cx_write(ch->cnt1_reg, 0); | ||
472 | return 0; | ||
473 | } else { | ||
474 | dprintk(1, "%s() Configuring channel [%s]\n", __func__, | ||
475 | ch->name); | ||
476 | } | ||
477 | |||
478 | bpl = (bpl + 7) & ~7; /* alignment */ | ||
479 | cdt = ch->cdt; | ||
480 | lines = ch->fifo_size / bpl; | ||
481 | if (lines > 6) | ||
482 | lines = 6; | ||
483 | BUG_ON(lines < 2); | ||
484 | |||
485 | cx_write(8 + 0, RISC_JUMP | RISC_IRQ1 | RISC_CNT_INC); | ||
486 | cx_write(8 + 4, 8); | ||
487 | cx_write(8 + 8, 0); | ||
488 | |||
489 | /* write CDT */ | ||
490 | for (i = 0; i < lines; i++) { | ||
491 | dprintk(2, "%s() 0x%08x <- 0x%08x\n", __func__, cdt + 16*i, | ||
492 | ch->fifo_start + bpl*i); | ||
493 | cx_write(cdt + 16*i, ch->fifo_start + bpl*i); | ||
494 | cx_write(cdt + 16*i + 4, 0); | ||
495 | cx_write(cdt + 16*i + 8, 0); | ||
496 | cx_write(cdt + 16*i + 12, 0); | ||
497 | } | ||
498 | |||
499 | /* write CMDS */ | ||
500 | if (ch->jumponly) | ||
501 | cx_write(ch->cmds_start + 0, 8); | ||
502 | else | ||
503 | cx_write(ch->cmds_start + 0, risc); | ||
504 | cx_write(ch->cmds_start + 4, 0); /* 64 bits 63-32 */ | ||
505 | cx_write(ch->cmds_start + 8, cdt); | ||
506 | cx_write(ch->cmds_start + 12, (lines*16) >> 3); | ||
507 | cx_write(ch->cmds_start + 16, ch->ctrl_start); | ||
508 | if (ch->jumponly) | ||
509 | cx_write(ch->cmds_start + 20, 0x80000000 | (64 >> 2)); | ||
510 | else | ||
511 | cx_write(ch->cmds_start + 20, 64 >> 2); | ||
512 | for (i = 24; i < 80; i += 4) | ||
513 | cx_write(ch->cmds_start + i, 0); | ||
514 | |||
515 | /* fill registers */ | ||
516 | cx_write(ch->ptr1_reg, ch->fifo_start); | ||
517 | cx_write(ch->ptr2_reg, cdt); | ||
518 | cx_write(ch->cnt2_reg, (lines*16) >> 3); | ||
519 | cx_write(ch->cnt1_reg, (bpl >> 3) - 1); | ||
520 | |||
521 | dprintk(2, "[bridge %d] sram setup %s: bpl=%d lines=%d\n", | ||
522 | dev->bridge, | ||
523 | ch->name, | ||
524 | bpl, | ||
525 | lines); | ||
526 | |||
527 | return 0; | ||
528 | } | ||
529 | |||
530 | void cx23885_sram_channel_dump(struct cx23885_dev *dev, | ||
531 | struct sram_channel *ch) | ||
532 | { | ||
533 | static char *name[] = { | ||
534 | "init risc lo", | ||
535 | "init risc hi", | ||
536 | "cdt base", | ||
537 | "cdt size", | ||
538 | "iq base", | ||
539 | "iq size", | ||
540 | "risc pc lo", | ||
541 | "risc pc hi", | ||
542 | "iq wr ptr", | ||
543 | "iq rd ptr", | ||
544 | "cdt current", | ||
545 | "pci target lo", | ||
546 | "pci target hi", | ||
547 | "line / byte", | ||
548 | }; | ||
549 | u32 risc; | ||
550 | unsigned int i, j, n; | ||
551 | |||
552 | printk(KERN_WARNING "%s: %s - dma channel status dump\n", | ||
553 | dev->name, ch->name); | ||
554 | for (i = 0; i < ARRAY_SIZE(name); i++) | ||
555 | printk(KERN_WARNING "%s: cmds: %-15s: 0x%08x\n", | ||
556 | dev->name, name[i], | ||
557 | cx_read(ch->cmds_start + 4*i)); | ||
558 | |||
559 | for (i = 0; i < 4; i++) { | ||
560 | risc = cx_read(ch->cmds_start + 4 * (i + 14)); | ||
561 | printk(KERN_WARNING "%s: risc%d: ", dev->name, i); | ||
562 | cx23885_risc_decode(risc); | ||
563 | } | ||
564 | for (i = 0; i < (64 >> 2); i += n) { | ||
565 | risc = cx_read(ch->ctrl_start + 4 * i); | ||
566 | /* No consideration for bits 63-32 */ | ||
567 | |||
568 | printk(KERN_WARNING "%s: (0x%08x) iq %x: ", dev->name, | ||
569 | ch->ctrl_start + 4 * i, i); | ||
570 | n = cx23885_risc_decode(risc); | ||
571 | for (j = 1; j < n; j++) { | ||
572 | risc = cx_read(ch->ctrl_start + 4 * (i + j)); | ||
573 | printk(KERN_WARNING "%s: iq %x: 0x%08x [ arg #%d ]\n", | ||
574 | dev->name, i+j, risc, j); | ||
575 | } | ||
576 | } | ||
577 | |||
578 | printk(KERN_WARNING "%s: fifo: 0x%08x -> 0x%x\n", | ||
579 | dev->name, ch->fifo_start, ch->fifo_start+ch->fifo_size); | ||
580 | printk(KERN_WARNING "%s: ctrl: 0x%08x -> 0x%x\n", | ||
581 | dev->name, ch->ctrl_start, ch->ctrl_start + 6*16); | ||
582 | printk(KERN_WARNING "%s: ptr1_reg: 0x%08x\n", | ||
583 | dev->name, cx_read(ch->ptr1_reg)); | ||
584 | printk(KERN_WARNING "%s: ptr2_reg: 0x%08x\n", | ||
585 | dev->name, cx_read(ch->ptr2_reg)); | ||
586 | printk(KERN_WARNING "%s: cnt1_reg: 0x%08x\n", | ||
587 | dev->name, cx_read(ch->cnt1_reg)); | ||
588 | printk(KERN_WARNING "%s: cnt2_reg: 0x%08x\n", | ||
589 | dev->name, cx_read(ch->cnt2_reg)); | ||
590 | } | ||
591 | |||
592 | static void cx23885_risc_disasm(struct cx23885_tsport *port, | ||
593 | struct btcx_riscmem *risc) | ||
594 | { | ||
595 | struct cx23885_dev *dev = port->dev; | ||
596 | unsigned int i, j, n; | ||
597 | |||
598 | printk(KERN_INFO "%s: risc disasm: %p [dma=0x%08lx]\n", | ||
599 | dev->name, risc->cpu, (unsigned long)risc->dma); | ||
600 | for (i = 0; i < (risc->size >> 2); i += n) { | ||
601 | printk(KERN_INFO "%s: %04d: ", dev->name, i); | ||
602 | n = cx23885_risc_decode(le32_to_cpu(risc->cpu[i])); | ||
603 | for (j = 1; j < n; j++) | ||
604 | printk(KERN_INFO "%s: %04d: 0x%08x [ arg #%d ]\n", | ||
605 | dev->name, i + j, risc->cpu[i + j], j); | ||
606 | if (risc->cpu[i] == cpu_to_le32(RISC_JUMP)) | ||
607 | break; | ||
608 | } | ||
609 | } | ||
610 | |||
611 | static void cx23885_shutdown(struct cx23885_dev *dev) | ||
612 | { | ||
613 | /* disable RISC controller */ | ||
614 | cx_write(DEV_CNTRL2, 0); | ||
615 | |||
616 | /* Disable all IR activity */ | ||
617 | cx_write(IR_CNTRL_REG, 0); | ||
618 | |||
619 | /* Disable Video A/B activity */ | ||
620 | cx_write(VID_A_DMA_CTL, 0); | ||
621 | cx_write(VID_B_DMA_CTL, 0); | ||
622 | cx_write(VID_C_DMA_CTL, 0); | ||
623 | |||
624 | /* Disable Audio activity */ | ||
625 | cx_write(AUD_INT_DMA_CTL, 0); | ||
626 | cx_write(AUD_EXT_DMA_CTL, 0); | ||
627 | |||
628 | /* Disable Serial port */ | ||
629 | cx_write(UART_CTL, 0); | ||
630 | |||
631 | /* Disable Interrupts */ | ||
632 | cx23885_irq_disable_all(dev); | ||
633 | cx_write(VID_A_INT_MSK, 0); | ||
634 | cx_write(VID_B_INT_MSK, 0); | ||
635 | cx_write(VID_C_INT_MSK, 0); | ||
636 | cx_write(AUDIO_INT_INT_MSK, 0); | ||
637 | cx_write(AUDIO_EXT_INT_MSK, 0); | ||
638 | |||
639 | } | ||
640 | |||
641 | static void cx23885_reset(struct cx23885_dev *dev) | ||
642 | { | ||
643 | dprintk(1, "%s()\n", __func__); | ||
644 | |||
645 | cx23885_shutdown(dev); | ||
646 | |||
647 | cx_write(PCI_INT_STAT, 0xffffffff); | ||
648 | cx_write(VID_A_INT_STAT, 0xffffffff); | ||
649 | cx_write(VID_B_INT_STAT, 0xffffffff); | ||
650 | cx_write(VID_C_INT_STAT, 0xffffffff); | ||
651 | cx_write(AUDIO_INT_INT_STAT, 0xffffffff); | ||
652 | cx_write(AUDIO_EXT_INT_STAT, 0xffffffff); | ||
653 | cx_write(CLK_DELAY, cx_read(CLK_DELAY) & 0x80000000); | ||
654 | cx_write(PAD_CTRL, 0x00500300); | ||
655 | |||
656 | mdelay(100); | ||
657 | |||
658 | cx23885_sram_channel_setup(dev, &dev->sram_channels[SRAM_CH01], | ||
659 | 720*4, 0); | ||
660 | cx23885_sram_channel_setup(dev, &dev->sram_channels[SRAM_CH02], 128, 0); | ||
661 | cx23885_sram_channel_setup(dev, &dev->sram_channels[SRAM_CH03], | ||
662 | 188*4, 0); | ||
663 | cx23885_sram_channel_setup(dev, &dev->sram_channels[SRAM_CH04], 128, 0); | ||
664 | cx23885_sram_channel_setup(dev, &dev->sram_channels[SRAM_CH05], 128, 0); | ||
665 | cx23885_sram_channel_setup(dev, &dev->sram_channels[SRAM_CH06], | ||
666 | 188*4, 0); | ||
667 | cx23885_sram_channel_setup(dev, &dev->sram_channels[SRAM_CH07], 128, 0); | ||
668 | cx23885_sram_channel_setup(dev, &dev->sram_channels[SRAM_CH08], 128, 0); | ||
669 | cx23885_sram_channel_setup(dev, &dev->sram_channels[SRAM_CH09], 128, 0); | ||
670 | |||
671 | cx23885_gpio_setup(dev); | ||
672 | } | ||
673 | |||
674 | |||
675 | static int cx23885_pci_quirks(struct cx23885_dev *dev) | ||
676 | { | ||
677 | dprintk(1, "%s()\n", __func__); | ||
678 | |||
679 | /* The cx23885 bridge has a weird bug which causes NMI to be asserted | ||
680 | * when DMA begins if RDR_TLCTL0 bit4 is not cleared. It does not | ||
681 | * occur on the cx23887 bridge. | ||
682 | */ | ||
683 | if (dev->bridge == CX23885_BRIDGE_885) | ||
684 | cx_clear(RDR_TLCTL0, 1 << 4); | ||
685 | |||
686 | return 0; | ||
687 | } | ||
688 | |||
689 | static int get_resources(struct cx23885_dev *dev) | ||
690 | { | ||
691 | if (request_mem_region(pci_resource_start(dev->pci, 0), | ||
692 | pci_resource_len(dev->pci, 0), | ||
693 | dev->name)) | ||
694 | return 0; | ||
695 | |||
696 | printk(KERN_ERR "%s: can't get MMIO memory @ 0x%llx\n", | ||
697 | dev->name, (unsigned long long)pci_resource_start(dev->pci, 0)); | ||
698 | |||
699 | return -EBUSY; | ||
700 | } | ||
701 | |||
702 | static void cx23885_timeout(unsigned long data); | ||
703 | int cx23885_risc_stopper(struct pci_dev *pci, struct btcx_riscmem *risc, | ||
704 | u32 reg, u32 mask, u32 value); | ||
705 | |||
706 | static int cx23885_init_tsport(struct cx23885_dev *dev, | ||
707 | struct cx23885_tsport *port, int portno) | ||
708 | { | ||
709 | dprintk(1, "%s(portno=%d)\n", __func__, portno); | ||
710 | |||
711 | /* Transport bus init dma queue - Common settings */ | ||
712 | port->dma_ctl_val = 0x11; /* Enable RISC controller and Fifo */ | ||
713 | port->ts_int_msk_val = 0x1111; /* TS port bits for RISC */ | ||
714 | port->vld_misc_val = 0x0; | ||
715 | port->hw_sop_ctrl_val = (0x47 << 16 | 188 << 4); | ||
716 | |||
717 | spin_lock_init(&port->slock); | ||
718 | port->dev = dev; | ||
719 | port->nr = portno; | ||
720 | |||
721 | INIT_LIST_HEAD(&port->mpegq.active); | ||
722 | INIT_LIST_HEAD(&port->mpegq.queued); | ||
723 | port->mpegq.timeout.function = cx23885_timeout; | ||
724 | port->mpegq.timeout.data = (unsigned long)port; | ||
725 | init_timer(&port->mpegq.timeout); | ||
726 | |||
727 | mutex_init(&port->frontends.lock); | ||
728 | INIT_LIST_HEAD(&port->frontends.felist); | ||
729 | port->frontends.active_fe_id = 0; | ||
730 | |||
731 | /* This should be hardcoded allow a single frontend | ||
732 | * attachment to this tsport, keeping the -dvb.c | ||
733 | * code clean and safe. | ||
734 | */ | ||
735 | if (!port->num_frontends) | ||
736 | port->num_frontends = 1; | ||
737 | |||
738 | switch (portno) { | ||
739 | case 1: | ||
740 | port->reg_gpcnt = VID_B_GPCNT; | ||
741 | port->reg_gpcnt_ctl = VID_B_GPCNT_CTL; | ||
742 | port->reg_dma_ctl = VID_B_DMA_CTL; | ||
743 | port->reg_lngth = VID_B_LNGTH; | ||
744 | port->reg_hw_sop_ctrl = VID_B_HW_SOP_CTL; | ||
745 | port->reg_gen_ctrl = VID_B_GEN_CTL; | ||
746 | port->reg_bd_pkt_status = VID_B_BD_PKT_STATUS; | ||
747 | port->reg_sop_status = VID_B_SOP_STATUS; | ||
748 | port->reg_fifo_ovfl_stat = VID_B_FIFO_OVFL_STAT; | ||
749 | port->reg_vld_misc = VID_B_VLD_MISC; | ||
750 | port->reg_ts_clk_en = VID_B_TS_CLK_EN; | ||
751 | port->reg_src_sel = VID_B_SRC_SEL; | ||
752 | port->reg_ts_int_msk = VID_B_INT_MSK; | ||
753 | port->reg_ts_int_stat = VID_B_INT_STAT; | ||
754 | port->sram_chno = SRAM_CH03; /* VID_B */ | ||
755 | port->pci_irqmask = 0x02; /* VID_B bit1 */ | ||
756 | break; | ||
757 | case 2: | ||
758 | port->reg_gpcnt = VID_C_GPCNT; | ||
759 | port->reg_gpcnt_ctl = VID_C_GPCNT_CTL; | ||
760 | port->reg_dma_ctl = VID_C_DMA_CTL; | ||
761 | port->reg_lngth = VID_C_LNGTH; | ||
762 | port->reg_hw_sop_ctrl = VID_C_HW_SOP_CTL; | ||
763 | port->reg_gen_ctrl = VID_C_GEN_CTL; | ||
764 | port->reg_bd_pkt_status = VID_C_BD_PKT_STATUS; | ||
765 | port->reg_sop_status = VID_C_SOP_STATUS; | ||
766 | port->reg_fifo_ovfl_stat = VID_C_FIFO_OVFL_STAT; | ||
767 | port->reg_vld_misc = VID_C_VLD_MISC; | ||
768 | port->reg_ts_clk_en = VID_C_TS_CLK_EN; | ||
769 | port->reg_src_sel = 0; | ||
770 | port->reg_ts_int_msk = VID_C_INT_MSK; | ||
771 | port->reg_ts_int_stat = VID_C_INT_STAT; | ||
772 | port->sram_chno = SRAM_CH06; /* VID_C */ | ||
773 | port->pci_irqmask = 0x04; /* VID_C bit2 */ | ||
774 | break; | ||
775 | default: | ||
776 | BUG(); | ||
777 | } | ||
778 | |||
779 | cx23885_risc_stopper(dev->pci, &port->mpegq.stopper, | ||
780 | port->reg_dma_ctl, port->dma_ctl_val, 0x00); | ||
781 | |||
782 | return 0; | ||
783 | } | ||
784 | |||
785 | static void cx23885_dev_checkrevision(struct cx23885_dev *dev) | ||
786 | { | ||
787 | switch (cx_read(RDR_CFG2) & 0xff) { | ||
788 | case 0x00: | ||
789 | /* cx23885 */ | ||
790 | dev->hwrevision = 0xa0; | ||
791 | break; | ||
792 | case 0x01: | ||
793 | /* CX23885-12Z */ | ||
794 | dev->hwrevision = 0xa1; | ||
795 | break; | ||
796 | case 0x02: | ||
797 | /* CX23885-13Z/14Z */ | ||
798 | dev->hwrevision = 0xb0; | ||
799 | break; | ||
800 | case 0x03: | ||
801 | if (dev->pci->device == 0x8880) { | ||
802 | /* CX23888-21Z/22Z */ | ||
803 | dev->hwrevision = 0xc0; | ||
804 | } else { | ||
805 | /* CX23885-14Z */ | ||
806 | dev->hwrevision = 0xa4; | ||
807 | } | ||
808 | break; | ||
809 | case 0x04: | ||
810 | if (dev->pci->device == 0x8880) { | ||
811 | /* CX23888-31Z */ | ||
812 | dev->hwrevision = 0xd0; | ||
813 | } else { | ||
814 | /* CX23885-15Z, CX23888-31Z */ | ||
815 | dev->hwrevision = 0xa5; | ||
816 | } | ||
817 | break; | ||
818 | case 0x0e: | ||
819 | /* CX23887-15Z */ | ||
820 | dev->hwrevision = 0xc0; | ||
821 | break; | ||
822 | case 0x0f: | ||
823 | /* CX23887-14Z */ | ||
824 | dev->hwrevision = 0xb1; | ||
825 | break; | ||
826 | default: | ||
827 | printk(KERN_ERR "%s() New hardware revision found 0x%x\n", | ||
828 | __func__, dev->hwrevision); | ||
829 | } | ||
830 | if (dev->hwrevision) | ||
831 | printk(KERN_INFO "%s() Hardware revision = 0x%02x\n", | ||
832 | __func__, dev->hwrevision); | ||
833 | else | ||
834 | printk(KERN_ERR "%s() Hardware revision unknown 0x%x\n", | ||
835 | __func__, dev->hwrevision); | ||
836 | } | ||
837 | |||
838 | /* Find the first v4l2_subdev member of the group id in hw */ | ||
839 | struct v4l2_subdev *cx23885_find_hw(struct cx23885_dev *dev, u32 hw) | ||
840 | { | ||
841 | struct v4l2_subdev *result = NULL; | ||
842 | struct v4l2_subdev *sd; | ||
843 | |||
844 | spin_lock(&dev->v4l2_dev.lock); | ||
845 | v4l2_device_for_each_subdev(sd, &dev->v4l2_dev) { | ||
846 | if (sd->grp_id == hw) { | ||
847 | result = sd; | ||
848 | break; | ||
849 | } | ||
850 | } | ||
851 | spin_unlock(&dev->v4l2_dev.lock); | ||
852 | return result; | ||
853 | } | ||
854 | |||
855 | static int cx23885_dev_setup(struct cx23885_dev *dev) | ||
856 | { | ||
857 | int i; | ||
858 | |||
859 | spin_lock_init(&dev->pci_irqmask_lock); | ||
860 | |||
861 | mutex_init(&dev->lock); | ||
862 | mutex_init(&dev->gpio_lock); | ||
863 | |||
864 | atomic_inc(&dev->refcount); | ||
865 | |||
866 | dev->nr = cx23885_devcount++; | ||
867 | sprintf(dev->name, "cx23885[%d]", dev->nr); | ||
868 | |||
869 | /* Configure the internal memory */ | ||
870 | if (dev->pci->device == 0x8880) { | ||
871 | /* Could be 887 or 888, assume a default */ | ||
872 | dev->bridge = CX23885_BRIDGE_887; | ||
873 | /* Apply a sensible clock frequency for the PCIe bridge */ | ||
874 | dev->clk_freq = 25000000; | ||
875 | dev->sram_channels = cx23887_sram_channels; | ||
876 | } else | ||
877 | if (dev->pci->device == 0x8852) { | ||
878 | dev->bridge = CX23885_BRIDGE_885; | ||
879 | /* Apply a sensible clock frequency for the PCIe bridge */ | ||
880 | dev->clk_freq = 28000000; | ||
881 | dev->sram_channels = cx23885_sram_channels; | ||
882 | } else | ||
883 | BUG(); | ||
884 | |||
885 | dprintk(1, "%s() Memory configured for PCIe bridge type %d\n", | ||
886 | __func__, dev->bridge); | ||
887 | |||
888 | /* board config */ | ||
889 | dev->board = UNSET; | ||
890 | if (card[dev->nr] < cx23885_bcount) | ||
891 | dev->board = card[dev->nr]; | ||
892 | for (i = 0; UNSET == dev->board && i < cx23885_idcount; i++) | ||
893 | if (dev->pci->subsystem_vendor == cx23885_subids[i].subvendor && | ||
894 | dev->pci->subsystem_device == cx23885_subids[i].subdevice) | ||
895 | dev->board = cx23885_subids[i].card; | ||
896 | if (UNSET == dev->board) { | ||
897 | dev->board = CX23885_BOARD_UNKNOWN; | ||
898 | cx23885_card_list(dev); | ||
899 | } | ||
900 | |||
901 | /* If the user specific a clk freq override, apply it */ | ||
902 | if (cx23885_boards[dev->board].clk_freq > 0) | ||
903 | dev->clk_freq = cx23885_boards[dev->board].clk_freq; | ||
904 | |||
905 | dev->pci_bus = dev->pci->bus->number; | ||
906 | dev->pci_slot = PCI_SLOT(dev->pci->devfn); | ||
907 | cx23885_irq_add(dev, 0x001f00); | ||
908 | |||
909 | /* External Master 1 Bus */ | ||
910 | dev->i2c_bus[0].nr = 0; | ||
911 | dev->i2c_bus[0].dev = dev; | ||
912 | dev->i2c_bus[0].reg_stat = I2C1_STAT; | ||
913 | dev->i2c_bus[0].reg_ctrl = I2C1_CTRL; | ||
914 | dev->i2c_bus[0].reg_addr = I2C1_ADDR; | ||
915 | dev->i2c_bus[0].reg_rdata = I2C1_RDATA; | ||
916 | dev->i2c_bus[0].reg_wdata = I2C1_WDATA; | ||
917 | dev->i2c_bus[0].i2c_period = (0x9d << 24); /* 100kHz */ | ||
918 | |||
919 | /* External Master 2 Bus */ | ||
920 | dev->i2c_bus[1].nr = 1; | ||
921 | dev->i2c_bus[1].dev = dev; | ||
922 | dev->i2c_bus[1].reg_stat = I2C2_STAT; | ||
923 | dev->i2c_bus[1].reg_ctrl = I2C2_CTRL; | ||
924 | dev->i2c_bus[1].reg_addr = I2C2_ADDR; | ||
925 | dev->i2c_bus[1].reg_rdata = I2C2_RDATA; | ||
926 | dev->i2c_bus[1].reg_wdata = I2C2_WDATA; | ||
927 | dev->i2c_bus[1].i2c_period = (0x9d << 24); /* 100kHz */ | ||
928 | |||
929 | /* Internal Master 3 Bus */ | ||
930 | dev->i2c_bus[2].nr = 2; | ||
931 | dev->i2c_bus[2].dev = dev; | ||
932 | dev->i2c_bus[2].reg_stat = I2C3_STAT; | ||
933 | dev->i2c_bus[2].reg_ctrl = I2C3_CTRL; | ||
934 | dev->i2c_bus[2].reg_addr = I2C3_ADDR; | ||
935 | dev->i2c_bus[2].reg_rdata = I2C3_RDATA; | ||
936 | dev->i2c_bus[2].reg_wdata = I2C3_WDATA; | ||
937 | dev->i2c_bus[2].i2c_period = (0x07 << 24); /* 1.95MHz */ | ||
938 | |||
939 | if ((cx23885_boards[dev->board].portb == CX23885_MPEG_DVB) || | ||
940 | (cx23885_boards[dev->board].portb == CX23885_MPEG_ENCODER)) | ||
941 | cx23885_init_tsport(dev, &dev->ts1, 1); | ||
942 | |||
943 | if ((cx23885_boards[dev->board].portc == CX23885_MPEG_DVB) || | ||
944 | (cx23885_boards[dev->board].portc == CX23885_MPEG_ENCODER)) | ||
945 | cx23885_init_tsport(dev, &dev->ts2, 2); | ||
946 | |||
947 | if (get_resources(dev) < 0) { | ||
948 | printk(KERN_ERR "CORE %s No more PCIe resources for " | ||
949 | "subsystem: %04x:%04x\n", | ||
950 | dev->name, dev->pci->subsystem_vendor, | ||
951 | dev->pci->subsystem_device); | ||
952 | |||
953 | cx23885_devcount--; | ||
954 | return -ENODEV; | ||
955 | } | ||
956 | |||
957 | /* PCIe stuff */ | ||
958 | dev->lmmio = ioremap(pci_resource_start(dev->pci, 0), | ||
959 | pci_resource_len(dev->pci, 0)); | ||
960 | |||
961 | dev->bmmio = (u8 __iomem *)dev->lmmio; | ||
962 | |||
963 | printk(KERN_INFO "CORE %s: subsystem: %04x:%04x, board: %s [card=%d,%s]\n", | ||
964 | dev->name, dev->pci->subsystem_vendor, | ||
965 | dev->pci->subsystem_device, cx23885_boards[dev->board].name, | ||
966 | dev->board, card[dev->nr] == dev->board ? | ||
967 | "insmod option" : "autodetected"); | ||
968 | |||
969 | cx23885_pci_quirks(dev); | ||
970 | |||
971 | /* Assume some sensible defaults */ | ||
972 | dev->tuner_type = cx23885_boards[dev->board].tuner_type; | ||
973 | dev->tuner_addr = cx23885_boards[dev->board].tuner_addr; | ||
974 | dev->tuner_bus = cx23885_boards[dev->board].tuner_bus; | ||
975 | dev->radio_type = cx23885_boards[dev->board].radio_type; | ||
976 | dev->radio_addr = cx23885_boards[dev->board].radio_addr; | ||
977 | |||
978 | dprintk(1, "%s() tuner_type = 0x%x tuner_addr = 0x%x tuner_bus = %d\n", | ||
979 | __func__, dev->tuner_type, dev->tuner_addr, dev->tuner_bus); | ||
980 | dprintk(1, "%s() radio_type = 0x%x radio_addr = 0x%x\n", | ||
981 | __func__, dev->radio_type, dev->radio_addr); | ||
982 | |||
983 | /* The cx23417 encoder has GPIO's that need to be initialised | ||
984 | * before DVB, so that demodulators and tuners are out of | ||
985 | * reset before DVB uses them. | ||
986 | */ | ||
987 | if ((cx23885_boards[dev->board].portb == CX23885_MPEG_ENCODER) || | ||
988 | (cx23885_boards[dev->board].portc == CX23885_MPEG_ENCODER)) | ||
989 | cx23885_mc417_init(dev); | ||
990 | |||
991 | /* init hardware */ | ||
992 | cx23885_reset(dev); | ||
993 | |||
994 | cx23885_i2c_register(&dev->i2c_bus[0]); | ||
995 | cx23885_i2c_register(&dev->i2c_bus[1]); | ||
996 | cx23885_i2c_register(&dev->i2c_bus[2]); | ||
997 | cx23885_card_setup(dev); | ||
998 | call_all(dev, core, s_power, 0); | ||
999 | cx23885_ir_init(dev); | ||
1000 | |||
1001 | if (cx23885_boards[dev->board].porta == CX23885_ANALOG_VIDEO) { | ||
1002 | if (cx23885_video_register(dev) < 0) { | ||
1003 | printk(KERN_ERR "%s() Failed to register analog " | ||
1004 | "video adapters on VID_A\n", __func__); | ||
1005 | } | ||
1006 | } | ||
1007 | |||
1008 | if (cx23885_boards[dev->board].portb == CX23885_MPEG_DVB) { | ||
1009 | if (cx23885_boards[dev->board].num_fds_portb) | ||
1010 | dev->ts1.num_frontends = | ||
1011 | cx23885_boards[dev->board].num_fds_portb; | ||
1012 | if (cx23885_dvb_register(&dev->ts1) < 0) { | ||
1013 | printk(KERN_ERR "%s() Failed to register dvb adapters on VID_B\n", | ||
1014 | __func__); | ||
1015 | } | ||
1016 | } else | ||
1017 | if (cx23885_boards[dev->board].portb == CX23885_MPEG_ENCODER) { | ||
1018 | if (cx23885_417_register(dev) < 0) { | ||
1019 | printk(KERN_ERR | ||
1020 | "%s() Failed to register 417 on VID_B\n", | ||
1021 | __func__); | ||
1022 | } | ||
1023 | } | ||
1024 | |||
1025 | if (cx23885_boards[dev->board].portc == CX23885_MPEG_DVB) { | ||
1026 | if (cx23885_boards[dev->board].num_fds_portc) | ||
1027 | dev->ts2.num_frontends = | ||
1028 | cx23885_boards[dev->board].num_fds_portc; | ||
1029 | if (cx23885_dvb_register(&dev->ts2) < 0) { | ||
1030 | printk(KERN_ERR | ||
1031 | "%s() Failed to register dvb on VID_C\n", | ||
1032 | __func__); | ||
1033 | } | ||
1034 | } else | ||
1035 | if (cx23885_boards[dev->board].portc == CX23885_MPEG_ENCODER) { | ||
1036 | if (cx23885_417_register(dev) < 0) { | ||
1037 | printk(KERN_ERR | ||
1038 | "%s() Failed to register 417 on VID_C\n", | ||
1039 | __func__); | ||
1040 | } | ||
1041 | } | ||
1042 | |||
1043 | cx23885_dev_checkrevision(dev); | ||
1044 | |||
1045 | /* disable MSI for NetUP cards, otherwise CI is not working */ | ||
1046 | if (cx23885_boards[dev->board].ci_type > 0) | ||
1047 | cx_clear(RDR_RDRCTL1, 1 << 8); | ||
1048 | |||
1049 | return 0; | ||
1050 | } | ||
1051 | |||
1052 | static void cx23885_dev_unregister(struct cx23885_dev *dev) | ||
1053 | { | ||
1054 | release_mem_region(pci_resource_start(dev->pci, 0), | ||
1055 | pci_resource_len(dev->pci, 0)); | ||
1056 | |||
1057 | if (!atomic_dec_and_test(&dev->refcount)) | ||
1058 | return; | ||
1059 | |||
1060 | if (cx23885_boards[dev->board].porta == CX23885_ANALOG_VIDEO) | ||
1061 | cx23885_video_unregister(dev); | ||
1062 | |||
1063 | if (cx23885_boards[dev->board].portb == CX23885_MPEG_DVB) | ||
1064 | cx23885_dvb_unregister(&dev->ts1); | ||
1065 | |||
1066 | if (cx23885_boards[dev->board].portb == CX23885_MPEG_ENCODER) | ||
1067 | cx23885_417_unregister(dev); | ||
1068 | |||
1069 | if (cx23885_boards[dev->board].portc == CX23885_MPEG_DVB) | ||
1070 | cx23885_dvb_unregister(&dev->ts2); | ||
1071 | |||
1072 | if (cx23885_boards[dev->board].portc == CX23885_MPEG_ENCODER) | ||
1073 | cx23885_417_unregister(dev); | ||
1074 | |||
1075 | cx23885_i2c_unregister(&dev->i2c_bus[2]); | ||
1076 | cx23885_i2c_unregister(&dev->i2c_bus[1]); | ||
1077 | cx23885_i2c_unregister(&dev->i2c_bus[0]); | ||
1078 | |||
1079 | iounmap(dev->lmmio); | ||
1080 | } | ||
1081 | |||
1082 | static __le32 *cx23885_risc_field(__le32 *rp, struct scatterlist *sglist, | ||
1083 | unsigned int offset, u32 sync_line, | ||
1084 | unsigned int bpl, unsigned int padding, | ||
1085 | unsigned int lines) | ||
1086 | { | ||
1087 | struct scatterlist *sg; | ||
1088 | unsigned int line, todo; | ||
1089 | |||
1090 | /* sync instruction */ | ||
1091 | if (sync_line != NO_SYNC_LINE) | ||
1092 | *(rp++) = cpu_to_le32(RISC_RESYNC | sync_line); | ||
1093 | |||
1094 | /* scan lines */ | ||
1095 | sg = sglist; | ||
1096 | for (line = 0; line < lines; line++) { | ||
1097 | while (offset && offset >= sg_dma_len(sg)) { | ||
1098 | offset -= sg_dma_len(sg); | ||
1099 | sg++; | ||
1100 | } | ||
1101 | if (bpl <= sg_dma_len(sg)-offset) { | ||
1102 | /* fits into current chunk */ | ||
1103 | *(rp++) = cpu_to_le32(RISC_WRITE|RISC_SOL|RISC_EOL|bpl); | ||
1104 | *(rp++) = cpu_to_le32(sg_dma_address(sg)+offset); | ||
1105 | *(rp++) = cpu_to_le32(0); /* bits 63-32 */ | ||
1106 | offset += bpl; | ||
1107 | } else { | ||
1108 | /* scanline needs to be split */ | ||
1109 | todo = bpl; | ||
1110 | *(rp++) = cpu_to_le32(RISC_WRITE|RISC_SOL| | ||
1111 | (sg_dma_len(sg)-offset)); | ||
1112 | *(rp++) = cpu_to_le32(sg_dma_address(sg)+offset); | ||
1113 | *(rp++) = cpu_to_le32(0); /* bits 63-32 */ | ||
1114 | todo -= (sg_dma_len(sg)-offset); | ||
1115 | offset = 0; | ||
1116 | sg++; | ||
1117 | while (todo > sg_dma_len(sg)) { | ||
1118 | *(rp++) = cpu_to_le32(RISC_WRITE| | ||
1119 | sg_dma_len(sg)); | ||
1120 | *(rp++) = cpu_to_le32(sg_dma_address(sg)); | ||
1121 | *(rp++) = cpu_to_le32(0); /* bits 63-32 */ | ||
1122 | todo -= sg_dma_len(sg); | ||
1123 | sg++; | ||
1124 | } | ||
1125 | *(rp++) = cpu_to_le32(RISC_WRITE|RISC_EOL|todo); | ||
1126 | *(rp++) = cpu_to_le32(sg_dma_address(sg)); | ||
1127 | *(rp++) = cpu_to_le32(0); /* bits 63-32 */ | ||
1128 | offset += todo; | ||
1129 | } | ||
1130 | offset += padding; | ||
1131 | } | ||
1132 | |||
1133 | return rp; | ||
1134 | } | ||
1135 | |||
1136 | int cx23885_risc_buffer(struct pci_dev *pci, struct btcx_riscmem *risc, | ||
1137 | struct scatterlist *sglist, unsigned int top_offset, | ||
1138 | unsigned int bottom_offset, unsigned int bpl, | ||
1139 | unsigned int padding, unsigned int lines) | ||
1140 | { | ||
1141 | u32 instructions, fields; | ||
1142 | __le32 *rp; | ||
1143 | int rc; | ||
1144 | |||
1145 | fields = 0; | ||
1146 | if (UNSET != top_offset) | ||
1147 | fields++; | ||
1148 | if (UNSET != bottom_offset) | ||
1149 | fields++; | ||
1150 | |||
1151 | /* estimate risc mem: worst case is one write per page border + | ||
1152 | one write per scan line + syncs + jump (all 2 dwords). Padding | ||
1153 | can cause next bpl to start close to a page border. First DMA | ||
1154 | region may be smaller than PAGE_SIZE */ | ||
1155 | /* write and jump need and extra dword */ | ||
1156 | instructions = fields * (1 + ((bpl + padding) * lines) | ||
1157 | / PAGE_SIZE + lines); | ||
1158 | instructions += 2; | ||
1159 | rc = btcx_riscmem_alloc(pci, risc, instructions*12); | ||
1160 | if (rc < 0) | ||
1161 | return rc; | ||
1162 | |||
1163 | /* write risc instructions */ | ||
1164 | rp = risc->cpu; | ||
1165 | if (UNSET != top_offset) | ||
1166 | rp = cx23885_risc_field(rp, sglist, top_offset, 0, | ||
1167 | bpl, padding, lines); | ||
1168 | if (UNSET != bottom_offset) | ||
1169 | rp = cx23885_risc_field(rp, sglist, bottom_offset, 0x200, | ||
1170 | bpl, padding, lines); | ||
1171 | |||
1172 | /* save pointer to jmp instruction address */ | ||
1173 | risc->jmp = rp; | ||
1174 | BUG_ON((risc->jmp - risc->cpu + 2) * sizeof(*risc->cpu) > risc->size); | ||
1175 | return 0; | ||
1176 | } | ||
1177 | |||
1178 | static int cx23885_risc_databuffer(struct pci_dev *pci, | ||
1179 | struct btcx_riscmem *risc, | ||
1180 | struct scatterlist *sglist, | ||
1181 | unsigned int bpl, | ||
1182 | unsigned int lines) | ||
1183 | { | ||
1184 | u32 instructions; | ||
1185 | __le32 *rp; | ||
1186 | int rc; | ||
1187 | |||
1188 | /* estimate risc mem: worst case is one write per page border + | ||
1189 | one write per scan line + syncs + jump (all 2 dwords). Here | ||
1190 | there is no padding and no sync. First DMA region may be smaller | ||
1191 | than PAGE_SIZE */ | ||
1192 | /* Jump and write need an extra dword */ | ||
1193 | instructions = 1 + (bpl * lines) / PAGE_SIZE + lines; | ||
1194 | instructions += 1; | ||
1195 | |||
1196 | rc = btcx_riscmem_alloc(pci, risc, instructions*12); | ||
1197 | if (rc < 0) | ||
1198 | return rc; | ||
1199 | |||
1200 | /* write risc instructions */ | ||
1201 | rp = risc->cpu; | ||
1202 | rp = cx23885_risc_field(rp, sglist, 0, NO_SYNC_LINE, bpl, 0, lines); | ||
1203 | |||
1204 | /* save pointer to jmp instruction address */ | ||
1205 | risc->jmp = rp; | ||
1206 | BUG_ON((risc->jmp - risc->cpu + 2) * sizeof(*risc->cpu) > risc->size); | ||
1207 | return 0; | ||
1208 | } | ||
1209 | |||
1210 | int cx23885_risc_stopper(struct pci_dev *pci, struct btcx_riscmem *risc, | ||
1211 | u32 reg, u32 mask, u32 value) | ||
1212 | { | ||
1213 | __le32 *rp; | ||
1214 | int rc; | ||
1215 | |||
1216 | rc = btcx_riscmem_alloc(pci, risc, 4*16); | ||
1217 | if (rc < 0) | ||
1218 | return rc; | ||
1219 | |||
1220 | /* write risc instructions */ | ||
1221 | rp = risc->cpu; | ||
1222 | *(rp++) = cpu_to_le32(RISC_WRITECR | RISC_IRQ2); | ||
1223 | *(rp++) = cpu_to_le32(reg); | ||
1224 | *(rp++) = cpu_to_le32(value); | ||
1225 | *(rp++) = cpu_to_le32(mask); | ||
1226 | *(rp++) = cpu_to_le32(RISC_JUMP); | ||
1227 | *(rp++) = cpu_to_le32(risc->dma); | ||
1228 | *(rp++) = cpu_to_le32(0); /* bits 63-32 */ | ||
1229 | return 0; | ||
1230 | } | ||
1231 | |||
1232 | void cx23885_free_buffer(struct videobuf_queue *q, struct cx23885_buffer *buf) | ||
1233 | { | ||
1234 | struct videobuf_dmabuf *dma = videobuf_to_dma(&buf->vb); | ||
1235 | |||
1236 | BUG_ON(in_interrupt()); | ||
1237 | videobuf_waiton(q, &buf->vb, 0, 0); | ||
1238 | videobuf_dma_unmap(q->dev, dma); | ||
1239 | videobuf_dma_free(dma); | ||
1240 | btcx_riscmem_free(to_pci_dev(q->dev), &buf->risc); | ||
1241 | buf->vb.state = VIDEOBUF_NEEDS_INIT; | ||
1242 | } | ||
1243 | |||
1244 | static void cx23885_tsport_reg_dump(struct cx23885_tsport *port) | ||
1245 | { | ||
1246 | struct cx23885_dev *dev = port->dev; | ||
1247 | |||
1248 | dprintk(1, "%s() Register Dump\n", __func__); | ||
1249 | dprintk(1, "%s() DEV_CNTRL2 0x%08X\n", __func__, | ||
1250 | cx_read(DEV_CNTRL2)); | ||
1251 | dprintk(1, "%s() PCI_INT_MSK 0x%08X\n", __func__, | ||
1252 | cx23885_irq_get_mask(dev)); | ||
1253 | dprintk(1, "%s() AUD_INT_INT_MSK 0x%08X\n", __func__, | ||
1254 | cx_read(AUDIO_INT_INT_MSK)); | ||
1255 | dprintk(1, "%s() AUD_INT_DMA_CTL 0x%08X\n", __func__, | ||
1256 | cx_read(AUD_INT_DMA_CTL)); | ||
1257 | dprintk(1, "%s() AUD_EXT_INT_MSK 0x%08X\n", __func__, | ||
1258 | cx_read(AUDIO_EXT_INT_MSK)); | ||
1259 | dprintk(1, "%s() AUD_EXT_DMA_CTL 0x%08X\n", __func__, | ||
1260 | cx_read(AUD_EXT_DMA_CTL)); | ||
1261 | dprintk(1, "%s() PAD_CTRL 0x%08X\n", __func__, | ||
1262 | cx_read(PAD_CTRL)); | ||
1263 | dprintk(1, "%s() ALT_PIN_OUT_SEL 0x%08X\n", __func__, | ||
1264 | cx_read(ALT_PIN_OUT_SEL)); | ||
1265 | dprintk(1, "%s() GPIO2 0x%08X\n", __func__, | ||
1266 | cx_read(GPIO2)); | ||
1267 | dprintk(1, "%s() gpcnt(0x%08X) 0x%08X\n", __func__, | ||
1268 | port->reg_gpcnt, cx_read(port->reg_gpcnt)); | ||
1269 | dprintk(1, "%s() gpcnt_ctl(0x%08X) 0x%08x\n", __func__, | ||
1270 | port->reg_gpcnt_ctl, cx_read(port->reg_gpcnt_ctl)); | ||
1271 | dprintk(1, "%s() dma_ctl(0x%08X) 0x%08x\n", __func__, | ||
1272 | port->reg_dma_ctl, cx_read(port->reg_dma_ctl)); | ||
1273 | if (port->reg_src_sel) | ||
1274 | dprintk(1, "%s() src_sel(0x%08X) 0x%08x\n", __func__, | ||
1275 | port->reg_src_sel, cx_read(port->reg_src_sel)); | ||
1276 | dprintk(1, "%s() lngth(0x%08X) 0x%08x\n", __func__, | ||
1277 | port->reg_lngth, cx_read(port->reg_lngth)); | ||
1278 | dprintk(1, "%s() hw_sop_ctrl(0x%08X) 0x%08x\n", __func__, | ||
1279 | port->reg_hw_sop_ctrl, cx_read(port->reg_hw_sop_ctrl)); | ||
1280 | dprintk(1, "%s() gen_ctrl(0x%08X) 0x%08x\n", __func__, | ||
1281 | port->reg_gen_ctrl, cx_read(port->reg_gen_ctrl)); | ||
1282 | dprintk(1, "%s() bd_pkt_status(0x%08X) 0x%08x\n", __func__, | ||
1283 | port->reg_bd_pkt_status, cx_read(port->reg_bd_pkt_status)); | ||
1284 | dprintk(1, "%s() sop_status(0x%08X) 0x%08x\n", __func__, | ||
1285 | port->reg_sop_status, cx_read(port->reg_sop_status)); | ||
1286 | dprintk(1, "%s() fifo_ovfl_stat(0x%08X) 0x%08x\n", __func__, | ||
1287 | port->reg_fifo_ovfl_stat, cx_read(port->reg_fifo_ovfl_stat)); | ||
1288 | dprintk(1, "%s() vld_misc(0x%08X) 0x%08x\n", __func__, | ||
1289 | port->reg_vld_misc, cx_read(port->reg_vld_misc)); | ||
1290 | dprintk(1, "%s() ts_clk_en(0x%08X) 0x%08x\n", __func__, | ||
1291 | port->reg_ts_clk_en, cx_read(port->reg_ts_clk_en)); | ||
1292 | dprintk(1, "%s() ts_int_msk(0x%08X) 0x%08x\n", __func__, | ||
1293 | port->reg_ts_int_msk, cx_read(port->reg_ts_int_msk)); | ||
1294 | } | ||
1295 | |||
1296 | static int cx23885_start_dma(struct cx23885_tsport *port, | ||
1297 | struct cx23885_dmaqueue *q, | ||
1298 | struct cx23885_buffer *buf) | ||
1299 | { | ||
1300 | struct cx23885_dev *dev = port->dev; | ||
1301 | u32 reg; | ||
1302 | |||
1303 | dprintk(1, "%s() w: %d, h: %d, f: %d\n", __func__, | ||
1304 | buf->vb.width, buf->vb.height, buf->vb.field); | ||
1305 | |||
1306 | /* Stop the fifo and risc engine for this port */ | ||
1307 | cx_clear(port->reg_dma_ctl, port->dma_ctl_val); | ||
1308 | |||
1309 | /* setup fifo + format */ | ||
1310 | cx23885_sram_channel_setup(dev, | ||
1311 | &dev->sram_channels[port->sram_chno], | ||
1312 | port->ts_packet_size, buf->risc.dma); | ||
1313 | if (debug > 5) { | ||
1314 | cx23885_sram_channel_dump(dev, | ||
1315 | &dev->sram_channels[port->sram_chno]); | ||
1316 | cx23885_risc_disasm(port, &buf->risc); | ||
1317 | } | ||
1318 | |||
1319 | /* write TS length to chip */ | ||
1320 | cx_write(port->reg_lngth, buf->vb.width); | ||
1321 | |||
1322 | if ((!(cx23885_boards[dev->board].portb & CX23885_MPEG_DVB)) && | ||
1323 | (!(cx23885_boards[dev->board].portc & CX23885_MPEG_DVB))) { | ||
1324 | printk("%s() Unsupported .portb/c (0x%08x)/(0x%08x)\n", | ||
1325 | __func__, | ||
1326 | cx23885_boards[dev->board].portb, | ||
1327 | cx23885_boards[dev->board].portc); | ||
1328 | return -EINVAL; | ||
1329 | } | ||
1330 | |||
1331 | if (cx23885_boards[dev->board].portb == CX23885_MPEG_ENCODER) | ||
1332 | cx23885_av_clk(dev, 0); | ||
1333 | |||
1334 | udelay(100); | ||
1335 | |||
1336 | /* If the port supports SRC SELECT, configure it */ | ||
1337 | if (port->reg_src_sel) | ||
1338 | cx_write(port->reg_src_sel, port->src_sel_val); | ||
1339 | |||
1340 | cx_write(port->reg_hw_sop_ctrl, port->hw_sop_ctrl_val); | ||
1341 | cx_write(port->reg_ts_clk_en, port->ts_clk_en_val); | ||
1342 | cx_write(port->reg_vld_misc, port->vld_misc_val); | ||
1343 | cx_write(port->reg_gen_ctrl, port->gen_ctrl_val); | ||
1344 | udelay(100); | ||
1345 | |||
1346 | /* NOTE: this is 2 (reserved) for portb, does it matter? */ | ||
1347 | /* reset counter to zero */ | ||
1348 | cx_write(port->reg_gpcnt_ctl, 3); | ||
1349 | q->count = 1; | ||
1350 | |||
1351 | /* Set VIDB pins to input */ | ||
1352 | if (cx23885_boards[dev->board].portb == CX23885_MPEG_DVB) { | ||
1353 | reg = cx_read(PAD_CTRL); | ||
1354 | reg &= ~0x3; /* Clear TS1_OE & TS1_SOP_OE */ | ||
1355 | cx_write(PAD_CTRL, reg); | ||
1356 | } | ||
1357 | |||
1358 | /* Set VIDC pins to input */ | ||
1359 | if (cx23885_boards[dev->board].portc == CX23885_MPEG_DVB) { | ||
1360 | reg = cx_read(PAD_CTRL); | ||
1361 | reg &= ~0x4; /* Clear TS2_SOP_OE */ | ||
1362 | cx_write(PAD_CTRL, reg); | ||
1363 | } | ||
1364 | |||
1365 | if (cx23885_boards[dev->board].portb == CX23885_MPEG_ENCODER) { | ||
1366 | |||
1367 | reg = cx_read(PAD_CTRL); | ||
1368 | reg = reg & ~0x1; /* Clear TS1_OE */ | ||
1369 | |||
1370 | /* FIXME, bit 2 writing here is questionable */ | ||
1371 | /* set TS1_SOP_OE and TS1_OE_HI */ | ||
1372 | reg = reg | 0xa; | ||
1373 | cx_write(PAD_CTRL, reg); | ||
1374 | |||
1375 | /* FIXME and these two registers should be documented. */ | ||
1376 | cx_write(CLK_DELAY, cx_read(CLK_DELAY) | 0x80000011); | ||
1377 | cx_write(ALT_PIN_OUT_SEL, 0x10100045); | ||
1378 | } | ||
1379 | |||
1380 | switch (dev->bridge) { | ||
1381 | case CX23885_BRIDGE_885: | ||
1382 | case CX23885_BRIDGE_887: | ||
1383 | case CX23885_BRIDGE_888: | ||
1384 | /* enable irqs */ | ||
1385 | dprintk(1, "%s() enabling TS int's and DMA\n", __func__); | ||
1386 | cx_set(port->reg_ts_int_msk, port->ts_int_msk_val); | ||
1387 | cx_set(port->reg_dma_ctl, port->dma_ctl_val); | ||
1388 | cx23885_irq_add(dev, port->pci_irqmask); | ||
1389 | cx23885_irq_enable_all(dev); | ||
1390 | break; | ||
1391 | default: | ||
1392 | BUG(); | ||
1393 | } | ||
1394 | |||
1395 | cx_set(DEV_CNTRL2, (1<<5)); /* Enable RISC controller */ | ||
1396 | |||
1397 | if (cx23885_boards[dev->board].portb == CX23885_MPEG_ENCODER) | ||
1398 | cx23885_av_clk(dev, 1); | ||
1399 | |||
1400 | if (debug > 4) | ||
1401 | cx23885_tsport_reg_dump(port); | ||
1402 | |||
1403 | return 0; | ||
1404 | } | ||
1405 | |||
1406 | static int cx23885_stop_dma(struct cx23885_tsport *port) | ||
1407 | { | ||
1408 | struct cx23885_dev *dev = port->dev; | ||
1409 | u32 reg; | ||
1410 | |||
1411 | dprintk(1, "%s()\n", __func__); | ||
1412 | |||
1413 | /* Stop interrupts and DMA */ | ||
1414 | cx_clear(port->reg_ts_int_msk, port->ts_int_msk_val); | ||
1415 | cx_clear(port->reg_dma_ctl, port->dma_ctl_val); | ||
1416 | |||
1417 | if (cx23885_boards[dev->board].portb == CX23885_MPEG_ENCODER) { | ||
1418 | |||
1419 | reg = cx_read(PAD_CTRL); | ||
1420 | |||
1421 | /* Set TS1_OE */ | ||
1422 | reg = reg | 0x1; | ||
1423 | |||
1424 | /* clear TS1_SOP_OE and TS1_OE_HI */ | ||
1425 | reg = reg & ~0xa; | ||
1426 | cx_write(PAD_CTRL, reg); | ||
1427 | cx_write(port->reg_src_sel, 0); | ||
1428 | cx_write(port->reg_gen_ctrl, 8); | ||
1429 | |||
1430 | } | ||
1431 | |||
1432 | if (cx23885_boards[dev->board].portb == CX23885_MPEG_ENCODER) | ||
1433 | cx23885_av_clk(dev, 0); | ||
1434 | |||
1435 | return 0; | ||
1436 | } | ||
1437 | |||
1438 | int cx23885_restart_queue(struct cx23885_tsport *port, | ||
1439 | struct cx23885_dmaqueue *q) | ||
1440 | { | ||
1441 | struct cx23885_dev *dev = port->dev; | ||
1442 | struct cx23885_buffer *buf; | ||
1443 | |||
1444 | dprintk(5, "%s()\n", __func__); | ||
1445 | if (list_empty(&q->active)) { | ||
1446 | struct cx23885_buffer *prev; | ||
1447 | prev = NULL; | ||
1448 | |||
1449 | dprintk(5, "%s() queue is empty\n", __func__); | ||
1450 | |||
1451 | for (;;) { | ||
1452 | if (list_empty(&q->queued)) | ||
1453 | return 0; | ||
1454 | buf = list_entry(q->queued.next, struct cx23885_buffer, | ||
1455 | vb.queue); | ||
1456 | if (NULL == prev) { | ||
1457 | list_del(&buf->vb.queue); | ||
1458 | list_add_tail(&buf->vb.queue, &q->active); | ||
1459 | cx23885_start_dma(port, q, buf); | ||
1460 | buf->vb.state = VIDEOBUF_ACTIVE; | ||
1461 | buf->count = q->count++; | ||
1462 | mod_timer(&q->timeout, jiffies+BUFFER_TIMEOUT); | ||
1463 | dprintk(5, "[%p/%d] restart_queue - f/active\n", | ||
1464 | buf, buf->vb.i); | ||
1465 | |||
1466 | } else if (prev->vb.width == buf->vb.width && | ||
1467 | prev->vb.height == buf->vb.height && | ||
1468 | prev->fmt == buf->fmt) { | ||
1469 | list_del(&buf->vb.queue); | ||
1470 | list_add_tail(&buf->vb.queue, &q->active); | ||
1471 | buf->vb.state = VIDEOBUF_ACTIVE; | ||
1472 | buf->count = q->count++; | ||
1473 | prev->risc.jmp[1] = cpu_to_le32(buf->risc.dma); | ||
1474 | /* 64 bit bits 63-32 */ | ||
1475 | prev->risc.jmp[2] = cpu_to_le32(0); | ||
1476 | dprintk(5, "[%p/%d] restart_queue - m/active\n", | ||
1477 | buf, buf->vb.i); | ||
1478 | } else { | ||
1479 | return 0; | ||
1480 | } | ||
1481 | prev = buf; | ||
1482 | } | ||
1483 | return 0; | ||
1484 | } | ||
1485 | |||
1486 | buf = list_entry(q->active.next, struct cx23885_buffer, vb.queue); | ||
1487 | dprintk(2, "restart_queue [%p/%d]: restart dma\n", | ||
1488 | buf, buf->vb.i); | ||
1489 | cx23885_start_dma(port, q, buf); | ||
1490 | list_for_each_entry(buf, &q->active, vb.queue) | ||
1491 | buf->count = q->count++; | ||
1492 | mod_timer(&q->timeout, jiffies + BUFFER_TIMEOUT); | ||
1493 | return 0; | ||
1494 | } | ||
1495 | |||
1496 | /* ------------------------------------------------------------------ */ | ||
1497 | |||
1498 | int cx23885_buf_prepare(struct videobuf_queue *q, struct cx23885_tsport *port, | ||
1499 | struct cx23885_buffer *buf, enum v4l2_field field) | ||
1500 | { | ||
1501 | struct cx23885_dev *dev = port->dev; | ||
1502 | int size = port->ts_packet_size * port->ts_packet_count; | ||
1503 | int rc; | ||
1504 | |||
1505 | dprintk(1, "%s: %p\n", __func__, buf); | ||
1506 | if (0 != buf->vb.baddr && buf->vb.bsize < size) | ||
1507 | return -EINVAL; | ||
1508 | |||
1509 | if (VIDEOBUF_NEEDS_INIT == buf->vb.state) { | ||
1510 | buf->vb.width = port->ts_packet_size; | ||
1511 | buf->vb.height = port->ts_packet_count; | ||
1512 | buf->vb.size = size; | ||
1513 | buf->vb.field = field /*V4L2_FIELD_TOP*/; | ||
1514 | |||
1515 | rc = videobuf_iolock(q, &buf->vb, NULL); | ||
1516 | if (0 != rc) | ||
1517 | goto fail; | ||
1518 | cx23885_risc_databuffer(dev->pci, &buf->risc, | ||
1519 | videobuf_to_dma(&buf->vb)->sglist, | ||
1520 | buf->vb.width, buf->vb.height); | ||
1521 | } | ||
1522 | buf->vb.state = VIDEOBUF_PREPARED; | ||
1523 | return 0; | ||
1524 | |||
1525 | fail: | ||
1526 | cx23885_free_buffer(q, buf); | ||
1527 | return rc; | ||
1528 | } | ||
1529 | |||
1530 | void cx23885_buf_queue(struct cx23885_tsport *port, struct cx23885_buffer *buf) | ||
1531 | { | ||
1532 | struct cx23885_buffer *prev; | ||
1533 | struct cx23885_dev *dev = port->dev; | ||
1534 | struct cx23885_dmaqueue *cx88q = &port->mpegq; | ||
1535 | |||
1536 | /* add jump to stopper */ | ||
1537 | buf->risc.jmp[0] = cpu_to_le32(RISC_JUMP | RISC_IRQ1 | RISC_CNT_INC); | ||
1538 | buf->risc.jmp[1] = cpu_to_le32(cx88q->stopper.dma); | ||
1539 | buf->risc.jmp[2] = cpu_to_le32(0); /* bits 63-32 */ | ||
1540 | |||
1541 | if (list_empty(&cx88q->active)) { | ||
1542 | dprintk(1, "queue is empty - first active\n"); | ||
1543 | list_add_tail(&buf->vb.queue, &cx88q->active); | ||
1544 | cx23885_start_dma(port, cx88q, buf); | ||
1545 | buf->vb.state = VIDEOBUF_ACTIVE; | ||
1546 | buf->count = cx88q->count++; | ||
1547 | mod_timer(&cx88q->timeout, jiffies + BUFFER_TIMEOUT); | ||
1548 | dprintk(1, "[%p/%d] %s - first active\n", | ||
1549 | buf, buf->vb.i, __func__); | ||
1550 | } else { | ||
1551 | dprintk(1, "queue is not empty - append to active\n"); | ||
1552 | prev = list_entry(cx88q->active.prev, struct cx23885_buffer, | ||
1553 | vb.queue); | ||
1554 | list_add_tail(&buf->vb.queue, &cx88q->active); | ||
1555 | buf->vb.state = VIDEOBUF_ACTIVE; | ||
1556 | buf->count = cx88q->count++; | ||
1557 | prev->risc.jmp[1] = cpu_to_le32(buf->risc.dma); | ||
1558 | prev->risc.jmp[2] = cpu_to_le32(0); /* 64 bit bits 63-32 */ | ||
1559 | dprintk(1, "[%p/%d] %s - append to active\n", | ||
1560 | buf, buf->vb.i, __func__); | ||
1561 | } | ||
1562 | } | ||
1563 | |||
1564 | /* ----------------------------------------------------------- */ | ||
1565 | |||
1566 | static void do_cancel_buffers(struct cx23885_tsport *port, char *reason, | ||
1567 | int restart) | ||
1568 | { | ||
1569 | struct cx23885_dev *dev = port->dev; | ||
1570 | struct cx23885_dmaqueue *q = &port->mpegq; | ||
1571 | struct cx23885_buffer *buf; | ||
1572 | unsigned long flags; | ||
1573 | |||
1574 | spin_lock_irqsave(&port->slock, flags); | ||
1575 | while (!list_empty(&q->active)) { | ||
1576 | buf = list_entry(q->active.next, struct cx23885_buffer, | ||
1577 | vb.queue); | ||
1578 | list_del(&buf->vb.queue); | ||
1579 | buf->vb.state = VIDEOBUF_ERROR; | ||
1580 | wake_up(&buf->vb.done); | ||
1581 | dprintk(1, "[%p/%d] %s - dma=0x%08lx\n", | ||
1582 | buf, buf->vb.i, reason, (unsigned long)buf->risc.dma); | ||
1583 | } | ||
1584 | if (restart) { | ||
1585 | dprintk(1, "restarting queue\n"); | ||
1586 | cx23885_restart_queue(port, q); | ||
1587 | } | ||
1588 | spin_unlock_irqrestore(&port->slock, flags); | ||
1589 | } | ||
1590 | |||
1591 | void cx23885_cancel_buffers(struct cx23885_tsport *port) | ||
1592 | { | ||
1593 | struct cx23885_dev *dev = port->dev; | ||
1594 | struct cx23885_dmaqueue *q = &port->mpegq; | ||
1595 | |||
1596 | dprintk(1, "%s()\n", __func__); | ||
1597 | del_timer_sync(&q->timeout); | ||
1598 | cx23885_stop_dma(port); | ||
1599 | do_cancel_buffers(port, "cancel", 0); | ||
1600 | } | ||
1601 | |||
1602 | static void cx23885_timeout(unsigned long data) | ||
1603 | { | ||
1604 | struct cx23885_tsport *port = (struct cx23885_tsport *)data; | ||
1605 | struct cx23885_dev *dev = port->dev; | ||
1606 | |||
1607 | dprintk(1, "%s()\n", __func__); | ||
1608 | |||
1609 | if (debug > 5) | ||
1610 | cx23885_sram_channel_dump(dev, | ||
1611 | &dev->sram_channels[port->sram_chno]); | ||
1612 | |||
1613 | cx23885_stop_dma(port); | ||
1614 | do_cancel_buffers(port, "timeout", 1); | ||
1615 | } | ||
1616 | |||
1617 | int cx23885_irq_417(struct cx23885_dev *dev, u32 status) | ||
1618 | { | ||
1619 | /* FIXME: port1 assumption here. */ | ||
1620 | struct cx23885_tsport *port = &dev->ts1; | ||
1621 | int count = 0; | ||
1622 | int handled = 0; | ||
1623 | |||
1624 | if (status == 0) | ||
1625 | return handled; | ||
1626 | |||
1627 | count = cx_read(port->reg_gpcnt); | ||
1628 | dprintk(7, "status: 0x%08x mask: 0x%08x count: 0x%x\n", | ||
1629 | status, cx_read(port->reg_ts_int_msk), count); | ||
1630 | |||
1631 | if ((status & VID_B_MSK_BAD_PKT) || | ||
1632 | (status & VID_B_MSK_OPC_ERR) || | ||
1633 | (status & VID_B_MSK_VBI_OPC_ERR) || | ||
1634 | (status & VID_B_MSK_SYNC) || | ||
1635 | (status & VID_B_MSK_VBI_SYNC) || | ||
1636 | (status & VID_B_MSK_OF) || | ||
1637 | (status & VID_B_MSK_VBI_OF)) { | ||
1638 | printk(KERN_ERR "%s: V4L mpeg risc op code error, status " | ||
1639 | "= 0x%x\n", dev->name, status); | ||
1640 | if (status & VID_B_MSK_BAD_PKT) | ||
1641 | dprintk(1, " VID_B_MSK_BAD_PKT\n"); | ||
1642 | if (status & VID_B_MSK_OPC_ERR) | ||
1643 | dprintk(1, " VID_B_MSK_OPC_ERR\n"); | ||
1644 | if (status & VID_B_MSK_VBI_OPC_ERR) | ||
1645 | dprintk(1, " VID_B_MSK_VBI_OPC_ERR\n"); | ||
1646 | if (status & VID_B_MSK_SYNC) | ||
1647 | dprintk(1, " VID_B_MSK_SYNC\n"); | ||
1648 | if (status & VID_B_MSK_VBI_SYNC) | ||
1649 | dprintk(1, " VID_B_MSK_VBI_SYNC\n"); | ||
1650 | if (status & VID_B_MSK_OF) | ||
1651 | dprintk(1, " VID_B_MSK_OF\n"); | ||
1652 | if (status & VID_B_MSK_VBI_OF) | ||
1653 | dprintk(1, " VID_B_MSK_VBI_OF\n"); | ||
1654 | |||
1655 | cx_clear(port->reg_dma_ctl, port->dma_ctl_val); | ||
1656 | cx23885_sram_channel_dump(dev, | ||
1657 | &dev->sram_channels[port->sram_chno]); | ||
1658 | cx23885_417_check_encoder(dev); | ||
1659 | } else if (status & VID_B_MSK_RISCI1) { | ||
1660 | dprintk(7, " VID_B_MSK_RISCI1\n"); | ||
1661 | spin_lock(&port->slock); | ||
1662 | cx23885_wakeup(port, &port->mpegq, count); | ||
1663 | spin_unlock(&port->slock); | ||
1664 | } else if (status & VID_B_MSK_RISCI2) { | ||
1665 | dprintk(7, " VID_B_MSK_RISCI2\n"); | ||
1666 | spin_lock(&port->slock); | ||
1667 | cx23885_restart_queue(port, &port->mpegq); | ||
1668 | spin_unlock(&port->slock); | ||
1669 | } | ||
1670 | if (status) { | ||
1671 | cx_write(port->reg_ts_int_stat, status); | ||
1672 | handled = 1; | ||
1673 | } | ||
1674 | |||
1675 | return handled; | ||
1676 | } | ||
1677 | |||
1678 | static int cx23885_irq_ts(struct cx23885_tsport *port, u32 status) | ||
1679 | { | ||
1680 | struct cx23885_dev *dev = port->dev; | ||
1681 | int handled = 0; | ||
1682 | u32 count; | ||
1683 | |||
1684 | if ((status & VID_BC_MSK_OPC_ERR) || | ||
1685 | (status & VID_BC_MSK_BAD_PKT) || | ||
1686 | (status & VID_BC_MSK_SYNC) || | ||
1687 | (status & VID_BC_MSK_OF)) { | ||
1688 | |||
1689 | if (status & VID_BC_MSK_OPC_ERR) | ||
1690 | dprintk(7, " (VID_BC_MSK_OPC_ERR 0x%08x)\n", | ||
1691 | VID_BC_MSK_OPC_ERR); | ||
1692 | |||
1693 | if (status & VID_BC_MSK_BAD_PKT) | ||
1694 | dprintk(7, " (VID_BC_MSK_BAD_PKT 0x%08x)\n", | ||
1695 | VID_BC_MSK_BAD_PKT); | ||
1696 | |||
1697 | if (status & VID_BC_MSK_SYNC) | ||
1698 | dprintk(7, " (VID_BC_MSK_SYNC 0x%08x)\n", | ||
1699 | VID_BC_MSK_SYNC); | ||
1700 | |||
1701 | if (status & VID_BC_MSK_OF) | ||
1702 | dprintk(7, " (VID_BC_MSK_OF 0x%08x)\n", | ||
1703 | VID_BC_MSK_OF); | ||
1704 | |||
1705 | printk(KERN_ERR "%s: mpeg risc op code error\n", dev->name); | ||
1706 | |||
1707 | cx_clear(port->reg_dma_ctl, port->dma_ctl_val); | ||
1708 | cx23885_sram_channel_dump(dev, | ||
1709 | &dev->sram_channels[port->sram_chno]); | ||
1710 | |||
1711 | } else if (status & VID_BC_MSK_RISCI1) { | ||
1712 | |||
1713 | dprintk(7, " (RISCI1 0x%08x)\n", VID_BC_MSK_RISCI1); | ||
1714 | |||
1715 | spin_lock(&port->slock); | ||
1716 | count = cx_read(port->reg_gpcnt); | ||
1717 | cx23885_wakeup(port, &port->mpegq, count); | ||
1718 | spin_unlock(&port->slock); | ||
1719 | |||
1720 | } else if (status & VID_BC_MSK_RISCI2) { | ||
1721 | |||
1722 | dprintk(7, " (RISCI2 0x%08x)\n", VID_BC_MSK_RISCI2); | ||
1723 | |||
1724 | spin_lock(&port->slock); | ||
1725 | cx23885_restart_queue(port, &port->mpegq); | ||
1726 | spin_unlock(&port->slock); | ||
1727 | |||
1728 | } | ||
1729 | if (status) { | ||
1730 | cx_write(port->reg_ts_int_stat, status); | ||
1731 | handled = 1; | ||
1732 | } | ||
1733 | |||
1734 | return handled; | ||
1735 | } | ||
1736 | |||
1737 | static irqreturn_t cx23885_irq(int irq, void *dev_id) | ||
1738 | { | ||
1739 | struct cx23885_dev *dev = dev_id; | ||
1740 | struct cx23885_tsport *ts1 = &dev->ts1; | ||
1741 | struct cx23885_tsport *ts2 = &dev->ts2; | ||
1742 | u32 pci_status, pci_mask; | ||
1743 | u32 vida_status, vida_mask; | ||
1744 | u32 ts1_status, ts1_mask; | ||
1745 | u32 ts2_status, ts2_mask; | ||
1746 | int vida_count = 0, ts1_count = 0, ts2_count = 0, handled = 0; | ||
1747 | bool subdev_handled; | ||
1748 | |||
1749 | pci_status = cx_read(PCI_INT_STAT); | ||
1750 | pci_mask = cx23885_irq_get_mask(dev); | ||
1751 | vida_status = cx_read(VID_A_INT_STAT); | ||
1752 | vida_mask = cx_read(VID_A_INT_MSK); | ||
1753 | ts1_status = cx_read(VID_B_INT_STAT); | ||
1754 | ts1_mask = cx_read(VID_B_INT_MSK); | ||
1755 | ts2_status = cx_read(VID_C_INT_STAT); | ||
1756 | ts2_mask = cx_read(VID_C_INT_MSK); | ||
1757 | |||
1758 | if ((pci_status == 0) && (ts2_status == 0) && (ts1_status == 0)) | ||
1759 | goto out; | ||
1760 | |||
1761 | vida_count = cx_read(VID_A_GPCNT); | ||
1762 | ts1_count = cx_read(ts1->reg_gpcnt); | ||
1763 | ts2_count = cx_read(ts2->reg_gpcnt); | ||
1764 | dprintk(7, "pci_status: 0x%08x pci_mask: 0x%08x\n", | ||
1765 | pci_status, pci_mask); | ||
1766 | dprintk(7, "vida_status: 0x%08x vida_mask: 0x%08x count: 0x%x\n", | ||
1767 | vida_status, vida_mask, vida_count); | ||
1768 | dprintk(7, "ts1_status: 0x%08x ts1_mask: 0x%08x count: 0x%x\n", | ||
1769 | ts1_status, ts1_mask, ts1_count); | ||
1770 | dprintk(7, "ts2_status: 0x%08x ts2_mask: 0x%08x count: 0x%x\n", | ||
1771 | ts2_status, ts2_mask, ts2_count); | ||
1772 | |||
1773 | if (pci_status & (PCI_MSK_RISC_RD | PCI_MSK_RISC_WR | | ||
1774 | PCI_MSK_AL_RD | PCI_MSK_AL_WR | PCI_MSK_APB_DMA | | ||
1775 | PCI_MSK_VID_C | PCI_MSK_VID_B | PCI_MSK_VID_A | | ||
1776 | PCI_MSK_AUD_INT | PCI_MSK_AUD_EXT | | ||
1777 | PCI_MSK_GPIO0 | PCI_MSK_GPIO1 | | ||
1778 | PCI_MSK_AV_CORE | PCI_MSK_IR)) { | ||
1779 | |||
1780 | if (pci_status & PCI_MSK_RISC_RD) | ||
1781 | dprintk(7, " (PCI_MSK_RISC_RD 0x%08x)\n", | ||
1782 | PCI_MSK_RISC_RD); | ||
1783 | |||
1784 | if (pci_status & PCI_MSK_RISC_WR) | ||
1785 | dprintk(7, " (PCI_MSK_RISC_WR 0x%08x)\n", | ||
1786 | PCI_MSK_RISC_WR); | ||
1787 | |||
1788 | if (pci_status & PCI_MSK_AL_RD) | ||
1789 | dprintk(7, " (PCI_MSK_AL_RD 0x%08x)\n", | ||
1790 | PCI_MSK_AL_RD); | ||
1791 | |||
1792 | if (pci_status & PCI_MSK_AL_WR) | ||
1793 | dprintk(7, " (PCI_MSK_AL_WR 0x%08x)\n", | ||
1794 | PCI_MSK_AL_WR); | ||
1795 | |||
1796 | if (pci_status & PCI_MSK_APB_DMA) | ||
1797 | dprintk(7, " (PCI_MSK_APB_DMA 0x%08x)\n", | ||
1798 | PCI_MSK_APB_DMA); | ||
1799 | |||
1800 | if (pci_status & PCI_MSK_VID_C) | ||
1801 | dprintk(7, " (PCI_MSK_VID_C 0x%08x)\n", | ||
1802 | PCI_MSK_VID_C); | ||
1803 | |||
1804 | if (pci_status & PCI_MSK_VID_B) | ||
1805 | dprintk(7, " (PCI_MSK_VID_B 0x%08x)\n", | ||
1806 | PCI_MSK_VID_B); | ||
1807 | |||
1808 | if (pci_status & PCI_MSK_VID_A) | ||
1809 | dprintk(7, " (PCI_MSK_VID_A 0x%08x)\n", | ||
1810 | PCI_MSK_VID_A); | ||
1811 | |||
1812 | if (pci_status & PCI_MSK_AUD_INT) | ||
1813 | dprintk(7, " (PCI_MSK_AUD_INT 0x%08x)\n", | ||
1814 | PCI_MSK_AUD_INT); | ||
1815 | |||
1816 | if (pci_status & PCI_MSK_AUD_EXT) | ||
1817 | dprintk(7, " (PCI_MSK_AUD_EXT 0x%08x)\n", | ||
1818 | PCI_MSK_AUD_EXT); | ||
1819 | |||
1820 | if (pci_status & PCI_MSK_GPIO0) | ||
1821 | dprintk(7, " (PCI_MSK_GPIO0 0x%08x)\n", | ||
1822 | PCI_MSK_GPIO0); | ||
1823 | |||
1824 | if (pci_status & PCI_MSK_GPIO1) | ||
1825 | dprintk(7, " (PCI_MSK_GPIO1 0x%08x)\n", | ||
1826 | PCI_MSK_GPIO1); | ||
1827 | |||
1828 | if (pci_status & PCI_MSK_AV_CORE) | ||
1829 | dprintk(7, " (PCI_MSK_AV_CORE 0x%08x)\n", | ||
1830 | PCI_MSK_AV_CORE); | ||
1831 | |||
1832 | if (pci_status & PCI_MSK_IR) | ||
1833 | dprintk(7, " (PCI_MSK_IR 0x%08x)\n", | ||
1834 | PCI_MSK_IR); | ||
1835 | } | ||
1836 | |||
1837 | if (cx23885_boards[dev->board].ci_type == 1 && | ||
1838 | (pci_status & (PCI_MSK_GPIO1 | PCI_MSK_GPIO0))) | ||
1839 | handled += netup_ci_slot_status(dev, pci_status); | ||
1840 | |||
1841 | if (cx23885_boards[dev->board].ci_type == 2 && | ||
1842 | (pci_status & PCI_MSK_GPIO0)) | ||
1843 | handled += altera_ci_irq(dev); | ||
1844 | |||
1845 | if (ts1_status) { | ||
1846 | if (cx23885_boards[dev->board].portb == CX23885_MPEG_DVB) | ||
1847 | handled += cx23885_irq_ts(ts1, ts1_status); | ||
1848 | else | ||
1849 | if (cx23885_boards[dev->board].portb == CX23885_MPEG_ENCODER) | ||
1850 | handled += cx23885_irq_417(dev, ts1_status); | ||
1851 | } | ||
1852 | |||
1853 | if (ts2_status) { | ||
1854 | if (cx23885_boards[dev->board].portc == CX23885_MPEG_DVB) | ||
1855 | handled += cx23885_irq_ts(ts2, ts2_status); | ||
1856 | else | ||
1857 | if (cx23885_boards[dev->board].portc == CX23885_MPEG_ENCODER) | ||
1858 | handled += cx23885_irq_417(dev, ts2_status); | ||
1859 | } | ||
1860 | |||
1861 | if (vida_status) | ||
1862 | handled += cx23885_video_irq(dev, vida_status); | ||
1863 | |||
1864 | if (pci_status & PCI_MSK_IR) { | ||
1865 | subdev_handled = false; | ||
1866 | v4l2_subdev_call(dev->sd_ir, core, interrupt_service_routine, | ||
1867 | pci_status, &subdev_handled); | ||
1868 | if (subdev_handled) | ||
1869 | handled++; | ||
1870 | } | ||
1871 | |||
1872 | if ((pci_status & pci_mask) & PCI_MSK_AV_CORE) { | ||
1873 | cx23885_irq_disable(dev, PCI_MSK_AV_CORE); | ||
1874 | if (!schedule_work(&dev->cx25840_work)) | ||
1875 | printk(KERN_ERR "%s: failed to set up deferred work for" | ||
1876 | " AV Core/IR interrupt. Interrupt is disabled" | ||
1877 | " and won't be re-enabled\n", dev->name); | ||
1878 | handled++; | ||
1879 | } | ||
1880 | |||
1881 | if (handled) | ||
1882 | cx_write(PCI_INT_STAT, pci_status); | ||
1883 | out: | ||
1884 | return IRQ_RETVAL(handled); | ||
1885 | } | ||
1886 | |||
1887 | static void cx23885_v4l2_dev_notify(struct v4l2_subdev *sd, | ||
1888 | unsigned int notification, void *arg) | ||
1889 | { | ||
1890 | struct cx23885_dev *dev; | ||
1891 | |||
1892 | if (sd == NULL) | ||
1893 | return; | ||
1894 | |||
1895 | dev = to_cx23885(sd->v4l2_dev); | ||
1896 | |||
1897 | switch (notification) { | ||
1898 | case V4L2_SUBDEV_IR_RX_NOTIFY: /* Possibly called in an IRQ context */ | ||
1899 | if (sd == dev->sd_ir) | ||
1900 | cx23885_ir_rx_v4l2_dev_notify(sd, *(u32 *)arg); | ||
1901 | break; | ||
1902 | case V4L2_SUBDEV_IR_TX_NOTIFY: /* Possibly called in an IRQ context */ | ||
1903 | if (sd == dev->sd_ir) | ||
1904 | cx23885_ir_tx_v4l2_dev_notify(sd, *(u32 *)arg); | ||
1905 | break; | ||
1906 | } | ||
1907 | } | ||
1908 | |||
1909 | static void cx23885_v4l2_dev_notify_init(struct cx23885_dev *dev) | ||
1910 | { | ||
1911 | INIT_WORK(&dev->cx25840_work, cx23885_av_work_handler); | ||
1912 | INIT_WORK(&dev->ir_rx_work, cx23885_ir_rx_work_handler); | ||
1913 | INIT_WORK(&dev->ir_tx_work, cx23885_ir_tx_work_handler); | ||
1914 | dev->v4l2_dev.notify = cx23885_v4l2_dev_notify; | ||
1915 | } | ||
1916 | |||
1917 | static inline int encoder_on_portb(struct cx23885_dev *dev) | ||
1918 | { | ||
1919 | return cx23885_boards[dev->board].portb == CX23885_MPEG_ENCODER; | ||
1920 | } | ||
1921 | |||
1922 | static inline int encoder_on_portc(struct cx23885_dev *dev) | ||
1923 | { | ||
1924 | return cx23885_boards[dev->board].portc == CX23885_MPEG_ENCODER; | ||
1925 | } | ||
1926 | |||
1927 | /* Mask represents 32 different GPIOs, GPIO's are split into multiple | ||
1928 | * registers depending on the board configuration (and whether the | ||
1929 | * 417 encoder (wi it's own GPIO's) are present. Each GPIO bit will | ||
1930 | * be pushed into the correct hardware register, regardless of the | ||
1931 | * physical location. Certain registers are shared so we sanity check | ||
1932 | * and report errors if we think we're tampering with a GPIo that might | ||
1933 | * be assigned to the encoder (and used for the host bus). | ||
1934 | * | ||
1935 | * GPIO 2 thru 0 - On the cx23885 bridge | ||
1936 | * GPIO 18 thru 3 - On the cx23417 host bus interface | ||
1937 | * GPIO 23 thru 19 - On the cx25840 a/v core | ||
1938 | */ | ||
1939 | void cx23885_gpio_set(struct cx23885_dev *dev, u32 mask) | ||
1940 | { | ||
1941 | if (mask & 0x7) | ||
1942 | cx_set(GP0_IO, mask & 0x7); | ||
1943 | |||
1944 | if (mask & 0x0007fff8) { | ||
1945 | if (encoder_on_portb(dev) || encoder_on_portc(dev)) | ||
1946 | printk(KERN_ERR | ||
1947 | "%s: Setting GPIO on encoder ports\n", | ||
1948 | dev->name); | ||
1949 | cx_set(MC417_RWD, (mask & 0x0007fff8) >> 3); | ||
1950 | } | ||
1951 | |||
1952 | /* TODO: 23-19 */ | ||
1953 | if (mask & 0x00f80000) | ||
1954 | printk(KERN_INFO "%s: Unsupported\n", dev->name); | ||
1955 | } | ||
1956 | |||
1957 | void cx23885_gpio_clear(struct cx23885_dev *dev, u32 mask) | ||
1958 | { | ||
1959 | if (mask & 0x00000007) | ||
1960 | cx_clear(GP0_IO, mask & 0x7); | ||
1961 | |||
1962 | if (mask & 0x0007fff8) { | ||
1963 | if (encoder_on_portb(dev) || encoder_on_portc(dev)) | ||
1964 | printk(KERN_ERR | ||
1965 | "%s: Clearing GPIO moving on encoder ports\n", | ||
1966 | dev->name); | ||
1967 | cx_clear(MC417_RWD, (mask & 0x7fff8) >> 3); | ||
1968 | } | ||
1969 | |||
1970 | /* TODO: 23-19 */ | ||
1971 | if (mask & 0x00f80000) | ||
1972 | printk(KERN_INFO "%s: Unsupported\n", dev->name); | ||
1973 | } | ||
1974 | |||
1975 | u32 cx23885_gpio_get(struct cx23885_dev *dev, u32 mask) | ||
1976 | { | ||
1977 | if (mask & 0x00000007) | ||
1978 | return (cx_read(GP0_IO) >> 8) & mask & 0x7; | ||
1979 | |||
1980 | if (mask & 0x0007fff8) { | ||
1981 | if (encoder_on_portb(dev) || encoder_on_portc(dev)) | ||
1982 | printk(KERN_ERR | ||
1983 | "%s: Reading GPIO moving on encoder ports\n", | ||
1984 | dev->name); | ||
1985 | return (cx_read(MC417_RWD) & ((mask & 0x7fff8) >> 3)) << 3; | ||
1986 | } | ||
1987 | |||
1988 | /* TODO: 23-19 */ | ||
1989 | if (mask & 0x00f80000) | ||
1990 | printk(KERN_INFO "%s: Unsupported\n", dev->name); | ||
1991 | |||
1992 | return 0; | ||
1993 | } | ||
1994 | |||
1995 | void cx23885_gpio_enable(struct cx23885_dev *dev, u32 mask, int asoutput) | ||
1996 | { | ||
1997 | if ((mask & 0x00000007) && asoutput) | ||
1998 | cx_set(GP0_IO, (mask & 0x7) << 16); | ||
1999 | else if ((mask & 0x00000007) && !asoutput) | ||
2000 | cx_clear(GP0_IO, (mask & 0x7) << 16); | ||
2001 | |||
2002 | if (mask & 0x0007fff8) { | ||
2003 | if (encoder_on_portb(dev) || encoder_on_portc(dev)) | ||
2004 | printk(KERN_ERR | ||
2005 | "%s: Enabling GPIO on encoder ports\n", | ||
2006 | dev->name); | ||
2007 | } | ||
2008 | |||
2009 | /* MC417_OEN is active low for output, write 1 for an input */ | ||
2010 | if ((mask & 0x0007fff8) && asoutput) | ||
2011 | cx_clear(MC417_OEN, (mask & 0x7fff8) >> 3); | ||
2012 | |||
2013 | else if ((mask & 0x0007fff8) && !asoutput) | ||
2014 | cx_set(MC417_OEN, (mask & 0x7fff8) >> 3); | ||
2015 | |||
2016 | /* TODO: 23-19 */ | ||
2017 | } | ||
2018 | |||
2019 | static int __devinit cx23885_initdev(struct pci_dev *pci_dev, | ||
2020 | const struct pci_device_id *pci_id) | ||
2021 | { | ||
2022 | struct cx23885_dev *dev; | ||
2023 | int err; | ||
2024 | |||
2025 | dev = kzalloc(sizeof(*dev), GFP_KERNEL); | ||
2026 | if (NULL == dev) | ||
2027 | return -ENOMEM; | ||
2028 | |||
2029 | err = v4l2_device_register(&pci_dev->dev, &dev->v4l2_dev); | ||
2030 | if (err < 0) | ||
2031 | goto fail_free; | ||
2032 | |||
2033 | /* Prepare to handle notifications from subdevices */ | ||
2034 | cx23885_v4l2_dev_notify_init(dev); | ||
2035 | |||
2036 | /* pci init */ | ||
2037 | dev->pci = pci_dev; | ||
2038 | if (pci_enable_device(pci_dev)) { | ||
2039 | err = -EIO; | ||
2040 | goto fail_unreg; | ||
2041 | } | ||
2042 | |||
2043 | if (cx23885_dev_setup(dev) < 0) { | ||
2044 | err = -EINVAL; | ||
2045 | goto fail_unreg; | ||
2046 | } | ||
2047 | |||
2048 | /* print pci info */ | ||
2049 | dev->pci_rev = pci_dev->revision; | ||
2050 | pci_read_config_byte(pci_dev, PCI_LATENCY_TIMER, &dev->pci_lat); | ||
2051 | printk(KERN_INFO "%s/0: found at %s, rev: %d, irq: %d, " | ||
2052 | "latency: %d, mmio: 0x%llx\n", dev->name, | ||
2053 | pci_name(pci_dev), dev->pci_rev, pci_dev->irq, | ||
2054 | dev->pci_lat, | ||
2055 | (unsigned long long)pci_resource_start(pci_dev, 0)); | ||
2056 | |||
2057 | pci_set_master(pci_dev); | ||
2058 | if (!pci_dma_supported(pci_dev, 0xffffffff)) { | ||
2059 | printk("%s/0: Oops: no 32bit PCI DMA ???\n", dev->name); | ||
2060 | err = -EIO; | ||
2061 | goto fail_irq; | ||
2062 | } | ||
2063 | |||
2064 | err = request_irq(pci_dev->irq, cx23885_irq, | ||
2065 | IRQF_SHARED | IRQF_DISABLED, dev->name, dev); | ||
2066 | if (err < 0) { | ||
2067 | printk(KERN_ERR "%s: can't get IRQ %d\n", | ||
2068 | dev->name, pci_dev->irq); | ||
2069 | goto fail_irq; | ||
2070 | } | ||
2071 | |||
2072 | switch (dev->board) { | ||
2073 | case CX23885_BOARD_NETUP_DUAL_DVBS2_CI: | ||
2074 | cx23885_irq_add_enable(dev, PCI_MSK_GPIO1 | PCI_MSK_GPIO0); | ||
2075 | break; | ||
2076 | case CX23885_BOARD_NETUP_DUAL_DVB_T_C_CI_RF: | ||
2077 | cx23885_irq_add_enable(dev, PCI_MSK_GPIO0); | ||
2078 | break; | ||
2079 | } | ||
2080 | |||
2081 | /* | ||
2082 | * The CX2388[58] IR controller can start firing interrupts when | ||
2083 | * enabled, so these have to take place after the cx23885_irq() handler | ||
2084 | * is hooked up by the call to request_irq() above. | ||
2085 | */ | ||
2086 | cx23885_ir_pci_int_enable(dev); | ||
2087 | cx23885_input_init(dev); | ||
2088 | |||
2089 | return 0; | ||
2090 | |||
2091 | fail_irq: | ||
2092 | cx23885_dev_unregister(dev); | ||
2093 | fail_unreg: | ||
2094 | v4l2_device_unregister(&dev->v4l2_dev); | ||
2095 | fail_free: | ||
2096 | kfree(dev); | ||
2097 | return err; | ||
2098 | } | ||
2099 | |||
2100 | static void __devexit cx23885_finidev(struct pci_dev *pci_dev) | ||
2101 | { | ||
2102 | struct v4l2_device *v4l2_dev = pci_get_drvdata(pci_dev); | ||
2103 | struct cx23885_dev *dev = to_cx23885(v4l2_dev); | ||
2104 | |||
2105 | cx23885_input_fini(dev); | ||
2106 | cx23885_ir_fini(dev); | ||
2107 | |||
2108 | cx23885_shutdown(dev); | ||
2109 | |||
2110 | pci_disable_device(pci_dev); | ||
2111 | |||
2112 | /* unregister stuff */ | ||
2113 | free_irq(pci_dev->irq, dev); | ||
2114 | |||
2115 | cx23885_dev_unregister(dev); | ||
2116 | v4l2_device_unregister(v4l2_dev); | ||
2117 | kfree(dev); | ||
2118 | } | ||
2119 | |||
2120 | static struct pci_device_id cx23885_pci_tbl[] = { | ||
2121 | { | ||
2122 | /* CX23885 */ | ||
2123 | .vendor = 0x14f1, | ||
2124 | .device = 0x8852, | ||
2125 | .subvendor = PCI_ANY_ID, | ||
2126 | .subdevice = PCI_ANY_ID, | ||
2127 | }, { | ||
2128 | /* CX23887 Rev 2 */ | ||
2129 | .vendor = 0x14f1, | ||
2130 | .device = 0x8880, | ||
2131 | .subvendor = PCI_ANY_ID, | ||
2132 | .subdevice = PCI_ANY_ID, | ||
2133 | }, { | ||
2134 | /* --- end of list --- */ | ||
2135 | } | ||
2136 | }; | ||
2137 | MODULE_DEVICE_TABLE(pci, cx23885_pci_tbl); | ||
2138 | |||
2139 | static struct pci_driver cx23885_pci_driver = { | ||
2140 | .name = "cx23885", | ||
2141 | .id_table = cx23885_pci_tbl, | ||
2142 | .probe = cx23885_initdev, | ||
2143 | .remove = __devexit_p(cx23885_finidev), | ||
2144 | /* TODO */ | ||
2145 | .suspend = NULL, | ||
2146 | .resume = NULL, | ||
2147 | }; | ||
2148 | |||
2149 | static int __init cx23885_init(void) | ||
2150 | { | ||
2151 | printk(KERN_INFO "cx23885 driver version %s loaded\n", | ||
2152 | CX23885_VERSION); | ||
2153 | return pci_register_driver(&cx23885_pci_driver); | ||
2154 | } | ||
2155 | |||
2156 | static void __exit cx23885_fini(void) | ||
2157 | { | ||
2158 | pci_unregister_driver(&cx23885_pci_driver); | ||
2159 | } | ||
2160 | |||
2161 | module_init(cx23885_init); | ||
2162 | module_exit(cx23885_fini); | ||
diff --git a/drivers/media/video/cx23885/cx23885-dvb.c b/drivers/media/video/cx23885/cx23885-dvb.c new file mode 100644 index 00000000000..bcb45be44bb --- /dev/null +++ b/drivers/media/video/cx23885/cx23885-dvb.c | |||
@@ -0,0 +1,1289 @@ | |||
1 | /* | ||
2 | * Driver for the Conexant CX23885 PCIe bridge | ||
3 | * | ||
4 | * Copyright (c) 2006 Steven Toth <stoth@linuxtv.org> | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify | ||
7 | * it under the terms of the GNU General Public License as published by | ||
8 | * the Free Software Foundation; either version 2 of the License, or | ||
9 | * (at your option) any later version. | ||
10 | * | ||
11 | * This program is distributed in the hope that it will be useful, | ||
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
14 | * | ||
15 | * GNU General Public License for more details. | ||
16 | * | ||
17 | * You should have received a copy of the GNU General Public License | ||
18 | * along with this program; if not, write to the Free Software | ||
19 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
20 | */ | ||
21 | |||
22 | #include <linux/module.h> | ||
23 | #include <linux/init.h> | ||
24 | #include <linux/device.h> | ||
25 | #include <linux/fs.h> | ||
26 | #include <linux/kthread.h> | ||
27 | #include <linux/file.h> | ||
28 | #include <linux/suspend.h> | ||
29 | |||
30 | #include "cx23885.h" | ||
31 | #include <media/v4l2-common.h> | ||
32 | |||
33 | #include "dvb_ca_en50221.h" | ||
34 | #include "s5h1409.h" | ||
35 | #include "s5h1411.h" | ||
36 | #include "mt2131.h" | ||
37 | #include "tda8290.h" | ||
38 | #include "tda18271.h" | ||
39 | #include "lgdt330x.h" | ||
40 | #include "xc4000.h" | ||
41 | #include "xc5000.h" | ||
42 | #include "max2165.h" | ||
43 | #include "tda10048.h" | ||
44 | #include "tuner-xc2028.h" | ||
45 | #include "tuner-simple.h" | ||
46 | #include "dib7000p.h" | ||
47 | #include "dibx000_common.h" | ||
48 | #include "zl10353.h" | ||
49 | #include "stv0900.h" | ||
50 | #include "stv0900_reg.h" | ||
51 | #include "stv6110.h" | ||
52 | #include "lnbh24.h" | ||
53 | #include "cx24116.h" | ||
54 | #include "cimax2.h" | ||
55 | #include "lgs8gxx.h" | ||
56 | #include "netup-eeprom.h" | ||
57 | #include "netup-init.h" | ||
58 | #include "lgdt3305.h" | ||
59 | #include "atbm8830.h" | ||
60 | #include "ds3000.h" | ||
61 | #include "cx23885-f300.h" | ||
62 | #include "altera-ci.h" | ||
63 | #include "stv0367.h" | ||
64 | |||
65 | static unsigned int debug; | ||
66 | |||
67 | #define dprintk(level, fmt, arg...)\ | ||
68 | do { if (debug >= level)\ | ||
69 | printk(KERN_DEBUG "%s/0: " fmt, dev->name, ## arg);\ | ||
70 | } while (0) | ||
71 | |||
72 | /* ------------------------------------------------------------------ */ | ||
73 | |||
74 | static unsigned int alt_tuner; | ||
75 | module_param(alt_tuner, int, 0644); | ||
76 | MODULE_PARM_DESC(alt_tuner, "Enable alternate tuner configuration"); | ||
77 | |||
78 | DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr); | ||
79 | |||
80 | /* ------------------------------------------------------------------ */ | ||
81 | |||
82 | static int dvb_buf_setup(struct videobuf_queue *q, | ||
83 | unsigned int *count, unsigned int *size) | ||
84 | { | ||
85 | struct cx23885_tsport *port = q->priv_data; | ||
86 | |||
87 | port->ts_packet_size = 188 * 4; | ||
88 | port->ts_packet_count = 32; | ||
89 | |||
90 | *size = port->ts_packet_size * port->ts_packet_count; | ||
91 | *count = 32; | ||
92 | return 0; | ||
93 | } | ||
94 | |||
95 | static int dvb_buf_prepare(struct videobuf_queue *q, | ||
96 | struct videobuf_buffer *vb, enum v4l2_field field) | ||
97 | { | ||
98 | struct cx23885_tsport *port = q->priv_data; | ||
99 | return cx23885_buf_prepare(q, port, (struct cx23885_buffer *)vb, field); | ||
100 | } | ||
101 | |||
102 | static void dvb_buf_queue(struct videobuf_queue *q, struct videobuf_buffer *vb) | ||
103 | { | ||
104 | struct cx23885_tsport *port = q->priv_data; | ||
105 | cx23885_buf_queue(port, (struct cx23885_buffer *)vb); | ||
106 | } | ||
107 | |||
108 | static void dvb_buf_release(struct videobuf_queue *q, | ||
109 | struct videobuf_buffer *vb) | ||
110 | { | ||
111 | cx23885_free_buffer(q, (struct cx23885_buffer *)vb); | ||
112 | } | ||
113 | |||
114 | static void cx23885_dvb_gate_ctrl(struct cx23885_tsport *port, int open) | ||
115 | { | ||
116 | struct videobuf_dvb_frontends *f; | ||
117 | struct videobuf_dvb_frontend *fe; | ||
118 | |||
119 | f = &port->frontends; | ||
120 | |||
121 | if (f->gate <= 1) /* undefined or fe0 */ | ||
122 | fe = videobuf_dvb_get_frontend(f, 1); | ||
123 | else | ||
124 | fe = videobuf_dvb_get_frontend(f, f->gate); | ||
125 | |||
126 | if (fe && fe->dvb.frontend && fe->dvb.frontend->ops.i2c_gate_ctrl) | ||
127 | fe->dvb.frontend->ops.i2c_gate_ctrl(fe->dvb.frontend, open); | ||
128 | } | ||
129 | |||
130 | static struct videobuf_queue_ops dvb_qops = { | ||
131 | .buf_setup = dvb_buf_setup, | ||
132 | .buf_prepare = dvb_buf_prepare, | ||
133 | .buf_queue = dvb_buf_queue, | ||
134 | .buf_release = dvb_buf_release, | ||
135 | }; | ||
136 | |||
137 | static struct s5h1409_config hauppauge_generic_config = { | ||
138 | .demod_address = 0x32 >> 1, | ||
139 | .output_mode = S5H1409_SERIAL_OUTPUT, | ||
140 | .gpio = S5H1409_GPIO_ON, | ||
141 | .qam_if = 44000, | ||
142 | .inversion = S5H1409_INVERSION_OFF, | ||
143 | .status_mode = S5H1409_DEMODLOCKING, | ||
144 | .mpeg_timing = S5H1409_MPEGTIMING_CONTINOUS_NONINVERTING_CLOCK, | ||
145 | }; | ||
146 | |||
147 | static struct tda10048_config hauppauge_hvr1200_config = { | ||
148 | .demod_address = 0x10 >> 1, | ||
149 | .output_mode = TDA10048_SERIAL_OUTPUT, | ||
150 | .fwbulkwritelen = TDA10048_BULKWRITE_200, | ||
151 | .inversion = TDA10048_INVERSION_ON, | ||
152 | .dtv6_if_freq_khz = TDA10048_IF_3300, | ||
153 | .dtv7_if_freq_khz = TDA10048_IF_3800, | ||
154 | .dtv8_if_freq_khz = TDA10048_IF_4300, | ||
155 | .clk_freq_khz = TDA10048_CLK_16000, | ||
156 | }; | ||
157 | |||
158 | static struct tda10048_config hauppauge_hvr1210_config = { | ||
159 | .demod_address = 0x10 >> 1, | ||
160 | .output_mode = TDA10048_SERIAL_OUTPUT, | ||
161 | .fwbulkwritelen = TDA10048_BULKWRITE_200, | ||
162 | .inversion = TDA10048_INVERSION_ON, | ||
163 | .dtv6_if_freq_khz = TDA10048_IF_3300, | ||
164 | .dtv7_if_freq_khz = TDA10048_IF_3500, | ||
165 | .dtv8_if_freq_khz = TDA10048_IF_4000, | ||
166 | .clk_freq_khz = TDA10048_CLK_16000, | ||
167 | }; | ||
168 | |||
169 | static struct s5h1409_config hauppauge_ezqam_config = { | ||
170 | .demod_address = 0x32 >> 1, | ||
171 | .output_mode = S5H1409_SERIAL_OUTPUT, | ||
172 | .gpio = S5H1409_GPIO_OFF, | ||
173 | .qam_if = 4000, | ||
174 | .inversion = S5H1409_INVERSION_ON, | ||
175 | .status_mode = S5H1409_DEMODLOCKING, | ||
176 | .mpeg_timing = S5H1409_MPEGTIMING_CONTINOUS_NONINVERTING_CLOCK, | ||
177 | }; | ||
178 | |||
179 | static struct s5h1409_config hauppauge_hvr1800lp_config = { | ||
180 | .demod_address = 0x32 >> 1, | ||
181 | .output_mode = S5H1409_SERIAL_OUTPUT, | ||
182 | .gpio = S5H1409_GPIO_OFF, | ||
183 | .qam_if = 44000, | ||
184 | .inversion = S5H1409_INVERSION_OFF, | ||
185 | .status_mode = S5H1409_DEMODLOCKING, | ||
186 | .mpeg_timing = S5H1409_MPEGTIMING_CONTINOUS_NONINVERTING_CLOCK, | ||
187 | }; | ||
188 | |||
189 | static struct s5h1409_config hauppauge_hvr1500_config = { | ||
190 | .demod_address = 0x32 >> 1, | ||
191 | .output_mode = S5H1409_SERIAL_OUTPUT, | ||
192 | .gpio = S5H1409_GPIO_OFF, | ||
193 | .inversion = S5H1409_INVERSION_OFF, | ||
194 | .status_mode = S5H1409_DEMODLOCKING, | ||
195 | .mpeg_timing = S5H1409_MPEGTIMING_CONTINOUS_NONINVERTING_CLOCK, | ||
196 | }; | ||
197 | |||
198 | static struct mt2131_config hauppauge_generic_tunerconfig = { | ||
199 | 0x61 | ||
200 | }; | ||
201 | |||
202 | static struct lgdt330x_config fusionhdtv_5_express = { | ||
203 | .demod_address = 0x0e, | ||
204 | .demod_chip = LGDT3303, | ||
205 | .serial_mpeg = 0x40, | ||
206 | }; | ||
207 | |||
208 | static struct s5h1409_config hauppauge_hvr1500q_config = { | ||
209 | .demod_address = 0x32 >> 1, | ||
210 | .output_mode = S5H1409_SERIAL_OUTPUT, | ||
211 | .gpio = S5H1409_GPIO_ON, | ||
212 | .qam_if = 44000, | ||
213 | .inversion = S5H1409_INVERSION_OFF, | ||
214 | .status_mode = S5H1409_DEMODLOCKING, | ||
215 | .mpeg_timing = S5H1409_MPEGTIMING_CONTINOUS_NONINVERTING_CLOCK, | ||
216 | }; | ||
217 | |||
218 | static struct s5h1409_config dvico_s5h1409_config = { | ||
219 | .demod_address = 0x32 >> 1, | ||
220 | .output_mode = S5H1409_SERIAL_OUTPUT, | ||
221 | .gpio = S5H1409_GPIO_ON, | ||
222 | .qam_if = 44000, | ||
223 | .inversion = S5H1409_INVERSION_OFF, | ||
224 | .status_mode = S5H1409_DEMODLOCKING, | ||
225 | .mpeg_timing = S5H1409_MPEGTIMING_CONTINOUS_NONINVERTING_CLOCK, | ||
226 | }; | ||
227 | |||
228 | static struct s5h1411_config dvico_s5h1411_config = { | ||
229 | .output_mode = S5H1411_SERIAL_OUTPUT, | ||
230 | .gpio = S5H1411_GPIO_ON, | ||
231 | .qam_if = S5H1411_IF_44000, | ||
232 | .vsb_if = S5H1411_IF_44000, | ||
233 | .inversion = S5H1411_INVERSION_OFF, | ||
234 | .status_mode = S5H1411_DEMODLOCKING, | ||
235 | .mpeg_timing = S5H1411_MPEGTIMING_CONTINOUS_NONINVERTING_CLOCK, | ||
236 | }; | ||
237 | |||
238 | static struct s5h1411_config hcw_s5h1411_config = { | ||
239 | .output_mode = S5H1411_SERIAL_OUTPUT, | ||
240 | .gpio = S5H1411_GPIO_OFF, | ||
241 | .vsb_if = S5H1411_IF_44000, | ||
242 | .qam_if = S5H1411_IF_4000, | ||
243 | .inversion = S5H1411_INVERSION_ON, | ||
244 | .status_mode = S5H1411_DEMODLOCKING, | ||
245 | .mpeg_timing = S5H1411_MPEGTIMING_CONTINOUS_NONINVERTING_CLOCK, | ||
246 | }; | ||
247 | |||
248 | static struct xc5000_config hauppauge_hvr1500q_tunerconfig = { | ||
249 | .i2c_address = 0x61, | ||
250 | .if_khz = 5380, | ||
251 | }; | ||
252 | |||
253 | static struct xc5000_config dvico_xc5000_tunerconfig = { | ||
254 | .i2c_address = 0x64, | ||
255 | .if_khz = 5380, | ||
256 | }; | ||
257 | |||
258 | static struct tda829x_config tda829x_no_probe = { | ||
259 | .probe_tuner = TDA829X_DONT_PROBE, | ||
260 | }; | ||
261 | |||
262 | static struct tda18271_std_map hauppauge_tda18271_std_map = { | ||
263 | .atsc_6 = { .if_freq = 5380, .agc_mode = 3, .std = 3, | ||
264 | .if_lvl = 6, .rfagc_top = 0x37 }, | ||
265 | .qam_6 = { .if_freq = 4000, .agc_mode = 3, .std = 0, | ||
266 | .if_lvl = 6, .rfagc_top = 0x37 }, | ||
267 | }; | ||
268 | |||
269 | static struct tda18271_std_map hauppauge_hvr1200_tda18271_std_map = { | ||
270 | .dvbt_6 = { .if_freq = 3300, .agc_mode = 3, .std = 4, | ||
271 | .if_lvl = 1, .rfagc_top = 0x37, }, | ||
272 | .dvbt_7 = { .if_freq = 3800, .agc_mode = 3, .std = 5, | ||
273 | .if_lvl = 1, .rfagc_top = 0x37, }, | ||
274 | .dvbt_8 = { .if_freq = 4300, .agc_mode = 3, .std = 6, | ||
275 | .if_lvl = 1, .rfagc_top = 0x37, }, | ||
276 | }; | ||
277 | |||
278 | static struct tda18271_config hauppauge_tda18271_config = { | ||
279 | .std_map = &hauppauge_tda18271_std_map, | ||
280 | .gate = TDA18271_GATE_ANALOG, | ||
281 | .output_opt = TDA18271_OUTPUT_LT_OFF, | ||
282 | }; | ||
283 | |||
284 | static struct tda18271_config hauppauge_hvr1200_tuner_config = { | ||
285 | .std_map = &hauppauge_hvr1200_tda18271_std_map, | ||
286 | .gate = TDA18271_GATE_ANALOG, | ||
287 | .output_opt = TDA18271_OUTPUT_LT_OFF, | ||
288 | }; | ||
289 | |||
290 | static struct tda18271_config hauppauge_hvr1210_tuner_config = { | ||
291 | .gate = TDA18271_GATE_DIGITAL, | ||
292 | .output_opt = TDA18271_OUTPUT_LT_OFF, | ||
293 | }; | ||
294 | |||
295 | static struct tda18271_std_map hauppauge_hvr127x_std_map = { | ||
296 | .atsc_6 = { .if_freq = 3250, .agc_mode = 3, .std = 4, | ||
297 | .if_lvl = 1, .rfagc_top = 0x58 }, | ||
298 | .qam_6 = { .if_freq = 4000, .agc_mode = 3, .std = 5, | ||
299 | .if_lvl = 1, .rfagc_top = 0x58 }, | ||
300 | }; | ||
301 | |||
302 | static struct tda18271_config hauppauge_hvr127x_config = { | ||
303 | .std_map = &hauppauge_hvr127x_std_map, | ||
304 | .output_opt = TDA18271_OUTPUT_LT_OFF, | ||
305 | }; | ||
306 | |||
307 | static struct lgdt3305_config hauppauge_lgdt3305_config = { | ||
308 | .i2c_addr = 0x0e, | ||
309 | .mpeg_mode = LGDT3305_MPEG_SERIAL, | ||
310 | .tpclk_edge = LGDT3305_TPCLK_FALLING_EDGE, | ||
311 | .tpvalid_polarity = LGDT3305_TP_VALID_HIGH, | ||
312 | .deny_i2c_rptr = 1, | ||
313 | .spectral_inversion = 1, | ||
314 | .qam_if_khz = 4000, | ||
315 | .vsb_if_khz = 3250, | ||
316 | }; | ||
317 | |||
318 | static struct dibx000_agc_config xc3028_agc_config = { | ||
319 | BAND_VHF | BAND_UHF, /* band_caps */ | ||
320 | |||
321 | /* P_agc_use_sd_mod1=0, P_agc_use_sd_mod2=0, P_agc_freq_pwm_div=0, | ||
322 | * P_agc_inv_pwm1=0, P_agc_inv_pwm2=0, | ||
323 | * P_agc_inh_dc_rv_est=0, P_agc_time_est=3, P_agc_freeze=0, | ||
324 | * P_agc_nb_est=2, P_agc_write=0 | ||
325 | */ | ||
326 | (0 << 15) | (0 << 14) | (0 << 11) | (0 << 10) | (0 << 9) | (0 << 8) | | ||
327 | (3 << 5) | (0 << 4) | (2 << 1) | (0 << 0), /* setup */ | ||
328 | |||
329 | 712, /* inv_gain */ | ||
330 | 21, /* time_stabiliz */ | ||
331 | |||
332 | 0, /* alpha_level */ | ||
333 | 118, /* thlock */ | ||
334 | |||
335 | 0, /* wbd_inv */ | ||
336 | 2867, /* wbd_ref */ | ||
337 | 0, /* wbd_sel */ | ||
338 | 2, /* wbd_alpha */ | ||
339 | |||
340 | 0, /* agc1_max */ | ||
341 | 0, /* agc1_min */ | ||
342 | 39718, /* agc2_max */ | ||
343 | 9930, /* agc2_min */ | ||
344 | 0, /* agc1_pt1 */ | ||
345 | 0, /* agc1_pt2 */ | ||
346 | 0, /* agc1_pt3 */ | ||
347 | 0, /* agc1_slope1 */ | ||
348 | 0, /* agc1_slope2 */ | ||
349 | 0, /* agc2_pt1 */ | ||
350 | 128, /* agc2_pt2 */ | ||
351 | 29, /* agc2_slope1 */ | ||
352 | 29, /* agc2_slope2 */ | ||
353 | |||
354 | 17, /* alpha_mant */ | ||
355 | 27, /* alpha_exp */ | ||
356 | 23, /* beta_mant */ | ||
357 | 51, /* beta_exp */ | ||
358 | |||
359 | 1, /* perform_agc_softsplit */ | ||
360 | }; | ||
361 | |||
362 | /* PLL Configuration for COFDM BW_MHz = 8.000000 | ||
363 | * With external clock = 30.000000 */ | ||
364 | static struct dibx000_bandwidth_config xc3028_bw_config = { | ||
365 | 60000, /* internal */ | ||
366 | 30000, /* sampling */ | ||
367 | 1, /* pll_cfg: prediv */ | ||
368 | 8, /* pll_cfg: ratio */ | ||
369 | 3, /* pll_cfg: range */ | ||
370 | 1, /* pll_cfg: reset */ | ||
371 | 0, /* pll_cfg: bypass */ | ||
372 | 0, /* misc: refdiv */ | ||
373 | 0, /* misc: bypclk_div */ | ||
374 | 1, /* misc: IO_CLK_en_core */ | ||
375 | 1, /* misc: ADClkSrc */ | ||
376 | 0, /* misc: modulo */ | ||
377 | (3 << 14) | (1 << 12) | (524 << 0), /* sad_cfg: refsel, sel, freq_15k */ | ||
378 | (1 << 25) | 5816102, /* ifreq = 5.200000 MHz */ | ||
379 | 20452225, /* timf */ | ||
380 | 30000000 /* xtal_hz */ | ||
381 | }; | ||
382 | |||
383 | static struct dib7000p_config hauppauge_hvr1400_dib7000_config = { | ||
384 | .output_mpeg2_in_188_bytes = 1, | ||
385 | .hostbus_diversity = 1, | ||
386 | .tuner_is_baseband = 0, | ||
387 | .update_lna = NULL, | ||
388 | |||
389 | .agc_config_count = 1, | ||
390 | .agc = &xc3028_agc_config, | ||
391 | .bw = &xc3028_bw_config, | ||
392 | |||
393 | .gpio_dir = DIB7000P_GPIO_DEFAULT_DIRECTIONS, | ||
394 | .gpio_val = DIB7000P_GPIO_DEFAULT_VALUES, | ||
395 | .gpio_pwm_pos = DIB7000P_GPIO_DEFAULT_PWM_POS, | ||
396 | |||
397 | .pwm_freq_div = 0, | ||
398 | .agc_control = NULL, | ||
399 | .spur_protect = 0, | ||
400 | |||
401 | .output_mode = OUTMODE_MPEG2_SERIAL, | ||
402 | }; | ||
403 | |||
404 | static struct zl10353_config dvico_fusionhdtv_xc3028 = { | ||
405 | .demod_address = 0x0f, | ||
406 | .if2 = 45600, | ||
407 | .no_tuner = 1, | ||
408 | .disable_i2c_gate_ctrl = 1, | ||
409 | }; | ||
410 | |||
411 | static struct stv0900_reg stv0900_ts_regs[] = { | ||
412 | { R0900_TSGENERAL, 0x00 }, | ||
413 | { R0900_P1_TSSPEED, 0x40 }, | ||
414 | { R0900_P2_TSSPEED, 0x40 }, | ||
415 | { R0900_P1_TSCFGM, 0xc0 }, | ||
416 | { R0900_P2_TSCFGM, 0xc0 }, | ||
417 | { R0900_P1_TSCFGH, 0xe0 }, | ||
418 | { R0900_P2_TSCFGH, 0xe0 }, | ||
419 | { R0900_P1_TSCFGL, 0x20 }, | ||
420 | { R0900_P2_TSCFGL, 0x20 }, | ||
421 | { 0xffff, 0xff }, /* terminate */ | ||
422 | }; | ||
423 | |||
424 | static struct stv0900_config netup_stv0900_config = { | ||
425 | .demod_address = 0x68, | ||
426 | .demod_mode = 1, /* dual */ | ||
427 | .xtal = 8000000, | ||
428 | .clkmode = 3,/* 0-CLKI, 2-XTALI, else AUTO */ | ||
429 | .diseqc_mode = 2,/* 2/3 PWM */ | ||
430 | .ts_config_regs = stv0900_ts_regs, | ||
431 | .tun1_maddress = 0,/* 0x60 */ | ||
432 | .tun2_maddress = 3,/* 0x63 */ | ||
433 | .tun1_adc = 1,/* 1 Vpp */ | ||
434 | .tun2_adc = 1,/* 1 Vpp */ | ||
435 | }; | ||
436 | |||
437 | static struct stv6110_config netup_stv6110_tunerconfig_a = { | ||
438 | .i2c_address = 0x60, | ||
439 | .mclk = 16000000, | ||
440 | .clk_div = 1, | ||
441 | .gain = 8, /* +16 dB - maximum gain */ | ||
442 | }; | ||
443 | |||
444 | static struct stv6110_config netup_stv6110_tunerconfig_b = { | ||
445 | .i2c_address = 0x63, | ||
446 | .mclk = 16000000, | ||
447 | .clk_div = 1, | ||
448 | .gain = 8, /* +16 dB - maximum gain */ | ||
449 | }; | ||
450 | |||
451 | static struct cx24116_config tbs_cx24116_config = { | ||
452 | .demod_address = 0x55, | ||
453 | }; | ||
454 | |||
455 | static struct ds3000_config tevii_ds3000_config = { | ||
456 | .demod_address = 0x68, | ||
457 | }; | ||
458 | |||
459 | static struct cx24116_config dvbworld_cx24116_config = { | ||
460 | .demod_address = 0x05, | ||
461 | }; | ||
462 | |||
463 | static struct lgs8gxx_config mygica_x8506_lgs8gl5_config = { | ||
464 | .prod = LGS8GXX_PROD_LGS8GL5, | ||
465 | .demod_address = 0x19, | ||
466 | .serial_ts = 0, | ||
467 | .ts_clk_pol = 1, | ||
468 | .ts_clk_gated = 1, | ||
469 | .if_clk_freq = 30400, /* 30.4 MHz */ | ||
470 | .if_freq = 5380, /* 5.38 MHz */ | ||
471 | .if_neg_center = 1, | ||
472 | .ext_adc = 0, | ||
473 | .adc_signed = 0, | ||
474 | .if_neg_edge = 0, | ||
475 | }; | ||
476 | |||
477 | static struct xc5000_config mygica_x8506_xc5000_config = { | ||
478 | .i2c_address = 0x61, | ||
479 | .if_khz = 5380, | ||
480 | }; | ||
481 | |||
482 | static int cx23885_dvb_set_frontend(struct dvb_frontend *fe, | ||
483 | struct dvb_frontend_parameters *param) | ||
484 | { | ||
485 | struct cx23885_tsport *port = fe->dvb->priv; | ||
486 | struct cx23885_dev *dev = port->dev; | ||
487 | |||
488 | switch (dev->board) { | ||
489 | case CX23885_BOARD_HAUPPAUGE_HVR1275: | ||
490 | switch (param->u.vsb.modulation) { | ||
491 | case VSB_8: | ||
492 | cx23885_gpio_clear(dev, GPIO_5); | ||
493 | break; | ||
494 | case QAM_64: | ||
495 | case QAM_256: | ||
496 | default: | ||
497 | cx23885_gpio_set(dev, GPIO_5); | ||
498 | break; | ||
499 | } | ||
500 | break; | ||
501 | case CX23885_BOARD_MYGICA_X8506: | ||
502 | case CX23885_BOARD_MAGICPRO_PROHDTVE2: | ||
503 | /* Select Digital TV */ | ||
504 | cx23885_gpio_set(dev, GPIO_0); | ||
505 | break; | ||
506 | } | ||
507 | return 0; | ||
508 | } | ||
509 | |||
510 | static int cx23885_dvb_fe_ioctl_override(struct dvb_frontend *fe, | ||
511 | unsigned int cmd, void *parg, | ||
512 | unsigned int stage) | ||
513 | { | ||
514 | int err = 0; | ||
515 | |||
516 | switch (stage) { | ||
517 | case DVB_FE_IOCTL_PRE: | ||
518 | |||
519 | switch (cmd) { | ||
520 | case FE_SET_FRONTEND: | ||
521 | err = cx23885_dvb_set_frontend(fe, | ||
522 | (struct dvb_frontend_parameters *) parg); | ||
523 | break; | ||
524 | } | ||
525 | break; | ||
526 | |||
527 | case DVB_FE_IOCTL_POST: | ||
528 | /* no post-ioctl handling required */ | ||
529 | break; | ||
530 | } | ||
531 | return err; | ||
532 | }; | ||
533 | |||
534 | |||
535 | static struct lgs8gxx_config magicpro_prohdtve2_lgs8g75_config = { | ||
536 | .prod = LGS8GXX_PROD_LGS8G75, | ||
537 | .demod_address = 0x19, | ||
538 | .serial_ts = 0, | ||
539 | .ts_clk_pol = 1, | ||
540 | .ts_clk_gated = 1, | ||
541 | .if_clk_freq = 30400, /* 30.4 MHz */ | ||
542 | .if_freq = 6500, /* 6.50 MHz */ | ||
543 | .if_neg_center = 1, | ||
544 | .ext_adc = 0, | ||
545 | .adc_signed = 1, | ||
546 | .adc_vpp = 2, /* 1.6 Vpp */ | ||
547 | .if_neg_edge = 1, | ||
548 | }; | ||
549 | |||
550 | static struct xc5000_config magicpro_prohdtve2_xc5000_config = { | ||
551 | .i2c_address = 0x61, | ||
552 | .if_khz = 6500, | ||
553 | }; | ||
554 | |||
555 | static struct atbm8830_config mygica_x8558pro_atbm8830_cfg1 = { | ||
556 | .prod = ATBM8830_PROD_8830, | ||
557 | .demod_address = 0x44, | ||
558 | .serial_ts = 0, | ||
559 | .ts_sampling_edge = 1, | ||
560 | .ts_clk_gated = 0, | ||
561 | .osc_clk_freq = 30400, /* in kHz */ | ||
562 | .if_freq = 0, /* zero IF */ | ||
563 | .zif_swap_iq = 1, | ||
564 | .agc_min = 0x2E, | ||
565 | .agc_max = 0xFF, | ||
566 | .agc_hold_loop = 0, | ||
567 | }; | ||
568 | |||
569 | static struct max2165_config mygic_x8558pro_max2165_cfg1 = { | ||
570 | .i2c_address = 0x60, | ||
571 | .osc_clk = 20 | ||
572 | }; | ||
573 | |||
574 | static struct atbm8830_config mygica_x8558pro_atbm8830_cfg2 = { | ||
575 | .prod = ATBM8830_PROD_8830, | ||
576 | .demod_address = 0x44, | ||
577 | .serial_ts = 1, | ||
578 | .ts_sampling_edge = 1, | ||
579 | .ts_clk_gated = 0, | ||
580 | .osc_clk_freq = 30400, /* in kHz */ | ||
581 | .if_freq = 0, /* zero IF */ | ||
582 | .zif_swap_iq = 1, | ||
583 | .agc_min = 0x2E, | ||
584 | .agc_max = 0xFF, | ||
585 | .agc_hold_loop = 0, | ||
586 | }; | ||
587 | |||
588 | static struct max2165_config mygic_x8558pro_max2165_cfg2 = { | ||
589 | .i2c_address = 0x60, | ||
590 | .osc_clk = 20 | ||
591 | }; | ||
592 | static struct stv0367_config netup_stv0367_config[] = { | ||
593 | { | ||
594 | .demod_address = 0x1c, | ||
595 | .xtal = 27000000, | ||
596 | .if_khz = 4500, | ||
597 | .if_iq_mode = 0, | ||
598 | .ts_mode = 1, | ||
599 | .clk_pol = 0, | ||
600 | }, { | ||
601 | .demod_address = 0x1d, | ||
602 | .xtal = 27000000, | ||
603 | .if_khz = 4500, | ||
604 | .if_iq_mode = 0, | ||
605 | .ts_mode = 1, | ||
606 | .clk_pol = 0, | ||
607 | }, | ||
608 | }; | ||
609 | |||
610 | static struct xc5000_config netup_xc5000_config[] = { | ||
611 | { | ||
612 | .i2c_address = 0x61, | ||
613 | .if_khz = 4500, | ||
614 | }, { | ||
615 | .i2c_address = 0x64, | ||
616 | .if_khz = 4500, | ||
617 | }, | ||
618 | }; | ||
619 | |||
620 | int netup_altera_fpga_rw(void *device, int flag, int data, int read) | ||
621 | { | ||
622 | struct cx23885_dev *dev = (struct cx23885_dev *)device; | ||
623 | unsigned long timeout = jiffies + msecs_to_jiffies(1); | ||
624 | uint32_t mem = 0; | ||
625 | |||
626 | mem = cx_read(MC417_RWD); | ||
627 | if (read) | ||
628 | cx_set(MC417_OEN, ALT_DATA); | ||
629 | else { | ||
630 | cx_clear(MC417_OEN, ALT_DATA);/* D0-D7 out */ | ||
631 | mem &= ~ALT_DATA; | ||
632 | mem |= (data & ALT_DATA); | ||
633 | } | ||
634 | |||
635 | if (flag) | ||
636 | mem |= ALT_AD_RG; | ||
637 | else | ||
638 | mem &= ~ALT_AD_RG; | ||
639 | |||
640 | mem &= ~ALT_CS; | ||
641 | if (read) | ||
642 | mem = (mem & ~ALT_RD) | ALT_WR; | ||
643 | else | ||
644 | mem = (mem & ~ALT_WR) | ALT_RD; | ||
645 | |||
646 | cx_write(MC417_RWD, mem); /* start RW cycle */ | ||
647 | |||
648 | for (;;) { | ||
649 | mem = cx_read(MC417_RWD); | ||
650 | if ((mem & ALT_RDY) == 0) | ||
651 | break; | ||
652 | if (time_after(jiffies, timeout)) | ||
653 | break; | ||
654 | udelay(1); | ||
655 | } | ||
656 | |||
657 | cx_set(MC417_RWD, ALT_RD | ALT_WR | ALT_CS); | ||
658 | if (read) | ||
659 | return mem & ALT_DATA; | ||
660 | |||
661 | return 0; | ||
662 | }; | ||
663 | |||
664 | static int dvb_register(struct cx23885_tsport *port) | ||
665 | { | ||
666 | struct cx23885_dev *dev = port->dev; | ||
667 | struct cx23885_i2c *i2c_bus = NULL, *i2c_bus2 = NULL; | ||
668 | struct videobuf_dvb_frontend *fe0, *fe1 = NULL; | ||
669 | int mfe_shared = 0; /* bus not shared by default */ | ||
670 | int ret; | ||
671 | |||
672 | /* Get the first frontend */ | ||
673 | fe0 = videobuf_dvb_get_frontend(&port->frontends, 1); | ||
674 | if (!fe0) | ||
675 | return -EINVAL; | ||
676 | |||
677 | /* init struct videobuf_dvb */ | ||
678 | fe0->dvb.name = dev->name; | ||
679 | |||
680 | /* multi-frontend gate control is undefined or defaults to fe0 */ | ||
681 | port->frontends.gate = 0; | ||
682 | |||
683 | /* Sets the gate control callback to be used by i2c command calls */ | ||
684 | port->gate_ctrl = cx23885_dvb_gate_ctrl; | ||
685 | |||
686 | /* init frontend */ | ||
687 | switch (dev->board) { | ||
688 | case CX23885_BOARD_HAUPPAUGE_HVR1250: | ||
689 | i2c_bus = &dev->i2c_bus[0]; | ||
690 | fe0->dvb.frontend = dvb_attach(s5h1409_attach, | ||
691 | &hauppauge_generic_config, | ||
692 | &i2c_bus->i2c_adap); | ||
693 | if (fe0->dvb.frontend != NULL) { | ||
694 | dvb_attach(mt2131_attach, fe0->dvb.frontend, | ||
695 | &i2c_bus->i2c_adap, | ||
696 | &hauppauge_generic_tunerconfig, 0); | ||
697 | } | ||
698 | break; | ||
699 | case CX23885_BOARD_HAUPPAUGE_HVR1270: | ||
700 | case CX23885_BOARD_HAUPPAUGE_HVR1275: | ||
701 | i2c_bus = &dev->i2c_bus[0]; | ||
702 | fe0->dvb.frontend = dvb_attach(lgdt3305_attach, | ||
703 | &hauppauge_lgdt3305_config, | ||
704 | &i2c_bus->i2c_adap); | ||
705 | if (fe0->dvb.frontend != NULL) { | ||
706 | dvb_attach(tda18271_attach, fe0->dvb.frontend, | ||
707 | 0x60, &dev->i2c_bus[1].i2c_adap, | ||
708 | &hauppauge_hvr127x_config); | ||
709 | } | ||
710 | break; | ||
711 | case CX23885_BOARD_HAUPPAUGE_HVR1255: | ||
712 | i2c_bus = &dev->i2c_bus[0]; | ||
713 | fe0->dvb.frontend = dvb_attach(s5h1411_attach, | ||
714 | &hcw_s5h1411_config, | ||
715 | &i2c_bus->i2c_adap); | ||
716 | if (fe0->dvb.frontend != NULL) { | ||
717 | dvb_attach(tda18271_attach, fe0->dvb.frontend, | ||
718 | 0x60, &dev->i2c_bus[1].i2c_adap, | ||
719 | &hauppauge_tda18271_config); | ||
720 | } | ||
721 | break; | ||
722 | case CX23885_BOARD_HAUPPAUGE_HVR1800: | ||
723 | i2c_bus = &dev->i2c_bus[0]; | ||
724 | switch (alt_tuner) { | ||
725 | case 1: | ||
726 | fe0->dvb.frontend = | ||
727 | dvb_attach(s5h1409_attach, | ||
728 | &hauppauge_ezqam_config, | ||
729 | &i2c_bus->i2c_adap); | ||
730 | if (fe0->dvb.frontend != NULL) { | ||
731 | dvb_attach(tda829x_attach, fe0->dvb.frontend, | ||
732 | &dev->i2c_bus[1].i2c_adap, 0x42, | ||
733 | &tda829x_no_probe); | ||
734 | dvb_attach(tda18271_attach, fe0->dvb.frontend, | ||
735 | 0x60, &dev->i2c_bus[1].i2c_adap, | ||
736 | &hauppauge_tda18271_config); | ||
737 | } | ||
738 | break; | ||
739 | case 0: | ||
740 | default: | ||
741 | fe0->dvb.frontend = | ||
742 | dvb_attach(s5h1409_attach, | ||
743 | &hauppauge_generic_config, | ||
744 | &i2c_bus->i2c_adap); | ||
745 | if (fe0->dvb.frontend != NULL) | ||
746 | dvb_attach(mt2131_attach, fe0->dvb.frontend, | ||
747 | &i2c_bus->i2c_adap, | ||
748 | &hauppauge_generic_tunerconfig, 0); | ||
749 | break; | ||
750 | } | ||
751 | break; | ||
752 | case CX23885_BOARD_HAUPPAUGE_HVR1800lp: | ||
753 | i2c_bus = &dev->i2c_bus[0]; | ||
754 | fe0->dvb.frontend = dvb_attach(s5h1409_attach, | ||
755 | &hauppauge_hvr1800lp_config, | ||
756 | &i2c_bus->i2c_adap); | ||
757 | if (fe0->dvb.frontend != NULL) { | ||
758 | dvb_attach(mt2131_attach, fe0->dvb.frontend, | ||
759 | &i2c_bus->i2c_adap, | ||
760 | &hauppauge_generic_tunerconfig, 0); | ||
761 | } | ||
762 | break; | ||
763 | case CX23885_BOARD_DVICO_FUSIONHDTV_5_EXP: | ||
764 | i2c_bus = &dev->i2c_bus[0]; | ||
765 | fe0->dvb.frontend = dvb_attach(lgdt330x_attach, | ||
766 | &fusionhdtv_5_express, | ||
767 | &i2c_bus->i2c_adap); | ||
768 | if (fe0->dvb.frontend != NULL) { | ||
769 | dvb_attach(simple_tuner_attach, fe0->dvb.frontend, | ||
770 | &i2c_bus->i2c_adap, 0x61, | ||
771 | TUNER_LG_TDVS_H06XF); | ||
772 | } | ||
773 | break; | ||
774 | case CX23885_BOARD_HAUPPAUGE_HVR1500Q: | ||
775 | i2c_bus = &dev->i2c_bus[1]; | ||
776 | fe0->dvb.frontend = dvb_attach(s5h1409_attach, | ||
777 | &hauppauge_hvr1500q_config, | ||
778 | &dev->i2c_bus[0].i2c_adap); | ||
779 | if (fe0->dvb.frontend != NULL) | ||
780 | dvb_attach(xc5000_attach, fe0->dvb.frontend, | ||
781 | &i2c_bus->i2c_adap, | ||
782 | &hauppauge_hvr1500q_tunerconfig); | ||
783 | break; | ||
784 | case CX23885_BOARD_HAUPPAUGE_HVR1500: | ||
785 | i2c_bus = &dev->i2c_bus[1]; | ||
786 | fe0->dvb.frontend = dvb_attach(s5h1409_attach, | ||
787 | &hauppauge_hvr1500_config, | ||
788 | &dev->i2c_bus[0].i2c_adap); | ||
789 | if (fe0->dvb.frontend != NULL) { | ||
790 | struct dvb_frontend *fe; | ||
791 | struct xc2028_config cfg = { | ||
792 | .i2c_adap = &i2c_bus->i2c_adap, | ||
793 | .i2c_addr = 0x61, | ||
794 | }; | ||
795 | static struct xc2028_ctrl ctl = { | ||
796 | .fname = XC2028_DEFAULT_FIRMWARE, | ||
797 | .max_len = 64, | ||
798 | .demod = XC3028_FE_OREN538, | ||
799 | }; | ||
800 | |||
801 | fe = dvb_attach(xc2028_attach, | ||
802 | fe0->dvb.frontend, &cfg); | ||
803 | if (fe != NULL && fe->ops.tuner_ops.set_config != NULL) | ||
804 | fe->ops.tuner_ops.set_config(fe, &ctl); | ||
805 | } | ||
806 | break; | ||
807 | case CX23885_BOARD_HAUPPAUGE_HVR1200: | ||
808 | case CX23885_BOARD_HAUPPAUGE_HVR1700: | ||
809 | i2c_bus = &dev->i2c_bus[0]; | ||
810 | fe0->dvb.frontend = dvb_attach(tda10048_attach, | ||
811 | &hauppauge_hvr1200_config, | ||
812 | &i2c_bus->i2c_adap); | ||
813 | if (fe0->dvb.frontend != NULL) { | ||
814 | dvb_attach(tda829x_attach, fe0->dvb.frontend, | ||
815 | &dev->i2c_bus[1].i2c_adap, 0x42, | ||
816 | &tda829x_no_probe); | ||
817 | dvb_attach(tda18271_attach, fe0->dvb.frontend, | ||
818 | 0x60, &dev->i2c_bus[1].i2c_adap, | ||
819 | &hauppauge_hvr1200_tuner_config); | ||
820 | } | ||
821 | break; | ||
822 | case CX23885_BOARD_HAUPPAUGE_HVR1210: | ||
823 | i2c_bus = &dev->i2c_bus[0]; | ||
824 | fe0->dvb.frontend = dvb_attach(tda10048_attach, | ||
825 | &hauppauge_hvr1210_config, | ||
826 | &i2c_bus->i2c_adap); | ||
827 | if (fe0->dvb.frontend != NULL) { | ||
828 | dvb_attach(tda18271_attach, fe0->dvb.frontend, | ||
829 | 0x60, &dev->i2c_bus[1].i2c_adap, | ||
830 | &hauppauge_hvr1210_tuner_config); | ||
831 | } | ||
832 | break; | ||
833 | case CX23885_BOARD_HAUPPAUGE_HVR1400: | ||
834 | i2c_bus = &dev->i2c_bus[0]; | ||
835 | fe0->dvb.frontend = dvb_attach(dib7000p_attach, | ||
836 | &i2c_bus->i2c_adap, | ||
837 | 0x12, &hauppauge_hvr1400_dib7000_config); | ||
838 | if (fe0->dvb.frontend != NULL) { | ||
839 | struct dvb_frontend *fe; | ||
840 | struct xc2028_config cfg = { | ||
841 | .i2c_adap = &dev->i2c_bus[1].i2c_adap, | ||
842 | .i2c_addr = 0x64, | ||
843 | }; | ||
844 | static struct xc2028_ctrl ctl = { | ||
845 | .fname = XC3028L_DEFAULT_FIRMWARE, | ||
846 | .max_len = 64, | ||
847 | .demod = XC3028_FE_DIBCOM52, | ||
848 | /* This is true for all demods with | ||
849 | v36 firmware? */ | ||
850 | .type = XC2028_D2633, | ||
851 | }; | ||
852 | |||
853 | fe = dvb_attach(xc2028_attach, | ||
854 | fe0->dvb.frontend, &cfg); | ||
855 | if (fe != NULL && fe->ops.tuner_ops.set_config != NULL) | ||
856 | fe->ops.tuner_ops.set_config(fe, &ctl); | ||
857 | } | ||
858 | break; | ||
859 | case CX23885_BOARD_DVICO_FUSIONHDTV_7_DUAL_EXP: | ||
860 | i2c_bus = &dev->i2c_bus[port->nr - 1]; | ||
861 | |||
862 | fe0->dvb.frontend = dvb_attach(s5h1409_attach, | ||
863 | &dvico_s5h1409_config, | ||
864 | &i2c_bus->i2c_adap); | ||
865 | if (fe0->dvb.frontend == NULL) | ||
866 | fe0->dvb.frontend = dvb_attach(s5h1411_attach, | ||
867 | &dvico_s5h1411_config, | ||
868 | &i2c_bus->i2c_adap); | ||
869 | if (fe0->dvb.frontend != NULL) | ||
870 | dvb_attach(xc5000_attach, fe0->dvb.frontend, | ||
871 | &i2c_bus->i2c_adap, | ||
872 | &dvico_xc5000_tunerconfig); | ||
873 | break; | ||
874 | case CX23885_BOARD_DVICO_FUSIONHDTV_DVB_T_DUAL_EXP: { | ||
875 | i2c_bus = &dev->i2c_bus[port->nr - 1]; | ||
876 | |||
877 | fe0->dvb.frontend = dvb_attach(zl10353_attach, | ||
878 | &dvico_fusionhdtv_xc3028, | ||
879 | &i2c_bus->i2c_adap); | ||
880 | if (fe0->dvb.frontend != NULL) { | ||
881 | struct dvb_frontend *fe; | ||
882 | struct xc2028_config cfg = { | ||
883 | .i2c_adap = &i2c_bus->i2c_adap, | ||
884 | .i2c_addr = 0x61, | ||
885 | }; | ||
886 | static struct xc2028_ctrl ctl = { | ||
887 | .fname = XC2028_DEFAULT_FIRMWARE, | ||
888 | .max_len = 64, | ||
889 | .demod = XC3028_FE_ZARLINK456, | ||
890 | }; | ||
891 | |||
892 | fe = dvb_attach(xc2028_attach, fe0->dvb.frontend, | ||
893 | &cfg); | ||
894 | if (fe != NULL && fe->ops.tuner_ops.set_config != NULL) | ||
895 | fe->ops.tuner_ops.set_config(fe, &ctl); | ||
896 | } | ||
897 | break; | ||
898 | } | ||
899 | case CX23885_BOARD_LEADTEK_WINFAST_PXDVR3200_H: | ||
900 | case CX23885_BOARD_COMPRO_VIDEOMATE_E650F: | ||
901 | case CX23885_BOARD_COMPRO_VIDEOMATE_E800: | ||
902 | i2c_bus = &dev->i2c_bus[0]; | ||
903 | |||
904 | fe0->dvb.frontend = dvb_attach(zl10353_attach, | ||
905 | &dvico_fusionhdtv_xc3028, | ||
906 | &i2c_bus->i2c_adap); | ||
907 | if (fe0->dvb.frontend != NULL) { | ||
908 | struct dvb_frontend *fe; | ||
909 | struct xc2028_config cfg = { | ||
910 | .i2c_adap = &dev->i2c_bus[1].i2c_adap, | ||
911 | .i2c_addr = 0x61, | ||
912 | }; | ||
913 | static struct xc2028_ctrl ctl = { | ||
914 | .fname = XC2028_DEFAULT_FIRMWARE, | ||
915 | .max_len = 64, | ||
916 | .demod = XC3028_FE_ZARLINK456, | ||
917 | }; | ||
918 | |||
919 | fe = dvb_attach(xc2028_attach, fe0->dvb.frontend, | ||
920 | &cfg); | ||
921 | if (fe != NULL && fe->ops.tuner_ops.set_config != NULL) | ||
922 | fe->ops.tuner_ops.set_config(fe, &ctl); | ||
923 | } | ||
924 | break; | ||
925 | case CX23885_BOARD_LEADTEK_WINFAST_PXDVR3200_H_XC4000: | ||
926 | i2c_bus = &dev->i2c_bus[0]; | ||
927 | |||
928 | fe0->dvb.frontend = dvb_attach(zl10353_attach, | ||
929 | &dvico_fusionhdtv_xc3028, | ||
930 | &i2c_bus->i2c_adap); | ||
931 | if (fe0->dvb.frontend != NULL) { | ||
932 | struct dvb_frontend *fe; | ||
933 | struct xc4000_config cfg = { | ||
934 | .i2c_address = 0x61, | ||
935 | .default_pm = 0, | ||
936 | .dvb_amplitude = 134, | ||
937 | .set_smoothedcvbs = 1, | ||
938 | .if_khz = 4560 | ||
939 | }; | ||
940 | |||
941 | fe = dvb_attach(xc4000_attach, fe0->dvb.frontend, | ||
942 | &dev->i2c_bus[1].i2c_adap, &cfg); | ||
943 | } | ||
944 | break; | ||
945 | case CX23885_BOARD_TBS_6920: | ||
946 | i2c_bus = &dev->i2c_bus[1]; | ||
947 | |||
948 | fe0->dvb.frontend = dvb_attach(cx24116_attach, | ||
949 | &tbs_cx24116_config, | ||
950 | &i2c_bus->i2c_adap); | ||
951 | if (fe0->dvb.frontend != NULL) | ||
952 | fe0->dvb.frontend->ops.set_voltage = f300_set_voltage; | ||
953 | |||
954 | break; | ||
955 | case CX23885_BOARD_TEVII_S470: | ||
956 | i2c_bus = &dev->i2c_bus[1]; | ||
957 | |||
958 | fe0->dvb.frontend = dvb_attach(ds3000_attach, | ||
959 | &tevii_ds3000_config, | ||
960 | &i2c_bus->i2c_adap); | ||
961 | if (fe0->dvb.frontend != NULL) | ||
962 | fe0->dvb.frontend->ops.set_voltage = f300_set_voltage; | ||
963 | |||
964 | break; | ||
965 | case CX23885_BOARD_DVBWORLD_2005: | ||
966 | i2c_bus = &dev->i2c_bus[1]; | ||
967 | |||
968 | fe0->dvb.frontend = dvb_attach(cx24116_attach, | ||
969 | &dvbworld_cx24116_config, | ||
970 | &i2c_bus->i2c_adap); | ||
971 | break; | ||
972 | case CX23885_BOARD_NETUP_DUAL_DVBS2_CI: | ||
973 | i2c_bus = &dev->i2c_bus[0]; | ||
974 | switch (port->nr) { | ||
975 | /* port B */ | ||
976 | case 1: | ||
977 | fe0->dvb.frontend = dvb_attach(stv0900_attach, | ||
978 | &netup_stv0900_config, | ||
979 | &i2c_bus->i2c_adap, 0); | ||
980 | if (fe0->dvb.frontend != NULL) { | ||
981 | if (dvb_attach(stv6110_attach, | ||
982 | fe0->dvb.frontend, | ||
983 | &netup_stv6110_tunerconfig_a, | ||
984 | &i2c_bus->i2c_adap)) { | ||
985 | if (!dvb_attach(lnbh24_attach, | ||
986 | fe0->dvb.frontend, | ||
987 | &i2c_bus->i2c_adap, | ||
988 | LNBH24_PCL | LNBH24_TTX, | ||
989 | LNBH24_TEN, 0x09)) | ||
990 | printk(KERN_ERR | ||
991 | "No LNBH24 found!\n"); | ||
992 | |||
993 | } | ||
994 | } | ||
995 | break; | ||
996 | /* port C */ | ||
997 | case 2: | ||
998 | fe0->dvb.frontend = dvb_attach(stv0900_attach, | ||
999 | &netup_stv0900_config, | ||
1000 | &i2c_bus->i2c_adap, 1); | ||
1001 | if (fe0->dvb.frontend != NULL) { | ||
1002 | if (dvb_attach(stv6110_attach, | ||
1003 | fe0->dvb.frontend, | ||
1004 | &netup_stv6110_tunerconfig_b, | ||
1005 | &i2c_bus->i2c_adap)) { | ||
1006 | if (!dvb_attach(lnbh24_attach, | ||
1007 | fe0->dvb.frontend, | ||
1008 | &i2c_bus->i2c_adap, | ||
1009 | LNBH24_PCL | LNBH24_TTX, | ||
1010 | LNBH24_TEN, 0x0a)) | ||
1011 | printk(KERN_ERR | ||
1012 | "No LNBH24 found!\n"); | ||
1013 | |||
1014 | } | ||
1015 | } | ||
1016 | break; | ||
1017 | } | ||
1018 | break; | ||
1019 | case CX23885_BOARD_MYGICA_X8506: | ||
1020 | i2c_bus = &dev->i2c_bus[0]; | ||
1021 | i2c_bus2 = &dev->i2c_bus[1]; | ||
1022 | fe0->dvb.frontend = dvb_attach(lgs8gxx_attach, | ||
1023 | &mygica_x8506_lgs8gl5_config, | ||
1024 | &i2c_bus->i2c_adap); | ||
1025 | if (fe0->dvb.frontend != NULL) { | ||
1026 | dvb_attach(xc5000_attach, | ||
1027 | fe0->dvb.frontend, | ||
1028 | &i2c_bus2->i2c_adap, | ||
1029 | &mygica_x8506_xc5000_config); | ||
1030 | } | ||
1031 | break; | ||
1032 | case CX23885_BOARD_MAGICPRO_PROHDTVE2: | ||
1033 | i2c_bus = &dev->i2c_bus[0]; | ||
1034 | i2c_bus2 = &dev->i2c_bus[1]; | ||
1035 | fe0->dvb.frontend = dvb_attach(lgs8gxx_attach, | ||
1036 | &magicpro_prohdtve2_lgs8g75_config, | ||
1037 | &i2c_bus->i2c_adap); | ||
1038 | if (fe0->dvb.frontend != NULL) { | ||
1039 | dvb_attach(xc5000_attach, | ||
1040 | fe0->dvb.frontend, | ||
1041 | &i2c_bus2->i2c_adap, | ||
1042 | &magicpro_prohdtve2_xc5000_config); | ||
1043 | } | ||
1044 | break; | ||
1045 | case CX23885_BOARD_HAUPPAUGE_HVR1850: | ||
1046 | case CX23885_BOARD_HAUPPAUGE_HVR1290: | ||
1047 | i2c_bus = &dev->i2c_bus[0]; | ||
1048 | fe0->dvb.frontend = dvb_attach(s5h1411_attach, | ||
1049 | &hcw_s5h1411_config, | ||
1050 | &i2c_bus->i2c_adap); | ||
1051 | if (fe0->dvb.frontend != NULL) | ||
1052 | dvb_attach(tda18271_attach, fe0->dvb.frontend, | ||
1053 | 0x60, &dev->i2c_bus[0].i2c_adap, | ||
1054 | &hauppauge_tda18271_config); | ||
1055 | break; | ||
1056 | case CX23885_BOARD_MYGICA_X8558PRO: | ||
1057 | switch (port->nr) { | ||
1058 | /* port B */ | ||
1059 | case 1: | ||
1060 | i2c_bus = &dev->i2c_bus[0]; | ||
1061 | fe0->dvb.frontend = dvb_attach(atbm8830_attach, | ||
1062 | &mygica_x8558pro_atbm8830_cfg1, | ||
1063 | &i2c_bus->i2c_adap); | ||
1064 | if (fe0->dvb.frontend != NULL) { | ||
1065 | dvb_attach(max2165_attach, | ||
1066 | fe0->dvb.frontend, | ||
1067 | &i2c_bus->i2c_adap, | ||
1068 | &mygic_x8558pro_max2165_cfg1); | ||
1069 | } | ||
1070 | break; | ||
1071 | /* port C */ | ||
1072 | case 2: | ||
1073 | i2c_bus = &dev->i2c_bus[1]; | ||
1074 | fe0->dvb.frontend = dvb_attach(atbm8830_attach, | ||
1075 | &mygica_x8558pro_atbm8830_cfg2, | ||
1076 | &i2c_bus->i2c_adap); | ||
1077 | if (fe0->dvb.frontend != NULL) { | ||
1078 | dvb_attach(max2165_attach, | ||
1079 | fe0->dvb.frontend, | ||
1080 | &i2c_bus->i2c_adap, | ||
1081 | &mygic_x8558pro_max2165_cfg2); | ||
1082 | } | ||
1083 | break; | ||
1084 | } | ||
1085 | break; | ||
1086 | case CX23885_BOARD_NETUP_DUAL_DVB_T_C_CI_RF: | ||
1087 | i2c_bus = &dev->i2c_bus[0]; | ||
1088 | mfe_shared = 1;/* MFE */ | ||
1089 | port->frontends.gate = 0;/* not clear for me yet */ | ||
1090 | /* ports B, C */ | ||
1091 | /* MFE frontend 1 DVB-T */ | ||
1092 | fe0->dvb.frontend = dvb_attach(stv0367ter_attach, | ||
1093 | &netup_stv0367_config[port->nr - 1], | ||
1094 | &i2c_bus->i2c_adap); | ||
1095 | if (fe0->dvb.frontend != NULL) { | ||
1096 | if (NULL == dvb_attach(xc5000_attach, | ||
1097 | fe0->dvb.frontend, | ||
1098 | &i2c_bus->i2c_adap, | ||
1099 | &netup_xc5000_config[port->nr - 1])) | ||
1100 | goto frontend_detach; | ||
1101 | /* load xc5000 firmware */ | ||
1102 | fe0->dvb.frontend->ops.tuner_ops.init(fe0->dvb.frontend); | ||
1103 | } | ||
1104 | /* MFE frontend 2 */ | ||
1105 | fe1 = videobuf_dvb_get_frontend(&port->frontends, 2); | ||
1106 | if (fe1 == NULL) | ||
1107 | goto frontend_detach; | ||
1108 | /* DVB-C init */ | ||
1109 | fe1->dvb.frontend = dvb_attach(stv0367cab_attach, | ||
1110 | &netup_stv0367_config[port->nr - 1], | ||
1111 | &i2c_bus->i2c_adap); | ||
1112 | if (fe1->dvb.frontend != NULL) { | ||
1113 | fe1->dvb.frontend->id = 1; | ||
1114 | if (NULL == dvb_attach(xc5000_attach, | ||
1115 | fe1->dvb.frontend, | ||
1116 | &i2c_bus->i2c_adap, | ||
1117 | &netup_xc5000_config[port->nr - 1])) | ||
1118 | goto frontend_detach; | ||
1119 | } | ||
1120 | break; | ||
1121 | default: | ||
1122 | printk(KERN_INFO "%s: The frontend of your DVB/ATSC card " | ||
1123 | " isn't supported yet\n", | ||
1124 | dev->name); | ||
1125 | break; | ||
1126 | } | ||
1127 | |||
1128 | if ((NULL == fe0->dvb.frontend) || (fe1 && NULL == fe1->dvb.frontend)) { | ||
1129 | printk(KERN_ERR "%s: frontend initialization failed\n", | ||
1130 | dev->name); | ||
1131 | goto frontend_detach; | ||
1132 | } | ||
1133 | |||
1134 | /* define general-purpose callback pointer */ | ||
1135 | fe0->dvb.frontend->callback = cx23885_tuner_callback; | ||
1136 | if (fe1) | ||
1137 | fe1->dvb.frontend->callback = cx23885_tuner_callback; | ||
1138 | #if 0 | ||
1139 | /* Ensure all frontends negotiate bus access */ | ||
1140 | fe0->dvb.frontend->ops.ts_bus_ctrl = cx23885_dvb_bus_ctrl; | ||
1141 | if (fe1) | ||
1142 | fe1->dvb.frontend->ops.ts_bus_ctrl = cx23885_dvb_bus_ctrl; | ||
1143 | #endif | ||
1144 | |||
1145 | /* Put the analog decoder in standby to keep it quiet */ | ||
1146 | call_all(dev, core, s_power, 0); | ||
1147 | |||
1148 | if (fe0->dvb.frontend->ops.analog_ops.standby) | ||
1149 | fe0->dvb.frontend->ops.analog_ops.standby(fe0->dvb.frontend); | ||
1150 | |||
1151 | /* register everything */ | ||
1152 | ret = videobuf_dvb_register_bus(&port->frontends, THIS_MODULE, port, | ||
1153 | &dev->pci->dev, adapter_nr, mfe_shared, | ||
1154 | cx23885_dvb_fe_ioctl_override); | ||
1155 | if (ret) | ||
1156 | goto frontend_detach; | ||
1157 | |||
1158 | /* init CI & MAC */ | ||
1159 | switch (dev->board) { | ||
1160 | case CX23885_BOARD_NETUP_DUAL_DVBS2_CI: { | ||
1161 | static struct netup_card_info cinfo; | ||
1162 | |||
1163 | netup_get_card_info(&dev->i2c_bus[0].i2c_adap, &cinfo); | ||
1164 | memcpy(port->frontends.adapter.proposed_mac, | ||
1165 | cinfo.port[port->nr - 1].mac, 6); | ||
1166 | printk(KERN_INFO "NetUP Dual DVB-S2 CI card port%d MAC=%pM\n", | ||
1167 | port->nr, port->frontends.adapter.proposed_mac); | ||
1168 | |||
1169 | netup_ci_init(port); | ||
1170 | break; | ||
1171 | } | ||
1172 | case CX23885_BOARD_NETUP_DUAL_DVB_T_C_CI_RF: { | ||
1173 | struct altera_ci_config netup_ci_cfg = { | ||
1174 | .dev = dev,/* magic number to identify*/ | ||
1175 | .adapter = &port->frontends.adapter,/* for CI */ | ||
1176 | .demux = &fe0->dvb.demux,/* for hw pid filter */ | ||
1177 | .fpga_rw = netup_altera_fpga_rw, | ||
1178 | }; | ||
1179 | |||
1180 | altera_ci_init(&netup_ci_cfg, port->nr); | ||
1181 | break; | ||
1182 | } | ||
1183 | case CX23885_BOARD_TEVII_S470: { | ||
1184 | u8 eeprom[256]; /* 24C02 i2c eeprom */ | ||
1185 | |||
1186 | if (port->nr != 1) | ||
1187 | break; | ||
1188 | |||
1189 | /* Read entire EEPROM */ | ||
1190 | dev->i2c_bus[0].i2c_client.addr = 0xa0 >> 1; | ||
1191 | tveeprom_read(&dev->i2c_bus[0].i2c_client, eeprom, sizeof(eeprom)); | ||
1192 | printk(KERN_INFO "TeVii S470 MAC= %pM\n", eeprom + 0xa0); | ||
1193 | memcpy(port->frontends.adapter.proposed_mac, eeprom + 0xa0, 6); | ||
1194 | break; | ||
1195 | } | ||
1196 | } | ||
1197 | |||
1198 | return ret; | ||
1199 | |||
1200 | frontend_detach: | ||
1201 | port->gate_ctrl = NULL; | ||
1202 | videobuf_dvb_dealloc_frontends(&port->frontends); | ||
1203 | return -EINVAL; | ||
1204 | } | ||
1205 | |||
1206 | int cx23885_dvb_register(struct cx23885_tsport *port) | ||
1207 | { | ||
1208 | |||
1209 | struct videobuf_dvb_frontend *fe0; | ||
1210 | struct cx23885_dev *dev = port->dev; | ||
1211 | int err, i; | ||
1212 | |||
1213 | /* Here we need to allocate the correct number of frontends, | ||
1214 | * as reflected in the cards struct. The reality is that currently | ||
1215 | * no cx23885 boards support this - yet. But, if we don't modify this | ||
1216 | * code then the second frontend would never be allocated (later) | ||
1217 | * and fail with error before the attach in dvb_register(). | ||
1218 | * Without these changes we risk an OOPS later. The changes here | ||
1219 | * are for safety, and should provide a good foundation for the | ||
1220 | * future addition of any multi-frontend cx23885 based boards. | ||
1221 | */ | ||
1222 | printk(KERN_INFO "%s() allocating %d frontend(s)\n", __func__, | ||
1223 | port->num_frontends); | ||
1224 | |||
1225 | for (i = 1; i <= port->num_frontends; i++) { | ||
1226 | if (videobuf_dvb_alloc_frontend( | ||
1227 | &port->frontends, i) == NULL) { | ||
1228 | printk(KERN_ERR "%s() failed to alloc\n", __func__); | ||
1229 | return -ENOMEM; | ||
1230 | } | ||
1231 | |||
1232 | fe0 = videobuf_dvb_get_frontend(&port->frontends, i); | ||
1233 | if (!fe0) | ||
1234 | err = -EINVAL; | ||
1235 | |||
1236 | dprintk(1, "%s\n", __func__); | ||
1237 | dprintk(1, " ->probed by Card=%d Name=%s, PCI %02x:%02x\n", | ||
1238 | dev->board, | ||
1239 | dev->name, | ||
1240 | dev->pci_bus, | ||
1241 | dev->pci_slot); | ||
1242 | |||
1243 | err = -ENODEV; | ||
1244 | |||
1245 | /* dvb stuff */ | ||
1246 | /* We have to init the queue for each frontend on a port. */ | ||
1247 | printk(KERN_INFO "%s: cx23885 based dvb card\n", dev->name); | ||
1248 | videobuf_queue_sg_init(&fe0->dvb.dvbq, &dvb_qops, | ||
1249 | &dev->pci->dev, &port->slock, | ||
1250 | V4L2_BUF_TYPE_VIDEO_CAPTURE, V4L2_FIELD_TOP, | ||
1251 | sizeof(struct cx23885_buffer), port, NULL); | ||
1252 | } | ||
1253 | err = dvb_register(port); | ||
1254 | if (err != 0) | ||
1255 | printk(KERN_ERR "%s() dvb_register failed err = %d\n", | ||
1256 | __func__, err); | ||
1257 | |||
1258 | return err; | ||
1259 | } | ||
1260 | |||
1261 | int cx23885_dvb_unregister(struct cx23885_tsport *port) | ||
1262 | { | ||
1263 | struct videobuf_dvb_frontend *fe0; | ||
1264 | |||
1265 | /* FIXME: in an error condition where the we have | ||
1266 | * an expected number of frontends (attach problem) | ||
1267 | * then this might not clean up correctly, if 1 | ||
1268 | * is invalid. | ||
1269 | * This comment only applies to future boards IF they | ||
1270 | * implement MFE support. | ||
1271 | */ | ||
1272 | fe0 = videobuf_dvb_get_frontend(&port->frontends, 1); | ||
1273 | if (fe0 && fe0->dvb.frontend) | ||
1274 | videobuf_dvb_unregister_bus(&port->frontends); | ||
1275 | |||
1276 | switch (port->dev->board) { | ||
1277 | case CX23885_BOARD_NETUP_DUAL_DVBS2_CI: | ||
1278 | netup_ci_exit(port); | ||
1279 | break; | ||
1280 | case CX23885_BOARD_NETUP_DUAL_DVB_T_C_CI_RF: | ||
1281 | altera_ci_release(port->dev, port->nr); | ||
1282 | break; | ||
1283 | } | ||
1284 | |||
1285 | port->gate_ctrl = NULL; | ||
1286 | |||
1287 | return 0; | ||
1288 | } | ||
1289 | |||
diff --git a/drivers/media/video/cx23885/cx23885-f300.c b/drivers/media/video/cx23885/cx23885-f300.c new file mode 100644 index 00000000000..93998f22098 --- /dev/null +++ b/drivers/media/video/cx23885/cx23885-f300.c | |||
@@ -0,0 +1,177 @@ | |||
1 | /* | ||
2 | * Driver for Silicon Labs C8051F300 microcontroller. | ||
3 | * | ||
4 | * It is used for LNB power control in TeVii S470, | ||
5 | * TBS 6920 PCIe DVB-S2 cards. | ||
6 | * | ||
7 | * Microcontroller connected to cx23885 GPIO pins: | ||
8 | * GPIO0 - data - P0.3 F300 | ||
9 | * GPIO1 - reset - P0.2 F300 | ||
10 | * GPIO2 - clk - P0.1 F300 | ||
11 | * GPIO3 - busy - P0.0 F300 | ||
12 | * | ||
13 | * Copyright (C) 2009 Igor M. Liplianin <liplianin@me.by> | ||
14 | * | ||
15 | * This program is free software; you can redistribute it and/or modify | ||
16 | * it under the terms of the GNU General Public License as published by | ||
17 | * the Free Software Foundation; either version 2 of the License, or | ||
18 | * (at your option) any later version. | ||
19 | * | ||
20 | * This program is distributed in the hope that it will be useful, | ||
21 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
22 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
23 | * | ||
24 | * GNU General Public License for more details. | ||
25 | * | ||
26 | * You should have received a copy of the GNU General Public License | ||
27 | * along with this program; if not, write to the Free Software | ||
28 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
29 | */ | ||
30 | |||
31 | #include "cx23885.h" | ||
32 | |||
33 | #define F300_DATA GPIO_0 | ||
34 | #define F300_RESET GPIO_1 | ||
35 | #define F300_CLK GPIO_2 | ||
36 | #define F300_BUSY GPIO_3 | ||
37 | |||
38 | static void f300_set_line(struct cx23885_dev *dev, u32 line, u8 lvl) | ||
39 | { | ||
40 | cx23885_gpio_enable(dev, line, 1); | ||
41 | if (lvl == 1) | ||
42 | cx23885_gpio_set(dev, line); | ||
43 | else | ||
44 | cx23885_gpio_clear(dev, line); | ||
45 | } | ||
46 | |||
47 | static u8 f300_get_line(struct cx23885_dev *dev, u32 line) | ||
48 | { | ||
49 | cx23885_gpio_enable(dev, line, 0); | ||
50 | |||
51 | return cx23885_gpio_get(dev, line); | ||
52 | } | ||
53 | |||
54 | static void f300_send_byte(struct cx23885_dev *dev, u8 dta) | ||
55 | { | ||
56 | u8 i; | ||
57 | |||
58 | for (i = 0; i < 8; i++) { | ||
59 | f300_set_line(dev, F300_CLK, 0); | ||
60 | udelay(30); | ||
61 | f300_set_line(dev, F300_DATA, (dta & 0x80) >> 7);/* msb first */ | ||
62 | udelay(30); | ||
63 | dta <<= 1; | ||
64 | f300_set_line(dev, F300_CLK, 1); | ||
65 | udelay(30); | ||
66 | } | ||
67 | } | ||
68 | |||
69 | static u8 f300_get_byte(struct cx23885_dev *dev) | ||
70 | { | ||
71 | u8 i, dta = 0; | ||
72 | |||
73 | for (i = 0; i < 8; i++) { | ||
74 | f300_set_line(dev, F300_CLK, 0); | ||
75 | udelay(30); | ||
76 | dta <<= 1; | ||
77 | f300_set_line(dev, F300_CLK, 1); | ||
78 | udelay(30); | ||
79 | dta |= f300_get_line(dev, F300_DATA);/* msb first */ | ||
80 | |||
81 | } | ||
82 | |||
83 | return dta; | ||
84 | } | ||
85 | |||
86 | static u8 f300_xfer(struct dvb_frontend *fe, u8 *buf) | ||
87 | { | ||
88 | struct cx23885_tsport *port = fe->dvb->priv; | ||
89 | struct cx23885_dev *dev = port->dev; | ||
90 | u8 i, temp, ret = 0; | ||
91 | |||
92 | temp = buf[0]; | ||
93 | for (i = 0; i < buf[0]; i++) | ||
94 | temp += buf[i + 1]; | ||
95 | temp = (~temp + 1);/* get check sum */ | ||
96 | buf[1 + buf[0]] = temp; | ||
97 | |||
98 | f300_set_line(dev, F300_RESET, 1); | ||
99 | f300_set_line(dev, F300_CLK, 1); | ||
100 | udelay(30); | ||
101 | f300_set_line(dev, F300_DATA, 1); | ||
102 | msleep(1); | ||
103 | |||
104 | /* question: */ | ||
105 | f300_set_line(dev, F300_RESET, 0);/* begin to send data */ | ||
106 | msleep(1); | ||
107 | |||
108 | f300_send_byte(dev, 0xe0);/* the slave address is 0xe0, write */ | ||
109 | msleep(1); | ||
110 | |||
111 | temp = buf[0]; | ||
112 | temp += 2; | ||
113 | for (i = 0; i < temp; i++) | ||
114 | f300_send_byte(dev, buf[i]); | ||
115 | |||
116 | f300_set_line(dev, F300_RESET, 1);/* sent data over */ | ||
117 | f300_set_line(dev, F300_DATA, 1); | ||
118 | |||
119 | /* answer: */ | ||
120 | temp = 0; | ||
121 | for (i = 0; ((i < 8) & (temp == 0)); i++) { | ||
122 | msleep(1); | ||
123 | if (f300_get_line(dev, F300_BUSY) == 0) | ||
124 | temp = 1; | ||
125 | } | ||
126 | |||
127 | if (i > 7) { | ||
128 | printk(KERN_ERR "%s: timeout, the slave no response\n", | ||
129 | __func__); | ||
130 | ret = 1; /* timeout, the slave no response */ | ||
131 | } else { /* the slave not busy, prepare for getting data */ | ||
132 | f300_set_line(dev, F300_RESET, 0);/*ready...*/ | ||
133 | msleep(1); | ||
134 | f300_send_byte(dev, 0xe1);/* 0xe1 is Read */ | ||
135 | msleep(1); | ||
136 | temp = f300_get_byte(dev);/*get the data length */ | ||
137 | if (temp > 14) | ||
138 | temp = 14; | ||
139 | |||
140 | for (i = 0; i < (temp + 1); i++) | ||
141 | f300_get_byte(dev);/* get data to empty buffer */ | ||
142 | |||
143 | f300_set_line(dev, F300_RESET, 1);/* received data over */ | ||
144 | f300_set_line(dev, F300_DATA, 1); | ||
145 | } | ||
146 | |||
147 | return ret; | ||
148 | } | ||
149 | |||
150 | int f300_set_voltage(struct dvb_frontend *fe, fe_sec_voltage_t voltage) | ||
151 | { | ||
152 | u8 buf[16]; | ||
153 | |||
154 | buf[0] = 0x05; | ||
155 | buf[1] = 0x38;/* write port */ | ||
156 | buf[2] = 0x01;/* A port, lnb power */ | ||
157 | |||
158 | switch (voltage) { | ||
159 | case SEC_VOLTAGE_13: | ||
160 | buf[3] = 0x01;/* power on */ | ||
161 | buf[4] = 0x02;/* B port, H/V */ | ||
162 | buf[5] = 0x00;/*13V v*/ | ||
163 | break; | ||
164 | case SEC_VOLTAGE_18: | ||
165 | buf[3] = 0x01; | ||
166 | buf[4] = 0x02; | ||
167 | buf[5] = 0x01;/* 18V h*/ | ||
168 | break; | ||
169 | case SEC_VOLTAGE_OFF: | ||
170 | buf[3] = 0x00;/* power off */ | ||
171 | buf[4] = 0x00; | ||
172 | buf[5] = 0x00; | ||
173 | break; | ||
174 | } | ||
175 | |||
176 | return f300_xfer(fe, buf); | ||
177 | } | ||
diff --git a/drivers/media/video/cx23885/cx23885-f300.h b/drivers/media/video/cx23885/cx23885-f300.h new file mode 100644 index 00000000000..e73344c9496 --- /dev/null +++ b/drivers/media/video/cx23885/cx23885-f300.h | |||
@@ -0,0 +1,2 @@ | |||
1 | extern int f300_set_voltage(struct dvb_frontend *fe, | ||
2 | fe_sec_voltage_t voltage); | ||
diff --git a/drivers/media/video/cx23885/cx23885-i2c.c b/drivers/media/video/cx23885/cx23885-i2c.c new file mode 100644 index 00000000000..307ff543c25 --- /dev/null +++ b/drivers/media/video/cx23885/cx23885-i2c.c | |||
@@ -0,0 +1,401 @@ | |||
1 | /* | ||
2 | * Driver for the Conexant CX23885 PCIe bridge | ||
3 | * | ||
4 | * Copyright (c) 2006 Steven Toth <stoth@linuxtv.org> | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify | ||
7 | * it under the terms of the GNU General Public License as published by | ||
8 | * the Free Software Foundation; either version 2 of the License, or | ||
9 | * (at your option) any later version. | ||
10 | * | ||
11 | * This program is distributed in the hope that it will be useful, | ||
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
14 | * | ||
15 | * GNU General Public License for more details. | ||
16 | * | ||
17 | * You should have received a copy of the GNU General Public License | ||
18 | * along with this program; if not, write to the Free Software | ||
19 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
20 | */ | ||
21 | |||
22 | #include <linux/module.h> | ||
23 | #include <linux/moduleparam.h> | ||
24 | #include <linux/init.h> | ||
25 | #include <linux/delay.h> | ||
26 | #include <asm/io.h> | ||
27 | |||
28 | #include "cx23885.h" | ||
29 | |||
30 | #include <media/v4l2-common.h> | ||
31 | |||
32 | static unsigned int i2c_debug; | ||
33 | module_param(i2c_debug, int, 0644); | ||
34 | MODULE_PARM_DESC(i2c_debug, "enable debug messages [i2c]"); | ||
35 | |||
36 | static unsigned int i2c_scan; | ||
37 | module_param(i2c_scan, int, 0444); | ||
38 | MODULE_PARM_DESC(i2c_scan, "scan i2c bus at insmod time"); | ||
39 | |||
40 | #define dprintk(level, fmt, arg...)\ | ||
41 | do { if (i2c_debug >= level)\ | ||
42 | printk(KERN_DEBUG "%s/0: " fmt, dev->name, ## arg);\ | ||
43 | } while (0) | ||
44 | |||
45 | #define I2C_WAIT_DELAY 32 | ||
46 | #define I2C_WAIT_RETRY 64 | ||
47 | |||
48 | #define I2C_EXTEND (1 << 3) | ||
49 | #define I2C_NOSTOP (1 << 4) | ||
50 | |||
51 | static inline int i2c_slave_did_ack(struct i2c_adapter *i2c_adap) | ||
52 | { | ||
53 | struct cx23885_i2c *bus = i2c_adap->algo_data; | ||
54 | struct cx23885_dev *dev = bus->dev; | ||
55 | return cx_read(bus->reg_stat) & 0x01; | ||
56 | } | ||
57 | |||
58 | static inline int i2c_is_busy(struct i2c_adapter *i2c_adap) | ||
59 | { | ||
60 | struct cx23885_i2c *bus = i2c_adap->algo_data; | ||
61 | struct cx23885_dev *dev = bus->dev; | ||
62 | return cx_read(bus->reg_stat) & 0x02 ? 1 : 0; | ||
63 | } | ||
64 | |||
65 | static int i2c_wait_done(struct i2c_adapter *i2c_adap) | ||
66 | { | ||
67 | int count; | ||
68 | |||
69 | for (count = 0; count < I2C_WAIT_RETRY; count++) { | ||
70 | if (!i2c_is_busy(i2c_adap)) | ||
71 | break; | ||
72 | udelay(I2C_WAIT_DELAY); | ||
73 | } | ||
74 | |||
75 | if (I2C_WAIT_RETRY == count) | ||
76 | return 0; | ||
77 | |||
78 | return 1; | ||
79 | } | ||
80 | |||
81 | static int i2c_sendbytes(struct i2c_adapter *i2c_adap, | ||
82 | const struct i2c_msg *msg, int joined_rlen) | ||
83 | { | ||
84 | struct cx23885_i2c *bus = i2c_adap->algo_data; | ||
85 | struct cx23885_dev *dev = bus->dev; | ||
86 | u32 wdata, addr, ctrl; | ||
87 | int retval, cnt; | ||
88 | |||
89 | if (joined_rlen) | ||
90 | dprintk(1, "%s(msg->wlen=%d, nextmsg->rlen=%d)\n", __func__, | ||
91 | msg->len, joined_rlen); | ||
92 | else | ||
93 | dprintk(1, "%s(msg->len=%d)\n", __func__, msg->len); | ||
94 | |||
95 | /* Deal with i2c probe functions with zero payload */ | ||
96 | if (msg->len == 0) { | ||
97 | cx_write(bus->reg_addr, msg->addr << 25); | ||
98 | cx_write(bus->reg_ctrl, bus->i2c_period | (1 << 2)); | ||
99 | if (!i2c_wait_done(i2c_adap)) | ||
100 | return -EIO; | ||
101 | if (!i2c_slave_did_ack(i2c_adap)) | ||
102 | return -ENXIO; | ||
103 | |||
104 | dprintk(1, "%s() returns 0\n", __func__); | ||
105 | return 0; | ||
106 | } | ||
107 | |||
108 | |||
109 | /* dev, reg + first byte */ | ||
110 | addr = (msg->addr << 25) | msg->buf[0]; | ||
111 | wdata = msg->buf[0]; | ||
112 | ctrl = bus->i2c_period | (1 << 12) | (1 << 2); | ||
113 | |||
114 | if (msg->len > 1) | ||
115 | ctrl |= I2C_NOSTOP | I2C_EXTEND; | ||
116 | else if (joined_rlen) | ||
117 | ctrl |= I2C_NOSTOP; | ||
118 | |||
119 | cx_write(bus->reg_addr, addr); | ||
120 | cx_write(bus->reg_wdata, wdata); | ||
121 | cx_write(bus->reg_ctrl, ctrl); | ||
122 | |||
123 | if (!i2c_wait_done(i2c_adap)) | ||
124 | goto eio; | ||
125 | if (i2c_debug) { | ||
126 | printk(" <W %02x %02x", msg->addr << 1, msg->buf[0]); | ||
127 | if (!(ctrl & I2C_NOSTOP)) | ||
128 | printk(" >\n"); | ||
129 | } | ||
130 | |||
131 | for (cnt = 1; cnt < msg->len; cnt++) { | ||
132 | /* following bytes */ | ||
133 | wdata = msg->buf[cnt]; | ||
134 | ctrl = bus->i2c_period | (1 << 12) | (1 << 2); | ||
135 | |||
136 | if (cnt < msg->len - 1) | ||
137 | ctrl |= I2C_NOSTOP | I2C_EXTEND; | ||
138 | else if (joined_rlen) | ||
139 | ctrl |= I2C_NOSTOP; | ||
140 | |||
141 | cx_write(bus->reg_addr, addr); | ||
142 | cx_write(bus->reg_wdata, wdata); | ||
143 | cx_write(bus->reg_ctrl, ctrl); | ||
144 | |||
145 | if (!i2c_wait_done(i2c_adap)) | ||
146 | goto eio; | ||
147 | if (i2c_debug) { | ||
148 | dprintk(1, " %02x", msg->buf[cnt]); | ||
149 | if (!(ctrl & I2C_NOSTOP)) | ||
150 | dprintk(1, " >\n"); | ||
151 | } | ||
152 | } | ||
153 | return msg->len; | ||
154 | |||
155 | eio: | ||
156 | retval = -EIO; | ||
157 | if (i2c_debug) | ||
158 | printk(KERN_ERR " ERR: %d\n", retval); | ||
159 | return retval; | ||
160 | } | ||
161 | |||
162 | static int i2c_readbytes(struct i2c_adapter *i2c_adap, | ||
163 | const struct i2c_msg *msg, int joined) | ||
164 | { | ||
165 | struct cx23885_i2c *bus = i2c_adap->algo_data; | ||
166 | struct cx23885_dev *dev = bus->dev; | ||
167 | u32 ctrl, cnt; | ||
168 | int retval; | ||
169 | |||
170 | |||
171 | if (i2c_debug && !joined) | ||
172 | dprintk(1, "%s(msg->len=%d)\n", __func__, msg->len); | ||
173 | |||
174 | /* Deal with i2c probe functions with zero payload */ | ||
175 | if (msg->len == 0) { | ||
176 | cx_write(bus->reg_addr, msg->addr << 25); | ||
177 | cx_write(bus->reg_ctrl, bus->i2c_period | (1 << 2) | 1); | ||
178 | if (!i2c_wait_done(i2c_adap)) | ||
179 | return -EIO; | ||
180 | if (!i2c_slave_did_ack(i2c_adap)) | ||
181 | return -ENXIO; | ||
182 | |||
183 | |||
184 | dprintk(1, "%s() returns 0\n", __func__); | ||
185 | return 0; | ||
186 | } | ||
187 | |||
188 | if (i2c_debug) { | ||
189 | if (joined) | ||
190 | dprintk(1, " R"); | ||
191 | else | ||
192 | dprintk(1, " <R %02x", (msg->addr << 1) + 1); | ||
193 | } | ||
194 | |||
195 | for (cnt = 0; cnt < msg->len; cnt++) { | ||
196 | |||
197 | ctrl = bus->i2c_period | (1 << 12) | (1 << 2) | 1; | ||
198 | |||
199 | if (cnt < msg->len - 1) | ||
200 | ctrl |= I2C_NOSTOP | I2C_EXTEND; | ||
201 | |||
202 | cx_write(bus->reg_addr, msg->addr << 25); | ||
203 | cx_write(bus->reg_ctrl, ctrl); | ||
204 | |||
205 | if (!i2c_wait_done(i2c_adap)) | ||
206 | goto eio; | ||
207 | msg->buf[cnt] = cx_read(bus->reg_rdata) & 0xff; | ||
208 | if (i2c_debug) { | ||
209 | dprintk(1, " %02x", msg->buf[cnt]); | ||
210 | if (!(ctrl & I2C_NOSTOP)) | ||
211 | dprintk(1, " >\n"); | ||
212 | } | ||
213 | } | ||
214 | return msg->len; | ||
215 | |||
216 | eio: | ||
217 | retval = -EIO; | ||
218 | if (i2c_debug) | ||
219 | printk(KERN_ERR " ERR: %d\n", retval); | ||
220 | return retval; | ||
221 | } | ||
222 | |||
223 | static int i2c_xfer(struct i2c_adapter *i2c_adap, | ||
224 | struct i2c_msg *msgs, int num) | ||
225 | { | ||
226 | struct cx23885_i2c *bus = i2c_adap->algo_data; | ||
227 | struct cx23885_dev *dev = bus->dev; | ||
228 | int i, retval = 0; | ||
229 | |||
230 | dprintk(1, "%s(num = %d)\n", __func__, num); | ||
231 | |||
232 | for (i = 0 ; i < num; i++) { | ||
233 | dprintk(1, "%s(num = %d) addr = 0x%02x len = 0x%x\n", | ||
234 | __func__, num, msgs[i].addr, msgs[i].len); | ||
235 | if (msgs[i].flags & I2C_M_RD) { | ||
236 | /* read */ | ||
237 | retval = i2c_readbytes(i2c_adap, &msgs[i], 0); | ||
238 | } else if (i + 1 < num && (msgs[i + 1].flags & I2C_M_RD) && | ||
239 | msgs[i].addr == msgs[i + 1].addr) { | ||
240 | /* write then read from same address */ | ||
241 | retval = i2c_sendbytes(i2c_adap, &msgs[i], | ||
242 | msgs[i + 1].len); | ||
243 | if (retval < 0) | ||
244 | goto err; | ||
245 | i++; | ||
246 | retval = i2c_readbytes(i2c_adap, &msgs[i], 1); | ||
247 | } else { | ||
248 | /* write */ | ||
249 | retval = i2c_sendbytes(i2c_adap, &msgs[i], 0); | ||
250 | } | ||
251 | if (retval < 0) | ||
252 | goto err; | ||
253 | } | ||
254 | return num; | ||
255 | |||
256 | err: | ||
257 | return retval; | ||
258 | } | ||
259 | |||
260 | static u32 cx23885_functionality(struct i2c_adapter *adap) | ||
261 | { | ||
262 | return I2C_FUNC_SMBUS_EMUL | I2C_FUNC_I2C; | ||
263 | } | ||
264 | |||
265 | static struct i2c_algorithm cx23885_i2c_algo_template = { | ||
266 | .master_xfer = i2c_xfer, | ||
267 | .functionality = cx23885_functionality, | ||
268 | }; | ||
269 | |||
270 | /* ----------------------------------------------------------------------- */ | ||
271 | |||
272 | static struct i2c_adapter cx23885_i2c_adap_template = { | ||
273 | .name = "cx23885", | ||
274 | .owner = THIS_MODULE, | ||
275 | .algo = &cx23885_i2c_algo_template, | ||
276 | }; | ||
277 | |||
278 | static struct i2c_client cx23885_i2c_client_template = { | ||
279 | .name = "cx23885 internal", | ||
280 | }; | ||
281 | |||
282 | static char *i2c_devs[128] = { | ||
283 | [0x10 >> 1] = "tda10048", | ||
284 | [0x12 >> 1] = "dib7000pc", | ||
285 | [0x1c >> 1] = "lgdt3303", | ||
286 | [0x86 >> 1] = "tda9887", | ||
287 | [0x32 >> 1] = "cx24227", | ||
288 | [0x88 >> 1] = "cx25837", | ||
289 | [0x84 >> 1] = "tda8295", | ||
290 | [0xa0 >> 1] = "eeprom", | ||
291 | [0xc0 >> 1] = "tuner/mt2131/tda8275", | ||
292 | [0xc2 >> 1] = "tuner/mt2131/tda8275/xc5000/xc3028", | ||
293 | [0xc8 >> 1] = "tuner/xc3028L", | ||
294 | }; | ||
295 | |||
296 | static void do_i2c_scan(char *name, struct i2c_client *c) | ||
297 | { | ||
298 | unsigned char buf; | ||
299 | int i, rc; | ||
300 | |||
301 | for (i = 0; i < 128; i++) { | ||
302 | c->addr = i; | ||
303 | rc = i2c_master_recv(c, &buf, 0); | ||
304 | if (rc < 0) | ||
305 | continue; | ||
306 | printk(KERN_INFO "%s: i2c scan: found device @ 0x%x [%s]\n", | ||
307 | name, i << 1, i2c_devs[i] ? i2c_devs[i] : "???"); | ||
308 | } | ||
309 | } | ||
310 | |||
311 | /* init + register i2c algo-bit adapter */ | ||
312 | int cx23885_i2c_register(struct cx23885_i2c *bus) | ||
313 | { | ||
314 | struct cx23885_dev *dev = bus->dev; | ||
315 | |||
316 | dprintk(1, "%s(bus = %d)\n", __func__, bus->nr); | ||
317 | |||
318 | memcpy(&bus->i2c_adap, &cx23885_i2c_adap_template, | ||
319 | sizeof(bus->i2c_adap)); | ||
320 | memcpy(&bus->i2c_algo, &cx23885_i2c_algo_template, | ||
321 | sizeof(bus->i2c_algo)); | ||
322 | memcpy(&bus->i2c_client, &cx23885_i2c_client_template, | ||
323 | sizeof(bus->i2c_client)); | ||
324 | |||
325 | bus->i2c_adap.dev.parent = &dev->pci->dev; | ||
326 | |||
327 | strlcpy(bus->i2c_adap.name, bus->dev->name, | ||
328 | sizeof(bus->i2c_adap.name)); | ||
329 | |||
330 | bus->i2c_algo.data = bus; | ||
331 | bus->i2c_adap.algo_data = bus; | ||
332 | i2c_set_adapdata(&bus->i2c_adap, &dev->v4l2_dev); | ||
333 | i2c_add_adapter(&bus->i2c_adap); | ||
334 | |||
335 | bus->i2c_client.adapter = &bus->i2c_adap; | ||
336 | |||
337 | if (0 == bus->i2c_rc) { | ||
338 | dprintk(1, "%s: i2c bus %d registered\n", dev->name, bus->nr); | ||
339 | if (i2c_scan) { | ||
340 | printk(KERN_INFO "%s: scan bus %d:\n", | ||
341 | dev->name, bus->nr); | ||
342 | do_i2c_scan(dev->name, &bus->i2c_client); | ||
343 | } | ||
344 | } else | ||
345 | printk(KERN_WARNING "%s: i2c bus %d register FAILED\n", | ||
346 | dev->name, bus->nr); | ||
347 | |||
348 | /* Instantiate the IR receiver device, if present */ | ||
349 | if (0 == bus->i2c_rc) { | ||
350 | struct i2c_board_info info; | ||
351 | const unsigned short addr_list[] = { | ||
352 | 0x6b, I2C_CLIENT_END | ||
353 | }; | ||
354 | |||
355 | memset(&info, 0, sizeof(struct i2c_board_info)); | ||
356 | strlcpy(info.type, "ir_video", I2C_NAME_SIZE); | ||
357 | /* Use quick read command for probe, some IR chips don't | ||
358 | * support writes */ | ||
359 | i2c_new_probed_device(&bus->i2c_adap, &info, addr_list, | ||
360 | i2c_probe_func_quick_read); | ||
361 | } | ||
362 | |||
363 | return bus->i2c_rc; | ||
364 | } | ||
365 | |||
366 | int cx23885_i2c_unregister(struct cx23885_i2c *bus) | ||
367 | { | ||
368 | i2c_del_adapter(&bus->i2c_adap); | ||
369 | return 0; | ||
370 | } | ||
371 | |||
372 | void cx23885_av_clk(struct cx23885_dev *dev, int enable) | ||
373 | { | ||
374 | /* write 0 to bus 2 addr 0x144 via i2x_xfer() */ | ||
375 | char buffer[3]; | ||
376 | struct i2c_msg msg; | ||
377 | dprintk(1, "%s(enabled = %d)\n", __func__, enable); | ||
378 | |||
379 | /* Register 0x144 */ | ||
380 | buffer[0] = 0x01; | ||
381 | buffer[1] = 0x44; | ||
382 | if (enable == 1) | ||
383 | buffer[2] = 0x05; | ||
384 | else | ||
385 | buffer[2] = 0x00; | ||
386 | |||
387 | msg.addr = 0x44; | ||
388 | msg.flags = I2C_M_TEN; | ||
389 | msg.len = 3; | ||
390 | msg.buf = buffer; | ||
391 | |||
392 | i2c_xfer(&dev->i2c_bus[2].i2c_adap, &msg, 1); | ||
393 | } | ||
394 | |||
395 | /* ----------------------------------------------------------------------- */ | ||
396 | |||
397 | /* | ||
398 | * Local variables: | ||
399 | * c-basic-offset: 8 | ||
400 | * End: | ||
401 | */ | ||
diff --git a/drivers/media/video/cx23885/cx23885-input.c b/drivers/media/video/cx23885/cx23885-input.c new file mode 100644 index 00000000000..ce765e3f77b --- /dev/null +++ b/drivers/media/video/cx23885/cx23885-input.c | |||
@@ -0,0 +1,356 @@ | |||
1 | /* | ||
2 | * Driver for the Conexant CX23885/7/8 PCIe bridge | ||
3 | * | ||
4 | * Infrared remote control input device | ||
5 | * | ||
6 | * Most of this file is | ||
7 | * | ||
8 | * Copyright (C) 2009 Andy Walls <awalls@md.metrocast.net> | ||
9 | * | ||
10 | * However, the cx23885_input_{init,fini} functions contained herein are | ||
11 | * derived from Linux kernel files linux/media/video/.../...-input.c marked as: | ||
12 | * | ||
13 | * Copyright (C) 2008 <srinivasa.deevi at conexant dot com> | ||
14 | * Copyright (C) 2005 Ludovico Cavedon <cavedon@sssup.it> | ||
15 | * Markus Rechberger <mrechberger@gmail.com> | ||
16 | * Mauro Carvalho Chehab <mchehab@infradead.org> | ||
17 | * Sascha Sommer <saschasommer@freenet.de> | ||
18 | * Copyright (C) 2004, 2005 Chris Pascoe | ||
19 | * Copyright (C) 2003, 2004 Gerd Knorr | ||
20 | * Copyright (C) 2003 Pavel Machek | ||
21 | * | ||
22 | * This program is free software; you can redistribute it and/or | ||
23 | * modify it under the terms of the GNU General Public License | ||
24 | * as published by the Free Software Foundation; either version 2 | ||
25 | * of the License, or (at your option) any later version. | ||
26 | * | ||
27 | * This program is distributed in the hope that it will be useful, | ||
28 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
29 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
30 | * GNU General Public License for more details. | ||
31 | * | ||
32 | * You should have received a copy of the GNU General Public License | ||
33 | * along with this program; if not, write to the Free Software | ||
34 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA | ||
35 | * 02110-1301, USA. | ||
36 | */ | ||
37 | |||
38 | #include <linux/slab.h> | ||
39 | #include <media/rc-core.h> | ||
40 | #include <media/v4l2-subdev.h> | ||
41 | |||
42 | #include "cx23885.h" | ||
43 | |||
44 | #define MODULE_NAME "cx23885" | ||
45 | |||
46 | static void cx23885_input_process_measurements(struct cx23885_dev *dev, | ||
47 | bool overrun) | ||
48 | { | ||
49 | struct cx23885_kernel_ir *kernel_ir = dev->kernel_ir; | ||
50 | |||
51 | ssize_t num; | ||
52 | int count, i; | ||
53 | bool handle = false; | ||
54 | struct ir_raw_event ir_core_event[64]; | ||
55 | |||
56 | do { | ||
57 | num = 0; | ||
58 | v4l2_subdev_call(dev->sd_ir, ir, rx_read, (u8 *) ir_core_event, | ||
59 | sizeof(ir_core_event), &num); | ||
60 | |||
61 | count = num / sizeof(struct ir_raw_event); | ||
62 | |||
63 | for (i = 0; i < count; i++) { | ||
64 | ir_raw_event_store(kernel_ir->rc, | ||
65 | &ir_core_event[i]); | ||
66 | handle = true; | ||
67 | } | ||
68 | } while (num != 0); | ||
69 | |||
70 | if (overrun) | ||
71 | ir_raw_event_reset(kernel_ir->rc); | ||
72 | else if (handle) | ||
73 | ir_raw_event_handle(kernel_ir->rc); | ||
74 | } | ||
75 | |||
76 | void cx23885_input_rx_work_handler(struct cx23885_dev *dev, u32 events) | ||
77 | { | ||
78 | struct v4l2_subdev_ir_parameters params; | ||
79 | int overrun, data_available; | ||
80 | |||
81 | if (dev->sd_ir == NULL || events == 0) | ||
82 | return; | ||
83 | |||
84 | switch (dev->board) { | ||
85 | case CX23885_BOARD_HAUPPAUGE_HVR1270: | ||
86 | case CX23885_BOARD_HAUPPAUGE_HVR1850: | ||
87 | case CX23885_BOARD_HAUPPAUGE_HVR1290: | ||
88 | case CX23885_BOARD_TEVII_S470: | ||
89 | case CX23885_BOARD_HAUPPAUGE_HVR1250: | ||
90 | /* | ||
91 | * The only boards we handle right now. However other boards | ||
92 | * using the CX2388x integrated IR controller should be similar | ||
93 | */ | ||
94 | break; | ||
95 | default: | ||
96 | return; | ||
97 | } | ||
98 | |||
99 | overrun = events & (V4L2_SUBDEV_IR_RX_SW_FIFO_OVERRUN | | ||
100 | V4L2_SUBDEV_IR_RX_HW_FIFO_OVERRUN); | ||
101 | |||
102 | data_available = events & (V4L2_SUBDEV_IR_RX_END_OF_RX_DETECTED | | ||
103 | V4L2_SUBDEV_IR_RX_FIFO_SERVICE_REQ); | ||
104 | |||
105 | if (overrun) { | ||
106 | /* If there was a FIFO overrun, stop the device */ | ||
107 | v4l2_subdev_call(dev->sd_ir, ir, rx_g_parameters, ¶ms); | ||
108 | params.enable = false; | ||
109 | /* Mitigate race with cx23885_input_ir_stop() */ | ||
110 | params.shutdown = atomic_read(&dev->ir_input_stopping); | ||
111 | v4l2_subdev_call(dev->sd_ir, ir, rx_s_parameters, ¶ms); | ||
112 | } | ||
113 | |||
114 | if (data_available) | ||
115 | cx23885_input_process_measurements(dev, overrun); | ||
116 | |||
117 | if (overrun) { | ||
118 | /* If there was a FIFO overrun, clear & restart the device */ | ||
119 | params.enable = true; | ||
120 | /* Mitigate race with cx23885_input_ir_stop() */ | ||
121 | params.shutdown = atomic_read(&dev->ir_input_stopping); | ||
122 | v4l2_subdev_call(dev->sd_ir, ir, rx_s_parameters, ¶ms); | ||
123 | } | ||
124 | } | ||
125 | |||
126 | static int cx23885_input_ir_start(struct cx23885_dev *dev) | ||
127 | { | ||
128 | struct v4l2_subdev_ir_parameters params; | ||
129 | |||
130 | if (dev->sd_ir == NULL) | ||
131 | return -ENODEV; | ||
132 | |||
133 | atomic_set(&dev->ir_input_stopping, 0); | ||
134 | |||
135 | v4l2_subdev_call(dev->sd_ir, ir, rx_g_parameters, ¶ms); | ||
136 | switch (dev->board) { | ||
137 | case CX23885_BOARD_HAUPPAUGE_HVR1270: | ||
138 | case CX23885_BOARD_HAUPPAUGE_HVR1850: | ||
139 | case CX23885_BOARD_HAUPPAUGE_HVR1290: | ||
140 | case CX23885_BOARD_HAUPPAUGE_HVR1250: | ||
141 | /* | ||
142 | * The IR controller on this board only returns pulse widths. | ||
143 | * Any other mode setting will fail to set up the device. | ||
144 | */ | ||
145 | params.mode = V4L2_SUBDEV_IR_MODE_PULSE_WIDTH; | ||
146 | params.enable = true; | ||
147 | params.interrupt_enable = true; | ||
148 | params.shutdown = false; | ||
149 | |||
150 | /* Setup for baseband compatible with both RC-5 and RC-6A */ | ||
151 | params.modulation = false; | ||
152 | /* RC-5: 2,222,222 ns = 1/36 kHz * 32 cycles * 2 marks * 1.25*/ | ||
153 | /* RC-6A: 3,333,333 ns = 1/36 kHz * 16 cycles * 6 marks * 1.25*/ | ||
154 | params.max_pulse_width = 3333333; /* ns */ | ||
155 | /* RC-5: 666,667 ns = 1/36 kHz * 32 cycles * 1 mark * 0.75 */ | ||
156 | /* RC-6A: 333,333 ns = 1/36 kHz * 16 cycles * 1 mark * 0.75 */ | ||
157 | params.noise_filter_min_width = 333333; /* ns */ | ||
158 | /* | ||
159 | * This board has inverted receive sense: | ||
160 | * mark is received as low logic level; | ||
161 | * falling edges are detected as rising edges; etc. | ||
162 | */ | ||
163 | params.invert_level = true; | ||
164 | break; | ||
165 | case CX23885_BOARD_TEVII_S470: | ||
166 | /* | ||
167 | * The IR controller on this board only returns pulse widths. | ||
168 | * Any other mode setting will fail to set up the device. | ||
169 | */ | ||
170 | params.mode = V4L2_SUBDEV_IR_MODE_PULSE_WIDTH; | ||
171 | params.enable = true; | ||
172 | params.interrupt_enable = true; | ||
173 | params.shutdown = false; | ||
174 | |||
175 | /* Setup for a standard NEC protocol */ | ||
176 | params.carrier_freq = 37917; /* Hz, 455 kHz/12 for NEC */ | ||
177 | params.carrier_range_lower = 33000; /* Hz */ | ||
178 | params.carrier_range_upper = 43000; /* Hz */ | ||
179 | params.duty_cycle = 33; /* percent, 33 percent for NEC */ | ||
180 | |||
181 | /* | ||
182 | * NEC max pulse width: (64/3)/(455 kHz/12) * 16 nec_units | ||
183 | * (64/3)/(455 kHz/12) * 16 nec_units * 1.375 = 12378022 ns | ||
184 | */ | ||
185 | params.max_pulse_width = 12378022; /* ns */ | ||
186 | |||
187 | /* | ||
188 | * NEC noise filter min width: (64/3)/(455 kHz/12) * 1 nec_unit | ||
189 | * (64/3)/(455 kHz/12) * 1 nec_units * 0.625 = 351648 ns | ||
190 | */ | ||
191 | params.noise_filter_min_width = 351648; /* ns */ | ||
192 | |||
193 | params.modulation = false; | ||
194 | params.invert_level = true; | ||
195 | break; | ||
196 | } | ||
197 | v4l2_subdev_call(dev->sd_ir, ir, rx_s_parameters, ¶ms); | ||
198 | return 0; | ||
199 | } | ||
200 | |||
201 | static int cx23885_input_ir_open(struct rc_dev *rc) | ||
202 | { | ||
203 | struct cx23885_kernel_ir *kernel_ir = rc->priv; | ||
204 | |||
205 | if (kernel_ir->cx == NULL) | ||
206 | return -ENODEV; | ||
207 | |||
208 | return cx23885_input_ir_start(kernel_ir->cx); | ||
209 | } | ||
210 | |||
211 | static void cx23885_input_ir_stop(struct cx23885_dev *dev) | ||
212 | { | ||
213 | struct v4l2_subdev_ir_parameters params; | ||
214 | |||
215 | if (dev->sd_ir == NULL) | ||
216 | return; | ||
217 | |||
218 | /* | ||
219 | * Stop the sd_ir subdevice from generating notifications and | ||
220 | * scheduling work. | ||
221 | * It is shutdown this way in order to mitigate a race with | ||
222 | * cx23885_input_rx_work_handler() in the overrun case, which could | ||
223 | * re-enable the subdevice. | ||
224 | */ | ||
225 | atomic_set(&dev->ir_input_stopping, 1); | ||
226 | v4l2_subdev_call(dev->sd_ir, ir, rx_g_parameters, ¶ms); | ||
227 | while (params.shutdown == false) { | ||
228 | params.enable = false; | ||
229 | params.interrupt_enable = false; | ||
230 | params.shutdown = true; | ||
231 | v4l2_subdev_call(dev->sd_ir, ir, rx_s_parameters, ¶ms); | ||
232 | v4l2_subdev_call(dev->sd_ir, ir, rx_g_parameters, ¶ms); | ||
233 | } | ||
234 | flush_work_sync(&dev->cx25840_work); | ||
235 | flush_work_sync(&dev->ir_rx_work); | ||
236 | flush_work_sync(&dev->ir_tx_work); | ||
237 | } | ||
238 | |||
239 | static void cx23885_input_ir_close(struct rc_dev *rc) | ||
240 | { | ||
241 | struct cx23885_kernel_ir *kernel_ir = rc->priv; | ||
242 | |||
243 | if (kernel_ir->cx != NULL) | ||
244 | cx23885_input_ir_stop(kernel_ir->cx); | ||
245 | } | ||
246 | |||
247 | int cx23885_input_init(struct cx23885_dev *dev) | ||
248 | { | ||
249 | struct cx23885_kernel_ir *kernel_ir; | ||
250 | struct rc_dev *rc; | ||
251 | char *rc_map; | ||
252 | enum rc_driver_type driver_type; | ||
253 | unsigned long allowed_protos; | ||
254 | |||
255 | int ret; | ||
256 | |||
257 | /* | ||
258 | * If the IR device (hardware registers, chip, GPIO lines, etc.) isn't | ||
259 | * encapsulated in a v4l2_subdev, then I'm not going to deal with it. | ||
260 | */ | ||
261 | if (dev->sd_ir == NULL) | ||
262 | return -ENODEV; | ||
263 | |||
264 | switch (dev->board) { | ||
265 | case CX23885_BOARD_HAUPPAUGE_HVR1270: | ||
266 | case CX23885_BOARD_HAUPPAUGE_HVR1850: | ||
267 | case CX23885_BOARD_HAUPPAUGE_HVR1290: | ||
268 | case CX23885_BOARD_HAUPPAUGE_HVR1250: | ||
269 | /* Integrated CX2388[58] IR controller */ | ||
270 | driver_type = RC_DRIVER_IR_RAW; | ||
271 | allowed_protos = RC_TYPE_ALL; | ||
272 | /* The grey Hauppauge RC-5 remote */ | ||
273 | rc_map = RC_MAP_HAUPPAUGE; | ||
274 | break; | ||
275 | case CX23885_BOARD_TEVII_S470: | ||
276 | /* Integrated CX23885 IR controller */ | ||
277 | driver_type = RC_DRIVER_IR_RAW; | ||
278 | allowed_protos = RC_TYPE_ALL; | ||
279 | /* A guess at the remote */ | ||
280 | rc_map = RC_MAP_TEVII_NEC; | ||
281 | break; | ||
282 | default: | ||
283 | return -ENODEV; | ||
284 | } | ||
285 | |||
286 | /* cx23885 board instance kernel IR state */ | ||
287 | kernel_ir = kzalloc(sizeof(struct cx23885_kernel_ir), GFP_KERNEL); | ||
288 | if (kernel_ir == NULL) | ||
289 | return -ENOMEM; | ||
290 | |||
291 | kernel_ir->cx = dev; | ||
292 | kernel_ir->name = kasprintf(GFP_KERNEL, "cx23885 IR (%s)", | ||
293 | cx23885_boards[dev->board].name); | ||
294 | kernel_ir->phys = kasprintf(GFP_KERNEL, "pci-%s/ir0", | ||
295 | pci_name(dev->pci)); | ||
296 | |||
297 | /* input device */ | ||
298 | rc = rc_allocate_device(); | ||
299 | if (!rc) { | ||
300 | ret = -ENOMEM; | ||
301 | goto err_out_free; | ||
302 | } | ||
303 | |||
304 | kernel_ir->rc = rc; | ||
305 | rc->input_name = kernel_ir->name; | ||
306 | rc->input_phys = kernel_ir->phys; | ||
307 | rc->input_id.bustype = BUS_PCI; | ||
308 | rc->input_id.version = 1; | ||
309 | if (dev->pci->subsystem_vendor) { | ||
310 | rc->input_id.vendor = dev->pci->subsystem_vendor; | ||
311 | rc->input_id.product = dev->pci->subsystem_device; | ||
312 | } else { | ||
313 | rc->input_id.vendor = dev->pci->vendor; | ||
314 | rc->input_id.product = dev->pci->device; | ||
315 | } | ||
316 | rc->dev.parent = &dev->pci->dev; | ||
317 | rc->driver_type = driver_type; | ||
318 | rc->allowed_protos = allowed_protos; | ||
319 | rc->priv = kernel_ir; | ||
320 | rc->open = cx23885_input_ir_open; | ||
321 | rc->close = cx23885_input_ir_close; | ||
322 | rc->map_name = rc_map; | ||
323 | rc->driver_name = MODULE_NAME; | ||
324 | |||
325 | /* Go */ | ||
326 | dev->kernel_ir = kernel_ir; | ||
327 | ret = rc_register_device(rc); | ||
328 | if (ret) | ||
329 | goto err_out_stop; | ||
330 | |||
331 | return 0; | ||
332 | |||
333 | err_out_stop: | ||
334 | cx23885_input_ir_stop(dev); | ||
335 | dev->kernel_ir = NULL; | ||
336 | rc_free_device(rc); | ||
337 | err_out_free: | ||
338 | kfree(kernel_ir->phys); | ||
339 | kfree(kernel_ir->name); | ||
340 | kfree(kernel_ir); | ||
341 | return ret; | ||
342 | } | ||
343 | |||
344 | void cx23885_input_fini(struct cx23885_dev *dev) | ||
345 | { | ||
346 | /* Always stop the IR hardware from generating interrupts */ | ||
347 | cx23885_input_ir_stop(dev); | ||
348 | |||
349 | if (dev->kernel_ir == NULL) | ||
350 | return; | ||
351 | rc_unregister_device(dev->kernel_ir->rc); | ||
352 | kfree(dev->kernel_ir->phys); | ||
353 | kfree(dev->kernel_ir->name); | ||
354 | kfree(dev->kernel_ir); | ||
355 | dev->kernel_ir = NULL; | ||
356 | } | ||
diff --git a/drivers/media/video/cx23885/cx23885-input.h b/drivers/media/video/cx23885/cx23885-input.h new file mode 100644 index 00000000000..75ef15d3f52 --- /dev/null +++ b/drivers/media/video/cx23885/cx23885-input.h | |||
@@ -0,0 +1,30 @@ | |||
1 | /* | ||
2 | * Driver for the Conexant CX23885/7/8 PCIe bridge | ||
3 | * | ||
4 | * Infrared remote control input device | ||
5 | * | ||
6 | * Copyright (C) 2009 Andy Walls <awalls@md.metrocast.net> | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or | ||
9 | * modify it under the terms of the GNU General Public License | ||
10 | * as published by the Free Software Foundation; either version 2 | ||
11 | * of the License, or (at your option) any later version. | ||
12 | * | ||
13 | * This program is distributed in the hope that it will be useful, | ||
14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
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., 51 Franklin Street, Fifth Floor, Boston, MA | ||
21 | * 02110-1301, USA. | ||
22 | */ | ||
23 | |||
24 | #ifndef _CX23885_INPUT_H_ | ||
25 | #define _CX23885_INPUT_H_ | ||
26 | int cx23885_input_rx_work_handler(struct cx23885_dev *dev, u32 events); | ||
27 | |||
28 | int cx23885_input_init(struct cx23885_dev *dev); | ||
29 | void cx23885_input_fini(struct cx23885_dev *dev); | ||
30 | #endif | ||
diff --git a/drivers/media/video/cx23885/cx23885-ioctl.c b/drivers/media/video/cx23885/cx23885-ioctl.c new file mode 100644 index 00000000000..44812ca7889 --- /dev/null +++ b/drivers/media/video/cx23885/cx23885-ioctl.c | |||
@@ -0,0 +1,208 @@ | |||
1 | /* | ||
2 | * Driver for the Conexant CX23885/7/8 PCIe bridge | ||
3 | * | ||
4 | * Various common ioctl() support functions | ||
5 | * | ||
6 | * Copyright (c) 2009 Andy Walls <awalls@md.metrocast.net> | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or modify | ||
9 | * it under the terms of the GNU General Public License as published by | ||
10 | * the Free Software Foundation; either version 2 of the License, or | ||
11 | * (at your option) any later version. | ||
12 | * | ||
13 | * This program is distributed in the hope that it will be useful, | ||
14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
16 | * | ||
17 | * GNU General Public License for more details. | ||
18 | * | ||
19 | * You should have received a copy of the GNU General Public License | ||
20 | * along with this program; if not, write to the Free Software | ||
21 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
22 | */ | ||
23 | |||
24 | #include "cx23885.h" | ||
25 | #include <media/v4l2-chip-ident.h> | ||
26 | |||
27 | int cx23885_g_chip_ident(struct file *file, void *fh, | ||
28 | struct v4l2_dbg_chip_ident *chip) | ||
29 | { | ||
30 | struct cx23885_dev *dev = ((struct cx23885_fh *)fh)->dev; | ||
31 | int err = 0; | ||
32 | u8 rev; | ||
33 | |||
34 | chip->ident = V4L2_IDENT_NONE; | ||
35 | chip->revision = 0; | ||
36 | switch (chip->match.type) { | ||
37 | case V4L2_CHIP_MATCH_HOST: | ||
38 | switch (chip->match.addr) { | ||
39 | case 0: | ||
40 | rev = cx_read(RDR_CFG2) & 0xff; | ||
41 | switch (dev->pci->device) { | ||
42 | case 0x8852: | ||
43 | /* rev 0x04 could be '885 or '888. Pick '888. */ | ||
44 | if (rev == 0x04) | ||
45 | chip->ident = V4L2_IDENT_CX23888; | ||
46 | else | ||
47 | chip->ident = V4L2_IDENT_CX23885; | ||
48 | break; | ||
49 | case 0x8880: | ||
50 | if (rev == 0x0e || rev == 0x0f) | ||
51 | chip->ident = V4L2_IDENT_CX23887; | ||
52 | else | ||
53 | chip->ident = V4L2_IDENT_CX23888; | ||
54 | break; | ||
55 | default: | ||
56 | chip->ident = V4L2_IDENT_UNKNOWN; | ||
57 | break; | ||
58 | } | ||
59 | chip->revision = (dev->pci->device << 16) | (rev << 8) | | ||
60 | (dev->hwrevision & 0xff); | ||
61 | break; | ||
62 | case 1: | ||
63 | if (dev->v4l_device != NULL) { | ||
64 | chip->ident = V4L2_IDENT_CX23417; | ||
65 | chip->revision = 0; | ||
66 | } | ||
67 | break; | ||
68 | case 2: | ||
69 | /* | ||
70 | * The integrated IR controller on the CX23888 is | ||
71 | * host chip 2. It may not be used/initialized or sd_ir | ||
72 | * may be pointing at the cx25840 subdevice for the | ||
73 | * IR controller on the CX23885. Thus we find it | ||
74 | * without using the dev->sd_ir pointer. | ||
75 | */ | ||
76 | call_hw(dev, CX23885_HW_888_IR, core, g_chip_ident, | ||
77 | chip); | ||
78 | break; | ||
79 | default: | ||
80 | err = -EINVAL; /* per V4L2 spec */ | ||
81 | break; | ||
82 | } | ||
83 | break; | ||
84 | case V4L2_CHIP_MATCH_I2C_DRIVER: | ||
85 | /* If needed, returns V4L2_IDENT_AMBIGUOUS without extra work */ | ||
86 | call_all(dev, core, g_chip_ident, chip); | ||
87 | break; | ||
88 | case V4L2_CHIP_MATCH_I2C_ADDR: | ||
89 | /* | ||
90 | * We could return V4L2_IDENT_UNKNOWN, but we don't do the work | ||
91 | * to look if a chip is at the address with no driver. That's a | ||
92 | * dangerous thing to do with EEPROMs anyway. | ||
93 | */ | ||
94 | call_all(dev, core, g_chip_ident, chip); | ||
95 | break; | ||
96 | default: | ||
97 | err = -EINVAL; | ||
98 | break; | ||
99 | } | ||
100 | return err; | ||
101 | } | ||
102 | |||
103 | #ifdef CONFIG_VIDEO_ADV_DEBUG | ||
104 | static int cx23885_g_host_register(struct cx23885_dev *dev, | ||
105 | struct v4l2_dbg_register *reg) | ||
106 | { | ||
107 | if ((reg->reg & 0x3) != 0 || reg->reg >= pci_resource_len(dev->pci, 0)) | ||
108 | return -EINVAL; | ||
109 | |||
110 | reg->size = 4; | ||
111 | reg->val = cx_read(reg->reg); | ||
112 | return 0; | ||
113 | } | ||
114 | |||
115 | static int cx23417_g_register(struct cx23885_dev *dev, | ||
116 | struct v4l2_dbg_register *reg) | ||
117 | { | ||
118 | u32 value; | ||
119 | |||
120 | if (dev->v4l_device == NULL) | ||
121 | return -EINVAL; | ||
122 | |||
123 | if ((reg->reg & 0x3) != 0 || reg->reg >= 0x10000) | ||
124 | return -EINVAL; | ||
125 | |||
126 | if (mc417_register_read(dev, (u16) reg->reg, &value)) | ||
127 | return -EINVAL; /* V4L2 spec, but -EREMOTEIO really */ | ||
128 | |||
129 | reg->size = 4; | ||
130 | reg->val = value; | ||
131 | return 0; | ||
132 | } | ||
133 | |||
134 | int cx23885_g_register(struct file *file, void *fh, | ||
135 | struct v4l2_dbg_register *reg) | ||
136 | { | ||
137 | struct cx23885_dev *dev = ((struct cx23885_fh *)fh)->dev; | ||
138 | |||
139 | if (!capable(CAP_SYS_ADMIN)) | ||
140 | return -EPERM; | ||
141 | |||
142 | if (reg->match.type == V4L2_CHIP_MATCH_HOST) { | ||
143 | switch (reg->match.addr) { | ||
144 | case 0: | ||
145 | return cx23885_g_host_register(dev, reg); | ||
146 | case 1: | ||
147 | return cx23417_g_register(dev, reg); | ||
148 | default: | ||
149 | break; | ||
150 | } | ||
151 | } | ||
152 | |||
153 | /* FIXME - any error returns should not be ignored */ | ||
154 | call_all(dev, core, g_register, reg); | ||
155 | return 0; | ||
156 | } | ||
157 | |||
158 | static int cx23885_s_host_register(struct cx23885_dev *dev, | ||
159 | struct v4l2_dbg_register *reg) | ||
160 | { | ||
161 | if ((reg->reg & 0x3) != 0 || reg->reg >= pci_resource_len(dev->pci, 0)) | ||
162 | return -EINVAL; | ||
163 | |||
164 | reg->size = 4; | ||
165 | cx_write(reg->reg, reg->val); | ||
166 | return 0; | ||
167 | } | ||
168 | |||
169 | static int cx23417_s_register(struct cx23885_dev *dev, | ||
170 | struct v4l2_dbg_register *reg) | ||
171 | { | ||
172 | if (dev->v4l_device == NULL) | ||
173 | return -EINVAL; | ||
174 | |||
175 | if ((reg->reg & 0x3) != 0 || reg->reg >= 0x10000) | ||
176 | return -EINVAL; | ||
177 | |||
178 | if (mc417_register_write(dev, (u16) reg->reg, (u32) reg->val)) | ||
179 | return -EINVAL; /* V4L2 spec, but -EREMOTEIO really */ | ||
180 | |||
181 | reg->size = 4; | ||
182 | return 0; | ||
183 | } | ||
184 | |||
185 | int cx23885_s_register(struct file *file, void *fh, | ||
186 | struct v4l2_dbg_register *reg) | ||
187 | { | ||
188 | struct cx23885_dev *dev = ((struct cx23885_fh *)fh)->dev; | ||
189 | |||
190 | if (!capable(CAP_SYS_ADMIN)) | ||
191 | return -EPERM; | ||
192 | |||
193 | if (reg->match.type == V4L2_CHIP_MATCH_HOST) { | ||
194 | switch (reg->match.addr) { | ||
195 | case 0: | ||
196 | return cx23885_s_host_register(dev, reg); | ||
197 | case 1: | ||
198 | return cx23417_s_register(dev, reg); | ||
199 | default: | ||
200 | break; | ||
201 | } | ||
202 | } | ||
203 | |||
204 | /* FIXME - any error returns should not be ignored */ | ||
205 | call_all(dev, core, s_register, reg); | ||
206 | return 0; | ||
207 | } | ||
208 | #endif | ||
diff --git a/drivers/media/video/cx23885/cx23885-ioctl.h b/drivers/media/video/cx23885/cx23885-ioctl.h new file mode 100644 index 00000000000..315be0ca5a0 --- /dev/null +++ b/drivers/media/video/cx23885/cx23885-ioctl.h | |||
@@ -0,0 +1,39 @@ | |||
1 | /* | ||
2 | * Driver for the Conexant CX23885/7/8 PCIe bridge | ||
3 | * | ||
4 | * Various common ioctl() support functions | ||
5 | * | ||
6 | * Copyright (c) 2009 Andy Walls <awalls@md.metrocast.net> | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or modify | ||
9 | * it under the terms of the GNU General Public License as published by | ||
10 | * the Free Software Foundation; either version 2 of the License, or | ||
11 | * (at your option) any later version. | ||
12 | * | ||
13 | * This program is distributed in the hope that it will be useful, | ||
14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
16 | * | ||
17 | * GNU General Public License for more details. | ||
18 | * | ||
19 | * You should have received a copy of the GNU General Public License | ||
20 | * along with this program; if not, write to the Free Software | ||
21 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
22 | */ | ||
23 | |||
24 | #ifndef _CX23885_IOCTL_H_ | ||
25 | #define _CX23885_IOCTL_H_ | ||
26 | |||
27 | int cx23885_g_chip_ident(struct file *file, void *fh, | ||
28 | struct v4l2_dbg_chip_ident *chip); | ||
29 | |||
30 | #ifdef CONFIG_VIDEO_ADV_DEBUG | ||
31 | int cx23885_g_register(struct file *file, void *fh, | ||
32 | struct v4l2_dbg_register *reg); | ||
33 | |||
34 | |||
35 | int cx23885_s_register(struct file *file, void *fh, | ||
36 | struct v4l2_dbg_register *reg); | ||
37 | |||
38 | #endif | ||
39 | #endif | ||
diff --git a/drivers/media/video/cx23885/cx23885-ir.c b/drivers/media/video/cx23885/cx23885-ir.c new file mode 100644 index 00000000000..7125247dd25 --- /dev/null +++ b/drivers/media/video/cx23885/cx23885-ir.c | |||
@@ -0,0 +1,117 @@ | |||
1 | /* | ||
2 | * Driver for the Conexant CX23885/7/8 PCIe bridge | ||
3 | * | ||
4 | * Infrared device support routines - non-input, non-vl42_subdev routines | ||
5 | * | ||
6 | * Copyright (C) 2009 Andy Walls <awalls@md.metrocast.net> | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or | ||
9 | * modify it under the terms of the GNU General Public License | ||
10 | * as published by the Free Software Foundation; either version 2 | ||
11 | * of the License, or (at your option) any later version. | ||
12 | * | ||
13 | * This program is distributed in the hope that it will be useful, | ||
14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
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., 51 Franklin Street, Fifth Floor, Boston, MA | ||
21 | * 02110-1301, USA. | ||
22 | */ | ||
23 | |||
24 | #include <media/v4l2-device.h> | ||
25 | |||
26 | #include "cx23885.h" | ||
27 | #include "cx23885-input.h" | ||
28 | |||
29 | #define CX23885_IR_RX_FIFO_SERVICE_REQ 0 | ||
30 | #define CX23885_IR_RX_END_OF_RX_DETECTED 1 | ||
31 | #define CX23885_IR_RX_HW_FIFO_OVERRUN 2 | ||
32 | #define CX23885_IR_RX_SW_FIFO_OVERRUN 3 | ||
33 | |||
34 | #define CX23885_IR_TX_FIFO_SERVICE_REQ 0 | ||
35 | |||
36 | |||
37 | void cx23885_ir_rx_work_handler(struct work_struct *work) | ||
38 | { | ||
39 | struct cx23885_dev *dev = | ||
40 | container_of(work, struct cx23885_dev, ir_rx_work); | ||
41 | u32 events = 0; | ||
42 | unsigned long *notifications = &dev->ir_rx_notifications; | ||
43 | |||
44 | if (test_and_clear_bit(CX23885_IR_RX_SW_FIFO_OVERRUN, notifications)) | ||
45 | events |= V4L2_SUBDEV_IR_RX_SW_FIFO_OVERRUN; | ||
46 | if (test_and_clear_bit(CX23885_IR_RX_HW_FIFO_OVERRUN, notifications)) | ||
47 | events |= V4L2_SUBDEV_IR_RX_HW_FIFO_OVERRUN; | ||
48 | if (test_and_clear_bit(CX23885_IR_RX_END_OF_RX_DETECTED, notifications)) | ||
49 | events |= V4L2_SUBDEV_IR_RX_END_OF_RX_DETECTED; | ||
50 | if (test_and_clear_bit(CX23885_IR_RX_FIFO_SERVICE_REQ, notifications)) | ||
51 | events |= V4L2_SUBDEV_IR_RX_FIFO_SERVICE_REQ; | ||
52 | |||
53 | if (events == 0) | ||
54 | return; | ||
55 | |||
56 | if (dev->kernel_ir) | ||
57 | cx23885_input_rx_work_handler(dev, events); | ||
58 | } | ||
59 | |||
60 | void cx23885_ir_tx_work_handler(struct work_struct *work) | ||
61 | { | ||
62 | struct cx23885_dev *dev = | ||
63 | container_of(work, struct cx23885_dev, ir_tx_work); | ||
64 | u32 events = 0; | ||
65 | unsigned long *notifications = &dev->ir_tx_notifications; | ||
66 | |||
67 | if (test_and_clear_bit(CX23885_IR_TX_FIFO_SERVICE_REQ, notifications)) | ||
68 | events |= V4L2_SUBDEV_IR_TX_FIFO_SERVICE_REQ; | ||
69 | |||
70 | if (events == 0) | ||
71 | return; | ||
72 | |||
73 | } | ||
74 | |||
75 | /* Possibly called in an IRQ context */ | ||
76 | void cx23885_ir_rx_v4l2_dev_notify(struct v4l2_subdev *sd, u32 events) | ||
77 | { | ||
78 | struct cx23885_dev *dev = to_cx23885(sd->v4l2_dev); | ||
79 | unsigned long *notifications = &dev->ir_rx_notifications; | ||
80 | |||
81 | if (events & V4L2_SUBDEV_IR_RX_FIFO_SERVICE_REQ) | ||
82 | set_bit(CX23885_IR_RX_FIFO_SERVICE_REQ, notifications); | ||
83 | if (events & V4L2_SUBDEV_IR_RX_END_OF_RX_DETECTED) | ||
84 | set_bit(CX23885_IR_RX_END_OF_RX_DETECTED, notifications); | ||
85 | if (events & V4L2_SUBDEV_IR_RX_HW_FIFO_OVERRUN) | ||
86 | set_bit(CX23885_IR_RX_HW_FIFO_OVERRUN, notifications); | ||
87 | if (events & V4L2_SUBDEV_IR_RX_SW_FIFO_OVERRUN) | ||
88 | set_bit(CX23885_IR_RX_SW_FIFO_OVERRUN, notifications); | ||
89 | |||
90 | /* | ||
91 | * For the integrated AV core, we are already in a workqueue context. | ||
92 | * For the CX23888 integrated IR, we are in an interrupt context. | ||
93 | */ | ||
94 | if (sd == dev->sd_cx25840) | ||
95 | cx23885_ir_rx_work_handler(&dev->ir_rx_work); | ||
96 | else | ||
97 | schedule_work(&dev->ir_rx_work); | ||
98 | } | ||
99 | |||
100 | /* Possibly called in an IRQ context */ | ||
101 | void cx23885_ir_tx_v4l2_dev_notify(struct v4l2_subdev *sd, u32 events) | ||
102 | { | ||
103 | struct cx23885_dev *dev = to_cx23885(sd->v4l2_dev); | ||
104 | unsigned long *notifications = &dev->ir_tx_notifications; | ||
105 | |||
106 | if (events & V4L2_SUBDEV_IR_TX_FIFO_SERVICE_REQ) | ||
107 | set_bit(CX23885_IR_TX_FIFO_SERVICE_REQ, notifications); | ||
108 | |||
109 | /* | ||
110 | * For the integrated AV core, we are already in a workqueue context. | ||
111 | * For the CX23888 integrated IR, we are in an interrupt context. | ||
112 | */ | ||
113 | if (sd == dev->sd_cx25840) | ||
114 | cx23885_ir_tx_work_handler(&dev->ir_tx_work); | ||
115 | else | ||
116 | schedule_work(&dev->ir_tx_work); | ||
117 | } | ||
diff --git a/drivers/media/video/cx23885/cx23885-ir.h b/drivers/media/video/cx23885/cx23885-ir.h new file mode 100644 index 00000000000..0c9d8bda9e2 --- /dev/null +++ b/drivers/media/video/cx23885/cx23885-ir.h | |||
@@ -0,0 +1,31 @@ | |||
1 | /* | ||
2 | * Driver for the Conexant CX23885/7/8 PCIe bridge | ||
3 | * | ||
4 | * Infrared device support routines - non-input, non-vl42_subdev routines | ||
5 | * | ||
6 | * Copyright (C) 2009 Andy Walls <awalls@md.metrocast.net> | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or | ||
9 | * modify it under the terms of the GNU General Public License | ||
10 | * as published by the Free Software Foundation; either version 2 | ||
11 | * of the License, or (at your option) any later version. | ||
12 | * | ||
13 | * This program is distributed in the hope that it will be useful, | ||
14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
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., 51 Franklin Street, Fifth Floor, Boston, MA | ||
21 | * 02110-1301, USA. | ||
22 | */ | ||
23 | |||
24 | #ifndef _CX23885_IR_H_ | ||
25 | #define _CX23885_IR_H_ | ||
26 | void cx23885_ir_rx_v4l2_dev_notify(struct v4l2_subdev *sd, u32 events); | ||
27 | void cx23885_ir_tx_v4l2_dev_notify(struct v4l2_subdev *sd, u32 events); | ||
28 | |||
29 | void cx23885_ir_rx_work_handler(struct work_struct *work); | ||
30 | void cx23885_ir_tx_work_handler(struct work_struct *work); | ||
31 | #endif | ||
diff --git a/drivers/media/video/cx23885/cx23885-reg.h b/drivers/media/video/cx23885/cx23885-reg.h new file mode 100644 index 00000000000..c87ac682ebb --- /dev/null +++ b/drivers/media/video/cx23885/cx23885-reg.h | |||
@@ -0,0 +1,449 @@ | |||
1 | /* | ||
2 | * Driver for the Conexant CX23885 PCIe bridge | ||
3 | * | ||
4 | * Copyright (c) 2006 Steven Toth <stoth@linuxtv.org> | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify | ||
7 | * it under the terms of the GNU General Public License as published by | ||
8 | * the Free Software Foundation; either version 2 of the License, or | ||
9 | * (at your option) any later version. | ||
10 | * | ||
11 | * This program is distributed in the hope that it will be useful, | ||
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
14 | * | ||
15 | * GNU General Public License for more details. | ||
16 | * | ||
17 | * You should have received a copy of the GNU General Public License | ||
18 | * along with this program; if not, write to the Free Software | ||
19 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
20 | */ | ||
21 | |||
22 | #ifndef _CX23885_REG_H_ | ||
23 | #define _CX23885_REG_H_ | ||
24 | |||
25 | /* | ||
26 | Address Map | ||
27 | 0x00000000 -> 0x00009000 TX SRAM (Fifos) | ||
28 | 0x00010000 -> 0x00013c00 RX SRAM CMDS + CDT | ||
29 | |||
30 | EACH CMDS struct is 0x80 bytes long | ||
31 | |||
32 | DMAx_PTR1 = 0x03040 address of first cluster | ||
33 | DMAx_PTR2 = 0x10600 address of the CDT | ||
34 | DMAx_CNT1 = cluster size in (bytes >> 4) -1 | ||
35 | DMAx_CNT2 = total cdt size for all entries >> 3 | ||
36 | |||
37 | Cluster Descriptor entry = 4 DWORDS | ||
38 | DWORD 0 -> ptr to cluster | ||
39 | DWORD 1 Reserved | ||
40 | DWORD 2 Reserved | ||
41 | DWORD 3 Reserved | ||
42 | |||
43 | Channel manager Data Structure entry = 20 DWORD | ||
44 | 0 IntialProgramCounterLow | ||
45 | 1 IntialProgramCounterHigh | ||
46 | 2 ClusterDescriptorTableBase | ||
47 | 3 ClusterDescriptorTableSize | ||
48 | 4 InstructionQueueBase | ||
49 | 5 InstructionQueueSize | ||
50 | ... Reserved | ||
51 | 19 Reserved | ||
52 | */ | ||
53 | |||
54 | /* Risc Instructions */ | ||
55 | #define RISC_CNT_INC 0x00010000 | ||
56 | #define RISC_CNT_RESET 0x00030000 | ||
57 | #define RISC_IRQ1 0x01000000 | ||
58 | #define RISC_IRQ2 0x02000000 | ||
59 | #define RISC_EOL 0x04000000 | ||
60 | #define RISC_SOL 0x08000000 | ||
61 | #define RISC_WRITE 0x10000000 | ||
62 | #define RISC_SKIP 0x20000000 | ||
63 | #define RISC_JUMP 0x70000000 | ||
64 | #define RISC_SYNC 0x80000000 | ||
65 | #define RISC_RESYNC 0x80008000 | ||
66 | #define RISC_READ 0x90000000 | ||
67 | #define RISC_WRITERM 0xB0000000 | ||
68 | #define RISC_WRITECM 0xC0000000 | ||
69 | #define RISC_WRITECR 0xD0000000 | ||
70 | #define RISC_WRITEC 0x50000000 | ||
71 | #define RISC_READC 0xA0000000 | ||
72 | |||
73 | |||
74 | /* Audio and Video Core */ | ||
75 | #define HOST_REG1 0x00000000 | ||
76 | #define HOST_REG2 0x00000001 | ||
77 | #define HOST_REG3 0x00000002 | ||
78 | |||
79 | /* Chip Configuration Registers */ | ||
80 | #define CHIP_CTRL 0x00000100 | ||
81 | #define AFE_CTRL 0x00000104 | ||
82 | #define VID_PLL_INT_POST 0x00000108 | ||
83 | #define VID_PLL_FRAC 0x0000010C | ||
84 | #define AUX_PLL_INT_POST 0x00000110 | ||
85 | #define AUX_PLL_FRAC 0x00000114 | ||
86 | #define SYS_PLL_INT_POST 0x00000118 | ||
87 | #define SYS_PLL_FRAC 0x0000011C | ||
88 | #define PIN_CTRL 0x00000120 | ||
89 | #define AUD_IO_CTRL 0x00000124 | ||
90 | #define AUD_LOCK1 0x00000128 | ||
91 | #define AUD_LOCK2 0x0000012C | ||
92 | #define POWER_CTRL 0x00000130 | ||
93 | #define AFE_DIAG_CTRL1 0x00000134 | ||
94 | #define AFE_DIAG_CTRL3 0x0000013C | ||
95 | #define PLL_DIAG_CTRL 0x00000140 | ||
96 | #define AFE_CLK_OUT_CTRL 0x00000144 | ||
97 | #define DLL1_DIAG_CTRL 0x0000015C | ||
98 | |||
99 | /* GPIO[23:19] Output Enable */ | ||
100 | #define GPIO2_OUT_EN_REG 0x00000160 | ||
101 | /* GPIO[23:19] Data Registers */ | ||
102 | #define GPIO2 0x00000164 | ||
103 | |||
104 | #define IFADC_CTRL 0x00000180 | ||
105 | |||
106 | /* Infrared Remote Registers */ | ||
107 | #define IR_CNTRL_REG 0x00000200 | ||
108 | #define IR_TXCLK_REG 0x00000204 | ||
109 | #define IR_RXCLK_REG 0x00000208 | ||
110 | #define IR_CDUTY_REG 0x0000020C | ||
111 | #define IR_STAT_REG 0x00000210 | ||
112 | #define IR_IRQEN_REG 0x00000214 | ||
113 | #define IR_FILTR_REG 0x00000218 | ||
114 | #define IR_FIFO_REG 0x0000023C | ||
115 | |||
116 | /* Video Decoder Registers */ | ||
117 | #define MODE_CTRL 0x00000400 | ||
118 | #define OUT_CTRL1 0x00000404 | ||
119 | #define OUT_CTRL2 0x00000408 | ||
120 | #define GEN_STAT 0x0000040C | ||
121 | #define INT_STAT_MASK 0x00000410 | ||
122 | #define LUMA_CTRL 0x00000414 | ||
123 | #define HSCALE_CTRL 0x00000418 | ||
124 | #define VSCALE_CTRL 0x0000041C | ||
125 | #define CHROMA_CTRL 0x00000420 | ||
126 | #define VBI_LINE_CTRL1 0x00000424 | ||
127 | #define VBI_LINE_CTRL2 0x00000428 | ||
128 | #define VBI_LINE_CTRL3 0x0000042C | ||
129 | #define VBI_LINE_CTRL4 0x00000430 | ||
130 | #define VBI_LINE_CTRL5 0x00000434 | ||
131 | #define VBI_FC_CFG 0x00000438 | ||
132 | #define VBI_MISC_CFG1 0x0000043C | ||
133 | #define VBI_MISC_CFG2 0x00000440 | ||
134 | #define VBI_PAY1 0x00000444 | ||
135 | #define VBI_PAY2 0x00000448 | ||
136 | #define VBI_CUST1_CFG1 0x0000044C | ||
137 | #define VBI_CUST1_CFG2 0x00000450 | ||
138 | #define VBI_CUST1_CFG3 0x00000454 | ||
139 | #define VBI_CUST2_CFG1 0x00000458 | ||
140 | #define VBI_CUST2_CFG2 0x0000045C | ||
141 | #define VBI_CUST2_CFG3 0x00000460 | ||
142 | #define VBI_CUST3_CFG1 0x00000464 | ||
143 | #define VBI_CUST3_CFG2 0x00000468 | ||
144 | #define VBI_CUST3_CFG3 0x0000046C | ||
145 | #define HORIZ_TIM_CTRL 0x00000470 | ||
146 | #define VERT_TIM_CTRL 0x00000474 | ||
147 | #define SRC_COMB_CFG 0x00000478 | ||
148 | #define CHROMA_VBIOFF_CFG 0x0000047C | ||
149 | #define FIELD_COUNT 0x00000480 | ||
150 | #define MISC_TIM_CTRL 0x00000484 | ||
151 | #define DFE_CTRL1 0x00000488 | ||
152 | #define DFE_CTRL2 0x0000048C | ||
153 | #define DFE_CTRL3 0x00000490 | ||
154 | #define PLL_CTRL 0x00000494 | ||
155 | #define HTL_CTRL 0x00000498 | ||
156 | #define COMB_CTRL 0x0000049C | ||
157 | #define CRUSH_CTRL 0x000004A0 | ||
158 | #define SOFT_RST_CTRL 0x000004A4 | ||
159 | #define CX885_VERSION 0x000004B4 | ||
160 | #define VBI_PASS_CTRL 0x000004BC | ||
161 | |||
162 | /* Audio Decoder Registers */ | ||
163 | /* 8051 Configuration */ | ||
164 | #define DL_CTL 0x00000800 | ||
165 | #define STD_DET_STATUS 0x00000804 | ||
166 | #define STD_DET_CTL 0x00000808 | ||
167 | #define DW8051_INT 0x0000080C | ||
168 | #define GENERAL_CTL 0x00000810 | ||
169 | #define AAGC_CTL 0x00000814 | ||
170 | #define DEMATRIX_CTL 0x000008CC | ||
171 | #define PATH1_CTL1 0x000008D0 | ||
172 | #define PATH1_VOL_CTL 0x000008D4 | ||
173 | #define PATH1_EQ_CTL 0x000008D8 | ||
174 | #define PATH1_SC_CTL 0x000008DC | ||
175 | #define PATH2_CTL1 0x000008E0 | ||
176 | #define PATH2_VOL_CTL 0x000008E4 | ||
177 | #define PATH2_EQ_CTL 0x000008E8 | ||
178 | #define PATH2_SC_CTL 0x000008EC | ||
179 | |||
180 | /* Sample Rate Converter */ | ||
181 | #define SRC_CTL 0x000008F0 | ||
182 | #define SRC_LF_COEF 0x000008F4 | ||
183 | #define SRC1_CTL 0x000008F8 | ||
184 | #define SRC2_CTL 0x000008FC | ||
185 | #define SRC3_CTL 0x00000900 | ||
186 | #define SRC4_CTL 0x00000904 | ||
187 | #define SRC5_CTL 0x00000908 | ||
188 | #define SRC6_CTL 0x0000090C | ||
189 | #define BAND_OUT_SEL 0x00000910 | ||
190 | #define I2S_N_CTL 0x00000914 | ||
191 | #define I2S_OUT_CTL 0x00000918 | ||
192 | #define AUTOCONFIG_REG 0x000009C4 | ||
193 | |||
194 | /* Audio ADC Registers */ | ||
195 | #define DSM_CTRL1 0x00000000 | ||
196 | #define DSM_CTRL2 0x00000001 | ||
197 | #define CHP_EN_CTRL 0x00000002 | ||
198 | #define CHP_CLK_CTRL1 0x00000004 | ||
199 | #define CHP_CLK_CTRL2 0x00000005 | ||
200 | #define BG_REF_CTRL 0x00000006 | ||
201 | #define SD2_SW_CTRL1 0x00000008 | ||
202 | #define SD2_SW_CTRL2 0x00000009 | ||
203 | #define SD2_BIAS_CTRL 0x0000000A | ||
204 | #define AMP_BIAS_CTRL 0x0000000C | ||
205 | #define CH_PWR_CTRL1 0x0000000E | ||
206 | #define CH_PWR_CTRL2 0x0000000F | ||
207 | #define DSM_STATUS1 0x00000010 | ||
208 | #define DSM_STATUS2 0x00000011 | ||
209 | #define DIG_CTL1 0x00000012 | ||
210 | #define DIG_CTL2 0x00000013 | ||
211 | #define I2S_TX_CFG 0x0000001A | ||
212 | |||
213 | #define DEV_CNTRL2 0x00040000 | ||
214 | |||
215 | #define PCI_MSK_IR (1 << 28) | ||
216 | #define PCI_MSK_AV_CORE (1 << 27) | ||
217 | #define PCI_MSK_GPIO1 (1 << 24) | ||
218 | #define PCI_MSK_GPIO0 (1 << 23) | ||
219 | #define PCI_MSK_APB_DMA (1 << 12) | ||
220 | #define PCI_MSK_AL_WR (1 << 11) | ||
221 | #define PCI_MSK_AL_RD (1 << 10) | ||
222 | #define PCI_MSK_RISC_WR (1 << 9) | ||
223 | #define PCI_MSK_RISC_RD (1 << 8) | ||
224 | #define PCI_MSK_AUD_EXT (1 << 4) | ||
225 | #define PCI_MSK_AUD_INT (1 << 3) | ||
226 | #define PCI_MSK_VID_C (1 << 2) | ||
227 | #define PCI_MSK_VID_B (1 << 1) | ||
228 | #define PCI_MSK_VID_A 1 | ||
229 | #define PCI_INT_MSK 0x00040010 | ||
230 | |||
231 | #define PCI_INT_STAT 0x00040014 | ||
232 | #define PCI_INT_MSTAT 0x00040018 | ||
233 | |||
234 | #define VID_A_INT_MSK 0x00040020 | ||
235 | #define VID_A_INT_STAT 0x00040024 | ||
236 | #define VID_A_INT_MSTAT 0x00040028 | ||
237 | #define VID_A_INT_SSTAT 0x0004002C | ||
238 | |||
239 | #define VID_B_INT_MSK 0x00040030 | ||
240 | #define VID_B_MSK_BAD_PKT (1 << 20) | ||
241 | #define VID_B_MSK_VBI_OPC_ERR (1 << 17) | ||
242 | #define VID_B_MSK_OPC_ERR (1 << 16) | ||
243 | #define VID_B_MSK_VBI_SYNC (1 << 13) | ||
244 | #define VID_B_MSK_SYNC (1 << 12) | ||
245 | #define VID_B_MSK_VBI_OF (1 << 9) | ||
246 | #define VID_B_MSK_OF (1 << 8) | ||
247 | #define VID_B_MSK_VBI_RISCI2 (1 << 5) | ||
248 | #define VID_B_MSK_RISCI2 (1 << 4) | ||
249 | #define VID_B_MSK_VBI_RISCI1 (1 << 1) | ||
250 | #define VID_B_MSK_RISCI1 1 | ||
251 | #define VID_B_INT_STAT 0x00040034 | ||
252 | #define VID_B_INT_MSTAT 0x00040038 | ||
253 | #define VID_B_INT_SSTAT 0x0004003C | ||
254 | |||
255 | #define VID_B_MSK_BAD_PKT (1 << 20) | ||
256 | #define VID_B_MSK_OPC_ERR (1 << 16) | ||
257 | #define VID_B_MSK_SYNC (1 << 12) | ||
258 | #define VID_B_MSK_OF (1 << 8) | ||
259 | #define VID_B_MSK_RISCI2 (1 << 4) | ||
260 | #define VID_B_MSK_RISCI1 1 | ||
261 | |||
262 | #define VID_C_MSK_BAD_PKT (1 << 20) | ||
263 | #define VID_C_MSK_OPC_ERR (1 << 16) | ||
264 | #define VID_C_MSK_SYNC (1 << 12) | ||
265 | #define VID_C_MSK_OF (1 << 8) | ||
266 | #define VID_C_MSK_RISCI2 (1 << 4) | ||
267 | #define VID_C_MSK_RISCI1 1 | ||
268 | |||
269 | /* A superset for testing purposes */ | ||
270 | #define VID_BC_MSK_BAD_PKT (1 << 20) | ||
271 | #define VID_BC_MSK_OPC_ERR (1 << 16) | ||
272 | #define VID_BC_MSK_SYNC (1 << 12) | ||
273 | #define VID_BC_MSK_OF (1 << 8) | ||
274 | #define VID_BC_MSK_RISCI2 (1 << 4) | ||
275 | #define VID_BC_MSK_RISCI1 1 | ||
276 | |||
277 | #define VID_C_INT_MSK 0x00040040 | ||
278 | #define VID_C_INT_STAT 0x00040044 | ||
279 | #define VID_C_INT_MSTAT 0x00040048 | ||
280 | #define VID_C_INT_SSTAT 0x0004004C | ||
281 | |||
282 | #define AUDIO_INT_INT_MSK 0x00040050 | ||
283 | #define AUDIO_INT_INT_STAT 0x00040054 | ||
284 | #define AUDIO_INT_INT_MSTAT 0x00040058 | ||
285 | #define AUDIO_INT_INT_SSTAT 0x0004005C | ||
286 | |||
287 | #define AUDIO_EXT_INT_MSK 0x00040060 | ||
288 | #define AUDIO_EXT_INT_STAT 0x00040064 | ||
289 | #define AUDIO_EXT_INT_MSTAT 0x00040068 | ||
290 | #define AUDIO_EXT_INT_SSTAT 0x0004006C | ||
291 | |||
292 | #define RDR_CFG0 0x00050000 | ||
293 | #define RDR_CFG1 0x00050004 | ||
294 | #define RDR_CFG2 0x00050008 | ||
295 | #define RDR_RDRCTL1 0x0005030c | ||
296 | #define RDR_TLCTL0 0x00050318 | ||
297 | |||
298 | /* APB DMAC Current Buffer Pointer */ | ||
299 | #define DMA1_PTR1 0x00100000 | ||
300 | #define DMA2_PTR1 0x00100004 | ||
301 | #define DMA3_PTR1 0x00100008 | ||
302 | #define DMA4_PTR1 0x0010000C | ||
303 | #define DMA5_PTR1 0x00100010 | ||
304 | #define DMA6_PTR1 0x00100014 | ||
305 | #define DMA7_PTR1 0x00100018 | ||
306 | #define DMA8_PTR1 0x0010001C | ||
307 | |||
308 | /* APB DMAC Current Table Pointer */ | ||
309 | #define DMA1_PTR2 0x00100040 | ||
310 | #define DMA2_PTR2 0x00100044 | ||
311 | #define DMA3_PTR2 0x00100048 | ||
312 | #define DMA4_PTR2 0x0010004C | ||
313 | #define DMA5_PTR2 0x00100050 | ||
314 | #define DMA6_PTR2 0x00100054 | ||
315 | #define DMA7_PTR2 0x00100058 | ||
316 | #define DMA8_PTR2 0x0010005C | ||
317 | |||
318 | /* APB DMAC Buffer Limit */ | ||
319 | #define DMA1_CNT1 0x00100080 | ||
320 | #define DMA2_CNT1 0x00100084 | ||
321 | #define DMA3_CNT1 0x00100088 | ||
322 | #define DMA4_CNT1 0x0010008C | ||
323 | #define DMA5_CNT1 0x00100090 | ||
324 | #define DMA6_CNT1 0x00100094 | ||
325 | #define DMA7_CNT1 0x00100098 | ||
326 | #define DMA8_CNT1 0x0010009C | ||
327 | |||
328 | /* APB DMAC Table Size */ | ||
329 | #define DMA1_CNT2 0x001000C0 | ||
330 | #define DMA2_CNT2 0x001000C4 | ||
331 | #define DMA3_CNT2 0x001000C8 | ||
332 | #define DMA4_CNT2 0x001000CC | ||
333 | #define DMA5_CNT2 0x001000D0 | ||
334 | #define DMA6_CNT2 0x001000D4 | ||
335 | #define DMA7_CNT2 0x001000D8 | ||
336 | #define DMA8_CNT2 0x001000DC | ||
337 | |||
338 | /* Timer Counters */ | ||
339 | #define TM_CNT_LDW 0x00110000 | ||
340 | #define TM_CNT_UW 0x00110004 | ||
341 | #define TM_LMT_LDW 0x00110008 | ||
342 | #define TM_LMT_UW 0x0011000C | ||
343 | |||
344 | /* GPIO */ | ||
345 | #define GP0_IO 0x00110010 | ||
346 | #define GPIO_ISM 0x00110014 | ||
347 | #define SOFT_RESET 0x0011001C | ||
348 | |||
349 | /* GPIO (417 Microsoftcontroller) RW Data */ | ||
350 | #define MC417_RWD 0x00110020 | ||
351 | |||
352 | /* GPIO (417 Microsoftcontroller) Output Enable, Low Active */ | ||
353 | #define MC417_OEN 0x00110024 | ||
354 | #define MC417_CTL 0x00110028 | ||
355 | #define ALT_PIN_OUT_SEL 0x0011002C | ||
356 | #define CLK_DELAY 0x00110048 | ||
357 | #define PAD_CTRL 0x0011004C | ||
358 | |||
359 | /* Video A Interface */ | ||
360 | #define VID_A_GPCNT 0x00130020 | ||
361 | #define VBI_A_GPCNT 0x00130024 | ||
362 | #define VID_A_GPCNT_CTL 0x00130030 | ||
363 | #define VBI_A_GPCNT_CTL 0x00130034 | ||
364 | #define VID_A_DMA_CTL 0x00130040 | ||
365 | #define VID_A_VIP_CTRL 0x00130080 | ||
366 | #define VID_A_PIXEL_FRMT 0x00130084 | ||
367 | #define VID_A_VBI_CTRL 0x00130088 | ||
368 | |||
369 | /* Video B Interface */ | ||
370 | #define VID_B_DMA 0x00130100 | ||
371 | #define VBI_B_DMA 0x00130108 | ||
372 | #define VID_B_GPCNT 0x00130120 | ||
373 | #define VBI_B_GPCNT 0x00130124 | ||
374 | #define VID_B_GPCNT_CTL 0x00130134 | ||
375 | #define VBI_B_GPCNT_CTL 0x00130138 | ||
376 | #define VID_B_DMA_CTL 0x00130140 | ||
377 | #define VID_B_SRC_SEL 0x00130144 | ||
378 | #define VID_B_LNGTH 0x00130150 | ||
379 | #define VID_B_HW_SOP_CTL 0x00130154 | ||
380 | #define VID_B_GEN_CTL 0x00130158 | ||
381 | #define VID_B_BD_PKT_STATUS 0x0013015C | ||
382 | #define VID_B_SOP_STATUS 0x00130160 | ||
383 | #define VID_B_FIFO_OVFL_STAT 0x00130164 | ||
384 | #define VID_B_VLD_MISC 0x00130168 | ||
385 | #define VID_B_TS_CLK_EN 0x0013016C | ||
386 | #define VID_B_VIP_CTRL 0x00130180 | ||
387 | #define VID_B_PIXEL_FRMT 0x00130184 | ||
388 | |||
389 | /* Video C Interface */ | ||
390 | #define VID_C_GPCNT 0x00130220 | ||
391 | #define VID_C_GPCNT_CTL 0x00130230 | ||
392 | #define VBI_C_GPCNT_CTL 0x00130234 | ||
393 | #define VID_C_DMA_CTL 0x00130240 | ||
394 | #define VID_C_LNGTH 0x00130250 | ||
395 | #define VID_C_HW_SOP_CTL 0x00130254 | ||
396 | #define VID_C_GEN_CTL 0x00130258 | ||
397 | #define VID_C_BD_PKT_STATUS 0x0013025C | ||
398 | #define VID_C_SOP_STATUS 0x00130260 | ||
399 | #define VID_C_FIFO_OVFL_STAT 0x00130264 | ||
400 | #define VID_C_VLD_MISC 0x00130268 | ||
401 | #define VID_C_TS_CLK_EN 0x0013026C | ||
402 | |||
403 | /* Internal Audio Interface */ | ||
404 | #define AUD_INT_A_GPCNT 0x00140020 | ||
405 | #define AUD_INT_B_GPCNT 0x00140024 | ||
406 | #define AUD_INT_A_GPCNT_CTL 0x00140030 | ||
407 | #define AUD_INT_B_GPCNT_CTL 0x00140034 | ||
408 | #define AUD_INT_DMA_CTL 0x00140040 | ||
409 | #define AUD_INT_A_LNGTH 0x00140050 | ||
410 | #define AUD_INT_B_LNGTH 0x00140054 | ||
411 | #define AUD_INT_A_MODE 0x00140058 | ||
412 | #define AUD_INT_B_MODE 0x0014005C | ||
413 | |||
414 | /* External Audio Interface */ | ||
415 | #define AUD_EXT_DMA 0x00140100 | ||
416 | #define AUD_EXT_GPCNT 0x00140120 | ||
417 | #define AUD_EXT_GPCNT_CTL 0x00140130 | ||
418 | #define AUD_EXT_DMA_CTL 0x00140140 | ||
419 | #define AUD_EXT_LNGTH 0x00140150 | ||
420 | #define AUD_EXT_A_MODE 0x00140158 | ||
421 | |||
422 | /* I2C Bus 1 */ | ||
423 | #define I2C1_ADDR 0x00180000 | ||
424 | #define I2C1_WDATA 0x00180004 | ||
425 | #define I2C1_CTRL 0x00180008 | ||
426 | #define I2C1_RDATA 0x0018000C | ||
427 | #define I2C1_STAT 0x00180010 | ||
428 | |||
429 | /* I2C Bus 2 */ | ||
430 | #define I2C2_ADDR 0x00190000 | ||
431 | #define I2C2_WDATA 0x00190004 | ||
432 | #define I2C2_CTRL 0x00190008 | ||
433 | #define I2C2_RDATA 0x0019000C | ||
434 | #define I2C2_STAT 0x00190010 | ||
435 | |||
436 | /* I2C Bus 3 */ | ||
437 | #define I2C3_ADDR 0x001A0000 | ||
438 | #define I2C3_WDATA 0x001A0004 | ||
439 | #define I2C3_CTRL 0x001A0008 | ||
440 | #define I2C3_RDATA 0x001A000C | ||
441 | #define I2C3_STAT 0x001A0010 | ||
442 | |||
443 | /* UART */ | ||
444 | #define UART_CTL 0x001B0000 | ||
445 | #define UART_BRD 0x001B0004 | ||
446 | #define UART_ISR 0x001B000C | ||
447 | #define UART_CNT 0x001B0010 | ||
448 | |||
449 | #endif /* _CX23885_REG_H_ */ | ||
diff --git a/drivers/media/video/cx23885/cx23885-vbi.c b/drivers/media/video/cx23885/cx23885-vbi.c new file mode 100644 index 00000000000..c0b60382ad1 --- /dev/null +++ b/drivers/media/video/cx23885/cx23885-vbi.c | |||
@@ -0,0 +1,247 @@ | |||
1 | /* | ||
2 | * Driver for the Conexant CX23885 PCIe bridge | ||
3 | * | ||
4 | * Copyright (c) 2007 Steven Toth <stoth@linuxtv.org> | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify | ||
7 | * it under the terms of the GNU General Public License as published by | ||
8 | * the Free Software Foundation; either version 2 of the License, or | ||
9 | * (at your option) any later version. | ||
10 | * | ||
11 | * This program is distributed in the hope that it will be useful, | ||
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
14 | * | ||
15 | * GNU General Public License for more details. | ||
16 | * | ||
17 | * You should have received a copy of the GNU General Public License | ||
18 | * along with this program; if not, write to the Free Software | ||
19 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
20 | */ | ||
21 | |||
22 | #include <linux/kernel.h> | ||
23 | #include <linux/module.h> | ||
24 | #include <linux/moduleparam.h> | ||
25 | #include <linux/init.h> | ||
26 | |||
27 | #include "cx23885.h" | ||
28 | |||
29 | static unsigned int vbibufs = 4; | ||
30 | module_param(vbibufs, int, 0644); | ||
31 | MODULE_PARM_DESC(vbibufs, "number of vbi buffers, range 2-32"); | ||
32 | |||
33 | static unsigned int vbi_debug; | ||
34 | module_param(vbi_debug, int, 0644); | ||
35 | MODULE_PARM_DESC(vbi_debug, "enable debug messages [vbi]"); | ||
36 | |||
37 | #define dprintk(level, fmt, arg...)\ | ||
38 | do { if (vbi_debug >= level)\ | ||
39 | printk(KERN_DEBUG "%s/0: " fmt, dev->name, ## arg);\ | ||
40 | } while (0) | ||
41 | |||
42 | /* ------------------------------------------------------------------ */ | ||
43 | |||
44 | int cx23885_vbi_fmt(struct file *file, void *priv, | ||
45 | struct v4l2_format *f) | ||
46 | { | ||
47 | struct cx23885_fh *fh = priv; | ||
48 | struct cx23885_dev *dev = fh->dev; | ||
49 | |||
50 | if (dev->tvnorm & V4L2_STD_525_60) { | ||
51 | /* ntsc */ | ||
52 | f->fmt.vbi.sampling_rate = 28636363; | ||
53 | f->fmt.vbi.start[0] = 10; | ||
54 | f->fmt.vbi.start[1] = 273; | ||
55 | |||
56 | } else if (dev->tvnorm & V4L2_STD_625_50) { | ||
57 | /* pal */ | ||
58 | f->fmt.vbi.sampling_rate = 35468950; | ||
59 | f->fmt.vbi.start[0] = 7 - 1; | ||
60 | f->fmt.vbi.start[1] = 319 - 1; | ||
61 | } | ||
62 | return 0; | ||
63 | } | ||
64 | |||
65 | static int cx23885_start_vbi_dma(struct cx23885_dev *dev, | ||
66 | struct cx23885_dmaqueue *q, | ||
67 | struct cx23885_buffer *buf) | ||
68 | { | ||
69 | /* setup fifo + format */ | ||
70 | cx23885_sram_channel_setup(dev, &dev->sram_channels[SRAM_CH02], | ||
71 | buf->vb.width, buf->risc.dma); | ||
72 | |||
73 | /* reset counter */ | ||
74 | q->count = 1; | ||
75 | |||
76 | /* enable irqs */ | ||
77 | cx23885_irq_add_enable(dev, 0x01); | ||
78 | cx_set(VID_A_INT_MSK, 0x000022); | ||
79 | |||
80 | /* start dma */ | ||
81 | cx_set(DEV_CNTRL2, (1<<5)); | ||
82 | cx_set(VID_A_DMA_CTL, 0x00000022); | ||
83 | |||
84 | return 0; | ||
85 | } | ||
86 | |||
87 | |||
88 | static int cx23885_restart_vbi_queue(struct cx23885_dev *dev, | ||
89 | struct cx23885_dmaqueue *q) | ||
90 | { | ||
91 | struct cx23885_buffer *buf; | ||
92 | struct list_head *item; | ||
93 | |||
94 | if (list_empty(&q->active)) | ||
95 | return 0; | ||
96 | |||
97 | buf = list_entry(q->active.next, struct cx23885_buffer, vb.queue); | ||
98 | dprintk(2, "restart_queue [%p/%d]: restart dma\n", | ||
99 | buf, buf->vb.i); | ||
100 | cx23885_start_vbi_dma(dev, q, buf); | ||
101 | list_for_each(item, &q->active) { | ||
102 | buf = list_entry(item, struct cx23885_buffer, vb.queue); | ||
103 | buf->count = q->count++; | ||
104 | } | ||
105 | mod_timer(&q->timeout, jiffies+BUFFER_TIMEOUT); | ||
106 | return 0; | ||
107 | } | ||
108 | |||
109 | void cx23885_vbi_timeout(unsigned long data) | ||
110 | { | ||
111 | struct cx23885_dev *dev = (struct cx23885_dev *)data; | ||
112 | struct cx23885_dmaqueue *q = &dev->vbiq; | ||
113 | struct cx23885_buffer *buf; | ||
114 | unsigned long flags; | ||
115 | |||
116 | cx23885_sram_channel_dump(dev, &dev->sram_channels[SRAM_CH02]); | ||
117 | |||
118 | cx_clear(VID_A_DMA_CTL, 0x22); | ||
119 | |||
120 | spin_lock_irqsave(&dev->slock, flags); | ||
121 | while (!list_empty(&q->active)) { | ||
122 | buf = list_entry(q->active.next, struct cx23885_buffer, | ||
123 | vb.queue); | ||
124 | list_del(&buf->vb.queue); | ||
125 | buf->vb.state = VIDEOBUF_ERROR; | ||
126 | wake_up(&buf->vb.done); | ||
127 | printk("%s/0: [%p/%d] timeout - dma=0x%08lx\n", dev->name, | ||
128 | buf, buf->vb.i, (unsigned long)buf->risc.dma); | ||
129 | } | ||
130 | cx23885_restart_vbi_queue(dev, q); | ||
131 | spin_unlock_irqrestore(&dev->slock, flags); | ||
132 | } | ||
133 | |||
134 | /* ------------------------------------------------------------------ */ | ||
135 | #define VBI_LINE_LENGTH 2048 | ||
136 | #define VBI_LINE_COUNT 17 | ||
137 | |||
138 | static int | ||
139 | vbi_setup(struct videobuf_queue *q, unsigned int *count, unsigned int *size) | ||
140 | { | ||
141 | *size = VBI_LINE_COUNT * VBI_LINE_LENGTH * 2; | ||
142 | if (0 == *count) | ||
143 | *count = vbibufs; | ||
144 | if (*count < 2) | ||
145 | *count = 2; | ||
146 | if (*count > 32) | ||
147 | *count = 32; | ||
148 | return 0; | ||
149 | } | ||
150 | |||
151 | static int | ||
152 | vbi_prepare(struct videobuf_queue *q, struct videobuf_buffer *vb, | ||
153 | enum v4l2_field field) | ||
154 | { | ||
155 | struct cx23885_fh *fh = q->priv_data; | ||
156 | struct cx23885_dev *dev = fh->dev; | ||
157 | struct cx23885_buffer *buf = container_of(vb, | ||
158 | struct cx23885_buffer, vb); | ||
159 | struct videobuf_dmabuf *dma = videobuf_to_dma(&buf->vb); | ||
160 | unsigned int size; | ||
161 | int rc; | ||
162 | |||
163 | size = VBI_LINE_COUNT * VBI_LINE_LENGTH * 2; | ||
164 | if (0 != buf->vb.baddr && buf->vb.bsize < size) | ||
165 | return -EINVAL; | ||
166 | |||
167 | if (VIDEOBUF_NEEDS_INIT == buf->vb.state) { | ||
168 | buf->vb.width = VBI_LINE_LENGTH; | ||
169 | buf->vb.height = VBI_LINE_COUNT; | ||
170 | buf->vb.size = size; | ||
171 | buf->vb.field = V4L2_FIELD_SEQ_TB; | ||
172 | |||
173 | rc = videobuf_iolock(q, &buf->vb, NULL); | ||
174 | if (0 != rc) | ||
175 | goto fail; | ||
176 | cx23885_risc_buffer(dev->pci, &buf->risc, | ||
177 | dma->sglist, | ||
178 | 0, buf->vb.width * buf->vb.height, | ||
179 | buf->vb.width, 0, | ||
180 | buf->vb.height); | ||
181 | } | ||
182 | buf->vb.state = VIDEOBUF_PREPARED; | ||
183 | return 0; | ||
184 | |||
185 | fail: | ||
186 | cx23885_free_buffer(q, buf); | ||
187 | return rc; | ||
188 | } | ||
189 | |||
190 | static void | ||
191 | vbi_queue(struct videobuf_queue *vq, struct videobuf_buffer *vb) | ||
192 | { | ||
193 | struct cx23885_buffer *buf = | ||
194 | container_of(vb, struct cx23885_buffer, vb); | ||
195 | struct cx23885_buffer *prev; | ||
196 | struct cx23885_fh *fh = vq->priv_data; | ||
197 | struct cx23885_dev *dev = fh->dev; | ||
198 | struct cx23885_dmaqueue *q = &dev->vbiq; | ||
199 | |||
200 | /* add jump to stopper */ | ||
201 | buf->risc.jmp[0] = cpu_to_le32(RISC_JUMP | RISC_IRQ1 | RISC_CNT_INC); | ||
202 | buf->risc.jmp[1] = cpu_to_le32(q->stopper.dma); | ||
203 | buf->risc.jmp[2] = cpu_to_le32(0); /* bits 63-32 */ | ||
204 | |||
205 | if (list_empty(&q->active)) { | ||
206 | list_add_tail(&buf->vb.queue, &q->active); | ||
207 | cx23885_start_vbi_dma(dev, q, buf); | ||
208 | buf->vb.state = VIDEOBUF_ACTIVE; | ||
209 | buf->count = q->count++; | ||
210 | mod_timer(&q->timeout, jiffies+BUFFER_TIMEOUT); | ||
211 | dprintk(2, "[%p/%d] vbi_queue - first active\n", | ||
212 | buf, buf->vb.i); | ||
213 | |||
214 | } else { | ||
215 | prev = list_entry(q->active.prev, struct cx23885_buffer, | ||
216 | vb.queue); | ||
217 | list_add_tail(&buf->vb.queue, &q->active); | ||
218 | buf->vb.state = VIDEOBUF_ACTIVE; | ||
219 | buf->count = q->count++; | ||
220 | prev->risc.jmp[1] = cpu_to_le32(buf->risc.dma); | ||
221 | prev->risc.jmp[2] = cpu_to_le32(0); /* Bits 63-32 */ | ||
222 | dprintk(2, "[%p/%d] buffer_queue - append to active\n", | ||
223 | buf, buf->vb.i); | ||
224 | } | ||
225 | } | ||
226 | |||
227 | static void vbi_release(struct videobuf_queue *q, struct videobuf_buffer *vb) | ||
228 | { | ||
229 | struct cx23885_buffer *buf = | ||
230 | container_of(vb, struct cx23885_buffer, vb); | ||
231 | |||
232 | cx23885_free_buffer(q, buf); | ||
233 | } | ||
234 | |||
235 | struct videobuf_queue_ops cx23885_vbi_qops = { | ||
236 | .buf_setup = vbi_setup, | ||
237 | .buf_prepare = vbi_prepare, | ||
238 | .buf_queue = vbi_queue, | ||
239 | .buf_release = vbi_release, | ||
240 | }; | ||
241 | |||
242 | /* ------------------------------------------------------------------ */ | ||
243 | /* | ||
244 | * Local variables: | ||
245 | * c-basic-offset: 8 | ||
246 | * End: | ||
247 | */ | ||
diff --git a/drivers/media/video/cx23885/cx23885-video.c b/drivers/media/video/cx23885/cx23885-video.c new file mode 100644 index 00000000000..896bb32dbf0 --- /dev/null +++ b/drivers/media/video/cx23885/cx23885-video.c | |||
@@ -0,0 +1,1533 @@ | |||
1 | /* | ||
2 | * Driver for the Conexant CX23885 PCIe bridge | ||
3 | * | ||
4 | * Copyright (c) 2007 Steven Toth <stoth@linuxtv.org> | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify | ||
7 | * it under the terms of the GNU General Public License as published by | ||
8 | * the Free Software Foundation; either version 2 of the License, or | ||
9 | * (at your option) any later version. | ||
10 | * | ||
11 | * This program is distributed in the hope that it will be useful, | ||
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
14 | * | ||
15 | * GNU General Public License for more details. | ||
16 | * | ||
17 | * You should have received a copy of the GNU General Public License | ||
18 | * along with this program; if not, write to the Free Software | ||
19 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
20 | */ | ||
21 | |||
22 | #include <linux/init.h> | ||
23 | #include <linux/list.h> | ||
24 | #include <linux/module.h> | ||
25 | #include <linux/moduleparam.h> | ||
26 | #include <linux/kmod.h> | ||
27 | #include <linux/kernel.h> | ||
28 | #include <linux/slab.h> | ||
29 | #include <linux/interrupt.h> | ||
30 | #include <linux/delay.h> | ||
31 | #include <linux/kthread.h> | ||
32 | #include <asm/div64.h> | ||
33 | |||
34 | #include "cx23885.h" | ||
35 | #include <media/v4l2-common.h> | ||
36 | #include <media/v4l2-ioctl.h> | ||
37 | #include "cx23885-ioctl.h" | ||
38 | #include "tuner-xc2028.h" | ||
39 | |||
40 | MODULE_DESCRIPTION("v4l2 driver module for cx23885 based TV cards"); | ||
41 | MODULE_AUTHOR("Steven Toth <stoth@linuxtv.org>"); | ||
42 | MODULE_LICENSE("GPL"); | ||
43 | |||
44 | /* ------------------------------------------------------------------ */ | ||
45 | |||
46 | static unsigned int video_nr[] = {[0 ... (CX23885_MAXBOARDS - 1)] = UNSET }; | ||
47 | static unsigned int vbi_nr[] = {[0 ... (CX23885_MAXBOARDS - 1)] = UNSET }; | ||
48 | static unsigned int radio_nr[] = {[0 ... (CX23885_MAXBOARDS - 1)] = UNSET }; | ||
49 | |||
50 | module_param_array(video_nr, int, NULL, 0444); | ||
51 | module_param_array(vbi_nr, int, NULL, 0444); | ||
52 | module_param_array(radio_nr, int, NULL, 0444); | ||
53 | |||
54 | MODULE_PARM_DESC(video_nr, "video device numbers"); | ||
55 | MODULE_PARM_DESC(vbi_nr, "vbi device numbers"); | ||
56 | MODULE_PARM_DESC(radio_nr, "radio device numbers"); | ||
57 | |||
58 | static unsigned int video_debug; | ||
59 | module_param(video_debug, int, 0644); | ||
60 | MODULE_PARM_DESC(video_debug, "enable debug messages [video]"); | ||
61 | |||
62 | static unsigned int irq_debug; | ||
63 | module_param(irq_debug, int, 0644); | ||
64 | MODULE_PARM_DESC(irq_debug, "enable debug messages [IRQ handler]"); | ||
65 | |||
66 | static unsigned int vid_limit = 16; | ||
67 | module_param(vid_limit, int, 0644); | ||
68 | MODULE_PARM_DESC(vid_limit, "capture memory limit in megabytes"); | ||
69 | |||
70 | #define dprintk(level, fmt, arg...)\ | ||
71 | do { if (video_debug >= level)\ | ||
72 | printk(KERN_DEBUG "%s/0: " fmt, dev->name, ## arg);\ | ||
73 | } while (0) | ||
74 | |||
75 | /* ------------------------------------------------------------------- */ | ||
76 | /* static data */ | ||
77 | |||
78 | #define FORMAT_FLAGS_PACKED 0x01 | ||
79 | |||
80 | static struct cx23885_fmt formats[] = { | ||
81 | { | ||
82 | .name = "8 bpp, gray", | ||
83 | .fourcc = V4L2_PIX_FMT_GREY, | ||
84 | .depth = 8, | ||
85 | .flags = FORMAT_FLAGS_PACKED, | ||
86 | }, { | ||
87 | .name = "15 bpp RGB, le", | ||
88 | .fourcc = V4L2_PIX_FMT_RGB555, | ||
89 | .depth = 16, | ||
90 | .flags = FORMAT_FLAGS_PACKED, | ||
91 | }, { | ||
92 | .name = "15 bpp RGB, be", | ||
93 | .fourcc = V4L2_PIX_FMT_RGB555X, | ||
94 | .depth = 16, | ||
95 | .flags = FORMAT_FLAGS_PACKED, | ||
96 | }, { | ||
97 | .name = "16 bpp RGB, le", | ||
98 | .fourcc = V4L2_PIX_FMT_RGB565, | ||
99 | .depth = 16, | ||
100 | .flags = FORMAT_FLAGS_PACKED, | ||
101 | }, { | ||
102 | .name = "16 bpp RGB, be", | ||
103 | .fourcc = V4L2_PIX_FMT_RGB565X, | ||
104 | .depth = 16, | ||
105 | .flags = FORMAT_FLAGS_PACKED, | ||
106 | }, { | ||
107 | .name = "24 bpp RGB, le", | ||
108 | .fourcc = V4L2_PIX_FMT_BGR24, | ||
109 | .depth = 24, | ||
110 | .flags = FORMAT_FLAGS_PACKED, | ||
111 | }, { | ||
112 | .name = "32 bpp RGB, le", | ||
113 | .fourcc = V4L2_PIX_FMT_BGR32, | ||
114 | .depth = 32, | ||
115 | .flags = FORMAT_FLAGS_PACKED, | ||
116 | }, { | ||
117 | .name = "32 bpp RGB, be", | ||
118 | .fourcc = V4L2_PIX_FMT_RGB32, | ||
119 | .depth = 32, | ||
120 | .flags = FORMAT_FLAGS_PACKED, | ||
121 | }, { | ||
122 | .name = "4:2:2, packed, YUYV", | ||
123 | .fourcc = V4L2_PIX_FMT_YUYV, | ||
124 | .depth = 16, | ||
125 | .flags = FORMAT_FLAGS_PACKED, | ||
126 | }, { | ||
127 | .name = "4:2:2, packed, UYVY", | ||
128 | .fourcc = V4L2_PIX_FMT_UYVY, | ||
129 | .depth = 16, | ||
130 | .flags = FORMAT_FLAGS_PACKED, | ||
131 | }, | ||
132 | }; | ||
133 | |||
134 | static struct cx23885_fmt *format_by_fourcc(unsigned int fourcc) | ||
135 | { | ||
136 | unsigned int i; | ||
137 | |||
138 | for (i = 0; i < ARRAY_SIZE(formats); i++) | ||
139 | if (formats[i].fourcc == fourcc) | ||
140 | return formats+i; | ||
141 | |||
142 | printk(KERN_ERR "%s(0x%08x) NOT FOUND\n", __func__, fourcc); | ||
143 | return NULL; | ||
144 | } | ||
145 | |||
146 | /* ------------------------------------------------------------------- */ | ||
147 | |||
148 | static const struct v4l2_queryctrl no_ctl = { | ||
149 | .name = "42", | ||
150 | .flags = V4L2_CTRL_FLAG_DISABLED, | ||
151 | }; | ||
152 | |||
153 | static struct cx23885_ctrl cx23885_ctls[] = { | ||
154 | /* --- video --- */ | ||
155 | { | ||
156 | .v = { | ||
157 | .id = V4L2_CID_BRIGHTNESS, | ||
158 | .name = "Brightness", | ||
159 | .minimum = 0x00, | ||
160 | .maximum = 0xff, | ||
161 | .step = 1, | ||
162 | .default_value = 0x7f, | ||
163 | .type = V4L2_CTRL_TYPE_INTEGER, | ||
164 | }, | ||
165 | .off = 128, | ||
166 | .reg = LUMA_CTRL, | ||
167 | .mask = 0x00ff, | ||
168 | .shift = 0, | ||
169 | }, { | ||
170 | .v = { | ||
171 | .id = V4L2_CID_CONTRAST, | ||
172 | .name = "Contrast", | ||
173 | .minimum = 0, | ||
174 | .maximum = 0xff, | ||
175 | .step = 1, | ||
176 | .default_value = 0x3f, | ||
177 | .type = V4L2_CTRL_TYPE_INTEGER, | ||
178 | }, | ||
179 | .off = 0, | ||
180 | .reg = LUMA_CTRL, | ||
181 | .mask = 0xff00, | ||
182 | .shift = 8, | ||
183 | }, { | ||
184 | .v = { | ||
185 | .id = V4L2_CID_HUE, | ||
186 | .name = "Hue", | ||
187 | .minimum = 0, | ||
188 | .maximum = 0xff, | ||
189 | .step = 1, | ||
190 | .default_value = 0x7f, | ||
191 | .type = V4L2_CTRL_TYPE_INTEGER, | ||
192 | }, | ||
193 | .off = 128, | ||
194 | .reg = CHROMA_CTRL, | ||
195 | .mask = 0xff0000, | ||
196 | .shift = 16, | ||
197 | }, { | ||
198 | /* strictly, this only describes only U saturation. | ||
199 | * V saturation is handled specially through code. | ||
200 | */ | ||
201 | .v = { | ||
202 | .id = V4L2_CID_SATURATION, | ||
203 | .name = "Saturation", | ||
204 | .minimum = 0, | ||
205 | .maximum = 0xff, | ||
206 | .step = 1, | ||
207 | .default_value = 0x7f, | ||
208 | .type = V4L2_CTRL_TYPE_INTEGER, | ||
209 | }, | ||
210 | .off = 0, | ||
211 | .reg = CHROMA_CTRL, | ||
212 | .mask = 0x00ff, | ||
213 | .shift = 0, | ||
214 | }, { | ||
215 | /* --- audio --- */ | ||
216 | .v = { | ||
217 | .id = V4L2_CID_AUDIO_MUTE, | ||
218 | .name = "Mute", | ||
219 | .minimum = 0, | ||
220 | .maximum = 1, | ||
221 | .default_value = 1, | ||
222 | .type = V4L2_CTRL_TYPE_BOOLEAN, | ||
223 | }, | ||
224 | .reg = PATH1_CTL1, | ||
225 | .mask = (0x1f << 24), | ||
226 | .shift = 24, | ||
227 | }, { | ||
228 | .v = { | ||
229 | .id = V4L2_CID_AUDIO_VOLUME, | ||
230 | .name = "Volume", | ||
231 | .minimum = 0, | ||
232 | .maximum = 0x3f, | ||
233 | .step = 1, | ||
234 | .default_value = 0x3f, | ||
235 | .type = V4L2_CTRL_TYPE_INTEGER, | ||
236 | }, | ||
237 | .reg = PATH1_VOL_CTL, | ||
238 | .mask = 0xff, | ||
239 | .shift = 0, | ||
240 | } | ||
241 | }; | ||
242 | static const int CX23885_CTLS = ARRAY_SIZE(cx23885_ctls); | ||
243 | |||
244 | /* Must be sorted from low to high control ID! */ | ||
245 | static const u32 cx23885_user_ctrls[] = { | ||
246 | V4L2_CID_USER_CLASS, | ||
247 | V4L2_CID_BRIGHTNESS, | ||
248 | V4L2_CID_CONTRAST, | ||
249 | V4L2_CID_SATURATION, | ||
250 | V4L2_CID_HUE, | ||
251 | V4L2_CID_AUDIO_VOLUME, | ||
252 | V4L2_CID_AUDIO_MUTE, | ||
253 | 0 | ||
254 | }; | ||
255 | |||
256 | static const u32 *ctrl_classes[] = { | ||
257 | cx23885_user_ctrls, | ||
258 | NULL | ||
259 | }; | ||
260 | |||
261 | static void cx23885_video_wakeup(struct cx23885_dev *dev, | ||
262 | struct cx23885_dmaqueue *q, u32 count) | ||
263 | { | ||
264 | struct cx23885_buffer *buf; | ||
265 | int bc; | ||
266 | |||
267 | for (bc = 0;; bc++) { | ||
268 | if (list_empty(&q->active)) | ||
269 | break; | ||
270 | buf = list_entry(q->active.next, | ||
271 | struct cx23885_buffer, vb.queue); | ||
272 | |||
273 | /* count comes from the hw and is is 16bit wide -- | ||
274 | * this trick handles wrap-arounds correctly for | ||
275 | * up to 32767 buffers in flight... */ | ||
276 | if ((s16) (count - buf->count) < 0) | ||
277 | break; | ||
278 | |||
279 | do_gettimeofday(&buf->vb.ts); | ||
280 | dprintk(2, "[%p/%d] wakeup reg=%d buf=%d\n", buf, buf->vb.i, | ||
281 | count, buf->count); | ||
282 | buf->vb.state = VIDEOBUF_DONE; | ||
283 | list_del(&buf->vb.queue); | ||
284 | wake_up(&buf->vb.done); | ||
285 | } | ||
286 | if (list_empty(&q->active)) | ||
287 | del_timer(&q->timeout); | ||
288 | else | ||
289 | mod_timer(&q->timeout, jiffies+BUFFER_TIMEOUT); | ||
290 | if (bc != 1) | ||
291 | printk(KERN_ERR "%s: %d buffers handled (should be 1)\n", | ||
292 | __func__, bc); | ||
293 | } | ||
294 | |||
295 | static int cx23885_set_tvnorm(struct cx23885_dev *dev, v4l2_std_id norm) | ||
296 | { | ||
297 | dprintk(1, "%s(norm = 0x%08x) name: [%s]\n", | ||
298 | __func__, | ||
299 | (unsigned int)norm, | ||
300 | v4l2_norm_to_name(norm)); | ||
301 | |||
302 | dev->tvnorm = norm; | ||
303 | |||
304 | call_all(dev, core, s_std, norm); | ||
305 | |||
306 | return 0; | ||
307 | } | ||
308 | |||
309 | static struct video_device *cx23885_vdev_init(struct cx23885_dev *dev, | ||
310 | struct pci_dev *pci, | ||
311 | struct video_device *template, | ||
312 | char *type) | ||
313 | { | ||
314 | struct video_device *vfd; | ||
315 | dprintk(1, "%s()\n", __func__); | ||
316 | |||
317 | vfd = video_device_alloc(); | ||
318 | if (NULL == vfd) | ||
319 | return NULL; | ||
320 | *vfd = *template; | ||
321 | vfd->v4l2_dev = &dev->v4l2_dev; | ||
322 | vfd->release = video_device_release; | ||
323 | snprintf(vfd->name, sizeof(vfd->name), "%s %s (%s)", | ||
324 | dev->name, type, cx23885_boards[dev->board].name); | ||
325 | video_set_drvdata(vfd, dev); | ||
326 | return vfd; | ||
327 | } | ||
328 | |||
329 | static int cx23885_ctrl_query(struct v4l2_queryctrl *qctrl) | ||
330 | { | ||
331 | int i; | ||
332 | |||
333 | if (qctrl->id < V4L2_CID_BASE || | ||
334 | qctrl->id >= V4L2_CID_LASTP1) | ||
335 | return -EINVAL; | ||
336 | for (i = 0; i < CX23885_CTLS; i++) | ||
337 | if (cx23885_ctls[i].v.id == qctrl->id) | ||
338 | break; | ||
339 | if (i == CX23885_CTLS) { | ||
340 | *qctrl = no_ctl; | ||
341 | return 0; | ||
342 | } | ||
343 | *qctrl = cx23885_ctls[i].v; | ||
344 | return 0; | ||
345 | } | ||
346 | |||
347 | /* ------------------------------------------------------------------- */ | ||
348 | /* resource management */ | ||
349 | |||
350 | static int res_get(struct cx23885_dev *dev, struct cx23885_fh *fh, | ||
351 | unsigned int bit) | ||
352 | { | ||
353 | dprintk(1, "%s()\n", __func__); | ||
354 | if (fh->resources & bit) | ||
355 | /* have it already allocated */ | ||
356 | return 1; | ||
357 | |||
358 | /* is it free? */ | ||
359 | mutex_lock(&dev->lock); | ||
360 | if (dev->resources & bit) { | ||
361 | /* no, someone else uses it */ | ||
362 | mutex_unlock(&dev->lock); | ||
363 | return 0; | ||
364 | } | ||
365 | /* it's free, grab it */ | ||
366 | fh->resources |= bit; | ||
367 | dev->resources |= bit; | ||
368 | dprintk(1, "res: get %d\n", bit); | ||
369 | mutex_unlock(&dev->lock); | ||
370 | return 1; | ||
371 | } | ||
372 | |||
373 | static int res_check(struct cx23885_fh *fh, unsigned int bit) | ||
374 | { | ||
375 | return fh->resources & bit; | ||
376 | } | ||
377 | |||
378 | static int res_locked(struct cx23885_dev *dev, unsigned int bit) | ||
379 | { | ||
380 | return dev->resources & bit; | ||
381 | } | ||
382 | |||
383 | static void res_free(struct cx23885_dev *dev, struct cx23885_fh *fh, | ||
384 | unsigned int bits) | ||
385 | { | ||
386 | BUG_ON((fh->resources & bits) != bits); | ||
387 | dprintk(1, "%s()\n", __func__); | ||
388 | |||
389 | mutex_lock(&dev->lock); | ||
390 | fh->resources &= ~bits; | ||
391 | dev->resources &= ~bits; | ||
392 | dprintk(1, "res: put %d\n", bits); | ||
393 | mutex_unlock(&dev->lock); | ||
394 | } | ||
395 | |||
396 | static int cx23885_video_mux(struct cx23885_dev *dev, unsigned int input) | ||
397 | { | ||
398 | dprintk(1, "%s() video_mux: %d [vmux=%d, gpio=0x%x,0x%x,0x%x,0x%x]\n", | ||
399 | __func__, | ||
400 | input, INPUT(input)->vmux, | ||
401 | INPUT(input)->gpio0, INPUT(input)->gpio1, | ||
402 | INPUT(input)->gpio2, INPUT(input)->gpio3); | ||
403 | dev->input = input; | ||
404 | |||
405 | if (dev->board == CX23885_BOARD_MYGICA_X8506 || | ||
406 | dev->board == CX23885_BOARD_MAGICPRO_PROHDTVE2) { | ||
407 | /* Select Analog TV */ | ||
408 | if (INPUT(input)->type == CX23885_VMUX_TELEVISION) | ||
409 | cx23885_gpio_clear(dev, GPIO_0); | ||
410 | } | ||
411 | |||
412 | /* Tell the internal A/V decoder */ | ||
413 | v4l2_subdev_call(dev->sd_cx25840, video, s_routing, | ||
414 | INPUT(input)->vmux, 0, 0); | ||
415 | |||
416 | return 0; | ||
417 | } | ||
418 | |||
419 | /* ------------------------------------------------------------------ */ | ||
420 | static int cx23885_set_scale(struct cx23885_dev *dev, unsigned int width, | ||
421 | unsigned int height, enum v4l2_field field) | ||
422 | { | ||
423 | dprintk(1, "%s()\n", __func__); | ||
424 | return 0; | ||
425 | } | ||
426 | |||
427 | static int cx23885_start_video_dma(struct cx23885_dev *dev, | ||
428 | struct cx23885_dmaqueue *q, | ||
429 | struct cx23885_buffer *buf) | ||
430 | { | ||
431 | dprintk(1, "%s()\n", __func__); | ||
432 | |||
433 | /* setup fifo + format */ | ||
434 | cx23885_sram_channel_setup(dev, &dev->sram_channels[SRAM_CH01], | ||
435 | buf->bpl, buf->risc.dma); | ||
436 | cx23885_set_scale(dev, buf->vb.width, buf->vb.height, buf->vb.field); | ||
437 | |||
438 | /* reset counter */ | ||
439 | cx_write(VID_A_GPCNT_CTL, 3); | ||
440 | q->count = 1; | ||
441 | |||
442 | /* enable irq */ | ||
443 | cx23885_irq_add_enable(dev, 0x01); | ||
444 | cx_set(VID_A_INT_MSK, 0x000011); | ||
445 | |||
446 | /* start dma */ | ||
447 | cx_set(DEV_CNTRL2, (1<<5)); | ||
448 | cx_set(VID_A_DMA_CTL, 0x11); /* FIFO and RISC enable */ | ||
449 | |||
450 | return 0; | ||
451 | } | ||
452 | |||
453 | |||
454 | static int cx23885_restart_video_queue(struct cx23885_dev *dev, | ||
455 | struct cx23885_dmaqueue *q) | ||
456 | { | ||
457 | struct cx23885_buffer *buf, *prev; | ||
458 | struct list_head *item; | ||
459 | dprintk(1, "%s()\n", __func__); | ||
460 | |||
461 | if (!list_empty(&q->active)) { | ||
462 | buf = list_entry(q->active.next, struct cx23885_buffer, | ||
463 | vb.queue); | ||
464 | dprintk(2, "restart_queue [%p/%d]: restart dma\n", | ||
465 | buf, buf->vb.i); | ||
466 | cx23885_start_video_dma(dev, q, buf); | ||
467 | list_for_each(item, &q->active) { | ||
468 | buf = list_entry(item, struct cx23885_buffer, | ||
469 | vb.queue); | ||
470 | buf->count = q->count++; | ||
471 | } | ||
472 | mod_timer(&q->timeout, jiffies+BUFFER_TIMEOUT); | ||
473 | return 0; | ||
474 | } | ||
475 | |||
476 | prev = NULL; | ||
477 | for (;;) { | ||
478 | if (list_empty(&q->queued)) | ||
479 | return 0; | ||
480 | buf = list_entry(q->queued.next, struct cx23885_buffer, | ||
481 | vb.queue); | ||
482 | if (NULL == prev) { | ||
483 | list_move_tail(&buf->vb.queue, &q->active); | ||
484 | cx23885_start_video_dma(dev, q, buf); | ||
485 | buf->vb.state = VIDEOBUF_ACTIVE; | ||
486 | buf->count = q->count++; | ||
487 | mod_timer(&q->timeout, jiffies+BUFFER_TIMEOUT); | ||
488 | dprintk(2, "[%p/%d] restart_queue - first active\n", | ||
489 | buf, buf->vb.i); | ||
490 | |||
491 | } else if (prev->vb.width == buf->vb.width && | ||
492 | prev->vb.height == buf->vb.height && | ||
493 | prev->fmt == buf->fmt) { | ||
494 | list_move_tail(&buf->vb.queue, &q->active); | ||
495 | buf->vb.state = VIDEOBUF_ACTIVE; | ||
496 | buf->count = q->count++; | ||
497 | prev->risc.jmp[1] = cpu_to_le32(buf->risc.dma); | ||
498 | prev->risc.jmp[2] = cpu_to_le32(0); /* Bits 63 - 32 */ | ||
499 | dprintk(2, "[%p/%d] restart_queue - move to active\n", | ||
500 | buf, buf->vb.i); | ||
501 | } else { | ||
502 | return 0; | ||
503 | } | ||
504 | prev = buf; | ||
505 | } | ||
506 | } | ||
507 | |||
508 | static int buffer_setup(struct videobuf_queue *q, unsigned int *count, | ||
509 | unsigned int *size) | ||
510 | { | ||
511 | struct cx23885_fh *fh = q->priv_data; | ||
512 | |||
513 | *size = fh->fmt->depth*fh->width*fh->height >> 3; | ||
514 | if (0 == *count) | ||
515 | *count = 32; | ||
516 | if (*size * *count > vid_limit * 1024 * 1024) | ||
517 | *count = (vid_limit * 1024 * 1024) / *size; | ||
518 | return 0; | ||
519 | } | ||
520 | |||
521 | static int buffer_prepare(struct videobuf_queue *q, struct videobuf_buffer *vb, | ||
522 | enum v4l2_field field) | ||
523 | { | ||
524 | struct cx23885_fh *fh = q->priv_data; | ||
525 | struct cx23885_dev *dev = fh->dev; | ||
526 | struct cx23885_buffer *buf = | ||
527 | container_of(vb, struct cx23885_buffer, vb); | ||
528 | int rc, init_buffer = 0; | ||
529 | u32 line0_offset, line1_offset; | ||
530 | struct videobuf_dmabuf *dma = videobuf_to_dma(&buf->vb); | ||
531 | |||
532 | BUG_ON(NULL == fh->fmt); | ||
533 | if (fh->width < 48 || fh->width > norm_maxw(dev->tvnorm) || | ||
534 | fh->height < 32 || fh->height > norm_maxh(dev->tvnorm)) | ||
535 | return -EINVAL; | ||
536 | buf->vb.size = (fh->width * fh->height * fh->fmt->depth) >> 3; | ||
537 | if (0 != buf->vb.baddr && buf->vb.bsize < buf->vb.size) | ||
538 | return -EINVAL; | ||
539 | |||
540 | if (buf->fmt != fh->fmt || | ||
541 | buf->vb.width != fh->width || | ||
542 | buf->vb.height != fh->height || | ||
543 | buf->vb.field != field) { | ||
544 | buf->fmt = fh->fmt; | ||
545 | buf->vb.width = fh->width; | ||
546 | buf->vb.height = fh->height; | ||
547 | buf->vb.field = field; | ||
548 | init_buffer = 1; | ||
549 | } | ||
550 | |||
551 | if (VIDEOBUF_NEEDS_INIT == buf->vb.state) { | ||
552 | init_buffer = 1; | ||
553 | rc = videobuf_iolock(q, &buf->vb, NULL); | ||
554 | if (0 != rc) | ||
555 | goto fail; | ||
556 | } | ||
557 | |||
558 | if (init_buffer) { | ||
559 | buf->bpl = buf->vb.width * buf->fmt->depth >> 3; | ||
560 | switch (buf->vb.field) { | ||
561 | case V4L2_FIELD_TOP: | ||
562 | cx23885_risc_buffer(dev->pci, &buf->risc, | ||
563 | dma->sglist, 0, UNSET, | ||
564 | buf->bpl, 0, buf->vb.height); | ||
565 | break; | ||
566 | case V4L2_FIELD_BOTTOM: | ||
567 | cx23885_risc_buffer(dev->pci, &buf->risc, | ||
568 | dma->sglist, UNSET, 0, | ||
569 | buf->bpl, 0, buf->vb.height); | ||
570 | break; | ||
571 | case V4L2_FIELD_INTERLACED: | ||
572 | if (dev->tvnorm & V4L2_STD_NTSC) { | ||
573 | /* cx25840 transmits NTSC bottom field first */ | ||
574 | dprintk(1, "%s() Creating NTSC risc\n", | ||
575 | __func__); | ||
576 | line0_offset = buf->bpl; | ||
577 | line1_offset = 0; | ||
578 | } else { | ||
579 | /* All other formats are top field first */ | ||
580 | dprintk(1, "%s() Creating PAL/SECAM risc\n", | ||
581 | __func__); | ||
582 | line0_offset = 0; | ||
583 | line1_offset = buf->bpl; | ||
584 | } | ||
585 | cx23885_risc_buffer(dev->pci, &buf->risc, | ||
586 | dma->sglist, line0_offset, | ||
587 | line1_offset, | ||
588 | buf->bpl, buf->bpl, | ||
589 | buf->vb.height >> 1); | ||
590 | break; | ||
591 | case V4L2_FIELD_SEQ_TB: | ||
592 | cx23885_risc_buffer(dev->pci, &buf->risc, | ||
593 | dma->sglist, | ||
594 | 0, buf->bpl * (buf->vb.height >> 1), | ||
595 | buf->bpl, 0, | ||
596 | buf->vb.height >> 1); | ||
597 | break; | ||
598 | case V4L2_FIELD_SEQ_BT: | ||
599 | cx23885_risc_buffer(dev->pci, &buf->risc, | ||
600 | dma->sglist, | ||
601 | buf->bpl * (buf->vb.height >> 1), 0, | ||
602 | buf->bpl, 0, | ||
603 | buf->vb.height >> 1); | ||
604 | break; | ||
605 | default: | ||
606 | BUG(); | ||
607 | } | ||
608 | } | ||
609 | dprintk(2, "[%p/%d] buffer_prep - %dx%d %dbpp \"%s\" - dma=0x%08lx\n", | ||
610 | buf, buf->vb.i, | ||
611 | fh->width, fh->height, fh->fmt->depth, fh->fmt->name, | ||
612 | (unsigned long)buf->risc.dma); | ||
613 | |||
614 | buf->vb.state = VIDEOBUF_PREPARED; | ||
615 | return 0; | ||
616 | |||
617 | fail: | ||
618 | cx23885_free_buffer(q, buf); | ||
619 | return rc; | ||
620 | } | ||
621 | |||
622 | static void buffer_queue(struct videobuf_queue *vq, struct videobuf_buffer *vb) | ||
623 | { | ||
624 | struct cx23885_buffer *buf = container_of(vb, | ||
625 | struct cx23885_buffer, vb); | ||
626 | struct cx23885_buffer *prev; | ||
627 | struct cx23885_fh *fh = vq->priv_data; | ||
628 | struct cx23885_dev *dev = fh->dev; | ||
629 | struct cx23885_dmaqueue *q = &dev->vidq; | ||
630 | |||
631 | /* add jump to stopper */ | ||
632 | buf->risc.jmp[0] = cpu_to_le32(RISC_JUMP | RISC_IRQ1 | RISC_CNT_INC); | ||
633 | buf->risc.jmp[1] = cpu_to_le32(q->stopper.dma); | ||
634 | buf->risc.jmp[2] = cpu_to_le32(0); /* bits 63-32 */ | ||
635 | |||
636 | if (!list_empty(&q->queued)) { | ||
637 | list_add_tail(&buf->vb.queue, &q->queued); | ||
638 | buf->vb.state = VIDEOBUF_QUEUED; | ||
639 | dprintk(2, "[%p/%d] buffer_queue - append to queued\n", | ||
640 | buf, buf->vb.i); | ||
641 | |||
642 | } else if (list_empty(&q->active)) { | ||
643 | list_add_tail(&buf->vb.queue, &q->active); | ||
644 | cx23885_start_video_dma(dev, q, buf); | ||
645 | buf->vb.state = VIDEOBUF_ACTIVE; | ||
646 | buf->count = q->count++; | ||
647 | mod_timer(&q->timeout, jiffies+BUFFER_TIMEOUT); | ||
648 | dprintk(2, "[%p/%d] buffer_queue - first active\n", | ||
649 | buf, buf->vb.i); | ||
650 | |||
651 | } else { | ||
652 | prev = list_entry(q->active.prev, struct cx23885_buffer, | ||
653 | vb.queue); | ||
654 | if (prev->vb.width == buf->vb.width && | ||
655 | prev->vb.height == buf->vb.height && | ||
656 | prev->fmt == buf->fmt) { | ||
657 | list_add_tail(&buf->vb.queue, &q->active); | ||
658 | buf->vb.state = VIDEOBUF_ACTIVE; | ||
659 | buf->count = q->count++; | ||
660 | prev->risc.jmp[1] = cpu_to_le32(buf->risc.dma); | ||
661 | /* 64 bit bits 63-32 */ | ||
662 | prev->risc.jmp[2] = cpu_to_le32(0); | ||
663 | dprintk(2, "[%p/%d] buffer_queue - append to active\n", | ||
664 | buf, buf->vb.i); | ||
665 | |||
666 | } else { | ||
667 | list_add_tail(&buf->vb.queue, &q->queued); | ||
668 | buf->vb.state = VIDEOBUF_QUEUED; | ||
669 | dprintk(2, "[%p/%d] buffer_queue - first queued\n", | ||
670 | buf, buf->vb.i); | ||
671 | } | ||
672 | } | ||
673 | } | ||
674 | |||
675 | static void buffer_release(struct videobuf_queue *q, | ||
676 | struct videobuf_buffer *vb) | ||
677 | { | ||
678 | struct cx23885_buffer *buf = container_of(vb, | ||
679 | struct cx23885_buffer, vb); | ||
680 | |||
681 | cx23885_free_buffer(q, buf); | ||
682 | } | ||
683 | |||
684 | static struct videobuf_queue_ops cx23885_video_qops = { | ||
685 | .buf_setup = buffer_setup, | ||
686 | .buf_prepare = buffer_prepare, | ||
687 | .buf_queue = buffer_queue, | ||
688 | .buf_release = buffer_release, | ||
689 | }; | ||
690 | |||
691 | static struct videobuf_queue *get_queue(struct cx23885_fh *fh) | ||
692 | { | ||
693 | switch (fh->type) { | ||
694 | case V4L2_BUF_TYPE_VIDEO_CAPTURE: | ||
695 | return &fh->vidq; | ||
696 | case V4L2_BUF_TYPE_VBI_CAPTURE: | ||
697 | return &fh->vbiq; | ||
698 | default: | ||
699 | BUG(); | ||
700 | return NULL; | ||
701 | } | ||
702 | } | ||
703 | |||
704 | static int get_resource(struct cx23885_fh *fh) | ||
705 | { | ||
706 | switch (fh->type) { | ||
707 | case V4L2_BUF_TYPE_VIDEO_CAPTURE: | ||
708 | return RESOURCE_VIDEO; | ||
709 | case V4L2_BUF_TYPE_VBI_CAPTURE: | ||
710 | return RESOURCE_VBI; | ||
711 | default: | ||
712 | BUG(); | ||
713 | return 0; | ||
714 | } | ||
715 | } | ||
716 | |||
717 | static int video_open(struct file *file) | ||
718 | { | ||
719 | struct video_device *vdev = video_devdata(file); | ||
720 | struct cx23885_dev *dev = video_drvdata(file); | ||
721 | struct cx23885_fh *fh; | ||
722 | enum v4l2_buf_type type = 0; | ||
723 | int radio = 0; | ||
724 | |||
725 | switch (vdev->vfl_type) { | ||
726 | case VFL_TYPE_GRABBER: | ||
727 | type = V4L2_BUF_TYPE_VIDEO_CAPTURE; | ||
728 | break; | ||
729 | case VFL_TYPE_VBI: | ||
730 | type = V4L2_BUF_TYPE_VBI_CAPTURE; | ||
731 | break; | ||
732 | case VFL_TYPE_RADIO: | ||
733 | radio = 1; | ||
734 | break; | ||
735 | } | ||
736 | |||
737 | dprintk(1, "open dev=%s radio=%d type=%s\n", | ||
738 | video_device_node_name(vdev), radio, v4l2_type_names[type]); | ||
739 | |||
740 | /* allocate + initialize per filehandle data */ | ||
741 | fh = kzalloc(sizeof(*fh), GFP_KERNEL); | ||
742 | if (NULL == fh) | ||
743 | return -ENOMEM; | ||
744 | |||
745 | file->private_data = fh; | ||
746 | fh->dev = dev; | ||
747 | fh->radio = radio; | ||
748 | fh->type = type; | ||
749 | fh->width = 320; | ||
750 | fh->height = 240; | ||
751 | fh->fmt = format_by_fourcc(V4L2_PIX_FMT_BGR24); | ||
752 | |||
753 | videobuf_queue_sg_init(&fh->vidq, &cx23885_video_qops, | ||
754 | &dev->pci->dev, &dev->slock, | ||
755 | V4L2_BUF_TYPE_VIDEO_CAPTURE, | ||
756 | V4L2_FIELD_INTERLACED, | ||
757 | sizeof(struct cx23885_buffer), | ||
758 | fh, NULL); | ||
759 | |||
760 | dprintk(1, "post videobuf_queue_init()\n"); | ||
761 | |||
762 | return 0; | ||
763 | } | ||
764 | |||
765 | static ssize_t video_read(struct file *file, char __user *data, | ||
766 | size_t count, loff_t *ppos) | ||
767 | { | ||
768 | struct cx23885_fh *fh = file->private_data; | ||
769 | |||
770 | switch (fh->type) { | ||
771 | case V4L2_BUF_TYPE_VIDEO_CAPTURE: | ||
772 | if (res_locked(fh->dev, RESOURCE_VIDEO)) | ||
773 | return -EBUSY; | ||
774 | return videobuf_read_one(&fh->vidq, data, count, ppos, | ||
775 | file->f_flags & O_NONBLOCK); | ||
776 | case V4L2_BUF_TYPE_VBI_CAPTURE: | ||
777 | if (!res_get(fh->dev, fh, RESOURCE_VBI)) | ||
778 | return -EBUSY; | ||
779 | return videobuf_read_stream(&fh->vbiq, data, count, ppos, 1, | ||
780 | file->f_flags & O_NONBLOCK); | ||
781 | default: | ||
782 | BUG(); | ||
783 | return 0; | ||
784 | } | ||
785 | } | ||
786 | |||
787 | static unsigned int video_poll(struct file *file, | ||
788 | struct poll_table_struct *wait) | ||
789 | { | ||
790 | struct cx23885_fh *fh = file->private_data; | ||
791 | struct cx23885_buffer *buf; | ||
792 | unsigned int rc = POLLERR; | ||
793 | |||
794 | if (V4L2_BUF_TYPE_VBI_CAPTURE == fh->type) { | ||
795 | if (!res_get(fh->dev, fh, RESOURCE_VBI)) | ||
796 | return POLLERR; | ||
797 | return videobuf_poll_stream(file, &fh->vbiq, wait); | ||
798 | } | ||
799 | |||
800 | mutex_lock(&fh->vidq.vb_lock); | ||
801 | if (res_check(fh, RESOURCE_VIDEO)) { | ||
802 | /* streaming capture */ | ||
803 | if (list_empty(&fh->vidq.stream)) | ||
804 | goto done; | ||
805 | buf = list_entry(fh->vidq.stream.next, | ||
806 | struct cx23885_buffer, vb.stream); | ||
807 | } else { | ||
808 | /* read() capture */ | ||
809 | buf = (struct cx23885_buffer *)fh->vidq.read_buf; | ||
810 | if (NULL == buf) | ||
811 | goto done; | ||
812 | } | ||
813 | poll_wait(file, &buf->vb.done, wait); | ||
814 | if (buf->vb.state == VIDEOBUF_DONE || | ||
815 | buf->vb.state == VIDEOBUF_ERROR) | ||
816 | rc = POLLIN|POLLRDNORM; | ||
817 | else | ||
818 | rc = 0; | ||
819 | done: | ||
820 | mutex_unlock(&fh->vidq.vb_lock); | ||
821 | return rc; | ||
822 | } | ||
823 | |||
824 | static int video_release(struct file *file) | ||
825 | { | ||
826 | struct cx23885_fh *fh = file->private_data; | ||
827 | struct cx23885_dev *dev = fh->dev; | ||
828 | |||
829 | /* turn off overlay */ | ||
830 | if (res_check(fh, RESOURCE_OVERLAY)) { | ||
831 | /* FIXME */ | ||
832 | res_free(dev, fh, RESOURCE_OVERLAY); | ||
833 | } | ||
834 | |||
835 | /* stop video capture */ | ||
836 | if (res_check(fh, RESOURCE_VIDEO)) { | ||
837 | videobuf_queue_cancel(&fh->vidq); | ||
838 | res_free(dev, fh, RESOURCE_VIDEO); | ||
839 | } | ||
840 | if (fh->vidq.read_buf) { | ||
841 | buffer_release(&fh->vidq, fh->vidq.read_buf); | ||
842 | kfree(fh->vidq.read_buf); | ||
843 | } | ||
844 | |||
845 | /* stop vbi capture */ | ||
846 | if (res_check(fh, RESOURCE_VBI)) { | ||
847 | if (fh->vbiq.streaming) | ||
848 | videobuf_streamoff(&fh->vbiq); | ||
849 | if (fh->vbiq.reading) | ||
850 | videobuf_read_stop(&fh->vbiq); | ||
851 | res_free(dev, fh, RESOURCE_VBI); | ||
852 | } | ||
853 | |||
854 | videobuf_mmap_free(&fh->vidq); | ||
855 | file->private_data = NULL; | ||
856 | kfree(fh); | ||
857 | |||
858 | /* We are not putting the tuner to sleep here on exit, because | ||
859 | * we want to use the mpeg encoder in another session to capture | ||
860 | * tuner video. Closing this will result in no video to the encoder. | ||
861 | */ | ||
862 | |||
863 | return 0; | ||
864 | } | ||
865 | |||
866 | static int video_mmap(struct file *file, struct vm_area_struct *vma) | ||
867 | { | ||
868 | struct cx23885_fh *fh = file->private_data; | ||
869 | |||
870 | return videobuf_mmap_mapper(get_queue(fh), vma); | ||
871 | } | ||
872 | |||
873 | /* ------------------------------------------------------------------ */ | ||
874 | /* VIDEO CTRL IOCTLS */ | ||
875 | |||
876 | static int cx23885_get_control(struct cx23885_dev *dev, | ||
877 | struct v4l2_control *ctl) | ||
878 | { | ||
879 | dprintk(1, "%s() calling cx25840(VIDIOC_G_CTRL)\n", __func__); | ||
880 | call_all(dev, core, g_ctrl, ctl); | ||
881 | return 0; | ||
882 | } | ||
883 | |||
884 | static int cx23885_set_control(struct cx23885_dev *dev, | ||
885 | struct v4l2_control *ctl) | ||
886 | { | ||
887 | dprintk(1, "%s() calling cx25840(VIDIOC_S_CTRL)" | ||
888 | " (disabled - no action)\n", __func__); | ||
889 | return 0; | ||
890 | } | ||
891 | |||
892 | static void init_controls(struct cx23885_dev *dev) | ||
893 | { | ||
894 | struct v4l2_control ctrl; | ||
895 | int i; | ||
896 | |||
897 | for (i = 0; i < CX23885_CTLS; i++) { | ||
898 | ctrl.id = cx23885_ctls[i].v.id; | ||
899 | ctrl.value = cx23885_ctls[i].v.default_value; | ||
900 | |||
901 | cx23885_set_control(dev, &ctrl); | ||
902 | } | ||
903 | } | ||
904 | |||
905 | /* ------------------------------------------------------------------ */ | ||
906 | /* VIDEO IOCTLS */ | ||
907 | |||
908 | static int vidioc_g_fmt_vid_cap(struct file *file, void *priv, | ||
909 | struct v4l2_format *f) | ||
910 | { | ||
911 | struct cx23885_fh *fh = priv; | ||
912 | |||
913 | f->fmt.pix.width = fh->width; | ||
914 | f->fmt.pix.height = fh->height; | ||
915 | f->fmt.pix.field = fh->vidq.field; | ||
916 | f->fmt.pix.pixelformat = fh->fmt->fourcc; | ||
917 | f->fmt.pix.bytesperline = | ||
918 | (f->fmt.pix.width * fh->fmt->depth) >> 3; | ||
919 | f->fmt.pix.sizeimage = | ||
920 | f->fmt.pix.height * f->fmt.pix.bytesperline; | ||
921 | |||
922 | return 0; | ||
923 | } | ||
924 | |||
925 | static int vidioc_try_fmt_vid_cap(struct file *file, void *priv, | ||
926 | struct v4l2_format *f) | ||
927 | { | ||
928 | struct cx23885_dev *dev = ((struct cx23885_fh *)priv)->dev; | ||
929 | struct cx23885_fmt *fmt; | ||
930 | enum v4l2_field field; | ||
931 | unsigned int maxw, maxh; | ||
932 | |||
933 | fmt = format_by_fourcc(f->fmt.pix.pixelformat); | ||
934 | if (NULL == fmt) | ||
935 | return -EINVAL; | ||
936 | |||
937 | field = f->fmt.pix.field; | ||
938 | maxw = norm_maxw(dev->tvnorm); | ||
939 | maxh = norm_maxh(dev->tvnorm); | ||
940 | |||
941 | if (V4L2_FIELD_ANY == field) { | ||
942 | field = (f->fmt.pix.height > maxh/2) | ||
943 | ? V4L2_FIELD_INTERLACED | ||
944 | : V4L2_FIELD_BOTTOM; | ||
945 | } | ||
946 | |||
947 | switch (field) { | ||
948 | case V4L2_FIELD_TOP: | ||
949 | case V4L2_FIELD_BOTTOM: | ||
950 | maxh = maxh / 2; | ||
951 | break; | ||
952 | case V4L2_FIELD_INTERLACED: | ||
953 | break; | ||
954 | default: | ||
955 | return -EINVAL; | ||
956 | } | ||
957 | |||
958 | f->fmt.pix.field = field; | ||
959 | v4l_bound_align_image(&f->fmt.pix.width, 48, maxw, 2, | ||
960 | &f->fmt.pix.height, 32, maxh, 0, 0); | ||
961 | f->fmt.pix.bytesperline = | ||
962 | (f->fmt.pix.width * fmt->depth) >> 3; | ||
963 | f->fmt.pix.sizeimage = | ||
964 | f->fmt.pix.height * f->fmt.pix.bytesperline; | ||
965 | |||
966 | return 0; | ||
967 | } | ||
968 | |||
969 | static int vidioc_s_fmt_vid_cap(struct file *file, void *priv, | ||
970 | struct v4l2_format *f) | ||
971 | { | ||
972 | struct cx23885_fh *fh = priv; | ||
973 | struct cx23885_dev *dev = ((struct cx23885_fh *)priv)->dev; | ||
974 | struct v4l2_mbus_framefmt mbus_fmt; | ||
975 | int err; | ||
976 | |||
977 | dprintk(2, "%s()\n", __func__); | ||
978 | err = vidioc_try_fmt_vid_cap(file, priv, f); | ||
979 | |||
980 | if (0 != err) | ||
981 | return err; | ||
982 | fh->fmt = format_by_fourcc(f->fmt.pix.pixelformat); | ||
983 | fh->width = f->fmt.pix.width; | ||
984 | fh->height = f->fmt.pix.height; | ||
985 | fh->vidq.field = f->fmt.pix.field; | ||
986 | dprintk(2, "%s() width=%d height=%d field=%d\n", __func__, | ||
987 | fh->width, fh->height, fh->vidq.field); | ||
988 | v4l2_fill_mbus_format(&mbus_fmt, &f->fmt.pix, V4L2_MBUS_FMT_FIXED); | ||
989 | call_all(dev, video, s_mbus_fmt, &mbus_fmt); | ||
990 | v4l2_fill_pix_format(&f->fmt.pix, &mbus_fmt); | ||
991 | return 0; | ||
992 | } | ||
993 | |||
994 | static int vidioc_querycap(struct file *file, void *priv, | ||
995 | struct v4l2_capability *cap) | ||
996 | { | ||
997 | struct cx23885_dev *dev = ((struct cx23885_fh *)priv)->dev; | ||
998 | |||
999 | strcpy(cap->driver, "cx23885"); | ||
1000 | strlcpy(cap->card, cx23885_boards[dev->board].name, | ||
1001 | sizeof(cap->card)); | ||
1002 | sprintf(cap->bus_info, "PCIe:%s", pci_name(dev->pci)); | ||
1003 | cap->capabilities = | ||
1004 | V4L2_CAP_VIDEO_CAPTURE | | ||
1005 | V4L2_CAP_READWRITE | | ||
1006 | V4L2_CAP_STREAMING | | ||
1007 | V4L2_CAP_VBI_CAPTURE; | ||
1008 | if (UNSET != dev->tuner_type) | ||
1009 | cap->capabilities |= V4L2_CAP_TUNER; | ||
1010 | return 0; | ||
1011 | } | ||
1012 | |||
1013 | static int vidioc_enum_fmt_vid_cap(struct file *file, void *priv, | ||
1014 | struct v4l2_fmtdesc *f) | ||
1015 | { | ||
1016 | if (unlikely(f->index >= ARRAY_SIZE(formats))) | ||
1017 | return -EINVAL; | ||
1018 | |||
1019 | strlcpy(f->description, formats[f->index].name, | ||
1020 | sizeof(f->description)); | ||
1021 | f->pixelformat = formats[f->index].fourcc; | ||
1022 | |||
1023 | return 0; | ||
1024 | } | ||
1025 | |||
1026 | static int vidioc_reqbufs(struct file *file, void *priv, | ||
1027 | struct v4l2_requestbuffers *p) | ||
1028 | { | ||
1029 | struct cx23885_fh *fh = priv; | ||
1030 | return videobuf_reqbufs(get_queue(fh), p); | ||
1031 | } | ||
1032 | |||
1033 | static int vidioc_querybuf(struct file *file, void *priv, | ||
1034 | struct v4l2_buffer *p) | ||
1035 | { | ||
1036 | struct cx23885_fh *fh = priv; | ||
1037 | return videobuf_querybuf(get_queue(fh), p); | ||
1038 | } | ||
1039 | |||
1040 | static int vidioc_qbuf(struct file *file, void *priv, | ||
1041 | struct v4l2_buffer *p) | ||
1042 | { | ||
1043 | struct cx23885_fh *fh = priv; | ||
1044 | return videobuf_qbuf(get_queue(fh), p); | ||
1045 | } | ||
1046 | |||
1047 | static int vidioc_dqbuf(struct file *file, void *priv, | ||
1048 | struct v4l2_buffer *p) | ||
1049 | { | ||
1050 | struct cx23885_fh *fh = priv; | ||
1051 | return videobuf_dqbuf(get_queue(fh), p, | ||
1052 | file->f_flags & O_NONBLOCK); | ||
1053 | } | ||
1054 | |||
1055 | static int vidioc_streamon(struct file *file, void *priv, | ||
1056 | enum v4l2_buf_type i) | ||
1057 | { | ||
1058 | struct cx23885_fh *fh = priv; | ||
1059 | struct cx23885_dev *dev = fh->dev; | ||
1060 | dprintk(1, "%s()\n", __func__); | ||
1061 | |||
1062 | if (unlikely(fh->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)) | ||
1063 | return -EINVAL; | ||
1064 | if (unlikely(i != fh->type)) | ||
1065 | return -EINVAL; | ||
1066 | |||
1067 | if (unlikely(!res_get(dev, fh, get_resource(fh)))) | ||
1068 | return -EBUSY; | ||
1069 | return videobuf_streamon(get_queue(fh)); | ||
1070 | } | ||
1071 | |||
1072 | static int vidioc_streamoff(struct file *file, void *priv, enum v4l2_buf_type i) | ||
1073 | { | ||
1074 | struct cx23885_fh *fh = priv; | ||
1075 | struct cx23885_dev *dev = fh->dev; | ||
1076 | int err, res; | ||
1077 | dprintk(1, "%s()\n", __func__); | ||
1078 | |||
1079 | if (fh->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) | ||
1080 | return -EINVAL; | ||
1081 | if (i != fh->type) | ||
1082 | return -EINVAL; | ||
1083 | |||
1084 | res = get_resource(fh); | ||
1085 | err = videobuf_streamoff(get_queue(fh)); | ||
1086 | if (err < 0) | ||
1087 | return err; | ||
1088 | res_free(dev, fh, res); | ||
1089 | return 0; | ||
1090 | } | ||
1091 | |||
1092 | static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id *tvnorms) | ||
1093 | { | ||
1094 | struct cx23885_dev *dev = ((struct cx23885_fh *)priv)->dev; | ||
1095 | dprintk(1, "%s()\n", __func__); | ||
1096 | |||
1097 | mutex_lock(&dev->lock); | ||
1098 | cx23885_set_tvnorm(dev, *tvnorms); | ||
1099 | mutex_unlock(&dev->lock); | ||
1100 | |||
1101 | return 0; | ||
1102 | } | ||
1103 | |||
1104 | static int cx23885_enum_input(struct cx23885_dev *dev, struct v4l2_input *i) | ||
1105 | { | ||
1106 | static const char *iname[] = { | ||
1107 | [CX23885_VMUX_COMPOSITE1] = "Composite1", | ||
1108 | [CX23885_VMUX_COMPOSITE2] = "Composite2", | ||
1109 | [CX23885_VMUX_COMPOSITE3] = "Composite3", | ||
1110 | [CX23885_VMUX_COMPOSITE4] = "Composite4", | ||
1111 | [CX23885_VMUX_SVIDEO] = "S-Video", | ||
1112 | [CX23885_VMUX_COMPONENT] = "Component", | ||
1113 | [CX23885_VMUX_TELEVISION] = "Television", | ||
1114 | [CX23885_VMUX_CABLE] = "Cable TV", | ||
1115 | [CX23885_VMUX_DVB] = "DVB", | ||
1116 | [CX23885_VMUX_DEBUG] = "for debug only", | ||
1117 | }; | ||
1118 | unsigned int n; | ||
1119 | dprintk(1, "%s()\n", __func__); | ||
1120 | |||
1121 | n = i->index; | ||
1122 | if (n >= 4) | ||
1123 | return -EINVAL; | ||
1124 | |||
1125 | if (0 == INPUT(n)->type) | ||
1126 | return -EINVAL; | ||
1127 | |||
1128 | i->index = n; | ||
1129 | i->type = V4L2_INPUT_TYPE_CAMERA; | ||
1130 | strcpy(i->name, iname[INPUT(n)->type]); | ||
1131 | if ((CX23885_VMUX_TELEVISION == INPUT(n)->type) || | ||
1132 | (CX23885_VMUX_CABLE == INPUT(n)->type)) { | ||
1133 | i->type = V4L2_INPUT_TYPE_TUNER; | ||
1134 | i->std = CX23885_NORMS; | ||
1135 | } | ||
1136 | return 0; | ||
1137 | } | ||
1138 | |||
1139 | static int vidioc_enum_input(struct file *file, void *priv, | ||
1140 | struct v4l2_input *i) | ||
1141 | { | ||
1142 | struct cx23885_dev *dev = ((struct cx23885_fh *)priv)->dev; | ||
1143 | dprintk(1, "%s()\n", __func__); | ||
1144 | return cx23885_enum_input(dev, i); | ||
1145 | } | ||
1146 | |||
1147 | static int vidioc_g_input(struct file *file, void *priv, unsigned int *i) | ||
1148 | { | ||
1149 | struct cx23885_dev *dev = ((struct cx23885_fh *)priv)->dev; | ||
1150 | |||
1151 | *i = dev->input; | ||
1152 | dprintk(1, "%s() returns %d\n", __func__, *i); | ||
1153 | return 0; | ||
1154 | } | ||
1155 | |||
1156 | static int vidioc_s_input(struct file *file, void *priv, unsigned int i) | ||
1157 | { | ||
1158 | struct cx23885_dev *dev = ((struct cx23885_fh *)priv)->dev; | ||
1159 | |||
1160 | dprintk(1, "%s(%d)\n", __func__, i); | ||
1161 | |||
1162 | if (i >= 4) { | ||
1163 | dprintk(1, "%s() -EINVAL\n", __func__); | ||
1164 | return -EINVAL; | ||
1165 | } | ||
1166 | |||
1167 | mutex_lock(&dev->lock); | ||
1168 | cx23885_video_mux(dev, i); | ||
1169 | mutex_unlock(&dev->lock); | ||
1170 | return 0; | ||
1171 | } | ||
1172 | |||
1173 | static int vidioc_log_status(struct file *file, void *priv) | ||
1174 | { | ||
1175 | struct cx23885_fh *fh = priv; | ||
1176 | struct cx23885_dev *dev = fh->dev; | ||
1177 | |||
1178 | printk(KERN_INFO | ||
1179 | "%s/0: ============ START LOG STATUS ============\n", | ||
1180 | dev->name); | ||
1181 | call_all(dev, core, log_status); | ||
1182 | printk(KERN_INFO | ||
1183 | "%s/0: ============= END LOG STATUS =============\n", | ||
1184 | dev->name); | ||
1185 | return 0; | ||
1186 | } | ||
1187 | |||
1188 | static int vidioc_queryctrl(struct file *file, void *priv, | ||
1189 | struct v4l2_queryctrl *qctrl) | ||
1190 | { | ||
1191 | qctrl->id = v4l2_ctrl_next(ctrl_classes, qctrl->id); | ||
1192 | if (unlikely(qctrl->id == 0)) | ||
1193 | return -EINVAL; | ||
1194 | return cx23885_ctrl_query(qctrl); | ||
1195 | } | ||
1196 | |||
1197 | static int vidioc_g_ctrl(struct file *file, void *priv, | ||
1198 | struct v4l2_control *ctl) | ||
1199 | { | ||
1200 | struct cx23885_dev *dev = ((struct cx23885_fh *)priv)->dev; | ||
1201 | |||
1202 | return cx23885_get_control(dev, ctl); | ||
1203 | } | ||
1204 | |||
1205 | static int vidioc_s_ctrl(struct file *file, void *priv, | ||
1206 | struct v4l2_control *ctl) | ||
1207 | { | ||
1208 | struct cx23885_dev *dev = ((struct cx23885_fh *)priv)->dev; | ||
1209 | |||
1210 | return cx23885_set_control(dev, ctl); | ||
1211 | } | ||
1212 | |||
1213 | static int vidioc_g_tuner(struct file *file, void *priv, | ||
1214 | struct v4l2_tuner *t) | ||
1215 | { | ||
1216 | struct cx23885_dev *dev = ((struct cx23885_fh *)priv)->dev; | ||
1217 | |||
1218 | if (unlikely(UNSET == dev->tuner_type)) | ||
1219 | return -EINVAL; | ||
1220 | if (0 != t->index) | ||
1221 | return -EINVAL; | ||
1222 | |||
1223 | strcpy(t->name, "Television"); | ||
1224 | t->type = V4L2_TUNER_ANALOG_TV; | ||
1225 | t->capability = V4L2_TUNER_CAP_NORM; | ||
1226 | t->rangehigh = 0xffffffffUL; | ||
1227 | t->signal = 0xffff ; /* LOCKED */ | ||
1228 | return 0; | ||
1229 | } | ||
1230 | |||
1231 | static int vidioc_s_tuner(struct file *file, void *priv, | ||
1232 | struct v4l2_tuner *t) | ||
1233 | { | ||
1234 | struct cx23885_dev *dev = ((struct cx23885_fh *)priv)->dev; | ||
1235 | |||
1236 | if (UNSET == dev->tuner_type) | ||
1237 | return -EINVAL; | ||
1238 | if (0 != t->index) | ||
1239 | return -EINVAL; | ||
1240 | return 0; | ||
1241 | } | ||
1242 | |||
1243 | static int vidioc_g_frequency(struct file *file, void *priv, | ||
1244 | struct v4l2_frequency *f) | ||
1245 | { | ||
1246 | struct cx23885_fh *fh = priv; | ||
1247 | struct cx23885_dev *dev = fh->dev; | ||
1248 | |||
1249 | if (unlikely(UNSET == dev->tuner_type)) | ||
1250 | return -EINVAL; | ||
1251 | |||
1252 | /* f->type = fh->radio ? V4L2_TUNER_RADIO : V4L2_TUNER_ANALOG_TV; */ | ||
1253 | f->type = fh->radio ? V4L2_TUNER_RADIO : V4L2_TUNER_ANALOG_TV; | ||
1254 | f->frequency = dev->freq; | ||
1255 | |||
1256 | call_all(dev, tuner, g_frequency, f); | ||
1257 | |||
1258 | return 0; | ||
1259 | } | ||
1260 | |||
1261 | static int cx23885_set_freq(struct cx23885_dev *dev, struct v4l2_frequency *f) | ||
1262 | { | ||
1263 | if (unlikely(UNSET == dev->tuner_type)) | ||
1264 | return -EINVAL; | ||
1265 | if (unlikely(f->tuner != 0)) | ||
1266 | return -EINVAL; | ||
1267 | |||
1268 | mutex_lock(&dev->lock); | ||
1269 | dev->freq = f->frequency; | ||
1270 | |||
1271 | call_all(dev, tuner, s_frequency, f); | ||
1272 | |||
1273 | /* When changing channels it is required to reset TVAUDIO */ | ||
1274 | msleep(10); | ||
1275 | |||
1276 | mutex_unlock(&dev->lock); | ||
1277 | |||
1278 | return 0; | ||
1279 | } | ||
1280 | |||
1281 | static int vidioc_s_frequency(struct file *file, void *priv, | ||
1282 | struct v4l2_frequency *f) | ||
1283 | { | ||
1284 | struct cx23885_fh *fh = priv; | ||
1285 | struct cx23885_dev *dev = fh->dev; | ||
1286 | |||
1287 | if (unlikely(0 == fh->radio && f->type != V4L2_TUNER_ANALOG_TV)) | ||
1288 | return -EINVAL; | ||
1289 | if (unlikely(1 == fh->radio && f->type != V4L2_TUNER_RADIO)) | ||
1290 | return -EINVAL; | ||
1291 | |||
1292 | return | ||
1293 | cx23885_set_freq(dev, f); | ||
1294 | } | ||
1295 | |||
1296 | /* ----------------------------------------------------------- */ | ||
1297 | |||
1298 | static void cx23885_vid_timeout(unsigned long data) | ||
1299 | { | ||
1300 | struct cx23885_dev *dev = (struct cx23885_dev *)data; | ||
1301 | struct cx23885_dmaqueue *q = &dev->vidq; | ||
1302 | struct cx23885_buffer *buf; | ||
1303 | unsigned long flags; | ||
1304 | |||
1305 | cx23885_sram_channel_dump(dev, &dev->sram_channels[SRAM_CH01]); | ||
1306 | |||
1307 | cx_clear(VID_A_DMA_CTL, 0x11); | ||
1308 | |||
1309 | spin_lock_irqsave(&dev->slock, flags); | ||
1310 | while (!list_empty(&q->active)) { | ||
1311 | buf = list_entry(q->active.next, | ||
1312 | struct cx23885_buffer, vb.queue); | ||
1313 | list_del(&buf->vb.queue); | ||
1314 | buf->vb.state = VIDEOBUF_ERROR; | ||
1315 | wake_up(&buf->vb.done); | ||
1316 | printk(KERN_ERR "%s/0: [%p/%d] timeout - dma=0x%08lx\n", | ||
1317 | dev->name, buf, buf->vb.i, | ||
1318 | (unsigned long)buf->risc.dma); | ||
1319 | } | ||
1320 | cx23885_restart_video_queue(dev, q); | ||
1321 | spin_unlock_irqrestore(&dev->slock, flags); | ||
1322 | } | ||
1323 | |||
1324 | int cx23885_video_irq(struct cx23885_dev *dev, u32 status) | ||
1325 | { | ||
1326 | u32 mask, count; | ||
1327 | int handled = 0; | ||
1328 | |||
1329 | mask = cx_read(VID_A_INT_MSK); | ||
1330 | if (0 == (status & mask)) | ||
1331 | return handled; | ||
1332 | cx_write(VID_A_INT_STAT, status); | ||
1333 | |||
1334 | dprintk(2, "%s() status = 0x%08x\n", __func__, status); | ||
1335 | /* risc op code error */ | ||
1336 | if (status & (1 << 16)) { | ||
1337 | printk(KERN_WARNING "%s/0: video risc op code error\n", | ||
1338 | dev->name); | ||
1339 | cx_clear(VID_A_DMA_CTL, 0x11); | ||
1340 | cx23885_sram_channel_dump(dev, &dev->sram_channels[SRAM_CH01]); | ||
1341 | } | ||
1342 | |||
1343 | /* risc1 y */ | ||
1344 | if (status & 0x01) { | ||
1345 | spin_lock(&dev->slock); | ||
1346 | count = cx_read(VID_A_GPCNT); | ||
1347 | cx23885_video_wakeup(dev, &dev->vidq, count); | ||
1348 | spin_unlock(&dev->slock); | ||
1349 | handled++; | ||
1350 | } | ||
1351 | /* risc2 y */ | ||
1352 | if (status & 0x10) { | ||
1353 | dprintk(2, "stopper video\n"); | ||
1354 | spin_lock(&dev->slock); | ||
1355 | cx23885_restart_video_queue(dev, &dev->vidq); | ||
1356 | spin_unlock(&dev->slock); | ||
1357 | handled++; | ||
1358 | } | ||
1359 | |||
1360 | return handled; | ||
1361 | } | ||
1362 | |||
1363 | /* ----------------------------------------------------------- */ | ||
1364 | /* exported stuff */ | ||
1365 | |||
1366 | static const struct v4l2_file_operations video_fops = { | ||
1367 | .owner = THIS_MODULE, | ||
1368 | .open = video_open, | ||
1369 | .release = video_release, | ||
1370 | .read = video_read, | ||
1371 | .poll = video_poll, | ||
1372 | .mmap = video_mmap, | ||
1373 | .ioctl = video_ioctl2, | ||
1374 | }; | ||
1375 | |||
1376 | static const struct v4l2_ioctl_ops video_ioctl_ops = { | ||
1377 | .vidioc_querycap = vidioc_querycap, | ||
1378 | .vidioc_enum_fmt_vid_cap = vidioc_enum_fmt_vid_cap, | ||
1379 | .vidioc_g_fmt_vid_cap = vidioc_g_fmt_vid_cap, | ||
1380 | .vidioc_try_fmt_vid_cap = vidioc_try_fmt_vid_cap, | ||
1381 | .vidioc_s_fmt_vid_cap = vidioc_s_fmt_vid_cap, | ||
1382 | .vidioc_g_fmt_vbi_cap = cx23885_vbi_fmt, | ||
1383 | .vidioc_try_fmt_vbi_cap = cx23885_vbi_fmt, | ||
1384 | .vidioc_s_fmt_vbi_cap = cx23885_vbi_fmt, | ||
1385 | .vidioc_reqbufs = vidioc_reqbufs, | ||
1386 | .vidioc_querybuf = vidioc_querybuf, | ||
1387 | .vidioc_qbuf = vidioc_qbuf, | ||
1388 | .vidioc_dqbuf = vidioc_dqbuf, | ||
1389 | .vidioc_s_std = vidioc_s_std, | ||
1390 | .vidioc_enum_input = vidioc_enum_input, | ||
1391 | .vidioc_g_input = vidioc_g_input, | ||
1392 | .vidioc_s_input = vidioc_s_input, | ||
1393 | .vidioc_log_status = vidioc_log_status, | ||
1394 | .vidioc_queryctrl = vidioc_queryctrl, | ||
1395 | .vidioc_g_ctrl = vidioc_g_ctrl, | ||
1396 | .vidioc_s_ctrl = vidioc_s_ctrl, | ||
1397 | .vidioc_streamon = vidioc_streamon, | ||
1398 | .vidioc_streamoff = vidioc_streamoff, | ||
1399 | .vidioc_g_tuner = vidioc_g_tuner, | ||
1400 | .vidioc_s_tuner = vidioc_s_tuner, | ||
1401 | .vidioc_g_frequency = vidioc_g_frequency, | ||
1402 | .vidioc_s_frequency = vidioc_s_frequency, | ||
1403 | .vidioc_g_chip_ident = cx23885_g_chip_ident, | ||
1404 | #ifdef CONFIG_VIDEO_ADV_DEBUG | ||
1405 | .vidioc_g_register = cx23885_g_register, | ||
1406 | .vidioc_s_register = cx23885_s_register, | ||
1407 | #endif | ||
1408 | }; | ||
1409 | |||
1410 | static struct video_device cx23885_vbi_template; | ||
1411 | static struct video_device cx23885_video_template = { | ||
1412 | .name = "cx23885-video", | ||
1413 | .fops = &video_fops, | ||
1414 | .ioctl_ops = &video_ioctl_ops, | ||
1415 | .tvnorms = CX23885_NORMS, | ||
1416 | .current_norm = V4L2_STD_NTSC_M, | ||
1417 | }; | ||
1418 | |||
1419 | static const struct v4l2_file_operations radio_fops = { | ||
1420 | .owner = THIS_MODULE, | ||
1421 | .open = video_open, | ||
1422 | .release = video_release, | ||
1423 | .ioctl = video_ioctl2, | ||
1424 | }; | ||
1425 | |||
1426 | |||
1427 | void cx23885_video_unregister(struct cx23885_dev *dev) | ||
1428 | { | ||
1429 | dprintk(1, "%s()\n", __func__); | ||
1430 | cx23885_irq_remove(dev, 0x01); | ||
1431 | |||
1432 | if (dev->video_dev) { | ||
1433 | if (video_is_registered(dev->video_dev)) | ||
1434 | video_unregister_device(dev->video_dev); | ||
1435 | else | ||
1436 | video_device_release(dev->video_dev); | ||
1437 | dev->video_dev = NULL; | ||
1438 | |||
1439 | btcx_riscmem_free(dev->pci, &dev->vidq.stopper); | ||
1440 | } | ||
1441 | } | ||
1442 | |||
1443 | int cx23885_video_register(struct cx23885_dev *dev) | ||
1444 | { | ||
1445 | int err; | ||
1446 | |||
1447 | dprintk(1, "%s()\n", __func__); | ||
1448 | spin_lock_init(&dev->slock); | ||
1449 | |||
1450 | /* Initialize VBI template */ | ||
1451 | memcpy(&cx23885_vbi_template, &cx23885_video_template, | ||
1452 | sizeof(cx23885_vbi_template)); | ||
1453 | strcpy(cx23885_vbi_template.name, "cx23885-vbi"); | ||
1454 | |||
1455 | dev->tvnorm = cx23885_video_template.current_norm; | ||
1456 | |||
1457 | /* init video dma queues */ | ||
1458 | INIT_LIST_HEAD(&dev->vidq.active); | ||
1459 | INIT_LIST_HEAD(&dev->vidq.queued); | ||
1460 | dev->vidq.timeout.function = cx23885_vid_timeout; | ||
1461 | dev->vidq.timeout.data = (unsigned long)dev; | ||
1462 | init_timer(&dev->vidq.timeout); | ||
1463 | cx23885_risc_stopper(dev->pci, &dev->vidq.stopper, | ||
1464 | VID_A_DMA_CTL, 0x11, 0x00); | ||
1465 | |||
1466 | /* Don't enable VBI yet */ | ||
1467 | |||
1468 | cx23885_irq_add_enable(dev, 0x01); | ||
1469 | |||
1470 | if ((TUNER_ABSENT != dev->tuner_type) && | ||
1471 | ((dev->tuner_bus == 0) || (dev->tuner_bus == 1))) { | ||
1472 | struct v4l2_subdev *sd = NULL; | ||
1473 | |||
1474 | if (dev->tuner_addr) | ||
1475 | sd = v4l2_i2c_new_subdev(&dev->v4l2_dev, | ||
1476 | &dev->i2c_bus[dev->tuner_bus].i2c_adap, | ||
1477 | "tuner", dev->tuner_addr, NULL); | ||
1478 | else | ||
1479 | sd = v4l2_i2c_new_subdev(&dev->v4l2_dev, | ||
1480 | &dev->i2c_bus[dev->tuner_bus].i2c_adap, | ||
1481 | "tuner", 0, v4l2_i2c_tuner_addrs(ADDRS_TV)); | ||
1482 | if (sd) { | ||
1483 | struct tuner_setup tun_setup; | ||
1484 | |||
1485 | memset(&tun_setup, 0, sizeof(tun_setup)); | ||
1486 | tun_setup.mode_mask = T_ANALOG_TV; | ||
1487 | tun_setup.type = dev->tuner_type; | ||
1488 | tun_setup.addr = v4l2_i2c_subdev_addr(sd); | ||
1489 | tun_setup.tuner_callback = cx23885_tuner_callback; | ||
1490 | |||
1491 | v4l2_subdev_call(sd, tuner, s_type_addr, &tun_setup); | ||
1492 | |||
1493 | if (dev->board == CX23885_BOARD_LEADTEK_WINFAST_PXTV1200) { | ||
1494 | struct xc2028_ctrl ctrl = { | ||
1495 | .fname = XC2028_DEFAULT_FIRMWARE, | ||
1496 | .max_len = 64 | ||
1497 | }; | ||
1498 | struct v4l2_priv_tun_config cfg = { | ||
1499 | .tuner = dev->tuner_type, | ||
1500 | .priv = &ctrl | ||
1501 | }; | ||
1502 | v4l2_subdev_call(sd, tuner, s_config, &cfg); | ||
1503 | } | ||
1504 | } | ||
1505 | } | ||
1506 | |||
1507 | |||
1508 | /* register v4l devices */ | ||
1509 | dev->video_dev = cx23885_vdev_init(dev, dev->pci, | ||
1510 | &cx23885_video_template, "video"); | ||
1511 | err = video_register_device(dev->video_dev, VFL_TYPE_GRABBER, | ||
1512 | video_nr[dev->nr]); | ||
1513 | if (err < 0) { | ||
1514 | printk(KERN_INFO "%s: can't register video device\n", | ||
1515 | dev->name); | ||
1516 | goto fail_unreg; | ||
1517 | } | ||
1518 | printk(KERN_INFO "%s/0: registered device %s [v4l2]\n", | ||
1519 | dev->name, video_device_node_name(dev->video_dev)); | ||
1520 | /* initial device configuration */ | ||
1521 | mutex_lock(&dev->lock); | ||
1522 | cx23885_set_tvnorm(dev, dev->tvnorm); | ||
1523 | init_controls(dev); | ||
1524 | cx23885_video_mux(dev, 0); | ||
1525 | mutex_unlock(&dev->lock); | ||
1526 | |||
1527 | return 0; | ||
1528 | |||
1529 | fail_unreg: | ||
1530 | cx23885_video_unregister(dev); | ||
1531 | return err; | ||
1532 | } | ||
1533 | |||
diff --git a/drivers/media/video/cx23885/cx23885.h b/drivers/media/video/cx23885/cx23885.h new file mode 100644 index 00000000000..d86bc0b1317 --- /dev/null +++ b/drivers/media/video/cx23885/cx23885.h | |||
@@ -0,0 +1,583 @@ | |||
1 | /* | ||
2 | * Driver for the Conexant CX23885 PCIe bridge | ||
3 | * | ||
4 | * Copyright (c) 2006 Steven Toth <stoth@linuxtv.org> | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify | ||
7 | * it under the terms of the GNU General Public License as published by | ||
8 | * the Free Software Foundation; either version 2 of the License, or | ||
9 | * (at your option) any later version. | ||
10 | * | ||
11 | * This program is distributed in the hope that it will be useful, | ||
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
14 | * | ||
15 | * GNU General Public License for more details. | ||
16 | * | ||
17 | * You should have received a copy of the GNU General Public License | ||
18 | * along with this program; if not, write to the Free Software | ||
19 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
20 | */ | ||
21 | |||
22 | #include <linux/pci.h> | ||
23 | #include <linux/i2c.h> | ||
24 | #include <linux/i2c-algo-bit.h> | ||
25 | #include <linux/kdev_t.h> | ||
26 | #include <linux/slab.h> | ||
27 | |||
28 | #include <media/v4l2-device.h> | ||
29 | #include <media/tuner.h> | ||
30 | #include <media/tveeprom.h> | ||
31 | #include <media/videobuf-dma-sg.h> | ||
32 | #include <media/videobuf-dvb.h> | ||
33 | #include <media/rc-core.h> | ||
34 | |||
35 | #include "btcx-risc.h" | ||
36 | #include "cx23885-reg.h" | ||
37 | #include "media/cx2341x.h" | ||
38 | |||
39 | #include <linux/mutex.h> | ||
40 | |||
41 | #define CX23885_VERSION "0.0.3" | ||
42 | |||
43 | #define UNSET (-1U) | ||
44 | |||
45 | #define CX23885_MAXBOARDS 8 | ||
46 | |||
47 | /* Max number of inputs by card */ | ||
48 | #define MAX_CX23885_INPUT 8 | ||
49 | #define INPUT(nr) (&cx23885_boards[dev->board].input[nr]) | ||
50 | #define RESOURCE_OVERLAY 1 | ||
51 | #define RESOURCE_VIDEO 2 | ||
52 | #define RESOURCE_VBI 4 | ||
53 | |||
54 | #define BUFFER_TIMEOUT (HZ) /* 0.5 seconds */ | ||
55 | |||
56 | #define CX23885_BOARD_NOAUTO UNSET | ||
57 | #define CX23885_BOARD_UNKNOWN 0 | ||
58 | #define CX23885_BOARD_HAUPPAUGE_HVR1800lp 1 | ||
59 | #define CX23885_BOARD_HAUPPAUGE_HVR1800 2 | ||
60 | #define CX23885_BOARD_HAUPPAUGE_HVR1250 3 | ||
61 | #define CX23885_BOARD_DVICO_FUSIONHDTV_5_EXP 4 | ||
62 | #define CX23885_BOARD_HAUPPAUGE_HVR1500Q 5 | ||
63 | #define CX23885_BOARD_HAUPPAUGE_HVR1500 6 | ||
64 | #define CX23885_BOARD_HAUPPAUGE_HVR1200 7 | ||
65 | #define CX23885_BOARD_HAUPPAUGE_HVR1700 8 | ||
66 | #define CX23885_BOARD_HAUPPAUGE_HVR1400 9 | ||
67 | #define CX23885_BOARD_DVICO_FUSIONHDTV_7_DUAL_EXP 10 | ||
68 | #define CX23885_BOARD_DVICO_FUSIONHDTV_DVB_T_DUAL_EXP 11 | ||
69 | #define CX23885_BOARD_LEADTEK_WINFAST_PXDVR3200_H 12 | ||
70 | #define CX23885_BOARD_COMPRO_VIDEOMATE_E650F 13 | ||
71 | #define CX23885_BOARD_TBS_6920 14 | ||
72 | #define CX23885_BOARD_TEVII_S470 15 | ||
73 | #define CX23885_BOARD_DVBWORLD_2005 16 | ||
74 | #define CX23885_BOARD_NETUP_DUAL_DVBS2_CI 17 | ||
75 | #define CX23885_BOARD_HAUPPAUGE_HVR1270 18 | ||
76 | #define CX23885_BOARD_HAUPPAUGE_HVR1275 19 | ||
77 | #define CX23885_BOARD_HAUPPAUGE_HVR1255 20 | ||
78 | #define CX23885_BOARD_HAUPPAUGE_HVR1210 21 | ||
79 | #define CX23885_BOARD_MYGICA_X8506 22 | ||
80 | #define CX23885_BOARD_MAGICPRO_PROHDTVE2 23 | ||
81 | #define CX23885_BOARD_HAUPPAUGE_HVR1850 24 | ||
82 | #define CX23885_BOARD_COMPRO_VIDEOMATE_E800 25 | ||
83 | #define CX23885_BOARD_HAUPPAUGE_HVR1290 26 | ||
84 | #define CX23885_BOARD_MYGICA_X8558PRO 27 | ||
85 | #define CX23885_BOARD_LEADTEK_WINFAST_PXTV1200 28 | ||
86 | #define CX23885_BOARD_GOTVIEW_X5_3D_HYBRID 29 | ||
87 | #define CX23885_BOARD_NETUP_DUAL_DVB_T_C_CI_RF 30 | ||
88 | #define CX23885_BOARD_LEADTEK_WINFAST_PXDVR3200_H_XC4000 31 | ||
89 | |||
90 | #define GPIO_0 0x00000001 | ||
91 | #define GPIO_1 0x00000002 | ||
92 | #define GPIO_2 0x00000004 | ||
93 | #define GPIO_3 0x00000008 | ||
94 | #define GPIO_4 0x00000010 | ||
95 | #define GPIO_5 0x00000020 | ||
96 | #define GPIO_6 0x00000040 | ||
97 | #define GPIO_7 0x00000080 | ||
98 | #define GPIO_8 0x00000100 | ||
99 | #define GPIO_9 0x00000200 | ||
100 | #define GPIO_10 0x00000400 | ||
101 | #define GPIO_11 0x00000800 | ||
102 | #define GPIO_12 0x00001000 | ||
103 | #define GPIO_13 0x00002000 | ||
104 | #define GPIO_14 0x00004000 | ||
105 | #define GPIO_15 0x00008000 | ||
106 | |||
107 | /* Currently unsupported by the driver: PAL/H, NTSC/Kr, SECAM B/G/H/LC */ | ||
108 | #define CX23885_NORMS (\ | ||
109 | V4L2_STD_NTSC_M | V4L2_STD_NTSC_M_JP | V4L2_STD_NTSC_443 | \ | ||
110 | V4L2_STD_PAL_BG | V4L2_STD_PAL_DK | V4L2_STD_PAL_I | \ | ||
111 | V4L2_STD_PAL_M | V4L2_STD_PAL_N | V4L2_STD_PAL_Nc | \ | ||
112 | V4L2_STD_PAL_60 | V4L2_STD_SECAM_L | V4L2_STD_SECAM_DK) | ||
113 | |||
114 | struct cx23885_fmt { | ||
115 | char *name; | ||
116 | u32 fourcc; /* v4l2 format id */ | ||
117 | int depth; | ||
118 | int flags; | ||
119 | u32 cxformat; | ||
120 | }; | ||
121 | |||
122 | struct cx23885_ctrl { | ||
123 | struct v4l2_queryctrl v; | ||
124 | u32 off; | ||
125 | u32 reg; | ||
126 | u32 mask; | ||
127 | u32 shift; | ||
128 | }; | ||
129 | |||
130 | struct cx23885_tvnorm { | ||
131 | char *name; | ||
132 | v4l2_std_id id; | ||
133 | u32 cxiformat; | ||
134 | u32 cxoformat; | ||
135 | }; | ||
136 | |||
137 | struct cx23885_fh { | ||
138 | struct cx23885_dev *dev; | ||
139 | enum v4l2_buf_type type; | ||
140 | int radio; | ||
141 | u32 resources; | ||
142 | |||
143 | /* video overlay */ | ||
144 | struct v4l2_window win; | ||
145 | struct v4l2_clip *clips; | ||
146 | unsigned int nclips; | ||
147 | |||
148 | /* video capture */ | ||
149 | struct cx23885_fmt *fmt; | ||
150 | unsigned int width, height; | ||
151 | |||
152 | /* vbi capture */ | ||
153 | struct videobuf_queue vidq; | ||
154 | struct videobuf_queue vbiq; | ||
155 | |||
156 | /* MPEG Encoder specifics ONLY */ | ||
157 | struct videobuf_queue mpegq; | ||
158 | atomic_t v4l_reading; | ||
159 | }; | ||
160 | |||
161 | enum cx23885_itype { | ||
162 | CX23885_VMUX_COMPOSITE1 = 1, | ||
163 | CX23885_VMUX_COMPOSITE2, | ||
164 | CX23885_VMUX_COMPOSITE3, | ||
165 | CX23885_VMUX_COMPOSITE4, | ||
166 | CX23885_VMUX_SVIDEO, | ||
167 | CX23885_VMUX_COMPONENT, | ||
168 | CX23885_VMUX_TELEVISION, | ||
169 | CX23885_VMUX_CABLE, | ||
170 | CX23885_VMUX_DVB, | ||
171 | CX23885_VMUX_DEBUG, | ||
172 | CX23885_RADIO, | ||
173 | }; | ||
174 | |||
175 | enum cx23885_src_sel_type { | ||
176 | CX23885_SRC_SEL_EXT_656_VIDEO = 0, | ||
177 | CX23885_SRC_SEL_PARALLEL_MPEG_VIDEO | ||
178 | }; | ||
179 | |||
180 | /* buffer for one video frame */ | ||
181 | struct cx23885_buffer { | ||
182 | /* common v4l buffer stuff -- must be first */ | ||
183 | struct videobuf_buffer vb; | ||
184 | |||
185 | /* cx23885 specific */ | ||
186 | unsigned int bpl; | ||
187 | struct btcx_riscmem risc; | ||
188 | struct cx23885_fmt *fmt; | ||
189 | u32 count; | ||
190 | }; | ||
191 | |||
192 | struct cx23885_input { | ||
193 | enum cx23885_itype type; | ||
194 | unsigned int vmux; | ||
195 | u32 gpio0, gpio1, gpio2, gpio3; | ||
196 | }; | ||
197 | |||
198 | typedef enum { | ||
199 | CX23885_MPEG_UNDEFINED = 0, | ||
200 | CX23885_MPEG_DVB, | ||
201 | CX23885_ANALOG_VIDEO, | ||
202 | CX23885_MPEG_ENCODER, | ||
203 | } port_t; | ||
204 | |||
205 | struct cx23885_board { | ||
206 | char *name; | ||
207 | port_t porta, portb, portc; | ||
208 | int num_fds_portb, num_fds_portc; | ||
209 | unsigned int tuner_type; | ||
210 | unsigned int radio_type; | ||
211 | unsigned char tuner_addr; | ||
212 | unsigned char radio_addr; | ||
213 | unsigned int tuner_bus; | ||
214 | |||
215 | /* Vendors can and do run the PCIe bridge at different | ||
216 | * clock rates, driven physically by crystals on the PCBs. | ||
217 | * The core has to accommodate this. This allows the user | ||
218 | * to add new boards with new frequencys. The value is | ||
219 | * expressed in Hz. | ||
220 | * | ||
221 | * The core framework will default this value based on | ||
222 | * current designs, but it can vary. | ||
223 | */ | ||
224 | u32 clk_freq; | ||
225 | struct cx23885_input input[MAX_CX23885_INPUT]; | ||
226 | int ci_type; /* for NetUP */ | ||
227 | }; | ||
228 | |||
229 | struct cx23885_subid { | ||
230 | u16 subvendor; | ||
231 | u16 subdevice; | ||
232 | u32 card; | ||
233 | }; | ||
234 | |||
235 | struct cx23885_i2c { | ||
236 | struct cx23885_dev *dev; | ||
237 | |||
238 | int nr; | ||
239 | |||
240 | /* i2c i/o */ | ||
241 | struct i2c_adapter i2c_adap; | ||
242 | struct i2c_algo_bit_data i2c_algo; | ||
243 | struct i2c_client i2c_client; | ||
244 | u32 i2c_rc; | ||
245 | |||
246 | /* 885 registers used for raw addess */ | ||
247 | u32 i2c_period; | ||
248 | u32 reg_ctrl; | ||
249 | u32 reg_stat; | ||
250 | u32 reg_addr; | ||
251 | u32 reg_rdata; | ||
252 | u32 reg_wdata; | ||
253 | }; | ||
254 | |||
255 | struct cx23885_dmaqueue { | ||
256 | struct list_head active; | ||
257 | struct list_head queued; | ||
258 | struct timer_list timeout; | ||
259 | struct btcx_riscmem stopper; | ||
260 | u32 count; | ||
261 | }; | ||
262 | |||
263 | struct cx23885_tsport { | ||
264 | struct cx23885_dev *dev; | ||
265 | |||
266 | int nr; | ||
267 | int sram_chno; | ||
268 | |||
269 | struct videobuf_dvb_frontends frontends; | ||
270 | |||
271 | /* dma queues */ | ||
272 | struct cx23885_dmaqueue mpegq; | ||
273 | u32 ts_packet_size; | ||
274 | u32 ts_packet_count; | ||
275 | |||
276 | int width; | ||
277 | int height; | ||
278 | |||
279 | spinlock_t slock; | ||
280 | |||
281 | /* registers */ | ||
282 | u32 reg_gpcnt; | ||
283 | u32 reg_gpcnt_ctl; | ||
284 | u32 reg_dma_ctl; | ||
285 | u32 reg_lngth; | ||
286 | u32 reg_hw_sop_ctrl; | ||
287 | u32 reg_gen_ctrl; | ||
288 | u32 reg_bd_pkt_status; | ||
289 | u32 reg_sop_status; | ||
290 | u32 reg_fifo_ovfl_stat; | ||
291 | u32 reg_vld_misc; | ||
292 | u32 reg_ts_clk_en; | ||
293 | u32 reg_ts_int_msk; | ||
294 | u32 reg_ts_int_stat; | ||
295 | u32 reg_src_sel; | ||
296 | |||
297 | /* Default register vals */ | ||
298 | int pci_irqmask; | ||
299 | u32 dma_ctl_val; | ||
300 | u32 ts_int_msk_val; | ||
301 | u32 gen_ctrl_val; | ||
302 | u32 ts_clk_en_val; | ||
303 | u32 src_sel_val; | ||
304 | u32 vld_misc_val; | ||
305 | u32 hw_sop_ctrl_val; | ||
306 | |||
307 | /* Allow a single tsport to have multiple frontends */ | ||
308 | u32 num_frontends; | ||
309 | void (*gate_ctrl)(struct cx23885_tsport *port, int open); | ||
310 | void *port_priv; | ||
311 | }; | ||
312 | |||
313 | struct cx23885_kernel_ir { | ||
314 | struct cx23885_dev *cx; | ||
315 | char *name; | ||
316 | char *phys; | ||
317 | |||
318 | struct rc_dev *rc; | ||
319 | }; | ||
320 | |||
321 | struct cx23885_dev { | ||
322 | atomic_t refcount; | ||
323 | struct v4l2_device v4l2_dev; | ||
324 | |||
325 | /* pci stuff */ | ||
326 | struct pci_dev *pci; | ||
327 | unsigned char pci_rev, pci_lat; | ||
328 | int pci_bus, pci_slot; | ||
329 | u32 __iomem *lmmio; | ||
330 | u8 __iomem *bmmio; | ||
331 | int pci_irqmask; | ||
332 | spinlock_t pci_irqmask_lock; /* protects mask reg too */ | ||
333 | int hwrevision; | ||
334 | |||
335 | /* This valud is board specific and is used to configure the | ||
336 | * AV core so we see nice clean and stable video and audio. */ | ||
337 | u32 clk_freq; | ||
338 | |||
339 | /* I2C adapters: Master 1 & 2 (External) & Master 3 (Internal only) */ | ||
340 | struct cx23885_i2c i2c_bus[3]; | ||
341 | |||
342 | int nr; | ||
343 | struct mutex lock; | ||
344 | struct mutex gpio_lock; | ||
345 | |||
346 | /* board details */ | ||
347 | unsigned int board; | ||
348 | char name[32]; | ||
349 | |||
350 | struct cx23885_tsport ts1, ts2; | ||
351 | |||
352 | /* sram configuration */ | ||
353 | struct sram_channel *sram_channels; | ||
354 | |||
355 | enum { | ||
356 | CX23885_BRIDGE_UNDEFINED = 0, | ||
357 | CX23885_BRIDGE_885 = 885, | ||
358 | CX23885_BRIDGE_887 = 887, | ||
359 | CX23885_BRIDGE_888 = 888, | ||
360 | } bridge; | ||
361 | |||
362 | /* Analog video */ | ||
363 | u32 resources; | ||
364 | unsigned int input; | ||
365 | u32 tvaudio; | ||
366 | v4l2_std_id tvnorm; | ||
367 | unsigned int tuner_type; | ||
368 | unsigned char tuner_addr; | ||
369 | unsigned int tuner_bus; | ||
370 | unsigned int radio_type; | ||
371 | unsigned char radio_addr; | ||
372 | unsigned int has_radio; | ||
373 | struct v4l2_subdev *sd_cx25840; | ||
374 | struct work_struct cx25840_work; | ||
375 | |||
376 | /* Infrared */ | ||
377 | struct v4l2_subdev *sd_ir; | ||
378 | struct work_struct ir_rx_work; | ||
379 | unsigned long ir_rx_notifications; | ||
380 | struct work_struct ir_tx_work; | ||
381 | unsigned long ir_tx_notifications; | ||
382 | |||
383 | struct cx23885_kernel_ir *kernel_ir; | ||
384 | atomic_t ir_input_stopping; | ||
385 | |||
386 | /* V4l */ | ||
387 | u32 freq; | ||
388 | struct video_device *video_dev; | ||
389 | struct video_device *vbi_dev; | ||
390 | struct video_device *radio_dev; | ||
391 | |||
392 | struct cx23885_dmaqueue vidq; | ||
393 | struct cx23885_dmaqueue vbiq; | ||
394 | spinlock_t slock; | ||
395 | |||
396 | /* MPEG Encoder ONLY settings */ | ||
397 | u32 cx23417_mailbox; | ||
398 | struct cx2341x_mpeg_params mpeg_params; | ||
399 | struct video_device *v4l_device; | ||
400 | atomic_t v4l_reader_count; | ||
401 | struct cx23885_tvnorm encodernorm; | ||
402 | |||
403 | }; | ||
404 | |||
405 | static inline struct cx23885_dev *to_cx23885(struct v4l2_device *v4l2_dev) | ||
406 | { | ||
407 | return container_of(v4l2_dev, struct cx23885_dev, v4l2_dev); | ||
408 | } | ||
409 | |||
410 | #define call_all(dev, o, f, args...) \ | ||
411 | v4l2_device_call_all(&dev->v4l2_dev, 0, o, f, ##args) | ||
412 | |||
413 | #define CX23885_HW_888_IR (1 << 0) | ||
414 | #define CX23885_HW_AV_CORE (1 << 1) | ||
415 | |||
416 | #define call_hw(dev, grpid, o, f, args...) \ | ||
417 | v4l2_device_call_all(&dev->v4l2_dev, grpid, o, f, ##args) | ||
418 | |||
419 | extern struct v4l2_subdev *cx23885_find_hw(struct cx23885_dev *dev, u32 hw); | ||
420 | |||
421 | #define SRAM_CH01 0 /* Video A */ | ||
422 | #define SRAM_CH02 1 /* VBI A */ | ||
423 | #define SRAM_CH03 2 /* Video B */ | ||
424 | #define SRAM_CH04 3 /* Transport via B */ | ||
425 | #define SRAM_CH05 4 /* VBI B */ | ||
426 | #define SRAM_CH06 5 /* Video C */ | ||
427 | #define SRAM_CH07 6 /* Transport via C */ | ||
428 | #define SRAM_CH08 7 /* Audio Internal A */ | ||
429 | #define SRAM_CH09 8 /* Audio Internal B */ | ||
430 | #define SRAM_CH10 9 /* Audio External */ | ||
431 | #define SRAM_CH11 10 /* COMB_3D_N */ | ||
432 | #define SRAM_CH12 11 /* Comb 3D N1 */ | ||
433 | #define SRAM_CH13 12 /* Comb 3D N2 */ | ||
434 | #define SRAM_CH14 13 /* MOE Vid */ | ||
435 | #define SRAM_CH15 14 /* MOE RSLT */ | ||
436 | |||
437 | struct sram_channel { | ||
438 | char *name; | ||
439 | u32 cmds_start; | ||
440 | u32 ctrl_start; | ||
441 | u32 cdt; | ||
442 | u32 fifo_start; | ||
443 | u32 fifo_size; | ||
444 | u32 ptr1_reg; | ||
445 | u32 ptr2_reg; | ||
446 | u32 cnt1_reg; | ||
447 | u32 cnt2_reg; | ||
448 | u32 jumponly; | ||
449 | }; | ||
450 | |||
451 | /* ----------------------------------------------------------- */ | ||
452 | |||
453 | #define cx_read(reg) readl(dev->lmmio + ((reg)>>2)) | ||
454 | #define cx_write(reg, value) writel((value), dev->lmmio + ((reg)>>2)) | ||
455 | |||
456 | #define cx_andor(reg, mask, value) \ | ||
457 | writel((readl(dev->lmmio+((reg)>>2)) & ~(mask)) |\ | ||
458 | ((value) & (mask)), dev->lmmio+((reg)>>2)) | ||
459 | |||
460 | #define cx_set(reg, bit) cx_andor((reg), (bit), (bit)) | ||
461 | #define cx_clear(reg, bit) cx_andor((reg), (bit), 0) | ||
462 | |||
463 | /* ----------------------------------------------------------- */ | ||
464 | /* cx23885-core.c */ | ||
465 | |||
466 | extern int cx23885_sram_channel_setup(struct cx23885_dev *dev, | ||
467 | struct sram_channel *ch, | ||
468 | unsigned int bpl, u32 risc); | ||
469 | |||
470 | extern void cx23885_sram_channel_dump(struct cx23885_dev *dev, | ||
471 | struct sram_channel *ch); | ||
472 | |||
473 | extern int cx23885_risc_stopper(struct pci_dev *pci, struct btcx_riscmem *risc, | ||
474 | u32 reg, u32 mask, u32 value); | ||
475 | |||
476 | extern int cx23885_risc_buffer(struct pci_dev *pci, struct btcx_riscmem *risc, | ||
477 | struct scatterlist *sglist, | ||
478 | unsigned int top_offset, unsigned int bottom_offset, | ||
479 | unsigned int bpl, unsigned int padding, unsigned int lines); | ||
480 | |||
481 | void cx23885_cancel_buffers(struct cx23885_tsport *port); | ||
482 | |||
483 | extern int cx23885_restart_queue(struct cx23885_tsport *port, | ||
484 | struct cx23885_dmaqueue *q); | ||
485 | |||
486 | extern void cx23885_wakeup(struct cx23885_tsport *port, | ||
487 | struct cx23885_dmaqueue *q, u32 count); | ||
488 | |||
489 | extern void cx23885_gpio_set(struct cx23885_dev *dev, u32 mask); | ||
490 | extern void cx23885_gpio_clear(struct cx23885_dev *dev, u32 mask); | ||
491 | extern u32 cx23885_gpio_get(struct cx23885_dev *dev, u32 mask); | ||
492 | extern void cx23885_gpio_enable(struct cx23885_dev *dev, u32 mask, | ||
493 | int asoutput); | ||
494 | |||
495 | extern void cx23885_irq_add_enable(struct cx23885_dev *dev, u32 mask); | ||
496 | extern void cx23885_irq_enable(struct cx23885_dev *dev, u32 mask); | ||
497 | extern void cx23885_irq_disable(struct cx23885_dev *dev, u32 mask); | ||
498 | extern void cx23885_irq_remove(struct cx23885_dev *dev, u32 mask); | ||
499 | |||
500 | /* ----------------------------------------------------------- */ | ||
501 | /* cx23885-cards.c */ | ||
502 | extern struct cx23885_board cx23885_boards[]; | ||
503 | extern const unsigned int cx23885_bcount; | ||
504 | |||
505 | extern struct cx23885_subid cx23885_subids[]; | ||
506 | extern const unsigned int cx23885_idcount; | ||
507 | |||
508 | extern int cx23885_tuner_callback(void *priv, int component, | ||
509 | int command, int arg); | ||
510 | extern void cx23885_card_list(struct cx23885_dev *dev); | ||
511 | extern int cx23885_ir_init(struct cx23885_dev *dev); | ||
512 | extern void cx23885_ir_pci_int_enable(struct cx23885_dev *dev); | ||
513 | extern void cx23885_ir_fini(struct cx23885_dev *dev); | ||
514 | extern void cx23885_gpio_setup(struct cx23885_dev *dev); | ||
515 | extern void cx23885_card_setup(struct cx23885_dev *dev); | ||
516 | extern void cx23885_card_setup_pre_i2c(struct cx23885_dev *dev); | ||
517 | |||
518 | extern int cx23885_dvb_register(struct cx23885_tsport *port); | ||
519 | extern int cx23885_dvb_unregister(struct cx23885_tsport *port); | ||
520 | |||
521 | extern int cx23885_buf_prepare(struct videobuf_queue *q, | ||
522 | struct cx23885_tsport *port, | ||
523 | struct cx23885_buffer *buf, | ||
524 | enum v4l2_field field); | ||
525 | extern void cx23885_buf_queue(struct cx23885_tsport *port, | ||
526 | struct cx23885_buffer *buf); | ||
527 | extern void cx23885_free_buffer(struct videobuf_queue *q, | ||
528 | struct cx23885_buffer *buf); | ||
529 | |||
530 | /* ----------------------------------------------------------- */ | ||
531 | /* cx23885-video.c */ | ||
532 | /* Video */ | ||
533 | extern int cx23885_video_register(struct cx23885_dev *dev); | ||
534 | extern void cx23885_video_unregister(struct cx23885_dev *dev); | ||
535 | extern int cx23885_video_irq(struct cx23885_dev *dev, u32 status); | ||
536 | |||
537 | /* ----------------------------------------------------------- */ | ||
538 | /* cx23885-vbi.c */ | ||
539 | extern int cx23885_vbi_fmt(struct file *file, void *priv, | ||
540 | struct v4l2_format *f); | ||
541 | extern void cx23885_vbi_timeout(unsigned long data); | ||
542 | extern struct videobuf_queue_ops cx23885_vbi_qops; | ||
543 | |||
544 | /* cx23885-i2c.c */ | ||
545 | extern int cx23885_i2c_register(struct cx23885_i2c *bus); | ||
546 | extern int cx23885_i2c_unregister(struct cx23885_i2c *bus); | ||
547 | extern void cx23885_av_clk(struct cx23885_dev *dev, int enable); | ||
548 | |||
549 | /* ----------------------------------------------------------- */ | ||
550 | /* cx23885-417.c */ | ||
551 | extern int cx23885_417_register(struct cx23885_dev *dev); | ||
552 | extern void cx23885_417_unregister(struct cx23885_dev *dev); | ||
553 | extern int cx23885_irq_417(struct cx23885_dev *dev, u32 status); | ||
554 | extern void cx23885_417_check_encoder(struct cx23885_dev *dev); | ||
555 | extern void cx23885_mc417_init(struct cx23885_dev *dev); | ||
556 | extern int mc417_memory_read(struct cx23885_dev *dev, u32 address, u32 *value); | ||
557 | extern int mc417_memory_write(struct cx23885_dev *dev, u32 address, u32 value); | ||
558 | extern int mc417_register_read(struct cx23885_dev *dev, | ||
559 | u16 address, u32 *value); | ||
560 | extern int mc417_register_write(struct cx23885_dev *dev, | ||
561 | u16 address, u32 value); | ||
562 | extern void mc417_gpio_set(struct cx23885_dev *dev, u32 mask); | ||
563 | extern void mc417_gpio_clear(struct cx23885_dev *dev, u32 mask); | ||
564 | extern void mc417_gpio_enable(struct cx23885_dev *dev, u32 mask, int asoutput); | ||
565 | |||
566 | |||
567 | /* ----------------------------------------------------------- */ | ||
568 | /* tv norms */ | ||
569 | |||
570 | static inline unsigned int norm_maxw(v4l2_std_id norm) | ||
571 | { | ||
572 | return (norm & (V4L2_STD_MN & ~V4L2_STD_PAL_Nc)) ? 720 : 768; | ||
573 | } | ||
574 | |||
575 | static inline unsigned int norm_maxh(v4l2_std_id norm) | ||
576 | { | ||
577 | return (norm & V4L2_STD_625_50) ? 576 : 480; | ||
578 | } | ||
579 | |||
580 | static inline unsigned int norm_swidth(v4l2_std_id norm) | ||
581 | { | ||
582 | return (norm & (V4L2_STD_MN & ~V4L2_STD_PAL_Nc)) ? 754 : 922; | ||
583 | } | ||
diff --git a/drivers/media/video/cx23885/cx23888-ir.c b/drivers/media/video/cx23885/cx23888-ir.c new file mode 100644 index 00000000000..e37be6fcf67 --- /dev/null +++ b/drivers/media/video/cx23885/cx23888-ir.c | |||
@@ -0,0 +1,1269 @@ | |||
1 | /* | ||
2 | * Driver for the Conexant CX23885/7/8 PCIe bridge | ||
3 | * | ||
4 | * CX23888 Integrated Consumer Infrared Controller | ||
5 | * | ||
6 | * Copyright (C) 2009 Andy Walls <awalls@md.metrocast.net> | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or | ||
9 | * modify it under the terms of the GNU General Public License | ||
10 | * as published by the Free Software Foundation; either version 2 | ||
11 | * of the License, or (at your option) any later version. | ||
12 | * | ||
13 | * This program is distributed in the hope that it will be useful, | ||
14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
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., 51 Franklin Street, Fifth Floor, Boston, MA | ||
21 | * 02110-1301, USA. | ||
22 | */ | ||
23 | |||
24 | #include <linux/kfifo.h> | ||
25 | #include <linux/slab.h> | ||
26 | |||
27 | #include <media/v4l2-device.h> | ||
28 | #include <media/v4l2-chip-ident.h> | ||
29 | #include <media/rc-core.h> | ||
30 | |||
31 | #include "cx23885.h" | ||
32 | |||
33 | static unsigned int ir_888_debug; | ||
34 | module_param(ir_888_debug, int, 0644); | ||
35 | MODULE_PARM_DESC(ir_888_debug, "enable debug messages [CX23888 IR controller]"); | ||
36 | |||
37 | #define CX23888_IR_REG_BASE 0x170000 | ||
38 | /* | ||
39 | * These CX23888 register offsets have a straightforward one to one mapping | ||
40 | * to the CX23885 register offsets of 0x200 through 0x218 | ||
41 | */ | ||
42 | #define CX23888_IR_CNTRL_REG 0x170000 | ||
43 | #define CNTRL_WIN_3_3 0x00000000 | ||
44 | #define CNTRL_WIN_4_3 0x00000001 | ||
45 | #define CNTRL_WIN_3_4 0x00000002 | ||
46 | #define CNTRL_WIN_4_4 0x00000003 | ||
47 | #define CNTRL_WIN 0x00000003 | ||
48 | #define CNTRL_EDG_NONE 0x00000000 | ||
49 | #define CNTRL_EDG_FALL 0x00000004 | ||
50 | #define CNTRL_EDG_RISE 0x00000008 | ||
51 | #define CNTRL_EDG_BOTH 0x0000000C | ||
52 | #define CNTRL_EDG 0x0000000C | ||
53 | #define CNTRL_DMD 0x00000010 | ||
54 | #define CNTRL_MOD 0x00000020 | ||
55 | #define CNTRL_RFE 0x00000040 | ||
56 | #define CNTRL_TFE 0x00000080 | ||
57 | #define CNTRL_RXE 0x00000100 | ||
58 | #define CNTRL_TXE 0x00000200 | ||
59 | #define CNTRL_RIC 0x00000400 | ||
60 | #define CNTRL_TIC 0x00000800 | ||
61 | #define CNTRL_CPL 0x00001000 | ||
62 | #define CNTRL_LBM 0x00002000 | ||
63 | #define CNTRL_R 0x00004000 | ||
64 | /* CX23888 specific control flag */ | ||
65 | #define CNTRL_IVO 0x00008000 | ||
66 | |||
67 | #define CX23888_IR_TXCLK_REG 0x170004 | ||
68 | #define TXCLK_TCD 0x0000FFFF | ||
69 | |||
70 | #define CX23888_IR_RXCLK_REG 0x170008 | ||
71 | #define RXCLK_RCD 0x0000FFFF | ||
72 | |||
73 | #define CX23888_IR_CDUTY_REG 0x17000C | ||
74 | #define CDUTY_CDC 0x0000000F | ||
75 | |||
76 | #define CX23888_IR_STATS_REG 0x170010 | ||
77 | #define STATS_RTO 0x00000001 | ||
78 | #define STATS_ROR 0x00000002 | ||
79 | #define STATS_RBY 0x00000004 | ||
80 | #define STATS_TBY 0x00000008 | ||
81 | #define STATS_RSR 0x00000010 | ||
82 | #define STATS_TSR 0x00000020 | ||
83 | |||
84 | #define CX23888_IR_IRQEN_REG 0x170014 | ||
85 | #define IRQEN_RTE 0x00000001 | ||
86 | #define IRQEN_ROE 0x00000002 | ||
87 | #define IRQEN_RSE 0x00000010 | ||
88 | #define IRQEN_TSE 0x00000020 | ||
89 | |||
90 | #define CX23888_IR_FILTR_REG 0x170018 | ||
91 | #define FILTR_LPF 0x0000FFFF | ||
92 | |||
93 | /* This register doesn't follow the pattern; it's 0x23C on a CX23885 */ | ||
94 | #define CX23888_IR_FIFO_REG 0x170040 | ||
95 | #define FIFO_RXTX 0x0000FFFF | ||
96 | #define FIFO_RXTX_LVL 0x00010000 | ||
97 | #define FIFO_RXTX_RTO 0x0001FFFF | ||
98 | #define FIFO_RX_NDV 0x00020000 | ||
99 | #define FIFO_RX_DEPTH 8 | ||
100 | #define FIFO_TX_DEPTH 8 | ||
101 | |||
102 | /* CX23888 unique registers */ | ||
103 | #define CX23888_IR_SEEDP_REG 0x17001C | ||
104 | #define CX23888_IR_TIMOL_REG 0x170020 | ||
105 | #define CX23888_IR_WAKE0_REG 0x170024 | ||
106 | #define CX23888_IR_WAKE1_REG 0x170028 | ||
107 | #define CX23888_IR_WAKE2_REG 0x17002C | ||
108 | #define CX23888_IR_MASK0_REG 0x170030 | ||
109 | #define CX23888_IR_MASK1_REG 0x170034 | ||
110 | #define CX23888_IR_MAKS2_REG 0x170038 | ||
111 | #define CX23888_IR_DPIPG_REG 0x17003C | ||
112 | #define CX23888_IR_LEARN_REG 0x170044 | ||
113 | |||
114 | #define CX23888_VIDCLK_FREQ 108000000 /* 108 MHz, BT.656 */ | ||
115 | #define CX23888_IR_REFCLK_FREQ (CX23888_VIDCLK_FREQ / 2) | ||
116 | |||
117 | /* | ||
118 | * We use this union internally for convenience, but callers to tx_write | ||
119 | * and rx_read will be expecting records of type struct ir_raw_event. | ||
120 | * Always ensure the size of this union is dictated by struct ir_raw_event. | ||
121 | */ | ||
122 | union cx23888_ir_fifo_rec { | ||
123 | u32 hw_fifo_data; | ||
124 | struct ir_raw_event ir_core_data; | ||
125 | }; | ||
126 | |||
127 | #define CX23888_IR_RX_KFIFO_SIZE (256 * sizeof(union cx23888_ir_fifo_rec)) | ||
128 | #define CX23888_IR_TX_KFIFO_SIZE (256 * sizeof(union cx23888_ir_fifo_rec)) | ||
129 | |||
130 | struct cx23888_ir_state { | ||
131 | struct v4l2_subdev sd; | ||
132 | struct cx23885_dev *dev; | ||
133 | u32 id; | ||
134 | u32 rev; | ||
135 | |||
136 | struct v4l2_subdev_ir_parameters rx_params; | ||
137 | struct mutex rx_params_lock; | ||
138 | atomic_t rxclk_divider; | ||
139 | atomic_t rx_invert; | ||
140 | |||
141 | struct kfifo rx_kfifo; | ||
142 | spinlock_t rx_kfifo_lock; | ||
143 | |||
144 | struct v4l2_subdev_ir_parameters tx_params; | ||
145 | struct mutex tx_params_lock; | ||
146 | atomic_t txclk_divider; | ||
147 | }; | ||
148 | |||
149 | static inline struct cx23888_ir_state *to_state(struct v4l2_subdev *sd) | ||
150 | { | ||
151 | return v4l2_get_subdevdata(sd); | ||
152 | } | ||
153 | |||
154 | /* | ||
155 | * IR register block read and write functions | ||
156 | */ | ||
157 | static | ||
158 | inline int cx23888_ir_write4(struct cx23885_dev *dev, u32 addr, u32 value) | ||
159 | { | ||
160 | cx_write(addr, value); | ||
161 | return 0; | ||
162 | } | ||
163 | |||
164 | static inline u32 cx23888_ir_read4(struct cx23885_dev *dev, u32 addr) | ||
165 | { | ||
166 | return cx_read(addr); | ||
167 | } | ||
168 | |||
169 | static inline int cx23888_ir_and_or4(struct cx23885_dev *dev, u32 addr, | ||
170 | u32 and_mask, u32 or_value) | ||
171 | { | ||
172 | cx_andor(addr, ~and_mask, or_value); | ||
173 | return 0; | ||
174 | } | ||
175 | |||
176 | /* | ||
177 | * Rx and Tx Clock Divider register computations | ||
178 | * | ||
179 | * Note the largest clock divider value of 0xffff corresponds to: | ||
180 | * (0xffff + 1) * 1000 / 108/2 MHz = 1,213,629.629... ns | ||
181 | * which fits in 21 bits, so we'll use unsigned int for time arguments. | ||
182 | */ | ||
183 | static inline u16 count_to_clock_divider(unsigned int d) | ||
184 | { | ||
185 | if (d > RXCLK_RCD + 1) | ||
186 | d = RXCLK_RCD; | ||
187 | else if (d < 2) | ||
188 | d = 1; | ||
189 | else | ||
190 | d--; | ||
191 | return (u16) d; | ||
192 | } | ||
193 | |||
194 | static inline u16 ns_to_clock_divider(unsigned int ns) | ||
195 | { | ||
196 | return count_to_clock_divider( | ||
197 | DIV_ROUND_CLOSEST(CX23888_IR_REFCLK_FREQ / 1000000 * ns, 1000)); | ||
198 | } | ||
199 | |||
200 | static inline unsigned int clock_divider_to_ns(unsigned int divider) | ||
201 | { | ||
202 | /* Period of the Rx or Tx clock in ns */ | ||
203 | return DIV_ROUND_CLOSEST((divider + 1) * 1000, | ||
204 | CX23888_IR_REFCLK_FREQ / 1000000); | ||
205 | } | ||
206 | |||
207 | static inline u16 carrier_freq_to_clock_divider(unsigned int freq) | ||
208 | { | ||
209 | return count_to_clock_divider( | ||
210 | DIV_ROUND_CLOSEST(CX23888_IR_REFCLK_FREQ, freq * 16)); | ||
211 | } | ||
212 | |||
213 | static inline unsigned int clock_divider_to_carrier_freq(unsigned int divider) | ||
214 | { | ||
215 | return DIV_ROUND_CLOSEST(CX23888_IR_REFCLK_FREQ, (divider + 1) * 16); | ||
216 | } | ||
217 | |||
218 | static inline u16 freq_to_clock_divider(unsigned int freq, | ||
219 | unsigned int rollovers) | ||
220 | { | ||
221 | return count_to_clock_divider( | ||
222 | DIV_ROUND_CLOSEST(CX23888_IR_REFCLK_FREQ, freq * rollovers)); | ||
223 | } | ||
224 | |||
225 | static inline unsigned int clock_divider_to_freq(unsigned int divider, | ||
226 | unsigned int rollovers) | ||
227 | { | ||
228 | return DIV_ROUND_CLOSEST(CX23888_IR_REFCLK_FREQ, | ||
229 | (divider + 1) * rollovers); | ||
230 | } | ||
231 | |||
232 | /* | ||
233 | * Low Pass Filter register calculations | ||
234 | * | ||
235 | * Note the largest count value of 0xffff corresponds to: | ||
236 | * 0xffff * 1000 / 108/2 MHz = 1,213,611.11... ns | ||
237 | * which fits in 21 bits, so we'll use unsigned int for time arguments. | ||
238 | */ | ||
239 | static inline u16 count_to_lpf_count(unsigned int d) | ||
240 | { | ||
241 | if (d > FILTR_LPF) | ||
242 | d = FILTR_LPF; | ||
243 | else if (d < 4) | ||
244 | d = 0; | ||
245 | return (u16) d; | ||
246 | } | ||
247 | |||
248 | static inline u16 ns_to_lpf_count(unsigned int ns) | ||
249 | { | ||
250 | return count_to_lpf_count( | ||
251 | DIV_ROUND_CLOSEST(CX23888_IR_REFCLK_FREQ / 1000000 * ns, 1000)); | ||
252 | } | ||
253 | |||
254 | static inline unsigned int lpf_count_to_ns(unsigned int count) | ||
255 | { | ||
256 | /* Duration of the Low Pass Filter rejection window in ns */ | ||
257 | return DIV_ROUND_CLOSEST(count * 1000, | ||
258 | CX23888_IR_REFCLK_FREQ / 1000000); | ||
259 | } | ||
260 | |||
261 | static inline unsigned int lpf_count_to_us(unsigned int count) | ||
262 | { | ||
263 | /* Duration of the Low Pass Filter rejection window in us */ | ||
264 | return DIV_ROUND_CLOSEST(count, CX23888_IR_REFCLK_FREQ / 1000000); | ||
265 | } | ||
266 | |||
267 | /* | ||
268 | * FIFO register pulse width count compuations | ||
269 | */ | ||
270 | static u32 clock_divider_to_resolution(u16 divider) | ||
271 | { | ||
272 | /* | ||
273 | * Resolution is the duration of 1 tick of the readable portion of | ||
274 | * of the pulse width counter as read from the FIFO. The two lsb's are | ||
275 | * not readable, hence the << 2. This function returns ns. | ||
276 | */ | ||
277 | return DIV_ROUND_CLOSEST((1 << 2) * ((u32) divider + 1) * 1000, | ||
278 | CX23888_IR_REFCLK_FREQ / 1000000); | ||
279 | } | ||
280 | |||
281 | static u64 pulse_width_count_to_ns(u16 count, u16 divider) | ||
282 | { | ||
283 | u64 n; | ||
284 | u32 rem; | ||
285 | |||
286 | /* | ||
287 | * The 2 lsb's of the pulse width timer count are not readable, hence | ||
288 | * the (count << 2) | 0x3 | ||
289 | */ | ||
290 | n = (((u64) count << 2) | 0x3) * (divider + 1) * 1000; /* millicycles */ | ||
291 | rem = do_div(n, CX23888_IR_REFCLK_FREQ / 1000000); /* / MHz => ns */ | ||
292 | if (rem >= CX23888_IR_REFCLK_FREQ / 1000000 / 2) | ||
293 | n++; | ||
294 | return n; | ||
295 | } | ||
296 | |||
297 | static unsigned int pulse_width_count_to_us(u16 count, u16 divider) | ||
298 | { | ||
299 | u64 n; | ||
300 | u32 rem; | ||
301 | |||
302 | /* | ||
303 | * The 2 lsb's of the pulse width timer count are not readable, hence | ||
304 | * the (count << 2) | 0x3 | ||
305 | */ | ||
306 | n = (((u64) count << 2) | 0x3) * (divider + 1); /* cycles */ | ||
307 | rem = do_div(n, CX23888_IR_REFCLK_FREQ / 1000000); /* / MHz => us */ | ||
308 | if (rem >= CX23888_IR_REFCLK_FREQ / 1000000 / 2) | ||
309 | n++; | ||
310 | return (unsigned int) n; | ||
311 | } | ||
312 | |||
313 | /* | ||
314 | * Pulse Clocks computations: Combined Pulse Width Count & Rx Clock Counts | ||
315 | * | ||
316 | * The total pulse clock count is an 18 bit pulse width timer count as the most | ||
317 | * significant part and (up to) 16 bit clock divider count as a modulus. | ||
318 | * When the Rx clock divider ticks down to 0, it increments the 18 bit pulse | ||
319 | * width timer count's least significant bit. | ||
320 | */ | ||
321 | static u64 ns_to_pulse_clocks(u32 ns) | ||
322 | { | ||
323 | u64 clocks; | ||
324 | u32 rem; | ||
325 | clocks = CX23888_IR_REFCLK_FREQ / 1000000 * (u64) ns; /* millicycles */ | ||
326 | rem = do_div(clocks, 1000); /* /1000 = cycles */ | ||
327 | if (rem >= 1000 / 2) | ||
328 | clocks++; | ||
329 | return clocks; | ||
330 | } | ||
331 | |||
332 | static u16 pulse_clocks_to_clock_divider(u64 count) | ||
333 | { | ||
334 | u32 rem; | ||
335 | |||
336 | rem = do_div(count, (FIFO_RXTX << 2) | 0x3); | ||
337 | |||
338 | /* net result needs to be rounded down and decremented by 1 */ | ||
339 | if (count > RXCLK_RCD + 1) | ||
340 | count = RXCLK_RCD; | ||
341 | else if (count < 2) | ||
342 | count = 1; | ||
343 | else | ||
344 | count--; | ||
345 | return (u16) count; | ||
346 | } | ||
347 | |||
348 | /* | ||
349 | * IR Control Register helpers | ||
350 | */ | ||
351 | enum tx_fifo_watermark { | ||
352 | TX_FIFO_HALF_EMPTY = 0, | ||
353 | TX_FIFO_EMPTY = CNTRL_TIC, | ||
354 | }; | ||
355 | |||
356 | enum rx_fifo_watermark { | ||
357 | RX_FIFO_HALF_FULL = 0, | ||
358 | RX_FIFO_NOT_EMPTY = CNTRL_RIC, | ||
359 | }; | ||
360 | |||
361 | static inline void control_tx_irq_watermark(struct cx23885_dev *dev, | ||
362 | enum tx_fifo_watermark level) | ||
363 | { | ||
364 | cx23888_ir_and_or4(dev, CX23888_IR_CNTRL_REG, ~CNTRL_TIC, level); | ||
365 | } | ||
366 | |||
367 | static inline void control_rx_irq_watermark(struct cx23885_dev *dev, | ||
368 | enum rx_fifo_watermark level) | ||
369 | { | ||
370 | cx23888_ir_and_or4(dev, CX23888_IR_CNTRL_REG, ~CNTRL_RIC, level); | ||
371 | } | ||
372 | |||
373 | static inline void control_tx_enable(struct cx23885_dev *dev, bool enable) | ||
374 | { | ||
375 | cx23888_ir_and_or4(dev, CX23888_IR_CNTRL_REG, ~(CNTRL_TXE | CNTRL_TFE), | ||
376 | enable ? (CNTRL_TXE | CNTRL_TFE) : 0); | ||
377 | } | ||
378 | |||
379 | static inline void control_rx_enable(struct cx23885_dev *dev, bool enable) | ||
380 | { | ||
381 | cx23888_ir_and_or4(dev, CX23888_IR_CNTRL_REG, ~(CNTRL_RXE | CNTRL_RFE), | ||
382 | enable ? (CNTRL_RXE | CNTRL_RFE) : 0); | ||
383 | } | ||
384 | |||
385 | static inline void control_tx_modulation_enable(struct cx23885_dev *dev, | ||
386 | bool enable) | ||
387 | { | ||
388 | cx23888_ir_and_or4(dev, CX23888_IR_CNTRL_REG, ~CNTRL_MOD, | ||
389 | enable ? CNTRL_MOD : 0); | ||
390 | } | ||
391 | |||
392 | static inline void control_rx_demodulation_enable(struct cx23885_dev *dev, | ||
393 | bool enable) | ||
394 | { | ||
395 | cx23888_ir_and_or4(dev, CX23888_IR_CNTRL_REG, ~CNTRL_DMD, | ||
396 | enable ? CNTRL_DMD : 0); | ||
397 | } | ||
398 | |||
399 | static inline void control_rx_s_edge_detection(struct cx23885_dev *dev, | ||
400 | u32 edge_types) | ||
401 | { | ||
402 | cx23888_ir_and_or4(dev, CX23888_IR_CNTRL_REG, ~CNTRL_EDG_BOTH, | ||
403 | edge_types & CNTRL_EDG_BOTH); | ||
404 | } | ||
405 | |||
406 | static void control_rx_s_carrier_window(struct cx23885_dev *dev, | ||
407 | unsigned int carrier, | ||
408 | unsigned int *carrier_range_low, | ||
409 | unsigned int *carrier_range_high) | ||
410 | { | ||
411 | u32 v; | ||
412 | unsigned int c16 = carrier * 16; | ||
413 | |||
414 | if (*carrier_range_low < DIV_ROUND_CLOSEST(c16, 16 + 3)) { | ||
415 | v = CNTRL_WIN_3_4; | ||
416 | *carrier_range_low = DIV_ROUND_CLOSEST(c16, 16 + 4); | ||
417 | } else { | ||
418 | v = CNTRL_WIN_3_3; | ||
419 | *carrier_range_low = DIV_ROUND_CLOSEST(c16, 16 + 3); | ||
420 | } | ||
421 | |||
422 | if (*carrier_range_high > DIV_ROUND_CLOSEST(c16, 16 - 3)) { | ||
423 | v |= CNTRL_WIN_4_3; | ||
424 | *carrier_range_high = DIV_ROUND_CLOSEST(c16, 16 - 4); | ||
425 | } else { | ||
426 | v |= CNTRL_WIN_3_3; | ||
427 | *carrier_range_high = DIV_ROUND_CLOSEST(c16, 16 - 3); | ||
428 | } | ||
429 | cx23888_ir_and_or4(dev, CX23888_IR_CNTRL_REG, ~CNTRL_WIN, v); | ||
430 | } | ||
431 | |||
432 | static inline void control_tx_polarity_invert(struct cx23885_dev *dev, | ||
433 | bool invert) | ||
434 | { | ||
435 | cx23888_ir_and_or4(dev, CX23888_IR_CNTRL_REG, ~CNTRL_CPL, | ||
436 | invert ? CNTRL_CPL : 0); | ||
437 | } | ||
438 | |||
439 | static inline void control_tx_level_invert(struct cx23885_dev *dev, | ||
440 | bool invert) | ||
441 | { | ||
442 | cx23888_ir_and_or4(dev, CX23888_IR_CNTRL_REG, ~CNTRL_IVO, | ||
443 | invert ? CNTRL_IVO : 0); | ||
444 | } | ||
445 | |||
446 | /* | ||
447 | * IR Rx & Tx Clock Register helpers | ||
448 | */ | ||
449 | static unsigned int txclk_tx_s_carrier(struct cx23885_dev *dev, | ||
450 | unsigned int freq, | ||
451 | u16 *divider) | ||
452 | { | ||
453 | *divider = carrier_freq_to_clock_divider(freq); | ||
454 | cx23888_ir_write4(dev, CX23888_IR_TXCLK_REG, *divider); | ||
455 | return clock_divider_to_carrier_freq(*divider); | ||
456 | } | ||
457 | |||
458 | static unsigned int rxclk_rx_s_carrier(struct cx23885_dev *dev, | ||
459 | unsigned int freq, | ||
460 | u16 *divider) | ||
461 | { | ||
462 | *divider = carrier_freq_to_clock_divider(freq); | ||
463 | cx23888_ir_write4(dev, CX23888_IR_RXCLK_REG, *divider); | ||
464 | return clock_divider_to_carrier_freq(*divider); | ||
465 | } | ||
466 | |||
467 | static u32 txclk_tx_s_max_pulse_width(struct cx23885_dev *dev, u32 ns, | ||
468 | u16 *divider) | ||
469 | { | ||
470 | u64 pulse_clocks; | ||
471 | |||
472 | if (ns > IR_MAX_DURATION) | ||
473 | ns = IR_MAX_DURATION; | ||
474 | pulse_clocks = ns_to_pulse_clocks(ns); | ||
475 | *divider = pulse_clocks_to_clock_divider(pulse_clocks); | ||
476 | cx23888_ir_write4(dev, CX23888_IR_TXCLK_REG, *divider); | ||
477 | return (u32) pulse_width_count_to_ns(FIFO_RXTX, *divider); | ||
478 | } | ||
479 | |||
480 | static u32 rxclk_rx_s_max_pulse_width(struct cx23885_dev *dev, u32 ns, | ||
481 | u16 *divider) | ||
482 | { | ||
483 | u64 pulse_clocks; | ||
484 | |||
485 | if (ns > IR_MAX_DURATION) | ||
486 | ns = IR_MAX_DURATION; | ||
487 | pulse_clocks = ns_to_pulse_clocks(ns); | ||
488 | *divider = pulse_clocks_to_clock_divider(pulse_clocks); | ||
489 | cx23888_ir_write4(dev, CX23888_IR_RXCLK_REG, *divider); | ||
490 | return (u32) pulse_width_count_to_ns(FIFO_RXTX, *divider); | ||
491 | } | ||
492 | |||
493 | /* | ||
494 | * IR Tx Carrier Duty Cycle register helpers | ||
495 | */ | ||
496 | static unsigned int cduty_tx_s_duty_cycle(struct cx23885_dev *dev, | ||
497 | unsigned int duty_cycle) | ||
498 | { | ||
499 | u32 n; | ||
500 | n = DIV_ROUND_CLOSEST(duty_cycle * 100, 625); /* 16ths of 100% */ | ||
501 | if (n != 0) | ||
502 | n--; | ||
503 | if (n > 15) | ||
504 | n = 15; | ||
505 | cx23888_ir_write4(dev, CX23888_IR_CDUTY_REG, n); | ||
506 | return DIV_ROUND_CLOSEST((n + 1) * 100, 16); | ||
507 | } | ||
508 | |||
509 | /* | ||
510 | * IR Filter Register helpers | ||
511 | */ | ||
512 | static u32 filter_rx_s_min_width(struct cx23885_dev *dev, u32 min_width_ns) | ||
513 | { | ||
514 | u32 count = ns_to_lpf_count(min_width_ns); | ||
515 | cx23888_ir_write4(dev, CX23888_IR_FILTR_REG, count); | ||
516 | return lpf_count_to_ns(count); | ||
517 | } | ||
518 | |||
519 | /* | ||
520 | * IR IRQ Enable Register helpers | ||
521 | */ | ||
522 | static inline void irqenable_rx(struct cx23885_dev *dev, u32 mask) | ||
523 | { | ||
524 | mask &= (IRQEN_RTE | IRQEN_ROE | IRQEN_RSE); | ||
525 | cx23888_ir_and_or4(dev, CX23888_IR_IRQEN_REG, | ||
526 | ~(IRQEN_RTE | IRQEN_ROE | IRQEN_RSE), mask); | ||
527 | } | ||
528 | |||
529 | static inline void irqenable_tx(struct cx23885_dev *dev, u32 mask) | ||
530 | { | ||
531 | mask &= IRQEN_TSE; | ||
532 | cx23888_ir_and_or4(dev, CX23888_IR_IRQEN_REG, ~IRQEN_TSE, mask); | ||
533 | } | ||
534 | |||
535 | /* | ||
536 | * V4L2 Subdevice IR Ops | ||
537 | */ | ||
538 | static int cx23888_ir_irq_handler(struct v4l2_subdev *sd, u32 status, | ||
539 | bool *handled) | ||
540 | { | ||
541 | struct cx23888_ir_state *state = to_state(sd); | ||
542 | struct cx23885_dev *dev = state->dev; | ||
543 | unsigned long flags; | ||
544 | |||
545 | u32 cntrl = cx23888_ir_read4(dev, CX23888_IR_CNTRL_REG); | ||
546 | u32 irqen = cx23888_ir_read4(dev, CX23888_IR_IRQEN_REG); | ||
547 | u32 stats = cx23888_ir_read4(dev, CX23888_IR_STATS_REG); | ||
548 | |||
549 | union cx23888_ir_fifo_rec rx_data[FIFO_RX_DEPTH]; | ||
550 | unsigned int i, j, k; | ||
551 | u32 events, v; | ||
552 | int tsr, rsr, rto, ror, tse, rse, rte, roe, kror; | ||
553 | |||
554 | tsr = stats & STATS_TSR; /* Tx FIFO Service Request */ | ||
555 | rsr = stats & STATS_RSR; /* Rx FIFO Service Request */ | ||
556 | rto = stats & STATS_RTO; /* Rx Pulse Width Timer Time Out */ | ||
557 | ror = stats & STATS_ROR; /* Rx FIFO Over Run */ | ||
558 | |||
559 | tse = irqen & IRQEN_TSE; /* Tx FIFO Service Request IRQ Enable */ | ||
560 | rse = irqen & IRQEN_RSE; /* Rx FIFO Service Reuqest IRQ Enable */ | ||
561 | rte = irqen & IRQEN_RTE; /* Rx Pulse Width Timer Time Out IRQ Enable */ | ||
562 | roe = irqen & IRQEN_ROE; /* Rx FIFO Over Run IRQ Enable */ | ||
563 | |||
564 | *handled = false; | ||
565 | v4l2_dbg(2, ir_888_debug, sd, "IRQ Status: %s %s %s %s %s %s\n", | ||
566 | tsr ? "tsr" : " ", rsr ? "rsr" : " ", | ||
567 | rto ? "rto" : " ", ror ? "ror" : " ", | ||
568 | stats & STATS_TBY ? "tby" : " ", | ||
569 | stats & STATS_RBY ? "rby" : " "); | ||
570 | |||
571 | v4l2_dbg(2, ir_888_debug, sd, "IRQ Enables: %s %s %s %s\n", | ||
572 | tse ? "tse" : " ", rse ? "rse" : " ", | ||
573 | rte ? "rte" : " ", roe ? "roe" : " "); | ||
574 | |||
575 | /* | ||
576 | * Transmitter interrupt service | ||
577 | */ | ||
578 | if (tse && tsr) { | ||
579 | /* | ||
580 | * TODO: | ||
581 | * Check the watermark threshold setting | ||
582 | * Pull FIFO_TX_DEPTH or FIFO_TX_DEPTH/2 entries from tx_kfifo | ||
583 | * Push the data to the hardware FIFO. | ||
584 | * If there was nothing more to send in the tx_kfifo, disable | ||
585 | * the TSR IRQ and notify the v4l2_device. | ||
586 | * If there was something in the tx_kfifo, check the tx_kfifo | ||
587 | * level and notify the v4l2_device, if it is low. | ||
588 | */ | ||
589 | /* For now, inhibit TSR interrupt until Tx is implemented */ | ||
590 | irqenable_tx(dev, 0); | ||
591 | events = V4L2_SUBDEV_IR_TX_FIFO_SERVICE_REQ; | ||
592 | v4l2_subdev_notify(sd, V4L2_SUBDEV_IR_TX_NOTIFY, &events); | ||
593 | *handled = true; | ||
594 | } | ||
595 | |||
596 | /* | ||
597 | * Receiver interrupt service | ||
598 | */ | ||
599 | kror = 0; | ||
600 | if ((rse && rsr) || (rte && rto)) { | ||
601 | /* | ||
602 | * Receive data on RSR to clear the STATS_RSR. | ||
603 | * Receive data on RTO, since we may not have yet hit the RSR | ||
604 | * watermark when we receive the RTO. | ||
605 | */ | ||
606 | for (i = 0, v = FIFO_RX_NDV; | ||
607 | (v & FIFO_RX_NDV) && !kror; i = 0) { | ||
608 | for (j = 0; | ||
609 | (v & FIFO_RX_NDV) && j < FIFO_RX_DEPTH; j++) { | ||
610 | v = cx23888_ir_read4(dev, CX23888_IR_FIFO_REG); | ||
611 | rx_data[i].hw_fifo_data = v & ~FIFO_RX_NDV; | ||
612 | i++; | ||
613 | } | ||
614 | if (i == 0) | ||
615 | break; | ||
616 | j = i * sizeof(union cx23888_ir_fifo_rec); | ||
617 | k = kfifo_in_locked(&state->rx_kfifo, | ||
618 | (unsigned char *) rx_data, j, | ||
619 | &state->rx_kfifo_lock); | ||
620 | if (k != j) | ||
621 | kror++; /* rx_kfifo over run */ | ||
622 | } | ||
623 | *handled = true; | ||
624 | } | ||
625 | |||
626 | events = 0; | ||
627 | v = 0; | ||
628 | if (kror) { | ||
629 | events |= V4L2_SUBDEV_IR_RX_SW_FIFO_OVERRUN; | ||
630 | v4l2_err(sd, "IR receiver software FIFO overrun\n"); | ||
631 | } | ||
632 | if (roe && ror) { | ||
633 | /* | ||
634 | * The RX FIFO Enable (CNTRL_RFE) must be toggled to clear | ||
635 | * the Rx FIFO Over Run status (STATS_ROR) | ||
636 | */ | ||
637 | v |= CNTRL_RFE; | ||
638 | events |= V4L2_SUBDEV_IR_RX_HW_FIFO_OVERRUN; | ||
639 | v4l2_err(sd, "IR receiver hardware FIFO overrun\n"); | ||
640 | } | ||
641 | if (rte && rto) { | ||
642 | /* | ||
643 | * The IR Receiver Enable (CNTRL_RXE) must be toggled to clear | ||
644 | * the Rx Pulse Width Timer Time Out (STATS_RTO) | ||
645 | */ | ||
646 | v |= CNTRL_RXE; | ||
647 | events |= V4L2_SUBDEV_IR_RX_END_OF_RX_DETECTED; | ||
648 | } | ||
649 | if (v) { | ||
650 | /* Clear STATS_ROR & STATS_RTO as needed by reseting hardware */ | ||
651 | cx23888_ir_write4(dev, CX23888_IR_CNTRL_REG, cntrl & ~v); | ||
652 | cx23888_ir_write4(dev, CX23888_IR_CNTRL_REG, cntrl); | ||
653 | *handled = true; | ||
654 | } | ||
655 | |||
656 | spin_lock_irqsave(&state->rx_kfifo_lock, flags); | ||
657 | if (kfifo_len(&state->rx_kfifo) >= CX23888_IR_RX_KFIFO_SIZE / 2) | ||
658 | events |= V4L2_SUBDEV_IR_RX_FIFO_SERVICE_REQ; | ||
659 | spin_unlock_irqrestore(&state->rx_kfifo_lock, flags); | ||
660 | |||
661 | if (events) | ||
662 | v4l2_subdev_notify(sd, V4L2_SUBDEV_IR_RX_NOTIFY, &events); | ||
663 | return 0; | ||
664 | } | ||
665 | |||
666 | /* Receiver */ | ||
667 | static int cx23888_ir_rx_read(struct v4l2_subdev *sd, u8 *buf, size_t count, | ||
668 | ssize_t *num) | ||
669 | { | ||
670 | struct cx23888_ir_state *state = to_state(sd); | ||
671 | bool invert = (bool) atomic_read(&state->rx_invert); | ||
672 | u16 divider = (u16) atomic_read(&state->rxclk_divider); | ||
673 | |||
674 | unsigned int i, n; | ||
675 | union cx23888_ir_fifo_rec *p; | ||
676 | unsigned u, v; | ||
677 | |||
678 | n = count / sizeof(union cx23888_ir_fifo_rec) | ||
679 | * sizeof(union cx23888_ir_fifo_rec); | ||
680 | if (n == 0) { | ||
681 | *num = 0; | ||
682 | return 0; | ||
683 | } | ||
684 | |||
685 | n = kfifo_out_locked(&state->rx_kfifo, buf, n, &state->rx_kfifo_lock); | ||
686 | |||
687 | n /= sizeof(union cx23888_ir_fifo_rec); | ||
688 | *num = n * sizeof(union cx23888_ir_fifo_rec); | ||
689 | |||
690 | for (p = (union cx23888_ir_fifo_rec *) buf, i = 0; i < n; p++, i++) { | ||
691 | |||
692 | if ((p->hw_fifo_data & FIFO_RXTX_RTO) == FIFO_RXTX_RTO) { | ||
693 | /* Assume RTO was because of no IR light input */ | ||
694 | u = 0; | ||
695 | v4l2_dbg(2, ir_888_debug, sd, "rx read: end of rx\n"); | ||
696 | } else { | ||
697 | u = (p->hw_fifo_data & FIFO_RXTX_LVL) ? 1 : 0; | ||
698 | if (invert) | ||
699 | u = u ? 0 : 1; | ||
700 | } | ||
701 | |||
702 | v = (unsigned) pulse_width_count_to_ns( | ||
703 | (u16) (p->hw_fifo_data & FIFO_RXTX), divider); | ||
704 | if (v > IR_MAX_DURATION) | ||
705 | v = IR_MAX_DURATION; | ||
706 | |||
707 | init_ir_raw_event(&p->ir_core_data); | ||
708 | p->ir_core_data.pulse = u; | ||
709 | p->ir_core_data.duration = v; | ||
710 | |||
711 | v4l2_dbg(2, ir_888_debug, sd, "rx read: %10u ns %s\n", | ||
712 | v, u ? "mark" : "space"); | ||
713 | } | ||
714 | return 0; | ||
715 | } | ||
716 | |||
717 | static int cx23888_ir_rx_g_parameters(struct v4l2_subdev *sd, | ||
718 | struct v4l2_subdev_ir_parameters *p) | ||
719 | { | ||
720 | struct cx23888_ir_state *state = to_state(sd); | ||
721 | mutex_lock(&state->rx_params_lock); | ||
722 | memcpy(p, &state->rx_params, sizeof(struct v4l2_subdev_ir_parameters)); | ||
723 | mutex_unlock(&state->rx_params_lock); | ||
724 | return 0; | ||
725 | } | ||
726 | |||
727 | static int cx23888_ir_rx_shutdown(struct v4l2_subdev *sd) | ||
728 | { | ||
729 | struct cx23888_ir_state *state = to_state(sd); | ||
730 | struct cx23885_dev *dev = state->dev; | ||
731 | |||
732 | mutex_lock(&state->rx_params_lock); | ||
733 | |||
734 | /* Disable or slow down all IR Rx circuits and counters */ | ||
735 | irqenable_rx(dev, 0); | ||
736 | control_rx_enable(dev, false); | ||
737 | control_rx_demodulation_enable(dev, false); | ||
738 | control_rx_s_edge_detection(dev, CNTRL_EDG_NONE); | ||
739 | filter_rx_s_min_width(dev, 0); | ||
740 | cx23888_ir_write4(dev, CX23888_IR_RXCLK_REG, RXCLK_RCD); | ||
741 | |||
742 | state->rx_params.shutdown = true; | ||
743 | |||
744 | mutex_unlock(&state->rx_params_lock); | ||
745 | return 0; | ||
746 | } | ||
747 | |||
748 | static int cx23888_ir_rx_s_parameters(struct v4l2_subdev *sd, | ||
749 | struct v4l2_subdev_ir_parameters *p) | ||
750 | { | ||
751 | struct cx23888_ir_state *state = to_state(sd); | ||
752 | struct cx23885_dev *dev = state->dev; | ||
753 | struct v4l2_subdev_ir_parameters *o = &state->rx_params; | ||
754 | u16 rxclk_divider; | ||
755 | |||
756 | if (p->shutdown) | ||
757 | return cx23888_ir_rx_shutdown(sd); | ||
758 | |||
759 | if (p->mode != V4L2_SUBDEV_IR_MODE_PULSE_WIDTH) | ||
760 | return -ENOSYS; | ||
761 | |||
762 | mutex_lock(&state->rx_params_lock); | ||
763 | |||
764 | o->shutdown = p->shutdown; | ||
765 | |||
766 | o->mode = p->mode = V4L2_SUBDEV_IR_MODE_PULSE_WIDTH; | ||
767 | |||
768 | o->bytes_per_data_element = p->bytes_per_data_element | ||
769 | = sizeof(union cx23888_ir_fifo_rec); | ||
770 | |||
771 | /* Before we tweak the hardware, we have to disable the receiver */ | ||
772 | irqenable_rx(dev, 0); | ||
773 | control_rx_enable(dev, false); | ||
774 | |||
775 | control_rx_demodulation_enable(dev, p->modulation); | ||
776 | o->modulation = p->modulation; | ||
777 | |||
778 | if (p->modulation) { | ||
779 | p->carrier_freq = rxclk_rx_s_carrier(dev, p->carrier_freq, | ||
780 | &rxclk_divider); | ||
781 | |||
782 | o->carrier_freq = p->carrier_freq; | ||
783 | |||
784 | o->duty_cycle = p->duty_cycle = 50; | ||
785 | |||
786 | control_rx_s_carrier_window(dev, p->carrier_freq, | ||
787 | &p->carrier_range_lower, | ||
788 | &p->carrier_range_upper); | ||
789 | o->carrier_range_lower = p->carrier_range_lower; | ||
790 | o->carrier_range_upper = p->carrier_range_upper; | ||
791 | |||
792 | p->max_pulse_width = | ||
793 | (u32) pulse_width_count_to_ns(FIFO_RXTX, rxclk_divider); | ||
794 | } else { | ||
795 | p->max_pulse_width = | ||
796 | rxclk_rx_s_max_pulse_width(dev, p->max_pulse_width, | ||
797 | &rxclk_divider); | ||
798 | } | ||
799 | o->max_pulse_width = p->max_pulse_width; | ||
800 | atomic_set(&state->rxclk_divider, rxclk_divider); | ||
801 | |||
802 | p->noise_filter_min_width = | ||
803 | filter_rx_s_min_width(dev, p->noise_filter_min_width); | ||
804 | o->noise_filter_min_width = p->noise_filter_min_width; | ||
805 | |||
806 | p->resolution = clock_divider_to_resolution(rxclk_divider); | ||
807 | o->resolution = p->resolution; | ||
808 | |||
809 | /* FIXME - make this dependent on resolution for better performance */ | ||
810 | control_rx_irq_watermark(dev, RX_FIFO_HALF_FULL); | ||
811 | |||
812 | control_rx_s_edge_detection(dev, CNTRL_EDG_BOTH); | ||
813 | |||
814 | o->invert_level = p->invert_level; | ||
815 | atomic_set(&state->rx_invert, p->invert_level); | ||
816 | |||
817 | o->interrupt_enable = p->interrupt_enable; | ||
818 | o->enable = p->enable; | ||
819 | if (p->enable) { | ||
820 | unsigned long flags; | ||
821 | |||
822 | spin_lock_irqsave(&state->rx_kfifo_lock, flags); | ||
823 | kfifo_reset(&state->rx_kfifo); | ||
824 | /* reset tx_fifo too if there is one... */ | ||
825 | spin_unlock_irqrestore(&state->rx_kfifo_lock, flags); | ||
826 | if (p->interrupt_enable) | ||
827 | irqenable_rx(dev, IRQEN_RSE | IRQEN_RTE | IRQEN_ROE); | ||
828 | control_rx_enable(dev, p->enable); | ||
829 | } | ||
830 | |||
831 | mutex_unlock(&state->rx_params_lock); | ||
832 | return 0; | ||
833 | } | ||
834 | |||
835 | /* Transmitter */ | ||
836 | static int cx23888_ir_tx_write(struct v4l2_subdev *sd, u8 *buf, size_t count, | ||
837 | ssize_t *num) | ||
838 | { | ||
839 | struct cx23888_ir_state *state = to_state(sd); | ||
840 | struct cx23885_dev *dev = state->dev; | ||
841 | /* For now enable the Tx FIFO Service interrupt & pretend we did work */ | ||
842 | irqenable_tx(dev, IRQEN_TSE); | ||
843 | *num = count; | ||
844 | return 0; | ||
845 | } | ||
846 | |||
847 | static int cx23888_ir_tx_g_parameters(struct v4l2_subdev *sd, | ||
848 | struct v4l2_subdev_ir_parameters *p) | ||
849 | { | ||
850 | struct cx23888_ir_state *state = to_state(sd); | ||
851 | mutex_lock(&state->tx_params_lock); | ||
852 | memcpy(p, &state->tx_params, sizeof(struct v4l2_subdev_ir_parameters)); | ||
853 | mutex_unlock(&state->tx_params_lock); | ||
854 | return 0; | ||
855 | } | ||
856 | |||
857 | static int cx23888_ir_tx_shutdown(struct v4l2_subdev *sd) | ||
858 | { | ||
859 | struct cx23888_ir_state *state = to_state(sd); | ||
860 | struct cx23885_dev *dev = state->dev; | ||
861 | |||
862 | mutex_lock(&state->tx_params_lock); | ||
863 | |||
864 | /* Disable or slow down all IR Tx circuits and counters */ | ||
865 | irqenable_tx(dev, 0); | ||
866 | control_tx_enable(dev, false); | ||
867 | control_tx_modulation_enable(dev, false); | ||
868 | cx23888_ir_write4(dev, CX23888_IR_TXCLK_REG, TXCLK_TCD); | ||
869 | |||
870 | state->tx_params.shutdown = true; | ||
871 | |||
872 | mutex_unlock(&state->tx_params_lock); | ||
873 | return 0; | ||
874 | } | ||
875 | |||
876 | static int cx23888_ir_tx_s_parameters(struct v4l2_subdev *sd, | ||
877 | struct v4l2_subdev_ir_parameters *p) | ||
878 | { | ||
879 | struct cx23888_ir_state *state = to_state(sd); | ||
880 | struct cx23885_dev *dev = state->dev; | ||
881 | struct v4l2_subdev_ir_parameters *o = &state->tx_params; | ||
882 | u16 txclk_divider; | ||
883 | |||
884 | if (p->shutdown) | ||
885 | return cx23888_ir_tx_shutdown(sd); | ||
886 | |||
887 | if (p->mode != V4L2_SUBDEV_IR_MODE_PULSE_WIDTH) | ||
888 | return -ENOSYS; | ||
889 | |||
890 | mutex_lock(&state->tx_params_lock); | ||
891 | |||
892 | o->shutdown = p->shutdown; | ||
893 | |||
894 | o->mode = p->mode = V4L2_SUBDEV_IR_MODE_PULSE_WIDTH; | ||
895 | |||
896 | o->bytes_per_data_element = p->bytes_per_data_element | ||
897 | = sizeof(union cx23888_ir_fifo_rec); | ||
898 | |||
899 | /* Before we tweak the hardware, we have to disable the transmitter */ | ||
900 | irqenable_tx(dev, 0); | ||
901 | control_tx_enable(dev, false); | ||
902 | |||
903 | control_tx_modulation_enable(dev, p->modulation); | ||
904 | o->modulation = p->modulation; | ||
905 | |||
906 | if (p->modulation) { | ||
907 | p->carrier_freq = txclk_tx_s_carrier(dev, p->carrier_freq, | ||
908 | &txclk_divider); | ||
909 | o->carrier_freq = p->carrier_freq; | ||
910 | |||
911 | p->duty_cycle = cduty_tx_s_duty_cycle(dev, p->duty_cycle); | ||
912 | o->duty_cycle = p->duty_cycle; | ||
913 | |||
914 | p->max_pulse_width = | ||
915 | (u32) pulse_width_count_to_ns(FIFO_RXTX, txclk_divider); | ||
916 | } else { | ||
917 | p->max_pulse_width = | ||
918 | txclk_tx_s_max_pulse_width(dev, p->max_pulse_width, | ||
919 | &txclk_divider); | ||
920 | } | ||
921 | o->max_pulse_width = p->max_pulse_width; | ||
922 | atomic_set(&state->txclk_divider, txclk_divider); | ||
923 | |||
924 | p->resolution = clock_divider_to_resolution(txclk_divider); | ||
925 | o->resolution = p->resolution; | ||
926 | |||
927 | /* FIXME - make this dependent on resolution for better performance */ | ||
928 | control_tx_irq_watermark(dev, TX_FIFO_HALF_EMPTY); | ||
929 | |||
930 | control_tx_polarity_invert(dev, p->invert_carrier_sense); | ||
931 | o->invert_carrier_sense = p->invert_carrier_sense; | ||
932 | |||
933 | control_tx_level_invert(dev, p->invert_level); | ||
934 | o->invert_level = p->invert_level; | ||
935 | |||
936 | o->interrupt_enable = p->interrupt_enable; | ||
937 | o->enable = p->enable; | ||
938 | if (p->enable) { | ||
939 | if (p->interrupt_enable) | ||
940 | irqenable_tx(dev, IRQEN_TSE); | ||
941 | control_tx_enable(dev, p->enable); | ||
942 | } | ||
943 | |||
944 | mutex_unlock(&state->tx_params_lock); | ||
945 | return 0; | ||
946 | } | ||
947 | |||
948 | |||
949 | /* | ||
950 | * V4L2 Subdevice Core Ops | ||
951 | */ | ||
952 | static int cx23888_ir_log_status(struct v4l2_subdev *sd) | ||
953 | { | ||
954 | struct cx23888_ir_state *state = to_state(sd); | ||
955 | struct cx23885_dev *dev = state->dev; | ||
956 | char *s; | ||
957 | int i, j; | ||
958 | |||
959 | u32 cntrl = cx23888_ir_read4(dev, CX23888_IR_CNTRL_REG); | ||
960 | u32 txclk = cx23888_ir_read4(dev, CX23888_IR_TXCLK_REG) & TXCLK_TCD; | ||
961 | u32 rxclk = cx23888_ir_read4(dev, CX23888_IR_RXCLK_REG) & RXCLK_RCD; | ||
962 | u32 cduty = cx23888_ir_read4(dev, CX23888_IR_CDUTY_REG) & CDUTY_CDC; | ||
963 | u32 stats = cx23888_ir_read4(dev, CX23888_IR_STATS_REG); | ||
964 | u32 irqen = cx23888_ir_read4(dev, CX23888_IR_IRQEN_REG); | ||
965 | u32 filtr = cx23888_ir_read4(dev, CX23888_IR_FILTR_REG) & FILTR_LPF; | ||
966 | |||
967 | v4l2_info(sd, "IR Receiver:\n"); | ||
968 | v4l2_info(sd, "\tEnabled: %s\n", | ||
969 | cntrl & CNTRL_RXE ? "yes" : "no"); | ||
970 | v4l2_info(sd, "\tDemodulation from a carrier: %s\n", | ||
971 | cntrl & CNTRL_DMD ? "enabled" : "disabled"); | ||
972 | v4l2_info(sd, "\tFIFO: %s\n", | ||
973 | cntrl & CNTRL_RFE ? "enabled" : "disabled"); | ||
974 | switch (cntrl & CNTRL_EDG) { | ||
975 | case CNTRL_EDG_NONE: | ||
976 | s = "disabled"; | ||
977 | break; | ||
978 | case CNTRL_EDG_FALL: | ||
979 | s = "falling edge"; | ||
980 | break; | ||
981 | case CNTRL_EDG_RISE: | ||
982 | s = "rising edge"; | ||
983 | break; | ||
984 | case CNTRL_EDG_BOTH: | ||
985 | s = "rising & falling edges"; | ||
986 | break; | ||
987 | default: | ||
988 | s = "??? edge"; | ||
989 | break; | ||
990 | } | ||
991 | v4l2_info(sd, "\tPulse timers' start/stop trigger: %s\n", s); | ||
992 | v4l2_info(sd, "\tFIFO data on pulse timer overflow: %s\n", | ||
993 | cntrl & CNTRL_R ? "not loaded" : "overflow marker"); | ||
994 | v4l2_info(sd, "\tFIFO interrupt watermark: %s\n", | ||
995 | cntrl & CNTRL_RIC ? "not empty" : "half full or greater"); | ||
996 | v4l2_info(sd, "\tLoopback mode: %s\n", | ||
997 | cntrl & CNTRL_LBM ? "loopback active" : "normal receive"); | ||
998 | if (cntrl & CNTRL_DMD) { | ||
999 | v4l2_info(sd, "\tExpected carrier (16 clocks): %u Hz\n", | ||
1000 | clock_divider_to_carrier_freq(rxclk)); | ||
1001 | switch (cntrl & CNTRL_WIN) { | ||
1002 | case CNTRL_WIN_3_3: | ||
1003 | i = 3; | ||
1004 | j = 3; | ||
1005 | break; | ||
1006 | case CNTRL_WIN_4_3: | ||
1007 | i = 4; | ||
1008 | j = 3; | ||
1009 | break; | ||
1010 | case CNTRL_WIN_3_4: | ||
1011 | i = 3; | ||
1012 | j = 4; | ||
1013 | break; | ||
1014 | case CNTRL_WIN_4_4: | ||
1015 | i = 4; | ||
1016 | j = 4; | ||
1017 | break; | ||
1018 | default: | ||
1019 | i = 0; | ||
1020 | j = 0; | ||
1021 | break; | ||
1022 | } | ||
1023 | v4l2_info(sd, "\tNext carrier edge window: 16 clocks " | ||
1024 | "-%1d/+%1d, %u to %u Hz\n", i, j, | ||
1025 | clock_divider_to_freq(rxclk, 16 + j), | ||
1026 | clock_divider_to_freq(rxclk, 16 - i)); | ||
1027 | } | ||
1028 | v4l2_info(sd, "\tMax measurable pulse width: %u us, %llu ns\n", | ||
1029 | pulse_width_count_to_us(FIFO_RXTX, rxclk), | ||
1030 | pulse_width_count_to_ns(FIFO_RXTX, rxclk)); | ||
1031 | v4l2_info(sd, "\tLow pass filter: %s\n", | ||
1032 | filtr ? "enabled" : "disabled"); | ||
1033 | if (filtr) | ||
1034 | v4l2_info(sd, "\tMin acceptable pulse width (LPF): %u us, " | ||
1035 | "%u ns\n", | ||
1036 | lpf_count_to_us(filtr), | ||
1037 | lpf_count_to_ns(filtr)); | ||
1038 | v4l2_info(sd, "\tPulse width timer timed-out: %s\n", | ||
1039 | stats & STATS_RTO ? "yes" : "no"); | ||
1040 | v4l2_info(sd, "\tPulse width timer time-out intr: %s\n", | ||
1041 | irqen & IRQEN_RTE ? "enabled" : "disabled"); | ||
1042 | v4l2_info(sd, "\tFIFO overrun: %s\n", | ||
1043 | stats & STATS_ROR ? "yes" : "no"); | ||
1044 | v4l2_info(sd, "\tFIFO overrun interrupt: %s\n", | ||
1045 | irqen & IRQEN_ROE ? "enabled" : "disabled"); | ||
1046 | v4l2_info(sd, "\tBusy: %s\n", | ||
1047 | stats & STATS_RBY ? "yes" : "no"); | ||
1048 | v4l2_info(sd, "\tFIFO service requested: %s\n", | ||
1049 | stats & STATS_RSR ? "yes" : "no"); | ||
1050 | v4l2_info(sd, "\tFIFO service request interrupt: %s\n", | ||
1051 | irqen & IRQEN_RSE ? "enabled" : "disabled"); | ||
1052 | |||
1053 | v4l2_info(sd, "IR Transmitter:\n"); | ||
1054 | v4l2_info(sd, "\tEnabled: %s\n", | ||
1055 | cntrl & CNTRL_TXE ? "yes" : "no"); | ||
1056 | v4l2_info(sd, "\tModulation onto a carrier: %s\n", | ||
1057 | cntrl & CNTRL_MOD ? "enabled" : "disabled"); | ||
1058 | v4l2_info(sd, "\tFIFO: %s\n", | ||
1059 | cntrl & CNTRL_TFE ? "enabled" : "disabled"); | ||
1060 | v4l2_info(sd, "\tFIFO interrupt watermark: %s\n", | ||
1061 | cntrl & CNTRL_TIC ? "not empty" : "half full or less"); | ||
1062 | v4l2_info(sd, "\tOutput pin level inversion %s\n", | ||
1063 | cntrl & CNTRL_IVO ? "yes" : "no"); | ||
1064 | v4l2_info(sd, "\tCarrier polarity: %s\n", | ||
1065 | cntrl & CNTRL_CPL ? "space:burst mark:noburst" | ||
1066 | : "space:noburst mark:burst"); | ||
1067 | if (cntrl & CNTRL_MOD) { | ||
1068 | v4l2_info(sd, "\tCarrier (16 clocks): %u Hz\n", | ||
1069 | clock_divider_to_carrier_freq(txclk)); | ||
1070 | v4l2_info(sd, "\tCarrier duty cycle: %2u/16\n", | ||
1071 | cduty + 1); | ||
1072 | } | ||
1073 | v4l2_info(sd, "\tMax pulse width: %u us, %llu ns\n", | ||
1074 | pulse_width_count_to_us(FIFO_RXTX, txclk), | ||
1075 | pulse_width_count_to_ns(FIFO_RXTX, txclk)); | ||
1076 | v4l2_info(sd, "\tBusy: %s\n", | ||
1077 | stats & STATS_TBY ? "yes" : "no"); | ||
1078 | v4l2_info(sd, "\tFIFO service requested: %s\n", | ||
1079 | stats & STATS_TSR ? "yes" : "no"); | ||
1080 | v4l2_info(sd, "\tFIFO service request interrupt: %s\n", | ||
1081 | irqen & IRQEN_TSE ? "enabled" : "disabled"); | ||
1082 | |||
1083 | return 0; | ||
1084 | } | ||
1085 | |||
1086 | static inline int cx23888_ir_dbg_match(const struct v4l2_dbg_match *match) | ||
1087 | { | ||
1088 | return match->type == V4L2_CHIP_MATCH_HOST && match->addr == 2; | ||
1089 | } | ||
1090 | |||
1091 | static int cx23888_ir_g_chip_ident(struct v4l2_subdev *sd, | ||
1092 | struct v4l2_dbg_chip_ident *chip) | ||
1093 | { | ||
1094 | struct cx23888_ir_state *state = to_state(sd); | ||
1095 | |||
1096 | if (cx23888_ir_dbg_match(&chip->match)) { | ||
1097 | chip->ident = state->id; | ||
1098 | chip->revision = state->rev; | ||
1099 | } | ||
1100 | return 0; | ||
1101 | } | ||
1102 | |||
1103 | #ifdef CONFIG_VIDEO_ADV_DEBUG | ||
1104 | static int cx23888_ir_g_register(struct v4l2_subdev *sd, | ||
1105 | struct v4l2_dbg_register *reg) | ||
1106 | { | ||
1107 | struct cx23888_ir_state *state = to_state(sd); | ||
1108 | u32 addr = CX23888_IR_REG_BASE + (u32) reg->reg; | ||
1109 | |||
1110 | if (!cx23888_ir_dbg_match(®->match)) | ||
1111 | return -EINVAL; | ||
1112 | if ((addr & 0x3) != 0) | ||
1113 | return -EINVAL; | ||
1114 | if (addr < CX23888_IR_CNTRL_REG || addr > CX23888_IR_LEARN_REG) | ||
1115 | return -EINVAL; | ||
1116 | if (!capable(CAP_SYS_ADMIN)) | ||
1117 | return -EPERM; | ||
1118 | reg->size = 4; | ||
1119 | reg->val = cx23888_ir_read4(state->dev, addr); | ||
1120 | return 0; | ||
1121 | } | ||
1122 | |||
1123 | static int cx23888_ir_s_register(struct v4l2_subdev *sd, | ||
1124 | struct v4l2_dbg_register *reg) | ||
1125 | { | ||
1126 | struct cx23888_ir_state *state = to_state(sd); | ||
1127 | u32 addr = CX23888_IR_REG_BASE + (u32) reg->reg; | ||
1128 | |||
1129 | if (!cx23888_ir_dbg_match(®->match)) | ||
1130 | return -EINVAL; | ||
1131 | if ((addr & 0x3) != 0) | ||
1132 | return -EINVAL; | ||
1133 | if (addr < CX23888_IR_CNTRL_REG || addr > CX23888_IR_LEARN_REG) | ||
1134 | return -EINVAL; | ||
1135 | if (!capable(CAP_SYS_ADMIN)) | ||
1136 | return -EPERM; | ||
1137 | cx23888_ir_write4(state->dev, addr, reg->val); | ||
1138 | return 0; | ||
1139 | } | ||
1140 | #endif | ||
1141 | |||
1142 | static const struct v4l2_subdev_core_ops cx23888_ir_core_ops = { | ||
1143 | .g_chip_ident = cx23888_ir_g_chip_ident, | ||
1144 | .log_status = cx23888_ir_log_status, | ||
1145 | #ifdef CONFIG_VIDEO_ADV_DEBUG | ||
1146 | .g_register = cx23888_ir_g_register, | ||
1147 | .s_register = cx23888_ir_s_register, | ||
1148 | #endif | ||
1149 | .interrupt_service_routine = cx23888_ir_irq_handler, | ||
1150 | }; | ||
1151 | |||
1152 | static const struct v4l2_subdev_ir_ops cx23888_ir_ir_ops = { | ||
1153 | .rx_read = cx23888_ir_rx_read, | ||
1154 | .rx_g_parameters = cx23888_ir_rx_g_parameters, | ||
1155 | .rx_s_parameters = cx23888_ir_rx_s_parameters, | ||
1156 | |||
1157 | .tx_write = cx23888_ir_tx_write, | ||
1158 | .tx_g_parameters = cx23888_ir_tx_g_parameters, | ||
1159 | .tx_s_parameters = cx23888_ir_tx_s_parameters, | ||
1160 | }; | ||
1161 | |||
1162 | static const struct v4l2_subdev_ops cx23888_ir_controller_ops = { | ||
1163 | .core = &cx23888_ir_core_ops, | ||
1164 | .ir = &cx23888_ir_ir_ops, | ||
1165 | }; | ||
1166 | |||
1167 | static const struct v4l2_subdev_ir_parameters default_rx_params = { | ||
1168 | .bytes_per_data_element = sizeof(union cx23888_ir_fifo_rec), | ||
1169 | .mode = V4L2_SUBDEV_IR_MODE_PULSE_WIDTH, | ||
1170 | |||
1171 | .enable = false, | ||
1172 | .interrupt_enable = false, | ||
1173 | .shutdown = true, | ||
1174 | |||
1175 | .modulation = true, | ||
1176 | .carrier_freq = 36000, /* 36 kHz - RC-5, RC-6, and RC-6A carrier */ | ||
1177 | |||
1178 | /* RC-5: 666,667 ns = 1/36 kHz * 32 cycles * 1 mark * 0.75 */ | ||
1179 | /* RC-6A: 333,333 ns = 1/36 kHz * 16 cycles * 1 mark * 0.75 */ | ||
1180 | .noise_filter_min_width = 333333, /* ns */ | ||
1181 | .carrier_range_lower = 35000, | ||
1182 | .carrier_range_upper = 37000, | ||
1183 | .invert_level = false, | ||
1184 | }; | ||
1185 | |||
1186 | static const struct v4l2_subdev_ir_parameters default_tx_params = { | ||
1187 | .bytes_per_data_element = sizeof(union cx23888_ir_fifo_rec), | ||
1188 | .mode = V4L2_SUBDEV_IR_MODE_PULSE_WIDTH, | ||
1189 | |||
1190 | .enable = false, | ||
1191 | .interrupt_enable = false, | ||
1192 | .shutdown = true, | ||
1193 | |||
1194 | .modulation = true, | ||
1195 | .carrier_freq = 36000, /* 36 kHz - RC-5 carrier */ | ||
1196 | .duty_cycle = 25, /* 25 % - RC-5 carrier */ | ||
1197 | .invert_level = false, | ||
1198 | .invert_carrier_sense = false, | ||
1199 | }; | ||
1200 | |||
1201 | int cx23888_ir_probe(struct cx23885_dev *dev) | ||
1202 | { | ||
1203 | struct cx23888_ir_state *state; | ||
1204 | struct v4l2_subdev *sd; | ||
1205 | struct v4l2_subdev_ir_parameters default_params; | ||
1206 | int ret; | ||
1207 | |||
1208 | state = kzalloc(sizeof(struct cx23888_ir_state), GFP_KERNEL); | ||
1209 | if (state == NULL) | ||
1210 | return -ENOMEM; | ||
1211 | |||
1212 | spin_lock_init(&state->rx_kfifo_lock); | ||
1213 | if (kfifo_alloc(&state->rx_kfifo, CX23888_IR_RX_KFIFO_SIZE, GFP_KERNEL)) | ||
1214 | return -ENOMEM; | ||
1215 | |||
1216 | state->dev = dev; | ||
1217 | state->id = V4L2_IDENT_CX23888_IR; | ||
1218 | state->rev = 0; | ||
1219 | sd = &state->sd; | ||
1220 | |||
1221 | v4l2_subdev_init(sd, &cx23888_ir_controller_ops); | ||
1222 | v4l2_set_subdevdata(sd, state); | ||
1223 | /* FIXME - fix the formatting of dev->v4l2_dev.name and use it */ | ||
1224 | snprintf(sd->name, sizeof(sd->name), "%s/888-ir", dev->name); | ||
1225 | sd->grp_id = CX23885_HW_888_IR; | ||
1226 | |||
1227 | ret = v4l2_device_register_subdev(&dev->v4l2_dev, sd); | ||
1228 | if (ret == 0) { | ||
1229 | /* | ||
1230 | * Ensure no interrupts arrive from '888 specific conditions, | ||
1231 | * since we ignore them in this driver to have commonality with | ||
1232 | * similar IR controller cores. | ||
1233 | */ | ||
1234 | cx23888_ir_write4(dev, CX23888_IR_IRQEN_REG, 0); | ||
1235 | |||
1236 | mutex_init(&state->rx_params_lock); | ||
1237 | memcpy(&default_params, &default_rx_params, | ||
1238 | sizeof(struct v4l2_subdev_ir_parameters)); | ||
1239 | v4l2_subdev_call(sd, ir, rx_s_parameters, &default_params); | ||
1240 | |||
1241 | mutex_init(&state->tx_params_lock); | ||
1242 | memcpy(&default_params, &default_tx_params, | ||
1243 | sizeof(struct v4l2_subdev_ir_parameters)); | ||
1244 | v4l2_subdev_call(sd, ir, tx_s_parameters, &default_params); | ||
1245 | } else { | ||
1246 | kfifo_free(&state->rx_kfifo); | ||
1247 | } | ||
1248 | return ret; | ||
1249 | } | ||
1250 | |||
1251 | int cx23888_ir_remove(struct cx23885_dev *dev) | ||
1252 | { | ||
1253 | struct v4l2_subdev *sd; | ||
1254 | struct cx23888_ir_state *state; | ||
1255 | |||
1256 | sd = cx23885_find_hw(dev, CX23885_HW_888_IR); | ||
1257 | if (sd == NULL) | ||
1258 | return -ENODEV; | ||
1259 | |||
1260 | cx23888_ir_rx_shutdown(sd); | ||
1261 | cx23888_ir_tx_shutdown(sd); | ||
1262 | |||
1263 | state = to_state(sd); | ||
1264 | v4l2_device_unregister_subdev(sd); | ||
1265 | kfifo_free(&state->rx_kfifo); | ||
1266 | kfree(state); | ||
1267 | /* Nothing more to free() as state held the actual v4l2_subdev object */ | ||
1268 | return 0; | ||
1269 | } | ||
diff --git a/drivers/media/video/cx23885/cx23888-ir.h b/drivers/media/video/cx23885/cx23888-ir.h new file mode 100644 index 00000000000..d2de41caaf1 --- /dev/null +++ b/drivers/media/video/cx23885/cx23888-ir.h | |||
@@ -0,0 +1,28 @@ | |||
1 | /* | ||
2 | * Driver for the Conexant CX23885/7/8 PCIe bridge | ||
3 | * | ||
4 | * CX23888 Integrated Consumer Infrared Controller | ||
5 | * | ||
6 | * Copyright (C) 2009 Andy Walls <awalls@md.metrocast.net> | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or | ||
9 | * modify it under the terms of the GNU General Public License | ||
10 | * as published by the Free Software Foundation; either version 2 | ||
11 | * of the License, or (at your option) any later version. | ||
12 | * | ||
13 | * This program is distributed in the hope that it will be useful, | ||
14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
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., 51 Franklin Street, Fifth Floor, Boston, MA | ||
21 | * 02110-1301, USA. | ||
22 | */ | ||
23 | |||
24 | #ifndef _CX23888_IR_H_ | ||
25 | #define _CX23888_IR_H_ | ||
26 | int cx23888_ir_probe(struct cx23885_dev *dev); | ||
27 | int cx23888_ir_remove(struct cx23885_dev *dev); | ||
28 | #endif | ||
diff --git a/drivers/media/video/cx23885/netup-eeprom.c b/drivers/media/video/cx23885/netup-eeprom.c new file mode 100644 index 00000000000..98a48f50068 --- /dev/null +++ b/drivers/media/video/cx23885/netup-eeprom.c | |||
@@ -0,0 +1,107 @@ | |||
1 | |||
2 | /* | ||
3 | * netup-eeprom.c | ||
4 | * | ||
5 | * 24LC02 EEPROM driver in conjunction with NetUP Dual DVB-S2 CI card | ||
6 | * | ||
7 | * Copyright (C) 2009 NetUP Inc. | ||
8 | * Copyright (C) 2009 Abylay Ospan <aospan@netup.ru> | ||
9 | * | ||
10 | * This program is free software; you can redistribute it and/or modify | ||
11 | * it under the terms of the GNU General Public License as published by | ||
12 | * the Free Software Foundation; either version 2 of the License, or | ||
13 | * (at your option) any later version. | ||
14 | * | ||
15 | * This program is distributed in the hope that it will be useful, | ||
16 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
17 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
18 | * | ||
19 | * GNU General Public License for more details. | ||
20 | * | ||
21 | * You should have received a copy of the GNU General Public License | ||
22 | * along with this program; if not, write to the Free Software | ||
23 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
24 | */ | ||
25 | |||
26 | # | ||
27 | #include "cx23885.h" | ||
28 | #include "netup-eeprom.h" | ||
29 | |||
30 | #define EEPROM_I2C_ADDR 0x50 | ||
31 | |||
32 | int netup_eeprom_read(struct i2c_adapter *i2c_adap, u8 addr) | ||
33 | { | ||
34 | int ret; | ||
35 | unsigned char buf[2]; | ||
36 | |||
37 | /* Read from EEPROM */ | ||
38 | struct i2c_msg msg[] = { | ||
39 | { | ||
40 | .addr = EEPROM_I2C_ADDR, | ||
41 | .flags = 0, | ||
42 | .buf = &buf[0], | ||
43 | .len = 1 | ||
44 | }, { | ||
45 | .addr = EEPROM_I2C_ADDR, | ||
46 | .flags = I2C_M_RD, | ||
47 | .buf = &buf[1], | ||
48 | .len = 1 | ||
49 | } | ||
50 | |||
51 | }; | ||
52 | |||
53 | buf[0] = addr; | ||
54 | buf[1] = 0x0; | ||
55 | |||
56 | ret = i2c_transfer(i2c_adap, msg, 2); | ||
57 | |||
58 | if (ret != 2) { | ||
59 | printk(KERN_ERR "eeprom i2c read error, status=%d\n", ret); | ||
60 | return -1; | ||
61 | } | ||
62 | |||
63 | return buf[1]; | ||
64 | }; | ||
65 | |||
66 | int netup_eeprom_write(struct i2c_adapter *i2c_adap, u8 addr, u8 data) | ||
67 | { | ||
68 | int ret; | ||
69 | unsigned char bufw[2]; | ||
70 | |||
71 | /* Write into EEPROM */ | ||
72 | struct i2c_msg msg[] = { | ||
73 | { | ||
74 | .addr = EEPROM_I2C_ADDR, | ||
75 | .flags = 0, | ||
76 | .buf = &bufw[0], | ||
77 | .len = 2 | ||
78 | } | ||
79 | }; | ||
80 | |||
81 | bufw[0] = addr; | ||
82 | bufw[1] = data; | ||
83 | |||
84 | ret = i2c_transfer(i2c_adap, msg, 1); | ||
85 | |||
86 | if (ret != 1) { | ||
87 | printk(KERN_ERR "eeprom i2c write error, status=%d\n", ret); | ||
88 | return -1; | ||
89 | } | ||
90 | |||
91 | mdelay(10); /* prophylactic delay, datasheet write cycle time = 5 ms */ | ||
92 | return 0; | ||
93 | }; | ||
94 | |||
95 | void netup_get_card_info(struct i2c_adapter *i2c_adap, | ||
96 | struct netup_card_info *cinfo) | ||
97 | { | ||
98 | int i, j; | ||
99 | |||
100 | cinfo->rev = netup_eeprom_read(i2c_adap, 63); | ||
101 | |||
102 | for (i = 64, j = 0; i < 70; i++, j++) | ||
103 | cinfo->port[0].mac[j] = netup_eeprom_read(i2c_adap, i); | ||
104 | |||
105 | for (i = 70, j = 0; i < 76; i++, j++) | ||
106 | cinfo->port[1].mac[j] = netup_eeprom_read(i2c_adap, i); | ||
107 | }; | ||
diff --git a/drivers/media/video/cx23885/netup-eeprom.h b/drivers/media/video/cx23885/netup-eeprom.h new file mode 100644 index 00000000000..13926e18feb --- /dev/null +++ b/drivers/media/video/cx23885/netup-eeprom.h | |||
@@ -0,0 +1,42 @@ | |||
1 | /* | ||
2 | * netup-eeprom.h | ||
3 | * | ||
4 | * 24LC02 EEPROM driver in conjunction with NetUP Dual DVB-S2 CI card | ||
5 | * | ||
6 | * Copyright (C) 2009 NetUP Inc. | ||
7 | * Copyright (C) 2009 Abylay Ospan <aospan@netup.ru> | ||
8 | * | ||
9 | * This program is free software; you can redistribute it and/or modify | ||
10 | * it under the terms of the GNU General Public License as published by | ||
11 | * the Free Software Foundation; either version 2 of the License, or | ||
12 | * (at your option) any later version. | ||
13 | * | ||
14 | * This program is distributed in the hope that it will be useful, | ||
15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
17 | * | ||
18 | * GNU General Public License for more details. | ||
19 | * | ||
20 | * You should have received a copy of the GNU General Public License | ||
21 | * along with this program; if not, write to the Free Software | ||
22 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
23 | */ | ||
24 | |||
25 | #ifndef NETUP_EEPROM_H | ||
26 | #define NETUP_EEPROM_H | ||
27 | |||
28 | struct netup_port_info { | ||
29 | u8 mac[6];/* card MAC address */ | ||
30 | }; | ||
31 | |||
32 | struct netup_card_info { | ||
33 | struct netup_port_info port[2];/* ports - 1,2 */ | ||
34 | u8 rev;/* card revision */ | ||
35 | }; | ||
36 | |||
37 | extern int netup_eeprom_read(struct i2c_adapter *i2c_adap, u8 addr); | ||
38 | extern int netup_eeprom_write(struct i2c_adapter *i2c_adap, u8 addr, u8 data); | ||
39 | extern void netup_get_card_info(struct i2c_adapter *i2c_adap, | ||
40 | struct netup_card_info *cinfo); | ||
41 | |||
42 | #endif | ||
diff --git a/drivers/media/video/cx23885/netup-init.c b/drivers/media/video/cx23885/netup-init.c new file mode 100644 index 00000000000..f4893e69cd8 --- /dev/null +++ b/drivers/media/video/cx23885/netup-init.c | |||
@@ -0,0 +1,125 @@ | |||
1 | /* | ||
2 | * netup-init.c | ||
3 | * | ||
4 | * NetUP Dual DVB-S2 CI driver | ||
5 | * | ||
6 | * Copyright (C) 2009 NetUP Inc. | ||
7 | * Copyright (C) 2009 Igor M. Liplianin <liplianin@netup.ru> | ||
8 | * Copyright (C) 2009 Abylay Ospan <aospan@netup.ru> | ||
9 | * | ||
10 | * This program is free software; you can redistribute it and/or modify | ||
11 | * it under the terms of the GNU General Public License as published by | ||
12 | * the Free Software Foundation; either version 2 of the License, or | ||
13 | * (at your option) any later version. | ||
14 | * | ||
15 | * This program is distributed in the hope that it will be useful, | ||
16 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
17 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
18 | * | ||
19 | * GNU General Public License for more details. | ||
20 | * | ||
21 | * You should have received a copy of the GNU General Public License | ||
22 | * along with this program; if not, write to the Free Software | ||
23 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
24 | */ | ||
25 | |||
26 | #include "cx23885.h" | ||
27 | |||
28 | static void i2c_av_write(struct i2c_adapter *i2c, u16 reg, u8 val) | ||
29 | { | ||
30 | int ret; | ||
31 | u8 buf[3]; | ||
32 | struct i2c_msg msg = { | ||
33 | .addr = 0x88 >> 1, | ||
34 | .flags = 0, | ||
35 | .buf = buf, | ||
36 | .len = 3 | ||
37 | }; | ||
38 | |||
39 | buf[0] = reg >> 8; | ||
40 | buf[1] = reg & 0xff; | ||
41 | buf[2] = val; | ||
42 | |||
43 | ret = i2c_transfer(i2c, &msg, 1); | ||
44 | |||
45 | if (ret != 1) | ||
46 | printk(KERN_ERR "%s: i2c write error!\n", __func__); | ||
47 | } | ||
48 | |||
49 | static void i2c_av_write4(struct i2c_adapter *i2c, u16 reg, u32 val) | ||
50 | { | ||
51 | int ret; | ||
52 | u8 buf[6]; | ||
53 | struct i2c_msg msg = { | ||
54 | .addr = 0x88 >> 1, | ||
55 | .flags = 0, | ||
56 | .buf = buf, | ||
57 | .len = 6 | ||
58 | }; | ||
59 | |||
60 | buf[0] = reg >> 8; | ||
61 | buf[1] = reg & 0xff; | ||
62 | buf[2] = val & 0xff; | ||
63 | buf[3] = (val >> 8) & 0xff; | ||
64 | buf[4] = (val >> 16) & 0xff; | ||
65 | buf[5] = val >> 24; | ||
66 | |||
67 | ret = i2c_transfer(i2c, &msg, 1); | ||
68 | |||
69 | if (ret != 1) | ||
70 | printk(KERN_ERR "%s: i2c write error!\n", __func__); | ||
71 | } | ||
72 | |||
73 | static u8 i2c_av_read(struct i2c_adapter *i2c, u16 reg) | ||
74 | { | ||
75 | int ret; | ||
76 | u8 buf[2]; | ||
77 | struct i2c_msg msg = { | ||
78 | .addr = 0x88 >> 1, | ||
79 | .flags = 0, | ||
80 | .buf = buf, | ||
81 | .len = 2 | ||
82 | }; | ||
83 | |||
84 | buf[0] = reg >> 8; | ||
85 | buf[1] = reg & 0xff; | ||
86 | |||
87 | ret = i2c_transfer(i2c, &msg, 1); | ||
88 | |||
89 | if (ret != 1) | ||
90 | printk(KERN_ERR "%s: i2c write error!\n", __func__); | ||
91 | |||
92 | msg.flags = I2C_M_RD; | ||
93 | msg.len = 1; | ||
94 | |||
95 | ret = i2c_transfer(i2c, &msg, 1); | ||
96 | |||
97 | if (ret != 1) | ||
98 | printk(KERN_ERR "%s: i2c read error!\n", __func__); | ||
99 | |||
100 | return buf[0]; | ||
101 | } | ||
102 | |||
103 | static void i2c_av_and_or(struct i2c_adapter *i2c, u16 reg, unsigned and_mask, | ||
104 | u8 or_value) | ||
105 | { | ||
106 | i2c_av_write(i2c, reg, (i2c_av_read(i2c, reg) & and_mask) | or_value); | ||
107 | } | ||
108 | /* set 27MHz on AUX_CLK */ | ||
109 | void netup_initialize(struct cx23885_dev *dev) | ||
110 | { | ||
111 | struct cx23885_i2c *i2c_bus = &dev->i2c_bus[2]; | ||
112 | struct i2c_adapter *i2c = &i2c_bus->i2c_adap; | ||
113 | |||
114 | /* Stop microcontroller */ | ||
115 | i2c_av_and_or(i2c, 0x803, ~0x10, 0x00); | ||
116 | |||
117 | /* Aux PLL frac for 27 MHz */ | ||
118 | i2c_av_write4(i2c, 0x114, 0xea0eb3); | ||
119 | |||
120 | /* Aux PLL int for 27 MHz */ | ||
121 | i2c_av_write4(i2c, 0x110, 0x090319); | ||
122 | |||
123 | /* start microcontroller */ | ||
124 | i2c_av_and_or(i2c, 0x803, ~0x10, 0x10); | ||
125 | } | ||
diff --git a/drivers/media/video/cx23885/netup-init.h b/drivers/media/video/cx23885/netup-init.h new file mode 100644 index 00000000000..d26ae4b1590 --- /dev/null +++ b/drivers/media/video/cx23885/netup-init.h | |||
@@ -0,0 +1,25 @@ | |||
1 | /* | ||
2 | * netup-init.h | ||
3 | * | ||
4 | * NetUP Dual DVB-S2 CI driver | ||
5 | * | ||
6 | * Copyright (C) 2009 NetUP Inc. | ||
7 | * Copyright (C) 2009 Igor M. Liplianin <liplianin@netup.ru> | ||
8 | * Copyright (C) 2009 Abylay Ospan <aospan@netup.ru> | ||
9 | * | ||
10 | * This program is free software; you can redistribute it and/or modify | ||
11 | * it under the terms of the GNU General Public License as published by | ||
12 | * the Free Software Foundation; either version 2 of the License, or | ||
13 | * (at your option) any later version. | ||
14 | * | ||
15 | * This program is distributed in the hope that it will be useful, | ||
16 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
17 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
18 | * | ||
19 | * GNU General Public License for more details. | ||
20 | * | ||
21 | * You should have received a copy of the GNU General Public License | ||
22 | * along with this program; if not, write to the Free Software | ||
23 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
24 | */ | ||
25 | extern void netup_initialize(struct cx23885_dev *dev); | ||