diff options
author | Mauro Carvalho Chehab <mchehab@redhat.com> | 2012-08-14 11:13:30 -0400 |
---|---|---|
committer | Mauro Carvalho Chehab <mchehab@redhat.com> | 2012-08-15 15:36:22 -0400 |
commit | b285192a43f0432d82c2c10974204e78af0da596 (patch) | |
tree | 618aa87e760c9c949eca9e4df6ae0eeffa11dcfc /drivers/media/pci/cx23885 | |
parent | 68de959f773a1d49096835c411390bceff5d1549 (diff) |
[media] rename most media/video pci drivers to media/pci
Rename all PCI drivers with their own directory under
drivers/media/video into drivers/media/pci and update the
building system.
Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
Diffstat (limited to 'drivers/media/pci/cx23885')
32 files changed, 15531 insertions, 0 deletions
diff --git a/drivers/media/pci/cx23885/Kconfig b/drivers/media/pci/cx23885/Kconfig new file mode 100644 index 000000000000..b391e9bda877 --- /dev/null +++ b/drivers/media/pci/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 ALTERA_STAPL | ||
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/pci/cx23885/Makefile b/drivers/media/pci/cx23885/Makefile new file mode 100644 index 000000000000..f92cc4c14f0c --- /dev/null +++ b/drivers/media/pci/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 cx23885-alsa.o | ||
6 | |||
7 | obj-$(CONFIG_VIDEO_CX23885) += cx23885.o | ||
8 | obj-$(CONFIG_MEDIA_ALTERA_CI) += altera-ci.o | ||
9 | |||
10 | ccflags-y += -Idrivers/media/video | ||
11 | ccflags-y += -Idrivers/media/tuners | ||
12 | ccflags-y += -Idrivers/media/dvb-core | ||
13 | ccflags-y += -Idrivers/media/dvb-frontends | ||
14 | |||
15 | ccflags-y += $(extra-cflags-y) $(extra-cflags-m) | ||
diff --git a/drivers/media/pci/cx23885/altera-ci.c b/drivers/media/pci/cx23885/altera-ci.c new file mode 100644 index 000000000000..1fa8927f0d36 --- /dev/null +++ b/drivers/media/pci/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/pci/cx23885/altera-ci.h b/drivers/media/pci/cx23885/altera-ci.h new file mode 100644 index 000000000000..70e4fd69ad9e --- /dev/null +++ b/drivers/media/pci/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/pci/cx23885/cimax2.c b/drivers/media/pci/cx23885/cimax2.c new file mode 100644 index 000000000000..c9f15d6dec40 --- /dev/null +++ b/drivers/media/pci/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/pci/cx23885/cimax2.h b/drivers/media/pci/cx23885/cimax2.h new file mode 100644 index 000000000000..518744a4c8a5 --- /dev/null +++ b/drivers/media/pci/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/pci/cx23885/cx23885-417.c b/drivers/media/pci/cx23885/cx23885-417.c new file mode 100644 index 000000000000..5d5052d0253f --- /dev/null +++ b/drivers/media/pci/cx23885/cx23885-417.c | |||
@@ -0,0 +1,1790 @@ | |||
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 gpio_value; | ||
904 | u32 checksum = 0; | ||
905 | u32 *dataptr; | ||
906 | |||
907 | dprintk(2, "%s()\n", __func__); | ||
908 | |||
909 | /* Save GPIO settings before reset of APU */ | ||
910 | retval |= mc417_memory_read(dev, 0x9020, &gpio_output); | ||
911 | retval |= mc417_memory_read(dev, 0x900C, &gpio_value); | ||
912 | |||
913 | retval = mc417_register_write(dev, | ||
914 | IVTV_REG_VPU, 0xFFFFFFED); | ||
915 | retval |= mc417_register_write(dev, | ||
916 | IVTV_REG_HW_BLOCKS, IVTV_CMD_HW_BLOCKS_RST); | ||
917 | retval |= mc417_register_write(dev, | ||
918 | IVTV_REG_ENC_SDRAM_REFRESH, 0x80000800); | ||
919 | retval |= mc417_register_write(dev, | ||
920 | IVTV_REG_ENC_SDRAM_PRECHARGE, 0x1A); | ||
921 | retval |= mc417_register_write(dev, | ||
922 | IVTV_REG_APU, 0); | ||
923 | |||
924 | if (retval != 0) { | ||
925 | printk(KERN_ERR "%s: Error with mc417_register_write\n", | ||
926 | __func__); | ||
927 | return -1; | ||
928 | } | ||
929 | |||
930 | retval = request_firmware(&firmware, CX23885_FIRM_IMAGE_NAME, | ||
931 | &dev->pci->dev); | ||
932 | |||
933 | if (retval != 0) { | ||
934 | printk(KERN_ERR | ||
935 | "ERROR: Hotplug firmware request failed (%s).\n", | ||
936 | CX23885_FIRM_IMAGE_NAME); | ||
937 | printk(KERN_ERR "Please fix your hotplug setup, the board will " | ||
938 | "not work without firmware loaded!\n"); | ||
939 | return -1; | ||
940 | } | ||
941 | |||
942 | if (firmware->size != CX23885_FIRM_IMAGE_SIZE) { | ||
943 | printk(KERN_ERR "ERROR: Firmware size mismatch " | ||
944 | "(have %zd, expected %d)\n", | ||
945 | firmware->size, CX23885_FIRM_IMAGE_SIZE); | ||
946 | release_firmware(firmware); | ||
947 | return -1; | ||
948 | } | ||
949 | |||
950 | if (0 != memcmp(firmware->data, magic, 8)) { | ||
951 | printk(KERN_ERR | ||
952 | "ERROR: Firmware magic mismatch, wrong file?\n"); | ||
953 | release_firmware(firmware); | ||
954 | return -1; | ||
955 | } | ||
956 | |||
957 | /* transfer to the chip */ | ||
958 | dprintk(2, "Loading firmware ...\n"); | ||
959 | dataptr = (u32 *)firmware->data; | ||
960 | for (i = 0; i < (firmware->size >> 2); i++) { | ||
961 | value = *dataptr; | ||
962 | checksum += ~value; | ||
963 | if (mc417_memory_write(dev, i, value) != 0) { | ||
964 | printk(KERN_ERR "ERROR: Loading firmware failed!\n"); | ||
965 | release_firmware(firmware); | ||
966 | return -1; | ||
967 | } | ||
968 | dataptr++; | ||
969 | } | ||
970 | |||
971 | /* read back to verify with the checksum */ | ||
972 | dprintk(1, "Verifying firmware ...\n"); | ||
973 | for (i--; i >= 0; i--) { | ||
974 | if (mc417_memory_read(dev, i, &value) != 0) { | ||
975 | printk(KERN_ERR "ERROR: Reading firmware failed!\n"); | ||
976 | release_firmware(firmware); | ||
977 | return -1; | ||
978 | } | ||
979 | checksum -= ~value; | ||
980 | } | ||
981 | if (checksum) { | ||
982 | printk(KERN_ERR | ||
983 | "ERROR: Firmware load failed (checksum mismatch).\n"); | ||
984 | release_firmware(firmware); | ||
985 | return -1; | ||
986 | } | ||
987 | release_firmware(firmware); | ||
988 | dprintk(1, "Firmware upload successful.\n"); | ||
989 | |||
990 | retval |= mc417_register_write(dev, IVTV_REG_HW_BLOCKS, | ||
991 | IVTV_CMD_HW_BLOCKS_RST); | ||
992 | |||
993 | /* F/W power up disturbs the GPIOs, restore state */ | ||
994 | retval |= mc417_register_write(dev, 0x9020, gpio_output); | ||
995 | retval |= mc417_register_write(dev, 0x900C, gpio_value); | ||
996 | |||
997 | retval |= mc417_register_read(dev, IVTV_REG_VPU, &value); | ||
998 | retval |= mc417_register_write(dev, IVTV_REG_VPU, value & 0xFFFFFFE8); | ||
999 | |||
1000 | /* Hardcoded GPIO's here */ | ||
1001 | retval |= mc417_register_write(dev, 0x9020, 0x4000); | ||
1002 | retval |= mc417_register_write(dev, 0x900C, 0x4000); | ||
1003 | |||
1004 | mc417_register_read(dev, 0x9020, &gpio_output); | ||
1005 | mc417_register_read(dev, 0x900C, &gpio_value); | ||
1006 | |||
1007 | if (retval < 0) | ||
1008 | printk(KERN_ERR "%s: Error with mc417_register_write\n", | ||
1009 | __func__); | ||
1010 | return 0; | ||
1011 | } | ||
1012 | |||
1013 | void cx23885_417_check_encoder(struct cx23885_dev *dev) | ||
1014 | { | ||
1015 | u32 status, seq; | ||
1016 | |||
1017 | status = seq = 0; | ||
1018 | cx23885_api_cmd(dev, CX2341X_ENC_GET_SEQ_END, 0, 2, &status, &seq); | ||
1019 | dprintk(1, "%s() status = %d, seq = %d\n", __func__, status, seq); | ||
1020 | } | ||
1021 | |||
1022 | static void cx23885_codec_settings(struct cx23885_dev *dev) | ||
1023 | { | ||
1024 | dprintk(1, "%s()\n", __func__); | ||
1025 | |||
1026 | /* Dynamically change the height based on video standard */ | ||
1027 | if (dev->encodernorm.id & V4L2_STD_525_60) | ||
1028 | dev->ts1.height = 480; | ||
1029 | else | ||
1030 | dev->ts1.height = 576; | ||
1031 | |||
1032 | /* assign frame size */ | ||
1033 | cx23885_api_cmd(dev, CX2341X_ENC_SET_FRAME_SIZE, 2, 0, | ||
1034 | dev->ts1.height, dev->ts1.width); | ||
1035 | |||
1036 | dev->mpeg_params.width = dev->ts1.width; | ||
1037 | dev->mpeg_params.height = dev->ts1.height; | ||
1038 | dev->mpeg_params.is_50hz = | ||
1039 | (dev->encodernorm.id & V4L2_STD_625_50) != 0; | ||
1040 | |||
1041 | cx2341x_update(dev, cx23885_mbox_func, NULL, &dev->mpeg_params); | ||
1042 | |||
1043 | cx23885_api_cmd(dev, CX2341X_ENC_MISC, 2, 0, 3, 1); | ||
1044 | cx23885_api_cmd(dev, CX2341X_ENC_MISC, 2, 0, 4, 1); | ||
1045 | } | ||
1046 | |||
1047 | static int cx23885_initialize_codec(struct cx23885_dev *dev, int startencoder) | ||
1048 | { | ||
1049 | int version; | ||
1050 | int retval; | ||
1051 | u32 i, data[7]; | ||
1052 | |||
1053 | dprintk(1, "%s()\n", __func__); | ||
1054 | |||
1055 | retval = cx23885_api_cmd(dev, CX2341X_ENC_PING_FW, 0, 0); /* ping */ | ||
1056 | if (retval < 0) { | ||
1057 | dprintk(2, "%s() PING OK\n", __func__); | ||
1058 | retval = cx23885_load_firmware(dev); | ||
1059 | if (retval < 0) { | ||
1060 | printk(KERN_ERR "%s() f/w load failed\n", __func__); | ||
1061 | return retval; | ||
1062 | } | ||
1063 | retval = cx23885_find_mailbox(dev); | ||
1064 | if (retval < 0) { | ||
1065 | printk(KERN_ERR "%s() mailbox < 0, error\n", | ||
1066 | __func__); | ||
1067 | return -1; | ||
1068 | } | ||
1069 | dev->cx23417_mailbox = retval; | ||
1070 | retval = cx23885_api_cmd(dev, CX2341X_ENC_PING_FW, 0, 0); | ||
1071 | if (retval < 0) { | ||
1072 | printk(KERN_ERR | ||
1073 | "ERROR: cx23417 firmware ping failed!\n"); | ||
1074 | return -1; | ||
1075 | } | ||
1076 | retval = cx23885_api_cmd(dev, CX2341X_ENC_GET_VERSION, 0, 1, | ||
1077 | &version); | ||
1078 | if (retval < 0) { | ||
1079 | printk(KERN_ERR "ERROR: cx23417 firmware get encoder :" | ||
1080 | "version failed!\n"); | ||
1081 | return -1; | ||
1082 | } | ||
1083 | dprintk(1, "cx23417 firmware version is 0x%08x\n", version); | ||
1084 | msleep(200); | ||
1085 | } | ||
1086 | |||
1087 | cx23885_codec_settings(dev); | ||
1088 | msleep(60); | ||
1089 | |||
1090 | cx23885_api_cmd(dev, CX2341X_ENC_SET_NUM_VSYNC_LINES, 2, 0, | ||
1091 | CX23885_FIELD1_SAA7115, CX23885_FIELD2_SAA7115); | ||
1092 | cx23885_api_cmd(dev, CX2341X_ENC_SET_PLACEHOLDER, 12, 0, | ||
1093 | CX23885_CUSTOM_EXTENSION_USR_DATA, 0, 0, 0, 0, 0, 0, 0, 0, 0, | ||
1094 | 0, 0); | ||
1095 | |||
1096 | /* Setup to capture VBI */ | ||
1097 | data[0] = 0x0001BD00; | ||
1098 | data[1] = 1; /* frames per interrupt */ | ||
1099 | data[2] = 4; /* total bufs */ | ||
1100 | data[3] = 0x91559155; /* start codes */ | ||
1101 | data[4] = 0x206080C0; /* stop codes */ | ||
1102 | data[5] = 6; /* lines */ | ||
1103 | data[6] = 64; /* BPL */ | ||
1104 | |||
1105 | cx23885_api_cmd(dev, CX2341X_ENC_SET_VBI_CONFIG, 7, 0, data[0], data[1], | ||
1106 | data[2], data[3], data[4], data[5], data[6]); | ||
1107 | |||
1108 | for (i = 2; i <= 24; i++) { | ||
1109 | int valid; | ||
1110 | |||
1111 | valid = ((i >= 19) && (i <= 21)); | ||
1112 | cx23885_api_cmd(dev, CX2341X_ENC_SET_VBI_LINE, 5, 0, i, | ||
1113 | valid, 0 , 0, 0); | ||
1114 | cx23885_api_cmd(dev, CX2341X_ENC_SET_VBI_LINE, 5, 0, | ||
1115 | i | 0x80000000, valid, 0, 0, 0); | ||
1116 | } | ||
1117 | |||
1118 | cx23885_api_cmd(dev, CX2341X_ENC_MUTE_AUDIO, 1, 0, CX23885_UNMUTE); | ||
1119 | msleep(60); | ||
1120 | |||
1121 | /* initialize the video input */ | ||
1122 | cx23885_api_cmd(dev, CX2341X_ENC_INITIALIZE_INPUT, 0, 0); | ||
1123 | msleep(60); | ||
1124 | |||
1125 | /* Enable VIP style pixel invalidation so we work with scaled mode */ | ||
1126 | mc417_memory_write(dev, 2120, 0x00000080); | ||
1127 | |||
1128 | /* start capturing to the host interface */ | ||
1129 | if (startencoder) { | ||
1130 | cx23885_api_cmd(dev, CX2341X_ENC_START_CAPTURE, 2, 0, | ||
1131 | CX23885_MPEG_CAPTURE, CX23885_RAW_BITS_NONE); | ||
1132 | msleep(10); | ||
1133 | } | ||
1134 | |||
1135 | return 0; | ||
1136 | } | ||
1137 | |||
1138 | /* ------------------------------------------------------------------ */ | ||
1139 | |||
1140 | static int bb_buf_setup(struct videobuf_queue *q, | ||
1141 | unsigned int *count, unsigned int *size) | ||
1142 | { | ||
1143 | struct cx23885_fh *fh = q->priv_data; | ||
1144 | |||
1145 | fh->dev->ts1.ts_packet_size = mpeglinesize; | ||
1146 | fh->dev->ts1.ts_packet_count = mpeglines; | ||
1147 | |||
1148 | *size = fh->dev->ts1.ts_packet_size * fh->dev->ts1.ts_packet_count; | ||
1149 | *count = mpegbufs; | ||
1150 | |||
1151 | return 0; | ||
1152 | } | ||
1153 | |||
1154 | static int bb_buf_prepare(struct videobuf_queue *q, | ||
1155 | struct videobuf_buffer *vb, enum v4l2_field field) | ||
1156 | { | ||
1157 | struct cx23885_fh *fh = q->priv_data; | ||
1158 | return cx23885_buf_prepare(q, &fh->dev->ts1, | ||
1159 | (struct cx23885_buffer *)vb, | ||
1160 | field); | ||
1161 | } | ||
1162 | |||
1163 | static void bb_buf_queue(struct videobuf_queue *q, | ||
1164 | struct videobuf_buffer *vb) | ||
1165 | { | ||
1166 | struct cx23885_fh *fh = q->priv_data; | ||
1167 | cx23885_buf_queue(&fh->dev->ts1, (struct cx23885_buffer *)vb); | ||
1168 | } | ||
1169 | |||
1170 | static void bb_buf_release(struct videobuf_queue *q, | ||
1171 | struct videobuf_buffer *vb) | ||
1172 | { | ||
1173 | cx23885_free_buffer(q, (struct cx23885_buffer *)vb); | ||
1174 | } | ||
1175 | |||
1176 | static struct videobuf_queue_ops cx23885_qops = { | ||
1177 | .buf_setup = bb_buf_setup, | ||
1178 | .buf_prepare = bb_buf_prepare, | ||
1179 | .buf_queue = bb_buf_queue, | ||
1180 | .buf_release = bb_buf_release, | ||
1181 | }; | ||
1182 | |||
1183 | /* ------------------------------------------------------------------ */ | ||
1184 | |||
1185 | static const u32 *ctrl_classes[] = { | ||
1186 | cx2341x_mpeg_ctrls, | ||
1187 | NULL | ||
1188 | }; | ||
1189 | |||
1190 | static int cx23885_queryctrl(struct cx23885_dev *dev, | ||
1191 | struct v4l2_queryctrl *qctrl) | ||
1192 | { | ||
1193 | qctrl->id = v4l2_ctrl_next(ctrl_classes, qctrl->id); | ||
1194 | if (qctrl->id == 0) | ||
1195 | return -EINVAL; | ||
1196 | |||
1197 | /* MPEG V4L2 controls */ | ||
1198 | if (cx2341x_ctrl_query(&dev->mpeg_params, qctrl)) | ||
1199 | qctrl->flags |= V4L2_CTRL_FLAG_DISABLED; | ||
1200 | |||
1201 | return 0; | ||
1202 | } | ||
1203 | |||
1204 | static int cx23885_querymenu(struct cx23885_dev *dev, | ||
1205 | struct v4l2_querymenu *qmenu) | ||
1206 | { | ||
1207 | struct v4l2_queryctrl qctrl; | ||
1208 | |||
1209 | qctrl.id = qmenu->id; | ||
1210 | cx23885_queryctrl(dev, &qctrl); | ||
1211 | return v4l2_ctrl_query_menu(qmenu, &qctrl, | ||
1212 | cx2341x_ctrl_get_menu(&dev->mpeg_params, qmenu->id)); | ||
1213 | } | ||
1214 | |||
1215 | static int vidioc_g_std(struct file *file, void *priv, v4l2_std_id *id) | ||
1216 | { | ||
1217 | struct cx23885_fh *fh = file->private_data; | ||
1218 | struct cx23885_dev *dev = fh->dev; | ||
1219 | |||
1220 | call_all(dev, core, g_std, id); | ||
1221 | |||
1222 | return 0; | ||
1223 | } | ||
1224 | |||
1225 | static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id *id) | ||
1226 | { | ||
1227 | struct cx23885_fh *fh = file->private_data; | ||
1228 | struct cx23885_dev *dev = fh->dev; | ||
1229 | unsigned int i; | ||
1230 | |||
1231 | for (i = 0; i < ARRAY_SIZE(cx23885_tvnorms); i++) | ||
1232 | if (*id & cx23885_tvnorms[i].id) | ||
1233 | break; | ||
1234 | if (i == ARRAY_SIZE(cx23885_tvnorms)) | ||
1235 | return -EINVAL; | ||
1236 | dev->encodernorm = cx23885_tvnorms[i]; | ||
1237 | |||
1238 | /* Have the drier core notify the subdevices */ | ||
1239 | mutex_lock(&dev->lock); | ||
1240 | cx23885_set_tvnorm(dev, *id); | ||
1241 | mutex_unlock(&dev->lock); | ||
1242 | |||
1243 | return 0; | ||
1244 | } | ||
1245 | |||
1246 | static int vidioc_enum_input(struct file *file, void *priv, | ||
1247 | struct v4l2_input *i) | ||
1248 | { | ||
1249 | struct cx23885_dev *dev = ((struct cx23885_fh *)priv)->dev; | ||
1250 | dprintk(1, "%s()\n", __func__); | ||
1251 | return cx23885_enum_input(dev, i); | ||
1252 | } | ||
1253 | |||
1254 | static int vidioc_g_input(struct file *file, void *priv, unsigned int *i) | ||
1255 | { | ||
1256 | return cx23885_get_input(file, priv, i); | ||
1257 | } | ||
1258 | |||
1259 | static int vidioc_s_input(struct file *file, void *priv, unsigned int i) | ||
1260 | { | ||
1261 | return cx23885_set_input(file, priv, i); | ||
1262 | } | ||
1263 | |||
1264 | static int vidioc_g_tuner(struct file *file, void *priv, | ||
1265 | struct v4l2_tuner *t) | ||
1266 | { | ||
1267 | struct cx23885_fh *fh = file->private_data; | ||
1268 | struct cx23885_dev *dev = fh->dev; | ||
1269 | |||
1270 | if (UNSET == dev->tuner_type) | ||
1271 | return -EINVAL; | ||
1272 | if (0 != t->index) | ||
1273 | return -EINVAL; | ||
1274 | strcpy(t->name, "Television"); | ||
1275 | call_all(dev, tuner, g_tuner, t); | ||
1276 | |||
1277 | dprintk(1, "VIDIOC_G_TUNER: tuner type %d\n", t->type); | ||
1278 | |||
1279 | return 0; | ||
1280 | } | ||
1281 | |||
1282 | static int vidioc_s_tuner(struct file *file, void *priv, | ||
1283 | struct v4l2_tuner *t) | ||
1284 | { | ||
1285 | struct cx23885_fh *fh = file->private_data; | ||
1286 | struct cx23885_dev *dev = fh->dev; | ||
1287 | |||
1288 | if (UNSET == dev->tuner_type) | ||
1289 | return -EINVAL; | ||
1290 | |||
1291 | /* Update the A/V core */ | ||
1292 | call_all(dev, tuner, s_tuner, t); | ||
1293 | |||
1294 | return 0; | ||
1295 | } | ||
1296 | |||
1297 | static int vidioc_g_frequency(struct file *file, void *priv, | ||
1298 | struct v4l2_frequency *f) | ||
1299 | { | ||
1300 | struct cx23885_fh *fh = file->private_data; | ||
1301 | struct cx23885_dev *dev = fh->dev; | ||
1302 | |||
1303 | if (UNSET == dev->tuner_type) | ||
1304 | return -EINVAL; | ||
1305 | f->type = V4L2_TUNER_ANALOG_TV; | ||
1306 | f->frequency = dev->freq; | ||
1307 | |||
1308 | call_all(dev, tuner, g_frequency, f); | ||
1309 | |||
1310 | return 0; | ||
1311 | } | ||
1312 | |||
1313 | static int vidioc_s_frequency(struct file *file, void *priv, | ||
1314 | struct v4l2_frequency *f) | ||
1315 | { | ||
1316 | return cx23885_set_frequency(file, priv, f); | ||
1317 | } | ||
1318 | |||
1319 | static int vidioc_g_ctrl(struct file *file, void *priv, | ||
1320 | struct v4l2_control *ctl) | ||
1321 | { | ||
1322 | struct cx23885_dev *dev = ((struct cx23885_fh *)priv)->dev; | ||
1323 | |||
1324 | return cx23885_get_control(dev, ctl); | ||
1325 | } | ||
1326 | |||
1327 | static int vidioc_s_ctrl(struct file *file, void *priv, | ||
1328 | struct v4l2_control *ctl) | ||
1329 | { | ||
1330 | struct cx23885_dev *dev = ((struct cx23885_fh *)priv)->dev; | ||
1331 | |||
1332 | return cx23885_set_control(dev, ctl); | ||
1333 | } | ||
1334 | |||
1335 | static int vidioc_querycap(struct file *file, void *priv, | ||
1336 | struct v4l2_capability *cap) | ||
1337 | { | ||
1338 | struct cx23885_fh *fh = file->private_data; | ||
1339 | struct cx23885_dev *dev = fh->dev; | ||
1340 | struct cx23885_tsport *tsport = &dev->ts1; | ||
1341 | |||
1342 | strlcpy(cap->driver, dev->name, sizeof(cap->driver)); | ||
1343 | strlcpy(cap->card, cx23885_boards[tsport->dev->board].name, | ||
1344 | sizeof(cap->card)); | ||
1345 | sprintf(cap->bus_info, "PCI:%s", pci_name(dev->pci)); | ||
1346 | cap->capabilities = | ||
1347 | V4L2_CAP_VIDEO_CAPTURE | | ||
1348 | V4L2_CAP_READWRITE | | ||
1349 | V4L2_CAP_STREAMING | | ||
1350 | 0; | ||
1351 | if (UNSET != dev->tuner_type) | ||
1352 | cap->capabilities |= V4L2_CAP_TUNER; | ||
1353 | |||
1354 | return 0; | ||
1355 | } | ||
1356 | |||
1357 | static int vidioc_enum_fmt_vid_cap(struct file *file, void *priv, | ||
1358 | struct v4l2_fmtdesc *f) | ||
1359 | { | ||
1360 | if (f->index != 0) | ||
1361 | return -EINVAL; | ||
1362 | |||
1363 | strlcpy(f->description, "MPEG", sizeof(f->description)); | ||
1364 | f->pixelformat = V4L2_PIX_FMT_MPEG; | ||
1365 | |||
1366 | return 0; | ||
1367 | } | ||
1368 | |||
1369 | static int vidioc_g_fmt_vid_cap(struct file *file, void *priv, | ||
1370 | struct v4l2_format *f) | ||
1371 | { | ||
1372 | struct cx23885_fh *fh = file->private_data; | ||
1373 | struct cx23885_dev *dev = fh->dev; | ||
1374 | |||
1375 | f->fmt.pix.pixelformat = V4L2_PIX_FMT_MPEG; | ||
1376 | f->fmt.pix.bytesperline = 0; | ||
1377 | f->fmt.pix.sizeimage = | ||
1378 | dev->ts1.ts_packet_size * dev->ts1.ts_packet_count; | ||
1379 | f->fmt.pix.colorspace = 0; | ||
1380 | f->fmt.pix.width = dev->ts1.width; | ||
1381 | f->fmt.pix.height = dev->ts1.height; | ||
1382 | f->fmt.pix.field = fh->mpegq.field; | ||
1383 | dprintk(1, "VIDIOC_G_FMT: w: %d, h: %d, f: %d\n", | ||
1384 | dev->ts1.width, dev->ts1.height, fh->mpegq.field); | ||
1385 | return 0; | ||
1386 | } | ||
1387 | |||
1388 | static int vidioc_try_fmt_vid_cap(struct file *file, void *priv, | ||
1389 | struct v4l2_format *f) | ||
1390 | { | ||
1391 | struct cx23885_fh *fh = file->private_data; | ||
1392 | struct cx23885_dev *dev = fh->dev; | ||
1393 | |||
1394 | f->fmt.pix.pixelformat = V4L2_PIX_FMT_MPEG; | ||
1395 | f->fmt.pix.bytesperline = 0; | ||
1396 | f->fmt.pix.sizeimage = | ||
1397 | dev->ts1.ts_packet_size * dev->ts1.ts_packet_count; | ||
1398 | f->fmt.pix.colorspace = 0; | ||
1399 | dprintk(1, "VIDIOC_TRY_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_s_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_S_FMT: w: %d, h: %d, f: %d\n", | ||
1416 | f->fmt.pix.width, f->fmt.pix.height, f->fmt.pix.field); | ||
1417 | return 0; | ||
1418 | } | ||
1419 | |||
1420 | static int vidioc_reqbufs(struct file *file, void *priv, | ||
1421 | struct v4l2_requestbuffers *p) | ||
1422 | { | ||
1423 | struct cx23885_fh *fh = file->private_data; | ||
1424 | |||
1425 | return videobuf_reqbufs(&fh->mpegq, p); | ||
1426 | } | ||
1427 | |||
1428 | static int vidioc_querybuf(struct file *file, void *priv, | ||
1429 | struct v4l2_buffer *p) | ||
1430 | { | ||
1431 | struct cx23885_fh *fh = file->private_data; | ||
1432 | |||
1433 | return videobuf_querybuf(&fh->mpegq, p); | ||
1434 | } | ||
1435 | |||
1436 | static int vidioc_qbuf(struct file *file, void *priv, | ||
1437 | struct v4l2_buffer *p) | ||
1438 | { | ||
1439 | struct cx23885_fh *fh = file->private_data; | ||
1440 | |||
1441 | return videobuf_qbuf(&fh->mpegq, p); | ||
1442 | } | ||
1443 | |||
1444 | static int vidioc_dqbuf(struct file *file, void *priv, struct v4l2_buffer *b) | ||
1445 | { | ||
1446 | struct cx23885_fh *fh = priv; | ||
1447 | |||
1448 | return videobuf_dqbuf(&fh->mpegq, b, file->f_flags & O_NONBLOCK); | ||
1449 | } | ||
1450 | |||
1451 | |||
1452 | static int vidioc_streamon(struct file *file, void *priv, | ||
1453 | enum v4l2_buf_type i) | ||
1454 | { | ||
1455 | struct cx23885_fh *fh = file->private_data; | ||
1456 | |||
1457 | return videobuf_streamon(&fh->mpegq); | ||
1458 | } | ||
1459 | |||
1460 | static int vidioc_streamoff(struct file *file, void *priv, enum v4l2_buf_type i) | ||
1461 | { | ||
1462 | struct cx23885_fh *fh = file->private_data; | ||
1463 | |||
1464 | return videobuf_streamoff(&fh->mpegq); | ||
1465 | } | ||
1466 | |||
1467 | static int vidioc_g_ext_ctrls(struct file *file, void *priv, | ||
1468 | struct v4l2_ext_controls *f) | ||
1469 | { | ||
1470 | struct cx23885_fh *fh = priv; | ||
1471 | struct cx23885_dev *dev = fh->dev; | ||
1472 | |||
1473 | if (f->ctrl_class != V4L2_CTRL_CLASS_MPEG) | ||
1474 | return -EINVAL; | ||
1475 | return cx2341x_ext_ctrls(&dev->mpeg_params, 0, f, VIDIOC_G_EXT_CTRLS); | ||
1476 | } | ||
1477 | |||
1478 | static int vidioc_s_ext_ctrls(struct file *file, void *priv, | ||
1479 | struct v4l2_ext_controls *f) | ||
1480 | { | ||
1481 | struct cx23885_fh *fh = priv; | ||
1482 | struct cx23885_dev *dev = fh->dev; | ||
1483 | struct cx2341x_mpeg_params p; | ||
1484 | int err; | ||
1485 | |||
1486 | if (f->ctrl_class != V4L2_CTRL_CLASS_MPEG) | ||
1487 | return -EINVAL; | ||
1488 | |||
1489 | p = dev->mpeg_params; | ||
1490 | err = cx2341x_ext_ctrls(&p, 0, f, VIDIOC_S_EXT_CTRLS); | ||
1491 | |||
1492 | if (err == 0) { | ||
1493 | err = cx2341x_update(dev, cx23885_mbox_func, | ||
1494 | &dev->mpeg_params, &p); | ||
1495 | dev->mpeg_params = p; | ||
1496 | } | ||
1497 | return err; | ||
1498 | } | ||
1499 | |||
1500 | static int vidioc_try_ext_ctrls(struct file *file, void *priv, | ||
1501 | struct v4l2_ext_controls *f) | ||
1502 | { | ||
1503 | struct cx23885_fh *fh = priv; | ||
1504 | struct cx23885_dev *dev = fh->dev; | ||
1505 | struct cx2341x_mpeg_params p; | ||
1506 | int err; | ||
1507 | |||
1508 | if (f->ctrl_class != V4L2_CTRL_CLASS_MPEG) | ||
1509 | return -EINVAL; | ||
1510 | |||
1511 | p = dev->mpeg_params; | ||
1512 | err = cx2341x_ext_ctrls(&p, 0, f, VIDIOC_TRY_EXT_CTRLS); | ||
1513 | return err; | ||
1514 | } | ||
1515 | |||
1516 | static int vidioc_log_status(struct file *file, void *priv) | ||
1517 | { | ||
1518 | struct cx23885_fh *fh = priv; | ||
1519 | struct cx23885_dev *dev = fh->dev; | ||
1520 | char name[32 + 2]; | ||
1521 | |||
1522 | snprintf(name, sizeof(name), "%s/2", dev->name); | ||
1523 | printk(KERN_INFO | ||
1524 | "%s/2: ============ START LOG STATUS ============\n", | ||
1525 | dev->name); | ||
1526 | call_all(dev, core, log_status); | ||
1527 | cx2341x_log_status(&dev->mpeg_params, name); | ||
1528 | printk(KERN_INFO | ||
1529 | "%s/2: ============= END LOG STATUS =============\n", | ||
1530 | dev->name); | ||
1531 | return 0; | ||
1532 | } | ||
1533 | |||
1534 | static int vidioc_querymenu(struct file *file, void *priv, | ||
1535 | struct v4l2_querymenu *a) | ||
1536 | { | ||
1537 | struct cx23885_fh *fh = priv; | ||
1538 | struct cx23885_dev *dev = fh->dev; | ||
1539 | |||
1540 | return cx23885_querymenu(dev, a); | ||
1541 | } | ||
1542 | |||
1543 | static int vidioc_queryctrl(struct file *file, void *priv, | ||
1544 | struct v4l2_queryctrl *c) | ||
1545 | { | ||
1546 | struct cx23885_fh *fh = priv; | ||
1547 | struct cx23885_dev *dev = fh->dev; | ||
1548 | |||
1549 | return cx23885_queryctrl(dev, c); | ||
1550 | } | ||
1551 | |||
1552 | static int mpeg_open(struct file *file) | ||
1553 | { | ||
1554 | struct cx23885_dev *dev = video_drvdata(file); | ||
1555 | struct cx23885_fh *fh; | ||
1556 | |||
1557 | dprintk(2, "%s()\n", __func__); | ||
1558 | |||
1559 | /* allocate + initialize per filehandle data */ | ||
1560 | fh = kzalloc(sizeof(*fh), GFP_KERNEL); | ||
1561 | if (!fh) | ||
1562 | return -ENOMEM; | ||
1563 | |||
1564 | file->private_data = fh; | ||
1565 | fh->dev = dev; | ||
1566 | |||
1567 | videobuf_queue_sg_init(&fh->mpegq, &cx23885_qops, | ||
1568 | &dev->pci->dev, &dev->ts1.slock, | ||
1569 | V4L2_BUF_TYPE_VIDEO_CAPTURE, | ||
1570 | V4L2_FIELD_INTERLACED, | ||
1571 | sizeof(struct cx23885_buffer), | ||
1572 | fh, NULL); | ||
1573 | return 0; | ||
1574 | } | ||
1575 | |||
1576 | static int mpeg_release(struct file *file) | ||
1577 | { | ||
1578 | struct cx23885_fh *fh = file->private_data; | ||
1579 | struct cx23885_dev *dev = fh->dev; | ||
1580 | |||
1581 | dprintk(2, "%s()\n", __func__); | ||
1582 | |||
1583 | /* FIXME: Review this crap */ | ||
1584 | /* Shut device down on last close */ | ||
1585 | if (atomic_cmpxchg(&fh->v4l_reading, 1, 0) == 1) { | ||
1586 | if (atomic_dec_return(&dev->v4l_reader_count) == 0) { | ||
1587 | /* stop mpeg capture */ | ||
1588 | cx23885_api_cmd(fh->dev, CX2341X_ENC_STOP_CAPTURE, 3, 0, | ||
1589 | CX23885_END_NOW, CX23885_MPEG_CAPTURE, | ||
1590 | CX23885_RAW_BITS_NONE); | ||
1591 | |||
1592 | msleep(500); | ||
1593 | cx23885_417_check_encoder(dev); | ||
1594 | |||
1595 | cx23885_cancel_buffers(&fh->dev->ts1); | ||
1596 | } | ||
1597 | } | ||
1598 | |||
1599 | if (fh->mpegq.streaming) | ||
1600 | videobuf_streamoff(&fh->mpegq); | ||
1601 | if (fh->mpegq.reading) | ||
1602 | videobuf_read_stop(&fh->mpegq); | ||
1603 | |||
1604 | videobuf_mmap_free(&fh->mpegq); | ||
1605 | file->private_data = NULL; | ||
1606 | kfree(fh); | ||
1607 | |||
1608 | return 0; | ||
1609 | } | ||
1610 | |||
1611 | static ssize_t mpeg_read(struct file *file, char __user *data, | ||
1612 | size_t count, loff_t *ppos) | ||
1613 | { | ||
1614 | struct cx23885_fh *fh = file->private_data; | ||
1615 | struct cx23885_dev *dev = fh->dev; | ||
1616 | |||
1617 | dprintk(2, "%s()\n", __func__); | ||
1618 | |||
1619 | /* Deal w/ A/V decoder * and mpeg encoder sync issues. */ | ||
1620 | /* Start mpeg encoder on first read. */ | ||
1621 | if (atomic_cmpxchg(&fh->v4l_reading, 0, 1) == 0) { | ||
1622 | if (atomic_inc_return(&dev->v4l_reader_count) == 1) { | ||
1623 | if (cx23885_initialize_codec(dev, 1) < 0) | ||
1624 | return -EINVAL; | ||
1625 | } | ||
1626 | } | ||
1627 | |||
1628 | return videobuf_read_stream(&fh->mpegq, data, count, ppos, 0, | ||
1629 | file->f_flags & O_NONBLOCK); | ||
1630 | } | ||
1631 | |||
1632 | static unsigned int mpeg_poll(struct file *file, | ||
1633 | struct poll_table_struct *wait) | ||
1634 | { | ||
1635 | struct cx23885_fh *fh = file->private_data; | ||
1636 | struct cx23885_dev *dev = fh->dev; | ||
1637 | |||
1638 | dprintk(2, "%s\n", __func__); | ||
1639 | |||
1640 | return videobuf_poll_stream(file, &fh->mpegq, wait); | ||
1641 | } | ||
1642 | |||
1643 | static int mpeg_mmap(struct file *file, struct vm_area_struct *vma) | ||
1644 | { | ||
1645 | struct cx23885_fh *fh = file->private_data; | ||
1646 | struct cx23885_dev *dev = fh->dev; | ||
1647 | |||
1648 | dprintk(2, "%s()\n", __func__); | ||
1649 | |||
1650 | return videobuf_mmap_mapper(&fh->mpegq, vma); | ||
1651 | } | ||
1652 | |||
1653 | static struct v4l2_file_operations mpeg_fops = { | ||
1654 | .owner = THIS_MODULE, | ||
1655 | .open = mpeg_open, | ||
1656 | .release = mpeg_release, | ||
1657 | .read = mpeg_read, | ||
1658 | .poll = mpeg_poll, | ||
1659 | .mmap = mpeg_mmap, | ||
1660 | .ioctl = video_ioctl2, | ||
1661 | }; | ||
1662 | |||
1663 | static const struct v4l2_ioctl_ops mpeg_ioctl_ops = { | ||
1664 | .vidioc_querystd = vidioc_g_std, | ||
1665 | .vidioc_g_std = vidioc_g_std, | ||
1666 | .vidioc_s_std = vidioc_s_std, | ||
1667 | .vidioc_enum_input = vidioc_enum_input, | ||
1668 | .vidioc_g_input = vidioc_g_input, | ||
1669 | .vidioc_s_input = vidioc_s_input, | ||
1670 | .vidioc_g_tuner = vidioc_g_tuner, | ||
1671 | .vidioc_s_tuner = vidioc_s_tuner, | ||
1672 | .vidioc_g_frequency = vidioc_g_frequency, | ||
1673 | .vidioc_s_frequency = vidioc_s_frequency, | ||
1674 | .vidioc_s_ctrl = vidioc_s_ctrl, | ||
1675 | .vidioc_g_ctrl = vidioc_g_ctrl, | ||
1676 | .vidioc_querycap = vidioc_querycap, | ||
1677 | .vidioc_enum_fmt_vid_cap = vidioc_enum_fmt_vid_cap, | ||
1678 | .vidioc_g_fmt_vid_cap = vidioc_g_fmt_vid_cap, | ||
1679 | .vidioc_try_fmt_vid_cap = vidioc_try_fmt_vid_cap, | ||
1680 | .vidioc_s_fmt_vid_cap = vidioc_s_fmt_vid_cap, | ||
1681 | .vidioc_reqbufs = vidioc_reqbufs, | ||
1682 | .vidioc_querybuf = vidioc_querybuf, | ||
1683 | .vidioc_qbuf = vidioc_qbuf, | ||
1684 | .vidioc_dqbuf = vidioc_dqbuf, | ||
1685 | .vidioc_streamon = vidioc_streamon, | ||
1686 | .vidioc_streamoff = vidioc_streamoff, | ||
1687 | .vidioc_g_ext_ctrls = vidioc_g_ext_ctrls, | ||
1688 | .vidioc_s_ext_ctrls = vidioc_s_ext_ctrls, | ||
1689 | .vidioc_try_ext_ctrls = vidioc_try_ext_ctrls, | ||
1690 | .vidioc_log_status = vidioc_log_status, | ||
1691 | .vidioc_querymenu = vidioc_querymenu, | ||
1692 | .vidioc_queryctrl = vidioc_queryctrl, | ||
1693 | .vidioc_g_chip_ident = cx23885_g_chip_ident, | ||
1694 | #ifdef CONFIG_VIDEO_ADV_DEBUG | ||
1695 | .vidioc_g_register = cx23885_g_register, | ||
1696 | .vidioc_s_register = cx23885_s_register, | ||
1697 | #endif | ||
1698 | }; | ||
1699 | |||
1700 | static struct video_device cx23885_mpeg_template = { | ||
1701 | .name = "cx23885", | ||
1702 | .fops = &mpeg_fops, | ||
1703 | .ioctl_ops = &mpeg_ioctl_ops, | ||
1704 | .tvnorms = CX23885_NORMS, | ||
1705 | .current_norm = V4L2_STD_NTSC_M, | ||
1706 | }; | ||
1707 | |||
1708 | void cx23885_417_unregister(struct cx23885_dev *dev) | ||
1709 | { | ||
1710 | dprintk(1, "%s()\n", __func__); | ||
1711 | |||
1712 | if (dev->v4l_device) { | ||
1713 | if (video_is_registered(dev->v4l_device)) | ||
1714 | video_unregister_device(dev->v4l_device); | ||
1715 | else | ||
1716 | video_device_release(dev->v4l_device); | ||
1717 | dev->v4l_device = NULL; | ||
1718 | } | ||
1719 | } | ||
1720 | |||
1721 | static struct video_device *cx23885_video_dev_alloc( | ||
1722 | struct cx23885_tsport *tsport, | ||
1723 | struct pci_dev *pci, | ||
1724 | struct video_device *template, | ||
1725 | char *type) | ||
1726 | { | ||
1727 | struct video_device *vfd; | ||
1728 | struct cx23885_dev *dev = tsport->dev; | ||
1729 | |||
1730 | dprintk(1, "%s()\n", __func__); | ||
1731 | |||
1732 | vfd = video_device_alloc(); | ||
1733 | if (NULL == vfd) | ||
1734 | return NULL; | ||
1735 | *vfd = *template; | ||
1736 | snprintf(vfd->name, sizeof(vfd->name), "%s (%s)", | ||
1737 | cx23885_boards[tsport->dev->board].name, type); | ||
1738 | vfd->parent = &pci->dev; | ||
1739 | vfd->release = video_device_release; | ||
1740 | return vfd; | ||
1741 | } | ||
1742 | |||
1743 | int cx23885_417_register(struct cx23885_dev *dev) | ||
1744 | { | ||
1745 | /* FIXME: Port1 hardcoded here */ | ||
1746 | int err = -ENODEV; | ||
1747 | struct cx23885_tsport *tsport = &dev->ts1; | ||
1748 | |||
1749 | dprintk(1, "%s()\n", __func__); | ||
1750 | |||
1751 | if (cx23885_boards[dev->board].portb != CX23885_MPEG_ENCODER) | ||
1752 | return err; | ||
1753 | |||
1754 | /* Set default TV standard */ | ||
1755 | dev->encodernorm = cx23885_tvnorms[0]; | ||
1756 | |||
1757 | if (dev->encodernorm.id & V4L2_STD_525_60) | ||
1758 | tsport->height = 480; | ||
1759 | else | ||
1760 | tsport->height = 576; | ||
1761 | |||
1762 | tsport->width = 720; | ||
1763 | cx2341x_fill_defaults(&dev->mpeg_params); | ||
1764 | |||
1765 | dev->mpeg_params.port = CX2341X_PORT_SERIAL; | ||
1766 | |||
1767 | /* Allocate and initialize V4L video device */ | ||
1768 | dev->v4l_device = cx23885_video_dev_alloc(tsport, | ||
1769 | dev->pci, &cx23885_mpeg_template, "mpeg"); | ||
1770 | video_set_drvdata(dev->v4l_device, dev); | ||
1771 | err = video_register_device(dev->v4l_device, | ||
1772 | VFL_TYPE_GRABBER, -1); | ||
1773 | if (err < 0) { | ||
1774 | printk(KERN_INFO "%s: can't register mpeg device\n", dev->name); | ||
1775 | return err; | ||
1776 | } | ||
1777 | |||
1778 | printk(KERN_INFO "%s: registered device %s [mpeg]\n", | ||
1779 | dev->name, video_device_node_name(dev->v4l_device)); | ||
1780 | |||
1781 | /* ST: Configure the encoder paramaters, but don't begin | ||
1782 | * encoding, this resolves an issue where the first time the | ||
1783 | * encoder is started video can be choppy. | ||
1784 | */ | ||
1785 | cx23885_initialize_codec(dev, 0); | ||
1786 | |||
1787 | return 0; | ||
1788 | } | ||
1789 | |||
1790 | MODULE_FIRMWARE(CX23885_FIRM_IMAGE_NAME); | ||
diff --git a/drivers/media/pci/cx23885/cx23885-alsa.c b/drivers/media/pci/cx23885/cx23885-alsa.c new file mode 100644 index 000000000000..795169237e70 --- /dev/null +++ b/drivers/media/pci/cx23885/cx23885-alsa.c | |||
@@ -0,0 +1,535 @@ | |||
1 | /* | ||
2 | * | ||
3 | * Support for CX23885 analog audio capture | ||
4 | * | ||
5 | * (c) 2008 Mijhail Moreyra <mijhail.moreyra@gmail.com> | ||
6 | * Adapted from cx88-alsa.c | ||
7 | * (c) 2009 Steven Toth <stoth@kernellabs.com> | ||
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 | * 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 <linux/module.h> | ||
25 | #include <linux/init.h> | ||
26 | #include <linux/device.h> | ||
27 | #include <linux/interrupt.h> | ||
28 | #include <linux/vmalloc.h> | ||
29 | #include <linux/dma-mapping.h> | ||
30 | #include <linux/pci.h> | ||
31 | |||
32 | #include <asm/delay.h> | ||
33 | |||
34 | #include <sound/core.h> | ||
35 | #include <sound/pcm.h> | ||
36 | #include <sound/pcm_params.h> | ||
37 | #include <sound/control.h> | ||
38 | #include <sound/initval.h> | ||
39 | |||
40 | #include <sound/tlv.h> | ||
41 | |||
42 | |||
43 | #include "cx23885.h" | ||
44 | #include "cx23885-reg.h" | ||
45 | |||
46 | #define AUDIO_SRAM_CHANNEL SRAM_CH07 | ||
47 | |||
48 | #define dprintk(level, fmt, arg...) if (audio_debug >= level) \ | ||
49 | printk(KERN_INFO "%s: " fmt, chip->dev->name , ## arg) | ||
50 | |||
51 | #define dprintk_core(level, fmt, arg...) if (audio_debug >= level) \ | ||
52 | printk(KERN_DEBUG "%s: " fmt, chip->dev->name , ## arg) | ||
53 | |||
54 | /**************************************************************************** | ||
55 | Module global static vars | ||
56 | ****************************************************************************/ | ||
57 | |||
58 | static unsigned int disable_analog_audio; | ||
59 | module_param(disable_analog_audio, int, 0644); | ||
60 | MODULE_PARM_DESC(disable_analog_audio, "disable analog audio ALSA driver"); | ||
61 | |||
62 | static unsigned int audio_debug; | ||
63 | module_param(audio_debug, int, 0644); | ||
64 | MODULE_PARM_DESC(audio_debug, "enable debug messages [analog audio]"); | ||
65 | |||
66 | /**************************************************************************** | ||
67 | Board specific funtions | ||
68 | ****************************************************************************/ | ||
69 | |||
70 | /* Constants taken from cx88-reg.h */ | ||
71 | #define AUD_INT_DN_RISCI1 (1 << 0) | ||
72 | #define AUD_INT_UP_RISCI1 (1 << 1) | ||
73 | #define AUD_INT_RDS_DN_RISCI1 (1 << 2) | ||
74 | #define AUD_INT_DN_RISCI2 (1 << 4) /* yes, 3 is skipped */ | ||
75 | #define AUD_INT_UP_RISCI2 (1 << 5) | ||
76 | #define AUD_INT_RDS_DN_RISCI2 (1 << 6) | ||
77 | #define AUD_INT_DN_SYNC (1 << 12) | ||
78 | #define AUD_INT_UP_SYNC (1 << 13) | ||
79 | #define AUD_INT_RDS_DN_SYNC (1 << 14) | ||
80 | #define AUD_INT_OPC_ERR (1 << 16) | ||
81 | #define AUD_INT_BER_IRQ (1 << 20) | ||
82 | #define AUD_INT_MCHG_IRQ (1 << 21) | ||
83 | #define GP_COUNT_CONTROL_RESET 0x3 | ||
84 | |||
85 | /* | ||
86 | * BOARD Specific: Sets audio DMA | ||
87 | */ | ||
88 | |||
89 | static int cx23885_start_audio_dma(struct cx23885_audio_dev *chip) | ||
90 | { | ||
91 | struct cx23885_audio_buffer *buf = chip->buf; | ||
92 | struct cx23885_dev *dev = chip->dev; | ||
93 | struct sram_channel *audio_ch = | ||
94 | &dev->sram_channels[AUDIO_SRAM_CHANNEL]; | ||
95 | |||
96 | dprintk(1, "%s()\n", __func__); | ||
97 | |||
98 | /* Make sure RISC/FIFO are off before changing FIFO/RISC settings */ | ||
99 | cx_clear(AUD_INT_DMA_CTL, 0x11); | ||
100 | |||
101 | /* setup fifo + format - out channel */ | ||
102 | cx23885_sram_channel_setup(chip->dev, audio_ch, buf->bpl, | ||
103 | buf->risc.dma); | ||
104 | |||
105 | /* sets bpl size */ | ||
106 | cx_write(AUD_INT_A_LNGTH, buf->bpl); | ||
107 | |||
108 | /* This is required to get good audio (1 seems to be ok) */ | ||
109 | cx_write(AUD_INT_A_MODE, 1); | ||
110 | |||
111 | /* reset counter */ | ||
112 | cx_write(AUD_INT_A_GPCNT_CTL, GP_COUNT_CONTROL_RESET); | ||
113 | atomic_set(&chip->count, 0); | ||
114 | |||
115 | dprintk(1, "Start audio DMA, %d B/line, %d lines/FIFO, %d periods, %d " | ||
116 | "byte buffer\n", buf->bpl, cx_read(audio_ch->cmds_start+12)>>1, | ||
117 | chip->num_periods, buf->bpl * chip->num_periods); | ||
118 | |||
119 | /* Enables corresponding bits at AUD_INT_STAT */ | ||
120 | cx_write(AUDIO_INT_INT_MSK, AUD_INT_OPC_ERR | AUD_INT_DN_SYNC | | ||
121 | AUD_INT_DN_RISCI1); | ||
122 | |||
123 | /* Clean any pending interrupt bits already set */ | ||
124 | cx_write(AUDIO_INT_INT_STAT, ~0); | ||
125 | |||
126 | /* enable audio irqs */ | ||
127 | cx_set(PCI_INT_MSK, chip->dev->pci_irqmask | PCI_MSK_AUD_INT); | ||
128 | |||
129 | /* start dma */ | ||
130 | cx_set(DEV_CNTRL2, (1<<5)); /* Enables Risc Processor */ | ||
131 | cx_set(AUD_INT_DMA_CTL, 0x11); /* audio downstream FIFO and | ||
132 | RISC enable */ | ||
133 | if (audio_debug) | ||
134 | cx23885_sram_channel_dump(chip->dev, audio_ch); | ||
135 | |||
136 | return 0; | ||
137 | } | ||
138 | |||
139 | /* | ||
140 | * BOARD Specific: Resets audio DMA | ||
141 | */ | ||
142 | static int cx23885_stop_audio_dma(struct cx23885_audio_dev *chip) | ||
143 | { | ||
144 | struct cx23885_dev *dev = chip->dev; | ||
145 | dprintk(1, "Stopping audio DMA\n"); | ||
146 | |||
147 | /* stop dma */ | ||
148 | cx_clear(AUD_INT_DMA_CTL, 0x11); | ||
149 | |||
150 | /* disable irqs */ | ||
151 | cx_clear(PCI_INT_MSK, PCI_MSK_AUD_INT); | ||
152 | cx_clear(AUDIO_INT_INT_MSK, AUD_INT_OPC_ERR | AUD_INT_DN_SYNC | | ||
153 | AUD_INT_DN_RISCI1); | ||
154 | |||
155 | if (audio_debug) | ||
156 | cx23885_sram_channel_dump(chip->dev, | ||
157 | &dev->sram_channels[AUDIO_SRAM_CHANNEL]); | ||
158 | |||
159 | return 0; | ||
160 | } | ||
161 | |||
162 | /* | ||
163 | * BOARD Specific: Handles audio IRQ | ||
164 | */ | ||
165 | int cx23885_audio_irq(struct cx23885_dev *dev, u32 status, u32 mask) | ||
166 | { | ||
167 | struct cx23885_audio_dev *chip = dev->audio_dev; | ||
168 | |||
169 | if (0 == (status & mask)) | ||
170 | return 0; | ||
171 | |||
172 | cx_write(AUDIO_INT_INT_STAT, status); | ||
173 | |||
174 | /* risc op code error */ | ||
175 | if (status & AUD_INT_OPC_ERR) { | ||
176 | printk(KERN_WARNING "%s/1: Audio risc op code error\n", | ||
177 | dev->name); | ||
178 | cx_clear(AUD_INT_DMA_CTL, 0x11); | ||
179 | cx23885_sram_channel_dump(dev, | ||
180 | &dev->sram_channels[AUDIO_SRAM_CHANNEL]); | ||
181 | } | ||
182 | if (status & AUD_INT_DN_SYNC) { | ||
183 | dprintk(1, "Downstream sync error\n"); | ||
184 | cx_write(AUD_INT_A_GPCNT_CTL, GP_COUNT_CONTROL_RESET); | ||
185 | return 1; | ||
186 | } | ||
187 | /* risc1 downstream */ | ||
188 | if (status & AUD_INT_DN_RISCI1) { | ||
189 | atomic_set(&chip->count, cx_read(AUD_INT_A_GPCNT)); | ||
190 | snd_pcm_period_elapsed(chip->substream); | ||
191 | } | ||
192 | /* FIXME: Any other status should deserve a special handling? */ | ||
193 | |||
194 | return 1; | ||
195 | } | ||
196 | |||
197 | static int dsp_buffer_free(struct cx23885_audio_dev *chip) | ||
198 | { | ||
199 | BUG_ON(!chip->dma_size); | ||
200 | |||
201 | dprintk(2, "Freeing buffer\n"); | ||
202 | videobuf_dma_unmap(&chip->pci->dev, chip->dma_risc); | ||
203 | videobuf_dma_free(chip->dma_risc); | ||
204 | btcx_riscmem_free(chip->pci, &chip->buf->risc); | ||
205 | kfree(chip->buf); | ||
206 | |||
207 | chip->dma_risc = NULL; | ||
208 | chip->dma_size = 0; | ||
209 | |||
210 | return 0; | ||
211 | } | ||
212 | |||
213 | /**************************************************************************** | ||
214 | ALSA PCM Interface | ||
215 | ****************************************************************************/ | ||
216 | |||
217 | /* | ||
218 | * Digital hardware definition | ||
219 | */ | ||
220 | #define DEFAULT_FIFO_SIZE 4096 | ||
221 | |||
222 | static struct snd_pcm_hardware snd_cx23885_digital_hw = { | ||
223 | .info = SNDRV_PCM_INFO_MMAP | | ||
224 | SNDRV_PCM_INFO_INTERLEAVED | | ||
225 | SNDRV_PCM_INFO_BLOCK_TRANSFER | | ||
226 | SNDRV_PCM_INFO_MMAP_VALID, | ||
227 | .formats = SNDRV_PCM_FMTBIT_S16_LE, | ||
228 | |||
229 | .rates = SNDRV_PCM_RATE_48000, | ||
230 | .rate_min = 48000, | ||
231 | .rate_max = 48000, | ||
232 | .channels_min = 2, | ||
233 | .channels_max = 2, | ||
234 | /* Analog audio output will be full of clicks and pops if there | ||
235 | are not exactly four lines in the SRAM FIFO buffer. */ | ||
236 | .period_bytes_min = DEFAULT_FIFO_SIZE/4, | ||
237 | .period_bytes_max = DEFAULT_FIFO_SIZE/4, | ||
238 | .periods_min = 1, | ||
239 | .periods_max = 1024, | ||
240 | .buffer_bytes_max = (1024*1024), | ||
241 | }; | ||
242 | |||
243 | /* | ||
244 | * audio pcm capture open callback | ||
245 | */ | ||
246 | static int snd_cx23885_pcm_open(struct snd_pcm_substream *substream) | ||
247 | { | ||
248 | struct cx23885_audio_dev *chip = snd_pcm_substream_chip(substream); | ||
249 | struct snd_pcm_runtime *runtime = substream->runtime; | ||
250 | int err; | ||
251 | |||
252 | if (!chip) { | ||
253 | printk(KERN_ERR "BUG: cx23885 can't find device struct." | ||
254 | " Can't proceed with open\n"); | ||
255 | return -ENODEV; | ||
256 | } | ||
257 | |||
258 | err = snd_pcm_hw_constraint_pow2(runtime, 0, | ||
259 | SNDRV_PCM_HW_PARAM_PERIODS); | ||
260 | if (err < 0) | ||
261 | goto _error; | ||
262 | |||
263 | chip->substream = substream; | ||
264 | |||
265 | runtime->hw = snd_cx23885_digital_hw; | ||
266 | |||
267 | if (chip->dev->sram_channels[AUDIO_SRAM_CHANNEL].fifo_size != | ||
268 | DEFAULT_FIFO_SIZE) { | ||
269 | unsigned int bpl = chip->dev-> | ||
270 | sram_channels[AUDIO_SRAM_CHANNEL].fifo_size / 4; | ||
271 | bpl &= ~7; /* must be multiple of 8 */ | ||
272 | runtime->hw.period_bytes_min = bpl; | ||
273 | runtime->hw.period_bytes_max = bpl; | ||
274 | } | ||
275 | |||
276 | return 0; | ||
277 | _error: | ||
278 | dprintk(1, "Error opening PCM!\n"); | ||
279 | return err; | ||
280 | } | ||
281 | |||
282 | /* | ||
283 | * audio close callback | ||
284 | */ | ||
285 | static int snd_cx23885_close(struct snd_pcm_substream *substream) | ||
286 | { | ||
287 | return 0; | ||
288 | } | ||
289 | |||
290 | /* | ||
291 | * hw_params callback | ||
292 | */ | ||
293 | static int snd_cx23885_hw_params(struct snd_pcm_substream *substream, | ||
294 | struct snd_pcm_hw_params *hw_params) | ||
295 | { | ||
296 | struct cx23885_audio_dev *chip = snd_pcm_substream_chip(substream); | ||
297 | struct videobuf_dmabuf *dma; | ||
298 | |||
299 | struct cx23885_audio_buffer *buf; | ||
300 | int ret; | ||
301 | |||
302 | if (substream->runtime->dma_area) { | ||
303 | dsp_buffer_free(chip); | ||
304 | substream->runtime->dma_area = NULL; | ||
305 | } | ||
306 | |||
307 | chip->period_size = params_period_bytes(hw_params); | ||
308 | chip->num_periods = params_periods(hw_params); | ||
309 | chip->dma_size = chip->period_size * params_periods(hw_params); | ||
310 | |||
311 | BUG_ON(!chip->dma_size); | ||
312 | BUG_ON(chip->num_periods & (chip->num_periods-1)); | ||
313 | |||
314 | buf = kzalloc(sizeof(*buf), GFP_KERNEL); | ||
315 | if (NULL == buf) | ||
316 | return -ENOMEM; | ||
317 | |||
318 | buf->bpl = chip->period_size; | ||
319 | |||
320 | dma = &buf->dma; | ||
321 | videobuf_dma_init(dma); | ||
322 | ret = videobuf_dma_init_kernel(dma, PCI_DMA_FROMDEVICE, | ||
323 | (PAGE_ALIGN(chip->dma_size) >> PAGE_SHIFT)); | ||
324 | if (ret < 0) | ||
325 | goto error; | ||
326 | |||
327 | ret = videobuf_dma_map(&chip->pci->dev, dma); | ||
328 | if (ret < 0) | ||
329 | goto error; | ||
330 | |||
331 | ret = cx23885_risc_databuffer(chip->pci, &buf->risc, dma->sglist, | ||
332 | chip->period_size, chip->num_periods, 1); | ||
333 | if (ret < 0) | ||
334 | goto error; | ||
335 | |||
336 | /* Loop back to start of program */ | ||
337 | buf->risc.jmp[0] = cpu_to_le32(RISC_JUMP|RISC_IRQ1|RISC_CNT_INC); | ||
338 | buf->risc.jmp[1] = cpu_to_le32(buf->risc.dma); | ||
339 | buf->risc.jmp[2] = cpu_to_le32(0); /* bits 63-32 */ | ||
340 | |||
341 | chip->buf = buf; | ||
342 | chip->dma_risc = dma; | ||
343 | |||
344 | substream->runtime->dma_area = chip->dma_risc->vaddr; | ||
345 | substream->runtime->dma_bytes = chip->dma_size; | ||
346 | substream->runtime->dma_addr = 0; | ||
347 | |||
348 | return 0; | ||
349 | |||
350 | error: | ||
351 | kfree(buf); | ||
352 | return ret; | ||
353 | } | ||
354 | |||
355 | /* | ||
356 | * hw free callback | ||
357 | */ | ||
358 | static int snd_cx23885_hw_free(struct snd_pcm_substream *substream) | ||
359 | { | ||
360 | |||
361 | struct cx23885_audio_dev *chip = snd_pcm_substream_chip(substream); | ||
362 | |||
363 | if (substream->runtime->dma_area) { | ||
364 | dsp_buffer_free(chip); | ||
365 | substream->runtime->dma_area = NULL; | ||
366 | } | ||
367 | |||
368 | return 0; | ||
369 | } | ||
370 | |||
371 | /* | ||
372 | * prepare callback | ||
373 | */ | ||
374 | static int snd_cx23885_prepare(struct snd_pcm_substream *substream) | ||
375 | { | ||
376 | return 0; | ||
377 | } | ||
378 | |||
379 | /* | ||
380 | * trigger callback | ||
381 | */ | ||
382 | static int snd_cx23885_card_trigger(struct snd_pcm_substream *substream, | ||
383 | int cmd) | ||
384 | { | ||
385 | struct cx23885_audio_dev *chip = snd_pcm_substream_chip(substream); | ||
386 | int err; | ||
387 | |||
388 | /* Local interrupts are already disabled by ALSA */ | ||
389 | spin_lock(&chip->lock); | ||
390 | |||
391 | switch (cmd) { | ||
392 | case SNDRV_PCM_TRIGGER_START: | ||
393 | err = cx23885_start_audio_dma(chip); | ||
394 | break; | ||
395 | case SNDRV_PCM_TRIGGER_STOP: | ||
396 | err = cx23885_stop_audio_dma(chip); | ||
397 | break; | ||
398 | default: | ||
399 | err = -EINVAL; | ||
400 | break; | ||
401 | } | ||
402 | |||
403 | spin_unlock(&chip->lock); | ||
404 | |||
405 | return err; | ||
406 | } | ||
407 | |||
408 | /* | ||
409 | * pointer callback | ||
410 | */ | ||
411 | static snd_pcm_uframes_t snd_cx23885_pointer( | ||
412 | struct snd_pcm_substream *substream) | ||
413 | { | ||
414 | struct cx23885_audio_dev *chip = snd_pcm_substream_chip(substream); | ||
415 | struct snd_pcm_runtime *runtime = substream->runtime; | ||
416 | u16 count; | ||
417 | |||
418 | count = atomic_read(&chip->count); | ||
419 | |||
420 | return runtime->period_size * (count & (runtime->periods-1)); | ||
421 | } | ||
422 | |||
423 | /* | ||
424 | * page callback (needed for mmap) | ||
425 | */ | ||
426 | static struct page *snd_cx23885_page(struct snd_pcm_substream *substream, | ||
427 | unsigned long offset) | ||
428 | { | ||
429 | void *pageptr = substream->runtime->dma_area + offset; | ||
430 | return vmalloc_to_page(pageptr); | ||
431 | } | ||
432 | |||
433 | /* | ||
434 | * operators | ||
435 | */ | ||
436 | static struct snd_pcm_ops snd_cx23885_pcm_ops = { | ||
437 | .open = snd_cx23885_pcm_open, | ||
438 | .close = snd_cx23885_close, | ||
439 | .ioctl = snd_pcm_lib_ioctl, | ||
440 | .hw_params = snd_cx23885_hw_params, | ||
441 | .hw_free = snd_cx23885_hw_free, | ||
442 | .prepare = snd_cx23885_prepare, | ||
443 | .trigger = snd_cx23885_card_trigger, | ||
444 | .pointer = snd_cx23885_pointer, | ||
445 | .page = snd_cx23885_page, | ||
446 | }; | ||
447 | |||
448 | /* | ||
449 | * create a PCM device | ||
450 | */ | ||
451 | static int snd_cx23885_pcm(struct cx23885_audio_dev *chip, int device, | ||
452 | char *name) | ||
453 | { | ||
454 | int err; | ||
455 | struct snd_pcm *pcm; | ||
456 | |||
457 | err = snd_pcm_new(chip->card, name, device, 0, 1, &pcm); | ||
458 | if (err < 0) | ||
459 | return err; | ||
460 | pcm->private_data = chip; | ||
461 | strcpy(pcm->name, name); | ||
462 | snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_cx23885_pcm_ops); | ||
463 | |||
464 | return 0; | ||
465 | } | ||
466 | |||
467 | /**************************************************************************** | ||
468 | Basic Flow for Sound Devices | ||
469 | ****************************************************************************/ | ||
470 | |||
471 | /* | ||
472 | * Alsa Constructor - Component probe | ||
473 | */ | ||
474 | |||
475 | struct cx23885_audio_dev *cx23885_audio_register(struct cx23885_dev *dev) | ||
476 | { | ||
477 | struct snd_card *card; | ||
478 | struct cx23885_audio_dev *chip; | ||
479 | int err; | ||
480 | |||
481 | if (disable_analog_audio) | ||
482 | return NULL; | ||
483 | |||
484 | if (dev->sram_channels[AUDIO_SRAM_CHANNEL].cmds_start == 0) { | ||
485 | printk(KERN_WARNING "%s(): Missing SRAM channel configuration " | ||
486 | "for analog TV Audio\n", __func__); | ||
487 | return NULL; | ||
488 | } | ||
489 | |||
490 | err = snd_card_create(SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1, | ||
491 | THIS_MODULE, sizeof(struct cx23885_audio_dev), &card); | ||
492 | if (err < 0) | ||
493 | goto error; | ||
494 | |||
495 | chip = (struct cx23885_audio_dev *) card->private_data; | ||
496 | chip->dev = dev; | ||
497 | chip->pci = dev->pci; | ||
498 | chip->card = card; | ||
499 | spin_lock_init(&chip->lock); | ||
500 | |||
501 | snd_card_set_dev(card, &dev->pci->dev); | ||
502 | |||
503 | err = snd_cx23885_pcm(chip, 0, "CX23885 Digital"); | ||
504 | if (err < 0) | ||
505 | goto error; | ||
506 | |||
507 | strcpy(card->driver, "CX23885"); | ||
508 | sprintf(card->shortname, "Conexant CX23885"); | ||
509 | sprintf(card->longname, "%s at %s", card->shortname, dev->name); | ||
510 | |||
511 | err = snd_card_register(card); | ||
512 | if (err < 0) | ||
513 | goto error; | ||
514 | |||
515 | dprintk(0, "registered ALSA audio device\n"); | ||
516 | |||
517 | return chip; | ||
518 | |||
519 | error: | ||
520 | snd_card_free(card); | ||
521 | printk(KERN_ERR "%s(): Failed to register analog " | ||
522 | "audio adapter\n", __func__); | ||
523 | |||
524 | return NULL; | ||
525 | } | ||
526 | |||
527 | /* | ||
528 | * ALSA destructor | ||
529 | */ | ||
530 | void cx23885_audio_unregister(struct cx23885_dev *dev) | ||
531 | { | ||
532 | struct cx23885_audio_dev *chip = dev->audio_dev; | ||
533 | |||
534 | snd_card_free(chip->card); | ||
535 | } | ||
diff --git a/drivers/media/pci/cx23885/cx23885-av.c b/drivers/media/pci/cx23885/cx23885-av.c new file mode 100644 index 000000000000..134ebddd860f --- /dev/null +++ b/drivers/media/pci/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/pci/cx23885/cx23885-av.h b/drivers/media/pci/cx23885/cx23885-av.h new file mode 100644 index 000000000000..d2915c3e53a2 --- /dev/null +++ b/drivers/media/pci/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/pci/cx23885/cx23885-cards.c b/drivers/media/pci/cx23885/cx23885-cards.c new file mode 100644 index 000000000000..d365e9a8efc4 --- /dev/null +++ b/drivers/media/pci/cx23885/cx23885-cards.c | |||
@@ -0,0 +1,1684 @@ | |||
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 | #include <misc/altera.h> | ||
29 | |||
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\tTerraTec Cinergy T PCIe Dual (not well tested, appears to be safe)\n" | ||
50 | "\t\t\tTeVii S470 (reported unsafe)\n" | ||
51 | "\t\t This can cause an interrupt storm with some cards.\n" | ||
52 | "\t\t Default: 0 [Disabled]"); | ||
53 | |||
54 | /* ------------------------------------------------------------------ */ | ||
55 | /* board config info */ | ||
56 | |||
57 | struct cx23885_board cx23885_boards[] = { | ||
58 | [CX23885_BOARD_UNKNOWN] = { | ||
59 | .name = "UNKNOWN/GENERIC", | ||
60 | /* Ensure safe default for unknown boards */ | ||
61 | .clk_freq = 0, | ||
62 | .input = {{ | ||
63 | .type = CX23885_VMUX_COMPOSITE1, | ||
64 | .vmux = 0, | ||
65 | }, { | ||
66 | .type = CX23885_VMUX_COMPOSITE2, | ||
67 | .vmux = 1, | ||
68 | }, { | ||
69 | .type = CX23885_VMUX_COMPOSITE3, | ||
70 | .vmux = 2, | ||
71 | }, { | ||
72 | .type = CX23885_VMUX_COMPOSITE4, | ||
73 | .vmux = 3, | ||
74 | } }, | ||
75 | }, | ||
76 | [CX23885_BOARD_HAUPPAUGE_HVR1800lp] = { | ||
77 | .name = "Hauppauge WinTV-HVR1800lp", | ||
78 | .portc = CX23885_MPEG_DVB, | ||
79 | .input = {{ | ||
80 | .type = CX23885_VMUX_TELEVISION, | ||
81 | .vmux = 0, | ||
82 | .gpio0 = 0xff00, | ||
83 | }, { | ||
84 | .type = CX23885_VMUX_DEBUG, | ||
85 | .vmux = 0, | ||
86 | .gpio0 = 0xff01, | ||
87 | }, { | ||
88 | .type = CX23885_VMUX_COMPOSITE1, | ||
89 | .vmux = 1, | ||
90 | .gpio0 = 0xff02, | ||
91 | }, { | ||
92 | .type = CX23885_VMUX_SVIDEO, | ||
93 | .vmux = 2, | ||
94 | .gpio0 = 0xff02, | ||
95 | } }, | ||
96 | }, | ||
97 | [CX23885_BOARD_HAUPPAUGE_HVR1800] = { | ||
98 | .name = "Hauppauge WinTV-HVR1800", | ||
99 | .porta = CX23885_ANALOG_VIDEO, | ||
100 | .portb = CX23885_MPEG_ENCODER, | ||
101 | .portc = CX23885_MPEG_DVB, | ||
102 | .tuner_type = TUNER_PHILIPS_TDA8290, | ||
103 | .tuner_addr = 0x42, /* 0x84 >> 1 */ | ||
104 | .tuner_bus = 1, | ||
105 | .input = {{ | ||
106 | .type = CX23885_VMUX_TELEVISION, | ||
107 | .vmux = CX25840_VIN7_CH3 | | ||
108 | CX25840_VIN5_CH2 | | ||
109 | CX25840_VIN2_CH1, | ||
110 | .amux = CX25840_AUDIO8, | ||
111 | .gpio0 = 0, | ||
112 | }, { | ||
113 | .type = CX23885_VMUX_COMPOSITE1, | ||
114 | .vmux = CX25840_VIN7_CH3 | | ||
115 | CX25840_VIN4_CH2 | | ||
116 | CX25840_VIN6_CH1, | ||
117 | .amux = CX25840_AUDIO7, | ||
118 | .gpio0 = 0, | ||
119 | }, { | ||
120 | .type = CX23885_VMUX_SVIDEO, | ||
121 | .vmux = CX25840_VIN7_CH3 | | ||
122 | CX25840_VIN4_CH2 | | ||
123 | CX25840_VIN8_CH1 | | ||
124 | CX25840_SVIDEO_ON, | ||
125 | .amux = CX25840_AUDIO7, | ||
126 | .gpio0 = 0, | ||
127 | } }, | ||
128 | }, | ||
129 | [CX23885_BOARD_HAUPPAUGE_HVR1250] = { | ||
130 | .name = "Hauppauge WinTV-HVR1250", | ||
131 | .porta = CX23885_ANALOG_VIDEO, | ||
132 | .portc = CX23885_MPEG_DVB, | ||
133 | #ifdef MT2131_NO_ANALOG_SUPPORT_YET | ||
134 | .tuner_type = TUNER_PHILIPS_TDA8290, | ||
135 | .tuner_addr = 0x42, /* 0x84 >> 1 */ | ||
136 | .tuner_bus = 1, | ||
137 | #endif | ||
138 | .force_bff = 1, | ||
139 | .input = {{ | ||
140 | #ifdef MT2131_NO_ANALOG_SUPPORT_YET | ||
141 | .type = CX23885_VMUX_TELEVISION, | ||
142 | .vmux = CX25840_VIN7_CH3 | | ||
143 | CX25840_VIN5_CH2 | | ||
144 | CX25840_VIN2_CH1, | ||
145 | .amux = CX25840_AUDIO8, | ||
146 | .gpio0 = 0xff00, | ||
147 | }, { | ||
148 | #endif | ||
149 | .type = CX23885_VMUX_COMPOSITE1, | ||
150 | .vmux = CX25840_VIN7_CH3 | | ||
151 | CX25840_VIN4_CH2 | | ||
152 | CX25840_VIN6_CH1, | ||
153 | .amux = CX25840_AUDIO7, | ||
154 | .gpio0 = 0xff02, | ||
155 | }, { | ||
156 | .type = CX23885_VMUX_SVIDEO, | ||
157 | .vmux = CX25840_VIN7_CH3 | | ||
158 | CX25840_VIN4_CH2 | | ||
159 | CX25840_VIN8_CH1 | | ||
160 | CX25840_SVIDEO_ON, | ||
161 | .amux = CX25840_AUDIO7, | ||
162 | .gpio0 = 0xff02, | ||
163 | } }, | ||
164 | }, | ||
165 | [CX23885_BOARD_DVICO_FUSIONHDTV_5_EXP] = { | ||
166 | .name = "DViCO FusionHDTV5 Express", | ||
167 | .portb = CX23885_MPEG_DVB, | ||
168 | }, | ||
169 | [CX23885_BOARD_HAUPPAUGE_HVR1500Q] = { | ||
170 | .name = "Hauppauge WinTV-HVR1500Q", | ||
171 | .portc = CX23885_MPEG_DVB, | ||
172 | }, | ||
173 | [CX23885_BOARD_HAUPPAUGE_HVR1500] = { | ||
174 | .name = "Hauppauge WinTV-HVR1500", | ||
175 | .porta = CX23885_ANALOG_VIDEO, | ||
176 | .portc = CX23885_MPEG_DVB, | ||
177 | .tuner_type = TUNER_XC2028, | ||
178 | .tuner_addr = 0x61, /* 0xc2 >> 1 */ | ||
179 | .input = {{ | ||
180 | .type = CX23885_VMUX_TELEVISION, | ||
181 | .vmux = CX25840_VIN7_CH3 | | ||
182 | CX25840_VIN5_CH2 | | ||
183 | CX25840_VIN2_CH1, | ||
184 | .gpio0 = 0, | ||
185 | }, { | ||
186 | .type = CX23885_VMUX_COMPOSITE1, | ||
187 | .vmux = CX25840_VIN7_CH3 | | ||
188 | CX25840_VIN4_CH2 | | ||
189 | CX25840_VIN6_CH1, | ||
190 | .gpio0 = 0, | ||
191 | }, { | ||
192 | .type = CX23885_VMUX_SVIDEO, | ||
193 | .vmux = CX25840_VIN7_CH3 | | ||
194 | CX25840_VIN4_CH2 | | ||
195 | CX25840_VIN8_CH1 | | ||
196 | CX25840_SVIDEO_ON, | ||
197 | .gpio0 = 0, | ||
198 | } }, | ||
199 | }, | ||
200 | [CX23885_BOARD_HAUPPAUGE_HVR1200] = { | ||
201 | .name = "Hauppauge WinTV-HVR1200", | ||
202 | .portc = CX23885_MPEG_DVB, | ||
203 | }, | ||
204 | [CX23885_BOARD_HAUPPAUGE_HVR1700] = { | ||
205 | .name = "Hauppauge WinTV-HVR1700", | ||
206 | .portc = CX23885_MPEG_DVB, | ||
207 | }, | ||
208 | [CX23885_BOARD_HAUPPAUGE_HVR1400] = { | ||
209 | .name = "Hauppauge WinTV-HVR1400", | ||
210 | .portc = CX23885_MPEG_DVB, | ||
211 | }, | ||
212 | [CX23885_BOARD_DVICO_FUSIONHDTV_7_DUAL_EXP] = { | ||
213 | .name = "DViCO FusionHDTV7 Dual Express", | ||
214 | .portb = CX23885_MPEG_DVB, | ||
215 | .portc = CX23885_MPEG_DVB, | ||
216 | }, | ||
217 | [CX23885_BOARD_DVICO_FUSIONHDTV_DVB_T_DUAL_EXP] = { | ||
218 | .name = "DViCO FusionHDTV DVB-T Dual Express", | ||
219 | .portb = CX23885_MPEG_DVB, | ||
220 | .portc = CX23885_MPEG_DVB, | ||
221 | }, | ||
222 | [CX23885_BOARD_LEADTEK_WINFAST_PXDVR3200_H] = { | ||
223 | .name = "Leadtek Winfast PxDVR3200 H", | ||
224 | .portc = CX23885_MPEG_DVB, | ||
225 | }, | ||
226 | [CX23885_BOARD_LEADTEK_WINFAST_PXDVR3200_H_XC4000] = { | ||
227 | .name = "Leadtek Winfast PxDVR3200 H XC4000", | ||
228 | .porta = CX23885_ANALOG_VIDEO, | ||
229 | .portc = CX23885_MPEG_DVB, | ||
230 | .tuner_type = TUNER_XC4000, | ||
231 | .tuner_addr = 0x61, | ||
232 | .radio_type = UNSET, | ||
233 | .radio_addr = ADDR_UNSET, | ||
234 | .input = {{ | ||
235 | .type = CX23885_VMUX_TELEVISION, | ||
236 | .vmux = CX25840_VIN2_CH1 | | ||
237 | CX25840_VIN5_CH2 | | ||
238 | CX25840_NONE0_CH3, | ||
239 | }, { | ||
240 | .type = CX23885_VMUX_COMPOSITE1, | ||
241 | .vmux = CX25840_COMPOSITE1, | ||
242 | }, { | ||
243 | .type = CX23885_VMUX_SVIDEO, | ||
244 | .vmux = CX25840_SVIDEO_LUMA3 | | ||
245 | CX25840_SVIDEO_CHROMA4, | ||
246 | }, { | ||
247 | .type = CX23885_VMUX_COMPONENT, | ||
248 | .vmux = CX25840_VIN7_CH1 | | ||
249 | CX25840_VIN6_CH2 | | ||
250 | CX25840_VIN8_CH3 | | ||
251 | CX25840_COMPONENT_ON, | ||
252 | } }, | ||
253 | }, | ||
254 | [CX23885_BOARD_COMPRO_VIDEOMATE_E650F] = { | ||
255 | .name = "Compro VideoMate E650F", | ||
256 | .portc = CX23885_MPEG_DVB, | ||
257 | }, | ||
258 | [CX23885_BOARD_TBS_6920] = { | ||
259 | .name = "TurboSight TBS 6920", | ||
260 | .portb = CX23885_MPEG_DVB, | ||
261 | }, | ||
262 | [CX23885_BOARD_TEVII_S470] = { | ||
263 | .name = "TeVii S470", | ||
264 | .portb = CX23885_MPEG_DVB, | ||
265 | }, | ||
266 | [CX23885_BOARD_DVBWORLD_2005] = { | ||
267 | .name = "DVBWorld DVB-S2 2005", | ||
268 | .portb = CX23885_MPEG_DVB, | ||
269 | }, | ||
270 | [CX23885_BOARD_NETUP_DUAL_DVBS2_CI] = { | ||
271 | .ci_type = 1, | ||
272 | .name = "NetUP Dual DVB-S2 CI", | ||
273 | .portb = CX23885_MPEG_DVB, | ||
274 | .portc = CX23885_MPEG_DVB, | ||
275 | }, | ||
276 | [CX23885_BOARD_HAUPPAUGE_HVR1270] = { | ||
277 | .name = "Hauppauge WinTV-HVR1270", | ||
278 | .portc = CX23885_MPEG_DVB, | ||
279 | }, | ||
280 | [CX23885_BOARD_HAUPPAUGE_HVR1275] = { | ||
281 | .name = "Hauppauge WinTV-HVR1275", | ||
282 | .portc = CX23885_MPEG_DVB, | ||
283 | }, | ||
284 | [CX23885_BOARD_HAUPPAUGE_HVR1255] = { | ||
285 | .name = "Hauppauge WinTV-HVR1255", | ||
286 | .porta = CX23885_ANALOG_VIDEO, | ||
287 | .portc = CX23885_MPEG_DVB, | ||
288 | .tuner_type = TUNER_ABSENT, | ||
289 | .tuner_addr = 0x42, /* 0x84 >> 1 */ | ||
290 | .force_bff = 1, | ||
291 | .input = {{ | ||
292 | .type = CX23885_VMUX_TELEVISION, | ||
293 | .vmux = CX25840_VIN7_CH3 | | ||
294 | CX25840_VIN5_CH2 | | ||
295 | CX25840_VIN2_CH1 | | ||
296 | CX25840_DIF_ON, | ||
297 | .amux = CX25840_AUDIO8, | ||
298 | }, { | ||
299 | .type = CX23885_VMUX_COMPOSITE1, | ||
300 | .vmux = CX25840_VIN7_CH3 | | ||
301 | CX25840_VIN4_CH2 | | ||
302 | CX25840_VIN6_CH1, | ||
303 | .amux = CX25840_AUDIO7, | ||
304 | }, { | ||
305 | .type = CX23885_VMUX_SVIDEO, | ||
306 | .vmux = CX25840_VIN7_CH3 | | ||
307 | CX25840_VIN4_CH2 | | ||
308 | CX25840_VIN8_CH1 | | ||
309 | CX25840_SVIDEO_ON, | ||
310 | .amux = CX25840_AUDIO7, | ||
311 | } }, | ||
312 | }, | ||
313 | [CX23885_BOARD_HAUPPAUGE_HVR1255_22111] = { | ||
314 | .name = "Hauppauge WinTV-HVR1255", | ||
315 | .porta = CX23885_ANALOG_VIDEO, | ||
316 | .portc = CX23885_MPEG_DVB, | ||
317 | .tuner_type = TUNER_ABSENT, | ||
318 | .tuner_addr = 0x42, /* 0x84 >> 1 */ | ||
319 | .force_bff = 1, | ||
320 | .input = {{ | ||
321 | .type = CX23885_VMUX_TELEVISION, | ||
322 | .vmux = CX25840_VIN7_CH3 | | ||
323 | CX25840_VIN5_CH2 | | ||
324 | CX25840_VIN2_CH1 | | ||
325 | CX25840_DIF_ON, | ||
326 | .amux = CX25840_AUDIO8, | ||
327 | }, { | ||
328 | .type = CX23885_VMUX_SVIDEO, | ||
329 | .vmux = CX25840_VIN7_CH3 | | ||
330 | CX25840_VIN4_CH2 | | ||
331 | CX25840_VIN8_CH1 | | ||
332 | CX25840_SVIDEO_ON, | ||
333 | .amux = CX25840_AUDIO7, | ||
334 | } }, | ||
335 | }, | ||
336 | [CX23885_BOARD_HAUPPAUGE_HVR1210] = { | ||
337 | .name = "Hauppauge WinTV-HVR1210", | ||
338 | .portc = CX23885_MPEG_DVB, | ||
339 | }, | ||
340 | [CX23885_BOARD_MYGICA_X8506] = { | ||
341 | .name = "Mygica X8506 DMB-TH", | ||
342 | .tuner_type = TUNER_XC5000, | ||
343 | .tuner_addr = 0x61, | ||
344 | .tuner_bus = 1, | ||
345 | .porta = CX23885_ANALOG_VIDEO, | ||
346 | .portb = CX23885_MPEG_DVB, | ||
347 | .input = { | ||
348 | { | ||
349 | .type = CX23885_VMUX_TELEVISION, | ||
350 | .vmux = CX25840_COMPOSITE2, | ||
351 | }, | ||
352 | { | ||
353 | .type = CX23885_VMUX_COMPOSITE1, | ||
354 | .vmux = CX25840_COMPOSITE8, | ||
355 | }, | ||
356 | { | ||
357 | .type = CX23885_VMUX_SVIDEO, | ||
358 | .vmux = CX25840_SVIDEO_LUMA3 | | ||
359 | CX25840_SVIDEO_CHROMA4, | ||
360 | }, | ||
361 | { | ||
362 | .type = CX23885_VMUX_COMPONENT, | ||
363 | .vmux = CX25840_COMPONENT_ON | | ||
364 | CX25840_VIN1_CH1 | | ||
365 | CX25840_VIN6_CH2 | | ||
366 | CX25840_VIN7_CH3, | ||
367 | }, | ||
368 | }, | ||
369 | }, | ||
370 | [CX23885_BOARD_MAGICPRO_PROHDTVE2] = { | ||
371 | .name = "Magic-Pro ProHDTV Extreme 2", | ||
372 | .tuner_type = TUNER_XC5000, | ||
373 | .tuner_addr = 0x61, | ||
374 | .tuner_bus = 1, | ||
375 | .porta = CX23885_ANALOG_VIDEO, | ||
376 | .portb = CX23885_MPEG_DVB, | ||
377 | .input = { | ||
378 | { | ||
379 | .type = CX23885_VMUX_TELEVISION, | ||
380 | .vmux = CX25840_COMPOSITE2, | ||
381 | }, | ||
382 | { | ||
383 | .type = CX23885_VMUX_COMPOSITE1, | ||
384 | .vmux = CX25840_COMPOSITE8, | ||
385 | }, | ||
386 | { | ||
387 | .type = CX23885_VMUX_SVIDEO, | ||
388 | .vmux = CX25840_SVIDEO_LUMA3 | | ||
389 | CX25840_SVIDEO_CHROMA4, | ||
390 | }, | ||
391 | { | ||
392 | .type = CX23885_VMUX_COMPONENT, | ||
393 | .vmux = CX25840_COMPONENT_ON | | ||
394 | CX25840_VIN1_CH1 | | ||
395 | CX25840_VIN6_CH2 | | ||
396 | CX25840_VIN7_CH3, | ||
397 | }, | ||
398 | }, | ||
399 | }, | ||
400 | [CX23885_BOARD_HAUPPAUGE_HVR1850] = { | ||
401 | .name = "Hauppauge WinTV-HVR1850", | ||
402 | .porta = CX23885_ANALOG_VIDEO, | ||
403 | .portb = CX23885_MPEG_ENCODER, | ||
404 | .portc = CX23885_MPEG_DVB, | ||
405 | .tuner_type = TUNER_ABSENT, | ||
406 | .tuner_addr = 0x42, /* 0x84 >> 1 */ | ||
407 | .force_bff = 1, | ||
408 | .input = {{ | ||
409 | .type = CX23885_VMUX_TELEVISION, | ||
410 | .vmux = CX25840_VIN7_CH3 | | ||
411 | CX25840_VIN5_CH2 | | ||
412 | CX25840_VIN2_CH1 | | ||
413 | CX25840_DIF_ON, | ||
414 | .amux = CX25840_AUDIO8, | ||
415 | }, { | ||
416 | .type = CX23885_VMUX_COMPOSITE1, | ||
417 | .vmux = CX25840_VIN7_CH3 | | ||
418 | CX25840_VIN4_CH2 | | ||
419 | CX25840_VIN6_CH1, | ||
420 | .amux = CX25840_AUDIO7, | ||
421 | }, { | ||
422 | .type = CX23885_VMUX_SVIDEO, | ||
423 | .vmux = CX25840_VIN7_CH3 | | ||
424 | CX25840_VIN4_CH2 | | ||
425 | CX25840_VIN8_CH1 | | ||
426 | CX25840_SVIDEO_ON, | ||
427 | .amux = CX25840_AUDIO7, | ||
428 | } }, | ||
429 | }, | ||
430 | [CX23885_BOARD_COMPRO_VIDEOMATE_E800] = { | ||
431 | .name = "Compro VideoMate E800", | ||
432 | .portc = CX23885_MPEG_DVB, | ||
433 | }, | ||
434 | [CX23885_BOARD_HAUPPAUGE_HVR1290] = { | ||
435 | .name = "Hauppauge WinTV-HVR1290", | ||
436 | .portc = CX23885_MPEG_DVB, | ||
437 | }, | ||
438 | [CX23885_BOARD_MYGICA_X8558PRO] = { | ||
439 | .name = "Mygica X8558 PRO DMB-TH", | ||
440 | .portb = CX23885_MPEG_DVB, | ||
441 | .portc = CX23885_MPEG_DVB, | ||
442 | }, | ||
443 | [CX23885_BOARD_LEADTEK_WINFAST_PXTV1200] = { | ||
444 | .name = "LEADTEK WinFast PxTV1200", | ||
445 | .porta = CX23885_ANALOG_VIDEO, | ||
446 | .tuner_type = TUNER_XC2028, | ||
447 | .tuner_addr = 0x61, | ||
448 | .tuner_bus = 1, | ||
449 | .input = {{ | ||
450 | .type = CX23885_VMUX_TELEVISION, | ||
451 | .vmux = CX25840_VIN2_CH1 | | ||
452 | CX25840_VIN5_CH2 | | ||
453 | CX25840_NONE0_CH3, | ||
454 | }, { | ||
455 | .type = CX23885_VMUX_COMPOSITE1, | ||
456 | .vmux = CX25840_COMPOSITE1, | ||
457 | }, { | ||
458 | .type = CX23885_VMUX_SVIDEO, | ||
459 | .vmux = CX25840_SVIDEO_LUMA3 | | ||
460 | CX25840_SVIDEO_CHROMA4, | ||
461 | }, { | ||
462 | .type = CX23885_VMUX_COMPONENT, | ||
463 | .vmux = CX25840_VIN7_CH1 | | ||
464 | CX25840_VIN6_CH2 | | ||
465 | CX25840_VIN8_CH3 | | ||
466 | CX25840_COMPONENT_ON, | ||
467 | } }, | ||
468 | }, | ||
469 | [CX23885_BOARD_GOTVIEW_X5_3D_HYBRID] = { | ||
470 | .name = "GoTView X5 3D Hybrid", | ||
471 | .tuner_type = TUNER_XC5000, | ||
472 | .tuner_addr = 0x64, | ||
473 | .tuner_bus = 1, | ||
474 | .porta = CX23885_ANALOG_VIDEO, | ||
475 | .portb = CX23885_MPEG_DVB, | ||
476 | .input = {{ | ||
477 | .type = CX23885_VMUX_TELEVISION, | ||
478 | .vmux = CX25840_VIN2_CH1 | | ||
479 | CX25840_VIN5_CH2, | ||
480 | .gpio0 = 0x02, | ||
481 | }, { | ||
482 | .type = CX23885_VMUX_COMPOSITE1, | ||
483 | .vmux = CX23885_VMUX_COMPOSITE1, | ||
484 | }, { | ||
485 | .type = CX23885_VMUX_SVIDEO, | ||
486 | .vmux = CX25840_SVIDEO_LUMA3 | | ||
487 | CX25840_SVIDEO_CHROMA4, | ||
488 | } }, | ||
489 | }, | ||
490 | [CX23885_BOARD_NETUP_DUAL_DVB_T_C_CI_RF] = { | ||
491 | .ci_type = 2, | ||
492 | .name = "NetUP Dual DVB-T/C-CI RF", | ||
493 | .porta = CX23885_ANALOG_VIDEO, | ||
494 | .portb = CX23885_MPEG_DVB, | ||
495 | .portc = CX23885_MPEG_DVB, | ||
496 | .num_fds_portb = 2, | ||
497 | .num_fds_portc = 2, | ||
498 | .tuner_type = TUNER_XC5000, | ||
499 | .tuner_addr = 0x64, | ||
500 | .input = { { | ||
501 | .type = CX23885_VMUX_TELEVISION, | ||
502 | .vmux = CX25840_COMPOSITE1, | ||
503 | } }, | ||
504 | }, | ||
505 | [CX23885_BOARD_MPX885] = { | ||
506 | .name = "MPX-885", | ||
507 | .porta = CX23885_ANALOG_VIDEO, | ||
508 | .input = {{ | ||
509 | .type = CX23885_VMUX_COMPOSITE1, | ||
510 | .vmux = CX25840_COMPOSITE1, | ||
511 | .amux = CX25840_AUDIO6, | ||
512 | .gpio0 = 0, | ||
513 | }, { | ||
514 | .type = CX23885_VMUX_COMPOSITE2, | ||
515 | .vmux = CX25840_COMPOSITE2, | ||
516 | .amux = CX25840_AUDIO6, | ||
517 | .gpio0 = 0, | ||
518 | }, { | ||
519 | .type = CX23885_VMUX_COMPOSITE3, | ||
520 | .vmux = CX25840_COMPOSITE3, | ||
521 | .amux = CX25840_AUDIO7, | ||
522 | .gpio0 = 0, | ||
523 | }, { | ||
524 | .type = CX23885_VMUX_COMPOSITE4, | ||
525 | .vmux = CX25840_COMPOSITE4, | ||
526 | .amux = CX25840_AUDIO7, | ||
527 | .gpio0 = 0, | ||
528 | } }, | ||
529 | }, | ||
530 | [CX23885_BOARD_MYGICA_X8507] = { | ||
531 | .name = "Mygica X8507", | ||
532 | .tuner_type = TUNER_XC5000, | ||
533 | .tuner_addr = 0x61, | ||
534 | .tuner_bus = 1, | ||
535 | .porta = CX23885_ANALOG_VIDEO, | ||
536 | .input = { | ||
537 | { | ||
538 | .type = CX23885_VMUX_TELEVISION, | ||
539 | .vmux = CX25840_COMPOSITE2, | ||
540 | .amux = CX25840_AUDIO8, | ||
541 | }, | ||
542 | { | ||
543 | .type = CX23885_VMUX_COMPOSITE1, | ||
544 | .vmux = CX25840_COMPOSITE8, | ||
545 | }, | ||
546 | { | ||
547 | .type = CX23885_VMUX_SVIDEO, | ||
548 | .vmux = CX25840_SVIDEO_LUMA3 | | ||
549 | CX25840_SVIDEO_CHROMA4, | ||
550 | }, | ||
551 | { | ||
552 | .type = CX23885_VMUX_COMPONENT, | ||
553 | .vmux = CX25840_COMPONENT_ON | | ||
554 | CX25840_VIN1_CH1 | | ||
555 | CX25840_VIN6_CH2 | | ||
556 | CX25840_VIN7_CH3, | ||
557 | }, | ||
558 | }, | ||
559 | }, | ||
560 | [CX23885_BOARD_TERRATEC_CINERGY_T_PCIE_DUAL] = { | ||
561 | .name = "TerraTec Cinergy T PCIe Dual", | ||
562 | .portb = CX23885_MPEG_DVB, | ||
563 | .portc = CX23885_MPEG_DVB, | ||
564 | }, | ||
565 | [CX23885_BOARD_TEVII_S471] = { | ||
566 | .name = "TeVii S471", | ||
567 | .portb = CX23885_MPEG_DVB, | ||
568 | } | ||
569 | }; | ||
570 | const unsigned int cx23885_bcount = ARRAY_SIZE(cx23885_boards); | ||
571 | |||
572 | /* ------------------------------------------------------------------ */ | ||
573 | /* PCI subsystem IDs */ | ||
574 | |||
575 | struct cx23885_subid cx23885_subids[] = { | ||
576 | { | ||
577 | .subvendor = 0x0070, | ||
578 | .subdevice = 0x3400, | ||
579 | .card = CX23885_BOARD_UNKNOWN, | ||
580 | }, { | ||
581 | .subvendor = 0x0070, | ||
582 | .subdevice = 0x7600, | ||
583 | .card = CX23885_BOARD_HAUPPAUGE_HVR1800lp, | ||
584 | }, { | ||
585 | .subvendor = 0x0070, | ||
586 | .subdevice = 0x7800, | ||
587 | .card = CX23885_BOARD_HAUPPAUGE_HVR1800, | ||
588 | }, { | ||
589 | .subvendor = 0x0070, | ||
590 | .subdevice = 0x7801, | ||
591 | .card = CX23885_BOARD_HAUPPAUGE_HVR1800, | ||
592 | }, { | ||
593 | .subvendor = 0x0070, | ||
594 | .subdevice = 0x7809, | ||
595 | .card = CX23885_BOARD_HAUPPAUGE_HVR1800, | ||
596 | }, { | ||
597 | .subvendor = 0x0070, | ||
598 | .subdevice = 0x7911, | ||
599 | .card = CX23885_BOARD_HAUPPAUGE_HVR1250, | ||
600 | }, { | ||
601 | .subvendor = 0x18ac, | ||
602 | .subdevice = 0xd500, | ||
603 | .card = CX23885_BOARD_DVICO_FUSIONHDTV_5_EXP, | ||
604 | }, { | ||
605 | .subvendor = 0x0070, | ||
606 | .subdevice = 0x7790, | ||
607 | .card = CX23885_BOARD_HAUPPAUGE_HVR1500Q, | ||
608 | }, { | ||
609 | .subvendor = 0x0070, | ||
610 | .subdevice = 0x7797, | ||
611 | .card = CX23885_BOARD_HAUPPAUGE_HVR1500Q, | ||
612 | }, { | ||
613 | .subvendor = 0x0070, | ||
614 | .subdevice = 0x7710, | ||
615 | .card = CX23885_BOARD_HAUPPAUGE_HVR1500, | ||
616 | }, { | ||
617 | .subvendor = 0x0070, | ||
618 | .subdevice = 0x7717, | ||
619 | .card = CX23885_BOARD_HAUPPAUGE_HVR1500, | ||
620 | }, { | ||
621 | .subvendor = 0x0070, | ||
622 | .subdevice = 0x71d1, | ||
623 | .card = CX23885_BOARD_HAUPPAUGE_HVR1200, | ||
624 | }, { | ||
625 | .subvendor = 0x0070, | ||
626 | .subdevice = 0x71d3, | ||
627 | .card = CX23885_BOARD_HAUPPAUGE_HVR1200, | ||
628 | }, { | ||
629 | .subvendor = 0x0070, | ||
630 | .subdevice = 0x8101, | ||
631 | .card = CX23885_BOARD_HAUPPAUGE_HVR1700, | ||
632 | }, { | ||
633 | .subvendor = 0x0070, | ||
634 | .subdevice = 0x8010, | ||
635 | .card = CX23885_BOARD_HAUPPAUGE_HVR1400, | ||
636 | }, { | ||
637 | .subvendor = 0x18ac, | ||
638 | .subdevice = 0xd618, | ||
639 | .card = CX23885_BOARD_DVICO_FUSIONHDTV_7_DUAL_EXP, | ||
640 | }, { | ||
641 | .subvendor = 0x18ac, | ||
642 | .subdevice = 0xdb78, | ||
643 | .card = CX23885_BOARD_DVICO_FUSIONHDTV_DVB_T_DUAL_EXP, | ||
644 | }, { | ||
645 | .subvendor = 0x107d, | ||
646 | .subdevice = 0x6681, | ||
647 | .card = CX23885_BOARD_LEADTEK_WINFAST_PXDVR3200_H, | ||
648 | }, { | ||
649 | .subvendor = 0x107d, | ||
650 | .subdevice = 0x6f39, | ||
651 | .card = CX23885_BOARD_LEADTEK_WINFAST_PXDVR3200_H_XC4000, | ||
652 | }, { | ||
653 | .subvendor = 0x185b, | ||
654 | .subdevice = 0xe800, | ||
655 | .card = CX23885_BOARD_COMPRO_VIDEOMATE_E650F, | ||
656 | }, { | ||
657 | .subvendor = 0x6920, | ||
658 | .subdevice = 0x8888, | ||
659 | .card = CX23885_BOARD_TBS_6920, | ||
660 | }, { | ||
661 | .subvendor = 0xd470, | ||
662 | .subdevice = 0x9022, | ||
663 | .card = CX23885_BOARD_TEVII_S470, | ||
664 | }, { | ||
665 | .subvendor = 0x0001, | ||
666 | .subdevice = 0x2005, | ||
667 | .card = CX23885_BOARD_DVBWORLD_2005, | ||
668 | }, { | ||
669 | .subvendor = 0x1b55, | ||
670 | .subdevice = 0x2a2c, | ||
671 | .card = CX23885_BOARD_NETUP_DUAL_DVBS2_CI, | ||
672 | }, { | ||
673 | .subvendor = 0x0070, | ||
674 | .subdevice = 0x2211, | ||
675 | .card = CX23885_BOARD_HAUPPAUGE_HVR1270, | ||
676 | }, { | ||
677 | .subvendor = 0x0070, | ||
678 | .subdevice = 0x2215, | ||
679 | .card = CX23885_BOARD_HAUPPAUGE_HVR1275, | ||
680 | }, { | ||
681 | .subvendor = 0x0070, | ||
682 | .subdevice = 0x221d, | ||
683 | .card = CX23885_BOARD_HAUPPAUGE_HVR1275, | ||
684 | }, { | ||
685 | .subvendor = 0x0070, | ||
686 | .subdevice = 0x2251, | ||
687 | .card = CX23885_BOARD_HAUPPAUGE_HVR1255, | ||
688 | }, { | ||
689 | .subvendor = 0x0070, | ||
690 | .subdevice = 0x2259, | ||
691 | .card = CX23885_BOARD_HAUPPAUGE_HVR1255_22111, | ||
692 | }, { | ||
693 | .subvendor = 0x0070, | ||
694 | .subdevice = 0x2291, | ||
695 | .card = CX23885_BOARD_HAUPPAUGE_HVR1210, | ||
696 | }, { | ||
697 | .subvendor = 0x0070, | ||
698 | .subdevice = 0x2295, | ||
699 | .card = CX23885_BOARD_HAUPPAUGE_HVR1210, | ||
700 | }, { | ||
701 | .subvendor = 0x0070, | ||
702 | .subdevice = 0x2299, | ||
703 | .card = CX23885_BOARD_HAUPPAUGE_HVR1210, | ||
704 | }, { | ||
705 | .subvendor = 0x0070, | ||
706 | .subdevice = 0x229d, | ||
707 | .card = CX23885_BOARD_HAUPPAUGE_HVR1210, /* HVR1215 */ | ||
708 | }, { | ||
709 | .subvendor = 0x0070, | ||
710 | .subdevice = 0x22f0, | ||
711 | .card = CX23885_BOARD_HAUPPAUGE_HVR1210, | ||
712 | }, { | ||
713 | .subvendor = 0x0070, | ||
714 | .subdevice = 0x22f1, | ||
715 | .card = CX23885_BOARD_HAUPPAUGE_HVR1255, | ||
716 | }, { | ||
717 | .subvendor = 0x0070, | ||
718 | .subdevice = 0x22f2, | ||
719 | .card = CX23885_BOARD_HAUPPAUGE_HVR1275, | ||
720 | }, { | ||
721 | .subvendor = 0x0070, | ||
722 | .subdevice = 0x22f3, | ||
723 | .card = CX23885_BOARD_HAUPPAUGE_HVR1210, /* HVR1215 */ | ||
724 | }, { | ||
725 | .subvendor = 0x0070, | ||
726 | .subdevice = 0x22f4, | ||
727 | .card = CX23885_BOARD_HAUPPAUGE_HVR1210, | ||
728 | }, { | ||
729 | .subvendor = 0x0070, | ||
730 | .subdevice = 0x22f5, | ||
731 | .card = CX23885_BOARD_HAUPPAUGE_HVR1210, /* HVR1215 */ | ||
732 | }, { | ||
733 | .subvendor = 0x14f1, | ||
734 | .subdevice = 0x8651, | ||
735 | .card = CX23885_BOARD_MYGICA_X8506, | ||
736 | }, { | ||
737 | .subvendor = 0x14f1, | ||
738 | .subdevice = 0x8657, | ||
739 | .card = CX23885_BOARD_MAGICPRO_PROHDTVE2, | ||
740 | }, { | ||
741 | .subvendor = 0x0070, | ||
742 | .subdevice = 0x8541, | ||
743 | .card = CX23885_BOARD_HAUPPAUGE_HVR1850, | ||
744 | }, { | ||
745 | .subvendor = 0x1858, | ||
746 | .subdevice = 0xe800, | ||
747 | .card = CX23885_BOARD_COMPRO_VIDEOMATE_E800, | ||
748 | }, { | ||
749 | .subvendor = 0x0070, | ||
750 | .subdevice = 0x8551, | ||
751 | .card = CX23885_BOARD_HAUPPAUGE_HVR1290, | ||
752 | }, { | ||
753 | .subvendor = 0x14f1, | ||
754 | .subdevice = 0x8578, | ||
755 | .card = CX23885_BOARD_MYGICA_X8558PRO, | ||
756 | }, { | ||
757 | .subvendor = 0x107d, | ||
758 | .subdevice = 0x6f22, | ||
759 | .card = CX23885_BOARD_LEADTEK_WINFAST_PXTV1200, | ||
760 | }, { | ||
761 | .subvendor = 0x5654, | ||
762 | .subdevice = 0x2390, | ||
763 | .card = CX23885_BOARD_GOTVIEW_X5_3D_HYBRID, | ||
764 | }, { | ||
765 | .subvendor = 0x1b55, | ||
766 | .subdevice = 0xe2e4, | ||
767 | .card = CX23885_BOARD_NETUP_DUAL_DVB_T_C_CI_RF, | ||
768 | }, { | ||
769 | .subvendor = 0x14f1, | ||
770 | .subdevice = 0x8502, | ||
771 | .card = CX23885_BOARD_MYGICA_X8507, | ||
772 | }, { | ||
773 | .subvendor = 0x153b, | ||
774 | .subdevice = 0x117e, | ||
775 | .card = CX23885_BOARD_TERRATEC_CINERGY_T_PCIE_DUAL, | ||
776 | }, { | ||
777 | .subvendor = 0xd471, | ||
778 | .subdevice = 0x9022, | ||
779 | .card = CX23885_BOARD_TEVII_S471, | ||
780 | }, | ||
781 | }; | ||
782 | const unsigned int cx23885_idcount = ARRAY_SIZE(cx23885_subids); | ||
783 | |||
784 | void cx23885_card_list(struct cx23885_dev *dev) | ||
785 | { | ||
786 | int i; | ||
787 | |||
788 | if (0 == dev->pci->subsystem_vendor && | ||
789 | 0 == dev->pci->subsystem_device) { | ||
790 | printk(KERN_INFO | ||
791 | "%s: Board has no valid PCIe Subsystem ID and can't\n" | ||
792 | "%s: be autodetected. Pass card=<n> insmod option\n" | ||
793 | "%s: to workaround that. Redirect complaints to the\n" | ||
794 | "%s: vendor of the TV card. Best regards,\n" | ||
795 | "%s: -- tux\n", | ||
796 | dev->name, dev->name, dev->name, dev->name, dev->name); | ||
797 | } else { | ||
798 | printk(KERN_INFO | ||
799 | "%s: Your board isn't known (yet) to the driver.\n" | ||
800 | "%s: Try to pick one of the existing card configs via\n" | ||
801 | "%s: card=<n> insmod option. Updating to the latest\n" | ||
802 | "%s: version might help as well.\n", | ||
803 | dev->name, dev->name, dev->name, dev->name); | ||
804 | } | ||
805 | printk(KERN_INFO "%s: Here is a list of valid choices for the card=<n> insmod option:\n", | ||
806 | dev->name); | ||
807 | for (i = 0; i < cx23885_bcount; i++) | ||
808 | printk(KERN_INFO "%s: card=%d -> %s\n", | ||
809 | dev->name, i, cx23885_boards[i].name); | ||
810 | } | ||
811 | |||
812 | static void hauppauge_eeprom(struct cx23885_dev *dev, u8 *eeprom_data) | ||
813 | { | ||
814 | struct tveeprom tv; | ||
815 | |||
816 | tveeprom_hauppauge_analog(&dev->i2c_bus[0].i2c_client, &tv, | ||
817 | eeprom_data); | ||
818 | |||
819 | /* Make sure we support the board model */ | ||
820 | switch (tv.model) { | ||
821 | case 22001: | ||
822 | /* WinTV-HVR1270 (PCIe, Retail, half height) | ||
823 | * ATSC/QAM and basic analog, IR Blast */ | ||
824 | case 22009: | ||
825 | /* WinTV-HVR1210 (PCIe, Retail, half height) | ||
826 | * DVB-T and basic analog, IR Blast */ | ||
827 | case 22011: | ||
828 | /* WinTV-HVR1270 (PCIe, Retail, half height) | ||
829 | * ATSC/QAM and basic analog, IR Recv */ | ||
830 | case 22019: | ||
831 | /* WinTV-HVR1210 (PCIe, Retail, half height) | ||
832 | * DVB-T and basic analog, IR Recv */ | ||
833 | case 22021: | ||
834 | /* WinTV-HVR1275 (PCIe, Retail, half height) | ||
835 | * ATSC/QAM and basic analog, IR Recv */ | ||
836 | case 22029: | ||
837 | /* WinTV-HVR1210 (PCIe, Retail, half height) | ||
838 | * DVB-T and basic analog, IR Recv */ | ||
839 | case 22101: | ||
840 | /* WinTV-HVR1270 (PCIe, Retail, full height) | ||
841 | * ATSC/QAM and basic analog, IR Blast */ | ||
842 | case 22109: | ||
843 | /* WinTV-HVR1210 (PCIe, Retail, full height) | ||
844 | * DVB-T and basic analog, IR Blast */ | ||
845 | case 22111: | ||
846 | /* WinTV-HVR1270 (PCIe, Retail, full height) | ||
847 | * ATSC/QAM and basic analog, IR Recv */ | ||
848 | case 22119: | ||
849 | /* WinTV-HVR1210 (PCIe, Retail, full height) | ||
850 | * DVB-T and basic analog, IR Recv */ | ||
851 | case 22121: | ||
852 | /* WinTV-HVR1275 (PCIe, Retail, full height) | ||
853 | * ATSC/QAM and basic analog, IR Recv */ | ||
854 | case 22129: | ||
855 | /* WinTV-HVR1210 (PCIe, Retail, full height) | ||
856 | * DVB-T and basic analog, IR Recv */ | ||
857 | case 71009: | ||
858 | /* WinTV-HVR1200 (PCIe, Retail, full height) | ||
859 | * DVB-T and basic analog */ | ||
860 | case 71359: | ||
861 | /* WinTV-HVR1200 (PCIe, OEM, half height) | ||
862 | * DVB-T and basic analog */ | ||
863 | case 71439: | ||
864 | /* WinTV-HVR1200 (PCIe, OEM, half height) | ||
865 | * DVB-T and basic analog */ | ||
866 | case 71449: | ||
867 | /* WinTV-HVR1200 (PCIe, OEM, full height) | ||
868 | * DVB-T and basic analog */ | ||
869 | case 71939: | ||
870 | /* WinTV-HVR1200 (PCIe, OEM, half height) | ||
871 | * DVB-T and basic analog */ | ||
872 | case 71949: | ||
873 | /* WinTV-HVR1200 (PCIe, OEM, full height) | ||
874 | * DVB-T and basic analog */ | ||
875 | case 71959: | ||
876 | /* WinTV-HVR1200 (PCIe, OEM, full height) | ||
877 | * DVB-T and basic analog */ | ||
878 | case 71979: | ||
879 | /* WinTV-HVR1200 (PCIe, OEM, half height) | ||
880 | * DVB-T and basic analog */ | ||
881 | case 71999: | ||
882 | /* WinTV-HVR1200 (PCIe, OEM, full height) | ||
883 | * DVB-T and basic analog */ | ||
884 | case 76601: | ||
885 | /* WinTV-HVR1800lp (PCIe, Retail, No IR, Dual | ||
886 | channel ATSC and MPEG2 HW Encoder */ | ||
887 | case 77001: | ||
888 | /* WinTV-HVR1500 (Express Card, OEM, No IR, ATSC | ||
889 | and Basic analog */ | ||
890 | case 77011: | ||
891 | /* WinTV-HVR1500 (Express Card, Retail, No IR, ATSC | ||
892 | and Basic analog */ | ||
893 | case 77041: | ||
894 | /* WinTV-HVR1500Q (Express Card, OEM, No IR, ATSC/QAM | ||
895 | and Basic analog */ | ||
896 | case 77051: | ||
897 | /* WinTV-HVR1500Q (Express Card, Retail, No IR, ATSC/QAM | ||
898 | and Basic analog */ | ||
899 | case 78011: | ||
900 | /* WinTV-HVR1800 (PCIe, Retail, 3.5mm in, IR, No FM, | ||
901 | Dual channel ATSC and MPEG2 HW Encoder */ | ||
902 | case 78501: | ||
903 | /* WinTV-HVR1800 (PCIe, OEM, RCA in, No IR, FM, | ||
904 | Dual channel ATSC and MPEG2 HW Encoder */ | ||
905 | case 78521: | ||
906 | /* WinTV-HVR1800 (PCIe, OEM, RCA in, No IR, FM, | ||
907 | Dual channel ATSC and MPEG2 HW Encoder */ | ||
908 | case 78531: | ||
909 | /* WinTV-HVR1800 (PCIe, OEM, RCA in, No IR, No FM, | ||
910 | Dual channel ATSC and MPEG2 HW Encoder */ | ||
911 | case 78631: | ||
912 | /* WinTV-HVR1800 (PCIe, OEM, No IR, No FM, | ||
913 | Dual channel ATSC and MPEG2 HW Encoder */ | ||
914 | case 79001: | ||
915 | /* WinTV-HVR1250 (PCIe, Retail, IR, full height, | ||
916 | ATSC and Basic analog */ | ||
917 | case 79101: | ||
918 | /* WinTV-HVR1250 (PCIe, Retail, IR, half height, | ||
919 | ATSC and Basic analog */ | ||
920 | case 79501: | ||
921 | /* WinTV-HVR1250 (PCIe, No IR, half height, | ||
922 | ATSC [at least] and Basic analog) */ | ||
923 | case 79561: | ||
924 | /* WinTV-HVR1250 (PCIe, OEM, No IR, half height, | ||
925 | ATSC and Basic analog */ | ||
926 | case 79571: | ||
927 | /* WinTV-HVR1250 (PCIe, OEM, No IR, full height, | ||
928 | ATSC and Basic analog */ | ||
929 | case 79671: | ||
930 | /* WinTV-HVR1250 (PCIe, OEM, No IR, half height, | ||
931 | ATSC and Basic analog */ | ||
932 | case 80019: | ||
933 | /* WinTV-HVR1400 (Express Card, Retail, IR, | ||
934 | * DVB-T and Basic analog */ | ||
935 | case 81509: | ||
936 | /* WinTV-HVR1700 (PCIe, OEM, No IR, half height) | ||
937 | * DVB-T and MPEG2 HW Encoder */ | ||
938 | case 81519: | ||
939 | /* WinTV-HVR1700 (PCIe, OEM, No IR, full height) | ||
940 | * DVB-T and MPEG2 HW Encoder */ | ||
941 | break; | ||
942 | case 85021: | ||
943 | /* WinTV-HVR1850 (PCIe, Retail, 3.5mm in, IR, FM, | ||
944 | Dual channel ATSC and MPEG2 HW Encoder */ | ||
945 | break; | ||
946 | case 85721: | ||
947 | /* WinTV-HVR1290 (PCIe, OEM, RCA in, IR, | ||
948 | Dual channel ATSC and Basic analog */ | ||
949 | break; | ||
950 | default: | ||
951 | printk(KERN_WARNING "%s: warning: " | ||
952 | "unknown hauppauge model #%d\n", | ||
953 | dev->name, tv.model); | ||
954 | break; | ||
955 | } | ||
956 | |||
957 | printk(KERN_INFO "%s: hauppauge eeprom: model=%d\n", | ||
958 | dev->name, tv.model); | ||
959 | } | ||
960 | |||
961 | int cx23885_tuner_callback(void *priv, int component, int command, int arg) | ||
962 | { | ||
963 | struct cx23885_tsport *port = priv; | ||
964 | struct cx23885_dev *dev = port->dev; | ||
965 | u32 bitmask = 0; | ||
966 | |||
967 | if ((command == XC2028_RESET_CLK) || (command == XC2028_I2C_FLUSH)) | ||
968 | return 0; | ||
969 | |||
970 | if (command != 0) { | ||
971 | printk(KERN_ERR "%s(): Unknown command 0x%x.\n", | ||
972 | __func__, command); | ||
973 | return -EINVAL; | ||
974 | } | ||
975 | |||
976 | switch (dev->board) { | ||
977 | case CX23885_BOARD_HAUPPAUGE_HVR1400: | ||
978 | case CX23885_BOARD_HAUPPAUGE_HVR1500: | ||
979 | case CX23885_BOARD_HAUPPAUGE_HVR1500Q: | ||
980 | case CX23885_BOARD_LEADTEK_WINFAST_PXDVR3200_H: | ||
981 | case CX23885_BOARD_LEADTEK_WINFAST_PXDVR3200_H_XC4000: | ||
982 | case CX23885_BOARD_COMPRO_VIDEOMATE_E650F: | ||
983 | case CX23885_BOARD_COMPRO_VIDEOMATE_E800: | ||
984 | case CX23885_BOARD_LEADTEK_WINFAST_PXTV1200: | ||
985 | /* Tuner Reset Command */ | ||
986 | bitmask = 0x04; | ||
987 | break; | ||
988 | case CX23885_BOARD_DVICO_FUSIONHDTV_7_DUAL_EXP: | ||
989 | case CX23885_BOARD_DVICO_FUSIONHDTV_DVB_T_DUAL_EXP: | ||
990 | /* Two identical tuners on two different i2c buses, | ||
991 | * we need to reset the correct gpio. */ | ||
992 | if (port->nr == 1) | ||
993 | bitmask = 0x01; | ||
994 | else if (port->nr == 2) | ||
995 | bitmask = 0x04; | ||
996 | break; | ||
997 | case CX23885_BOARD_GOTVIEW_X5_3D_HYBRID: | ||
998 | /* Tuner Reset Command */ | ||
999 | bitmask = 0x02; | ||
1000 | break; | ||
1001 | case CX23885_BOARD_NETUP_DUAL_DVB_T_C_CI_RF: | ||
1002 | altera_ci_tuner_reset(dev, port->nr); | ||
1003 | break; | ||
1004 | } | ||
1005 | |||
1006 | if (bitmask) { | ||
1007 | /* Drive the tuner into reset and back out */ | ||
1008 | cx_clear(GP0_IO, bitmask); | ||
1009 | mdelay(200); | ||
1010 | cx_set(GP0_IO, bitmask); | ||
1011 | } | ||
1012 | |||
1013 | return 0; | ||
1014 | } | ||
1015 | |||
1016 | void cx23885_gpio_setup(struct cx23885_dev *dev) | ||
1017 | { | ||
1018 | switch (dev->board) { | ||
1019 | case CX23885_BOARD_HAUPPAUGE_HVR1250: | ||
1020 | /* GPIO-0 cx24227 demodulator reset */ | ||
1021 | cx_set(GP0_IO, 0x00010001); /* Bring the part out of reset */ | ||
1022 | break; | ||
1023 | case CX23885_BOARD_HAUPPAUGE_HVR1500: | ||
1024 | /* GPIO-0 cx24227 demodulator */ | ||
1025 | /* GPIO-2 xc3028 tuner */ | ||
1026 | |||
1027 | /* Put the parts into reset */ | ||
1028 | cx_set(GP0_IO, 0x00050000); | ||
1029 | cx_clear(GP0_IO, 0x00000005); | ||
1030 | msleep(5); | ||
1031 | |||
1032 | /* Bring the parts out of reset */ | ||
1033 | cx_set(GP0_IO, 0x00050005); | ||
1034 | break; | ||
1035 | case CX23885_BOARD_HAUPPAUGE_HVR1500Q: | ||
1036 | /* GPIO-0 cx24227 demodulator reset */ | ||
1037 | /* GPIO-2 xc5000 tuner reset */ | ||
1038 | cx_set(GP0_IO, 0x00050005); /* Bring the part out of reset */ | ||
1039 | break; | ||
1040 | case CX23885_BOARD_HAUPPAUGE_HVR1800: | ||
1041 | /* GPIO-0 656_CLK */ | ||
1042 | /* GPIO-1 656_D0 */ | ||
1043 | /* GPIO-2 8295A Reset */ | ||
1044 | /* GPIO-3-10 cx23417 data0-7 */ | ||
1045 | /* GPIO-11-14 cx23417 addr0-3 */ | ||
1046 | /* GPIO-15-18 cx23417 READY, CS, RD, WR */ | ||
1047 | /* GPIO-19 IR_RX */ | ||
1048 | |||
1049 | /* CX23417 GPIO's */ | ||
1050 | /* EIO15 Zilog Reset */ | ||
1051 | /* EIO14 S5H1409/CX24227 Reset */ | ||
1052 | mc417_gpio_enable(dev, GPIO_15 | GPIO_14, 1); | ||
1053 | |||
1054 | /* Put the demod into reset and protect the eeprom */ | ||
1055 | mc417_gpio_clear(dev, GPIO_15 | GPIO_14); | ||
1056 | mdelay(100); | ||
1057 | |||
1058 | /* Bring the demod and blaster out of reset */ | ||
1059 | mc417_gpio_set(dev, GPIO_15 | GPIO_14); | ||
1060 | mdelay(100); | ||
1061 | |||
1062 | /* Force the TDA8295A into reset and back */ | ||
1063 | cx23885_gpio_enable(dev, GPIO_2, 1); | ||
1064 | cx23885_gpio_set(dev, GPIO_2); | ||
1065 | mdelay(20); | ||
1066 | cx23885_gpio_clear(dev, GPIO_2); | ||
1067 | mdelay(20); | ||
1068 | cx23885_gpio_set(dev, GPIO_2); | ||
1069 | mdelay(20); | ||
1070 | break; | ||
1071 | case CX23885_BOARD_HAUPPAUGE_HVR1200: | ||
1072 | /* GPIO-0 tda10048 demodulator reset */ | ||
1073 | /* GPIO-2 tda18271 tuner reset */ | ||
1074 | |||
1075 | /* Put the parts into reset and back */ | ||
1076 | cx_set(GP0_IO, 0x00050000); | ||
1077 | mdelay(20); | ||
1078 | cx_clear(GP0_IO, 0x00000005); | ||
1079 | mdelay(20); | ||
1080 | cx_set(GP0_IO, 0x00050005); | ||
1081 | break; | ||
1082 | case CX23885_BOARD_HAUPPAUGE_HVR1700: | ||
1083 | /* GPIO-0 TDA10048 demodulator reset */ | ||
1084 | /* GPIO-2 TDA8295A Reset */ | ||
1085 | /* GPIO-3-10 cx23417 data0-7 */ | ||
1086 | /* GPIO-11-14 cx23417 addr0-3 */ | ||
1087 | /* GPIO-15-18 cx23417 READY, CS, RD, WR */ | ||
1088 | |||
1089 | /* The following GPIO's are on the interna AVCore (cx25840) */ | ||
1090 | /* GPIO-19 IR_RX */ | ||
1091 | /* GPIO-20 IR_TX 416/DVBT Select */ | ||
1092 | /* GPIO-21 IIS DAT */ | ||
1093 | /* GPIO-22 IIS WCLK */ | ||
1094 | /* GPIO-23 IIS BCLK */ | ||
1095 | |||
1096 | /* Put the parts into reset and back */ | ||
1097 | cx_set(GP0_IO, 0x00050000); | ||
1098 | mdelay(20); | ||
1099 | cx_clear(GP0_IO, 0x00000005); | ||
1100 | mdelay(20); | ||
1101 | cx_set(GP0_IO, 0x00050005); | ||
1102 | break; | ||
1103 | case CX23885_BOARD_HAUPPAUGE_HVR1400: | ||
1104 | /* GPIO-0 Dibcom7000p demodulator reset */ | ||
1105 | /* GPIO-2 xc3028L tuner reset */ | ||
1106 | /* GPIO-13 LED */ | ||
1107 | |||
1108 | /* Put the parts into reset and back */ | ||
1109 | cx_set(GP0_IO, 0x00050000); | ||
1110 | mdelay(20); | ||
1111 | cx_clear(GP0_IO, 0x00000005); | ||
1112 | mdelay(20); | ||
1113 | cx_set(GP0_IO, 0x00050005); | ||
1114 | break; | ||
1115 | case CX23885_BOARD_DVICO_FUSIONHDTV_7_DUAL_EXP: | ||
1116 | /* GPIO-0 xc5000 tuner reset i2c bus 0 */ | ||
1117 | /* GPIO-1 s5h1409 demod reset i2c bus 0 */ | ||
1118 | /* GPIO-2 xc5000 tuner reset i2c bus 1 */ | ||
1119 | /* GPIO-3 s5h1409 demod reset i2c bus 0 */ | ||
1120 | |||
1121 | /* Put the parts into reset and back */ | ||
1122 | cx_set(GP0_IO, 0x000f0000); | ||
1123 | mdelay(20); | ||
1124 | cx_clear(GP0_IO, 0x0000000f); | ||
1125 | mdelay(20); | ||
1126 | cx_set(GP0_IO, 0x000f000f); | ||
1127 | break; | ||
1128 | case CX23885_BOARD_DVICO_FUSIONHDTV_DVB_T_DUAL_EXP: | ||
1129 | /* GPIO-0 portb xc3028 reset */ | ||
1130 | /* GPIO-1 portb zl10353 reset */ | ||
1131 | /* GPIO-2 portc xc3028 reset */ | ||
1132 | /* GPIO-3 portc zl10353 reset */ | ||
1133 | |||
1134 | /* Put the parts into reset and back */ | ||
1135 | cx_set(GP0_IO, 0x000f0000); | ||
1136 | mdelay(20); | ||
1137 | cx_clear(GP0_IO, 0x0000000f); | ||
1138 | mdelay(20); | ||
1139 | cx_set(GP0_IO, 0x000f000f); | ||
1140 | break; | ||
1141 | case CX23885_BOARD_LEADTEK_WINFAST_PXDVR3200_H: | ||
1142 | case CX23885_BOARD_LEADTEK_WINFAST_PXDVR3200_H_XC4000: | ||
1143 | case CX23885_BOARD_COMPRO_VIDEOMATE_E650F: | ||
1144 | case CX23885_BOARD_COMPRO_VIDEOMATE_E800: | ||
1145 | case CX23885_BOARD_LEADTEK_WINFAST_PXTV1200: | ||
1146 | /* GPIO-2 xc3028 tuner reset */ | ||
1147 | |||
1148 | /* The following GPIO's are on the internal AVCore (cx25840) */ | ||
1149 | /* GPIO-? zl10353 demod reset */ | ||
1150 | |||
1151 | /* Put the parts into reset and back */ | ||
1152 | cx_set(GP0_IO, 0x00040000); | ||
1153 | mdelay(20); | ||
1154 | cx_clear(GP0_IO, 0x00000004); | ||
1155 | mdelay(20); | ||
1156 | cx_set(GP0_IO, 0x00040004); | ||
1157 | break; | ||
1158 | case CX23885_BOARD_TBS_6920: | ||
1159 | cx_write(MC417_CTL, 0x00000036); | ||
1160 | cx_write(MC417_OEN, 0x00001000); | ||
1161 | cx_set(MC417_RWD, 0x00000002); | ||
1162 | mdelay(200); | ||
1163 | cx_clear(MC417_RWD, 0x00000800); | ||
1164 | mdelay(200); | ||
1165 | cx_set(MC417_RWD, 0x00000800); | ||
1166 | mdelay(200); | ||
1167 | break; | ||
1168 | case CX23885_BOARD_NETUP_DUAL_DVBS2_CI: | ||
1169 | /* GPIO-0 INTA from CiMax1 | ||
1170 | GPIO-1 INTB from CiMax2 | ||
1171 | GPIO-2 reset chips | ||
1172 | GPIO-3 to GPIO-10 data/addr for CA | ||
1173 | GPIO-11 ~CS0 to CiMax1 | ||
1174 | GPIO-12 ~CS1 to CiMax2 | ||
1175 | GPIO-13 ADL0 load LSB addr | ||
1176 | GPIO-14 ADL1 load MSB addr | ||
1177 | GPIO-15 ~RDY from CiMax | ||
1178 | GPIO-17 ~RD to CiMax | ||
1179 | GPIO-18 ~WR to CiMax | ||
1180 | */ | ||
1181 | cx_set(GP0_IO, 0x00040000); /* GPIO as out */ | ||
1182 | /* GPIO1 and GPIO2 as INTA and INTB from CiMaxes, reset low */ | ||
1183 | cx_clear(GP0_IO, 0x00030004); | ||
1184 | mdelay(100);/* reset delay */ | ||
1185 | cx_set(GP0_IO, 0x00040004); /* GPIO as out, reset high */ | ||
1186 | cx_write(MC417_CTL, 0x00000037);/* enable GPIO3-18 pins */ | ||
1187 | /* GPIO-15 IN as ~ACK, rest as OUT */ | ||
1188 | cx_write(MC417_OEN, 0x00001000); | ||
1189 | /* ~RD, ~WR high; ADL0, ADL1 low; ~CS0, ~CS1 high */ | ||
1190 | cx_write(MC417_RWD, 0x0000c300); | ||
1191 | /* enable irq */ | ||
1192 | cx_write(GPIO_ISM, 0x00000000);/* INTERRUPTS active low*/ | ||
1193 | break; | ||
1194 | case CX23885_BOARD_HAUPPAUGE_HVR1270: | ||
1195 | case CX23885_BOARD_HAUPPAUGE_HVR1275: | ||
1196 | case CX23885_BOARD_HAUPPAUGE_HVR1255: | ||
1197 | case CX23885_BOARD_HAUPPAUGE_HVR1255_22111: | ||
1198 | case CX23885_BOARD_HAUPPAUGE_HVR1210: | ||
1199 | /* GPIO-5 RF Control: 0 = RF1 Terrestrial, 1 = RF2 Cable */ | ||
1200 | /* GPIO-6 I2C Gate which can isolate the demod from the bus */ | ||
1201 | /* GPIO-9 Demod reset */ | ||
1202 | |||
1203 | /* Put the parts into reset and back */ | ||
1204 | cx23885_gpio_enable(dev, GPIO_9 | GPIO_6 | GPIO_5, 1); | ||
1205 | cx23885_gpio_set(dev, GPIO_9 | GPIO_6 | GPIO_5); | ||
1206 | cx23885_gpio_clear(dev, GPIO_9); | ||
1207 | mdelay(20); | ||
1208 | cx23885_gpio_set(dev, GPIO_9); | ||
1209 | break; | ||
1210 | case CX23885_BOARD_MYGICA_X8506: | ||
1211 | case CX23885_BOARD_MAGICPRO_PROHDTVE2: | ||
1212 | case CX23885_BOARD_MYGICA_X8507: | ||
1213 | /* GPIO-0 (0)Analog / (1)Digital TV */ | ||
1214 | /* GPIO-1 reset XC5000 */ | ||
1215 | /* GPIO-2 reset LGS8GL5 / LGS8G75 */ | ||
1216 | cx23885_gpio_enable(dev, GPIO_0 | GPIO_1 | GPIO_2, 1); | ||
1217 | cx23885_gpio_clear(dev, GPIO_1 | GPIO_2); | ||
1218 | mdelay(100); | ||
1219 | cx23885_gpio_set(dev, GPIO_0 | GPIO_1 | GPIO_2); | ||
1220 | mdelay(100); | ||
1221 | break; | ||
1222 | case CX23885_BOARD_MYGICA_X8558PRO: | ||
1223 | /* GPIO-0 reset first ATBM8830 */ | ||
1224 | /* GPIO-1 reset second ATBM8830 */ | ||
1225 | cx23885_gpio_enable(dev, GPIO_0 | GPIO_1, 1); | ||
1226 | cx23885_gpio_clear(dev, GPIO_0 | GPIO_1); | ||
1227 | mdelay(100); | ||
1228 | cx23885_gpio_set(dev, GPIO_0 | GPIO_1); | ||
1229 | mdelay(100); | ||
1230 | break; | ||
1231 | case CX23885_BOARD_HAUPPAUGE_HVR1850: | ||
1232 | case CX23885_BOARD_HAUPPAUGE_HVR1290: | ||
1233 | /* GPIO-0 656_CLK */ | ||
1234 | /* GPIO-1 656_D0 */ | ||
1235 | /* GPIO-2 Wake# */ | ||
1236 | /* GPIO-3-10 cx23417 data0-7 */ | ||
1237 | /* GPIO-11-14 cx23417 addr0-3 */ | ||
1238 | /* GPIO-15-18 cx23417 READY, CS, RD, WR */ | ||
1239 | /* GPIO-19 IR_RX */ | ||
1240 | /* GPIO-20 C_IR_TX */ | ||
1241 | /* GPIO-21 I2S DAT */ | ||
1242 | /* GPIO-22 I2S WCLK */ | ||
1243 | /* GPIO-23 I2S BCLK */ | ||
1244 | /* ALT GPIO: EXP GPIO LATCH */ | ||
1245 | |||
1246 | /* CX23417 GPIO's */ | ||
1247 | /* GPIO-14 S5H1411/CX24228 Reset */ | ||
1248 | /* GPIO-13 EEPROM write protect */ | ||
1249 | mc417_gpio_enable(dev, GPIO_14 | GPIO_13, 1); | ||
1250 | |||
1251 | /* Put the demod into reset and protect the eeprom */ | ||
1252 | mc417_gpio_clear(dev, GPIO_14 | GPIO_13); | ||
1253 | mdelay(100); | ||
1254 | |||
1255 | /* Bring the demod out of reset */ | ||
1256 | mc417_gpio_set(dev, GPIO_14); | ||
1257 | mdelay(100); | ||
1258 | |||
1259 | /* CX24228 GPIO */ | ||
1260 | /* Connected to IF / Mux */ | ||
1261 | break; | ||
1262 | case CX23885_BOARD_GOTVIEW_X5_3D_HYBRID: | ||
1263 | cx_set(GP0_IO, 0x00010001); /* Bring the part out of reset */ | ||
1264 | break; | ||
1265 | case CX23885_BOARD_NETUP_DUAL_DVB_T_C_CI_RF: | ||
1266 | /* GPIO-0 ~INT in | ||
1267 | GPIO-1 TMS out | ||
1268 | GPIO-2 ~reset chips out | ||
1269 | GPIO-3 to GPIO-10 data/addr for CA in/out | ||
1270 | GPIO-11 ~CS out | ||
1271 | GPIO-12 ADDR out | ||
1272 | GPIO-13 ~WR out | ||
1273 | GPIO-14 ~RD out | ||
1274 | GPIO-15 ~RDY in | ||
1275 | GPIO-16 TCK out | ||
1276 | GPIO-17 TDO in | ||
1277 | GPIO-18 TDI out | ||
1278 | */ | ||
1279 | cx_set(GP0_IO, 0x00060000); /* GPIO-1,2 as out */ | ||
1280 | /* GPIO-0 as INT, reset & TMS low */ | ||
1281 | cx_clear(GP0_IO, 0x00010006); | ||
1282 | mdelay(100);/* reset delay */ | ||
1283 | cx_set(GP0_IO, 0x00000004); /* reset high */ | ||
1284 | cx_write(MC417_CTL, 0x00000037);/* enable GPIO-3..18 pins */ | ||
1285 | /* GPIO-17 is TDO in, GPIO-15 is ~RDY in, rest is out */ | ||
1286 | cx_write(MC417_OEN, 0x00005000); | ||
1287 | /* ~RD, ~WR high; ADDR low; ~CS high */ | ||
1288 | cx_write(MC417_RWD, 0x00000d00); | ||
1289 | /* enable irq */ | ||
1290 | cx_write(GPIO_ISM, 0x00000000);/* INTERRUPTS active low*/ | ||
1291 | break; | ||
1292 | } | ||
1293 | } | ||
1294 | |||
1295 | int cx23885_ir_init(struct cx23885_dev *dev) | ||
1296 | { | ||
1297 | static struct v4l2_subdev_io_pin_config ir_rxtx_pin_cfg[] = { | ||
1298 | { | ||
1299 | .flags = V4L2_SUBDEV_IO_PIN_INPUT, | ||
1300 | .pin = CX23885_PIN_IR_RX_GPIO19, | ||
1301 | .function = CX23885_PAD_IR_RX, | ||
1302 | .value = 0, | ||
1303 | .strength = CX25840_PIN_DRIVE_MEDIUM, | ||
1304 | }, { | ||
1305 | .flags = V4L2_SUBDEV_IO_PIN_OUTPUT, | ||
1306 | .pin = CX23885_PIN_IR_TX_GPIO20, | ||
1307 | .function = CX23885_PAD_IR_TX, | ||
1308 | .value = 0, | ||
1309 | .strength = CX25840_PIN_DRIVE_MEDIUM, | ||
1310 | } | ||
1311 | }; | ||
1312 | const size_t ir_rxtx_pin_cfg_count = ARRAY_SIZE(ir_rxtx_pin_cfg); | ||
1313 | |||
1314 | static struct v4l2_subdev_io_pin_config ir_rx_pin_cfg[] = { | ||
1315 | { | ||
1316 | .flags = V4L2_SUBDEV_IO_PIN_INPUT, | ||
1317 | .pin = CX23885_PIN_IR_RX_GPIO19, | ||
1318 | .function = CX23885_PAD_IR_RX, | ||
1319 | .value = 0, | ||
1320 | .strength = CX25840_PIN_DRIVE_MEDIUM, | ||
1321 | } | ||
1322 | }; | ||
1323 | const size_t ir_rx_pin_cfg_count = ARRAY_SIZE(ir_rx_pin_cfg); | ||
1324 | |||
1325 | struct v4l2_subdev_ir_parameters params; | ||
1326 | int ret = 0; | ||
1327 | switch (dev->board) { | ||
1328 | case CX23885_BOARD_HAUPPAUGE_HVR1500: | ||
1329 | case CX23885_BOARD_HAUPPAUGE_HVR1500Q: | ||
1330 | case CX23885_BOARD_HAUPPAUGE_HVR1800: | ||
1331 | case CX23885_BOARD_HAUPPAUGE_HVR1200: | ||
1332 | case CX23885_BOARD_HAUPPAUGE_HVR1400: | ||
1333 | case CX23885_BOARD_HAUPPAUGE_HVR1275: | ||
1334 | case CX23885_BOARD_HAUPPAUGE_HVR1255: | ||
1335 | case CX23885_BOARD_HAUPPAUGE_HVR1255_22111: | ||
1336 | case CX23885_BOARD_HAUPPAUGE_HVR1210: | ||
1337 | /* FIXME: Implement me */ | ||
1338 | break; | ||
1339 | case CX23885_BOARD_HAUPPAUGE_HVR1270: | ||
1340 | ret = cx23888_ir_probe(dev); | ||
1341 | if (ret) | ||
1342 | break; | ||
1343 | dev->sd_ir = cx23885_find_hw(dev, CX23885_HW_888_IR); | ||
1344 | v4l2_subdev_call(dev->sd_cx25840, core, s_io_pin_config, | ||
1345 | ir_rx_pin_cfg_count, ir_rx_pin_cfg); | ||
1346 | break; | ||
1347 | case CX23885_BOARD_HAUPPAUGE_HVR1850: | ||
1348 | case CX23885_BOARD_HAUPPAUGE_HVR1290: | ||
1349 | ret = cx23888_ir_probe(dev); | ||
1350 | if (ret) | ||
1351 | break; | ||
1352 | dev->sd_ir = cx23885_find_hw(dev, CX23885_HW_888_IR); | ||
1353 | v4l2_subdev_call(dev->sd_cx25840, core, s_io_pin_config, | ||
1354 | ir_rxtx_pin_cfg_count, ir_rxtx_pin_cfg); | ||
1355 | /* | ||
1356 | * For these boards we need to invert the Tx output via the | ||
1357 | * IR controller to have the LED off while idle | ||
1358 | */ | ||
1359 | v4l2_subdev_call(dev->sd_ir, ir, tx_g_parameters, ¶ms); | ||
1360 | params.enable = false; | ||
1361 | params.shutdown = false; | ||
1362 | params.invert_level = true; | ||
1363 | v4l2_subdev_call(dev->sd_ir, ir, tx_s_parameters, ¶ms); | ||
1364 | params.shutdown = true; | ||
1365 | v4l2_subdev_call(dev->sd_ir, ir, tx_s_parameters, ¶ms); | ||
1366 | break; | ||
1367 | case CX23885_BOARD_TERRATEC_CINERGY_T_PCIE_DUAL: | ||
1368 | case CX23885_BOARD_TEVII_S470: | ||
1369 | if (!enable_885_ir) | ||
1370 | break; | ||
1371 | dev->sd_ir = cx23885_find_hw(dev, CX23885_HW_AV_CORE); | ||
1372 | if (dev->sd_ir == NULL) { | ||
1373 | ret = -ENODEV; | ||
1374 | break; | ||
1375 | } | ||
1376 | v4l2_subdev_call(dev->sd_cx25840, core, s_io_pin_config, | ||
1377 | ir_rx_pin_cfg_count, ir_rx_pin_cfg); | ||
1378 | break; | ||
1379 | case CX23885_BOARD_HAUPPAUGE_HVR1250: | ||
1380 | if (!enable_885_ir) | ||
1381 | break; | ||
1382 | dev->sd_ir = cx23885_find_hw(dev, CX23885_HW_AV_CORE); | ||
1383 | if (dev->sd_ir == NULL) { | ||
1384 | ret = -ENODEV; | ||
1385 | break; | ||
1386 | } | ||
1387 | v4l2_subdev_call(dev->sd_cx25840, core, s_io_pin_config, | ||
1388 | ir_rxtx_pin_cfg_count, ir_rxtx_pin_cfg); | ||
1389 | break; | ||
1390 | case CX23885_BOARD_DVICO_FUSIONHDTV_DVB_T_DUAL_EXP: | ||
1391 | request_module("ir-kbd-i2c"); | ||
1392 | break; | ||
1393 | } | ||
1394 | |||
1395 | return ret; | ||
1396 | } | ||
1397 | |||
1398 | void cx23885_ir_fini(struct cx23885_dev *dev) | ||
1399 | { | ||
1400 | switch (dev->board) { | ||
1401 | case CX23885_BOARD_HAUPPAUGE_HVR1270: | ||
1402 | case CX23885_BOARD_HAUPPAUGE_HVR1850: | ||
1403 | case CX23885_BOARD_HAUPPAUGE_HVR1290: | ||
1404 | cx23885_irq_remove(dev, PCI_MSK_IR); | ||
1405 | cx23888_ir_remove(dev); | ||
1406 | dev->sd_ir = NULL; | ||
1407 | break; | ||
1408 | case CX23885_BOARD_TERRATEC_CINERGY_T_PCIE_DUAL: | ||
1409 | case CX23885_BOARD_TEVII_S470: | ||
1410 | case CX23885_BOARD_HAUPPAUGE_HVR1250: | ||
1411 | cx23885_irq_remove(dev, PCI_MSK_AV_CORE); | ||
1412 | /* sd_ir is a duplicate pointer to the AV Core, just clear it */ | ||
1413 | dev->sd_ir = NULL; | ||
1414 | break; | ||
1415 | } | ||
1416 | } | ||
1417 | |||
1418 | int netup_jtag_io(void *device, int tms, int tdi, int read_tdo) | ||
1419 | { | ||
1420 | int data; | ||
1421 | int tdo = 0; | ||
1422 | struct cx23885_dev *dev = (struct cx23885_dev *)device; | ||
1423 | /*TMS*/ | ||
1424 | data = ((cx_read(GP0_IO)) & (~0x00000002)); | ||
1425 | data |= (tms ? 0x00020002 : 0x00020000); | ||
1426 | cx_write(GP0_IO, data); | ||
1427 | |||
1428 | /*TDI*/ | ||
1429 | data = ((cx_read(MC417_RWD)) & (~0x0000a000)); | ||
1430 | data |= (tdi ? 0x00008000 : 0); | ||
1431 | cx_write(MC417_RWD, data); | ||
1432 | if (read_tdo) | ||
1433 | tdo = (data & 0x00004000) ? 1 : 0; /*TDO*/ | ||
1434 | |||
1435 | cx_write(MC417_RWD, data | 0x00002000); | ||
1436 | udelay(1); | ||
1437 | /*TCK*/ | ||
1438 | cx_write(MC417_RWD, data); | ||
1439 | |||
1440 | return tdo; | ||
1441 | } | ||
1442 | |||
1443 | void cx23885_ir_pci_int_enable(struct cx23885_dev *dev) | ||
1444 | { | ||
1445 | switch (dev->board) { | ||
1446 | case CX23885_BOARD_HAUPPAUGE_HVR1270: | ||
1447 | case CX23885_BOARD_HAUPPAUGE_HVR1850: | ||
1448 | case CX23885_BOARD_HAUPPAUGE_HVR1290: | ||
1449 | if (dev->sd_ir) | ||
1450 | cx23885_irq_add_enable(dev, PCI_MSK_IR); | ||
1451 | break; | ||
1452 | case CX23885_BOARD_TERRATEC_CINERGY_T_PCIE_DUAL: | ||
1453 | case CX23885_BOARD_TEVII_S470: | ||
1454 | case CX23885_BOARD_HAUPPAUGE_HVR1250: | ||
1455 | if (dev->sd_ir) | ||
1456 | cx23885_irq_add_enable(dev, PCI_MSK_AV_CORE); | ||
1457 | break; | ||
1458 | } | ||
1459 | } | ||
1460 | |||
1461 | void cx23885_card_setup(struct cx23885_dev *dev) | ||
1462 | { | ||
1463 | struct cx23885_tsport *ts1 = &dev->ts1; | ||
1464 | struct cx23885_tsport *ts2 = &dev->ts2; | ||
1465 | |||
1466 | static u8 eeprom[256]; | ||
1467 | |||
1468 | if (dev->i2c_bus[0].i2c_rc == 0) { | ||
1469 | dev->i2c_bus[0].i2c_client.addr = 0xa0 >> 1; | ||
1470 | tveeprom_read(&dev->i2c_bus[0].i2c_client, | ||
1471 | eeprom, sizeof(eeprom)); | ||
1472 | } | ||
1473 | |||
1474 | switch (dev->board) { | ||
1475 | case CX23885_BOARD_HAUPPAUGE_HVR1250: | ||
1476 | if (dev->i2c_bus[0].i2c_rc == 0) { | ||
1477 | if (eeprom[0x80] != 0x84) | ||
1478 | hauppauge_eeprom(dev, eeprom+0xc0); | ||
1479 | else | ||
1480 | hauppauge_eeprom(dev, eeprom+0x80); | ||
1481 | } | ||
1482 | break; | ||
1483 | case CX23885_BOARD_HAUPPAUGE_HVR1500: | ||
1484 | case CX23885_BOARD_HAUPPAUGE_HVR1500Q: | ||
1485 | case CX23885_BOARD_HAUPPAUGE_HVR1400: | ||
1486 | if (dev->i2c_bus[0].i2c_rc == 0) | ||
1487 | hauppauge_eeprom(dev, eeprom+0x80); | ||
1488 | break; | ||
1489 | case CX23885_BOARD_HAUPPAUGE_HVR1800: | ||
1490 | case CX23885_BOARD_HAUPPAUGE_HVR1800lp: | ||
1491 | case CX23885_BOARD_HAUPPAUGE_HVR1200: | ||
1492 | case CX23885_BOARD_HAUPPAUGE_HVR1700: | ||
1493 | case CX23885_BOARD_HAUPPAUGE_HVR1270: | ||
1494 | case CX23885_BOARD_HAUPPAUGE_HVR1275: | ||
1495 | case CX23885_BOARD_HAUPPAUGE_HVR1255: | ||
1496 | case CX23885_BOARD_HAUPPAUGE_HVR1255_22111: | ||
1497 | case CX23885_BOARD_HAUPPAUGE_HVR1210: | ||
1498 | case CX23885_BOARD_HAUPPAUGE_HVR1850: | ||
1499 | case CX23885_BOARD_HAUPPAUGE_HVR1290: | ||
1500 | if (dev->i2c_bus[0].i2c_rc == 0) | ||
1501 | hauppauge_eeprom(dev, eeprom+0xc0); | ||
1502 | break; | ||
1503 | } | ||
1504 | |||
1505 | switch (dev->board) { | ||
1506 | case CX23885_BOARD_DVICO_FUSIONHDTV_7_DUAL_EXP: | ||
1507 | case CX23885_BOARD_DVICO_FUSIONHDTV_DVB_T_DUAL_EXP: | ||
1508 | ts2->gen_ctrl_val = 0xc; /* Serial bus + punctured clock */ | ||
1509 | ts2->ts_clk_en_val = 0x1; /* Enable TS_CLK */ | ||
1510 | ts2->src_sel_val = CX23885_SRC_SEL_PARALLEL_MPEG_VIDEO; | ||
1511 | /* break omitted intentionally */ | ||
1512 | case CX23885_BOARD_DVICO_FUSIONHDTV_5_EXP: | ||
1513 | ts1->gen_ctrl_val = 0xc; /* Serial bus + punctured clock */ | ||
1514 | ts1->ts_clk_en_val = 0x1; /* Enable TS_CLK */ | ||
1515 | ts1->src_sel_val = CX23885_SRC_SEL_PARALLEL_MPEG_VIDEO; | ||
1516 | break; | ||
1517 | case CX23885_BOARD_HAUPPAUGE_HVR1850: | ||
1518 | case CX23885_BOARD_HAUPPAUGE_HVR1800: | ||
1519 | /* Defaults for VID B - Analog encoder */ | ||
1520 | /* DREQ_POL, SMODE, PUNC_CLK, MCLK_POL Serial bus + punc clk */ | ||
1521 | ts1->gen_ctrl_val = 0x10e; | ||
1522 | ts1->ts_clk_en_val = 0x1; /* Enable TS_CLK */ | ||
1523 | ts1->src_sel_val = CX23885_SRC_SEL_PARALLEL_MPEG_VIDEO; | ||
1524 | |||
1525 | /* APB_TSVALERR_POL (active low)*/ | ||
1526 | ts1->vld_misc_val = 0x2000; | ||
1527 | ts1->hw_sop_ctrl_val = (0x47 << 16 | 188 << 4 | 0xc); | ||
1528 | cx_write(0x130184, 0xc); | ||
1529 | |||
1530 | /* Defaults for VID C */ | ||
1531 | ts2->gen_ctrl_val = 0xc; /* Serial bus + punctured clock */ | ||
1532 | ts2->ts_clk_en_val = 0x1; /* Enable TS_CLK */ | ||
1533 | ts2->src_sel_val = CX23885_SRC_SEL_PARALLEL_MPEG_VIDEO; | ||
1534 | break; | ||
1535 | case CX23885_BOARD_TBS_6920: | ||
1536 | ts1->gen_ctrl_val = 0x4; /* Parallel */ | ||
1537 | ts1->ts_clk_en_val = 0x1; /* Enable TS_CLK */ | ||
1538 | ts1->src_sel_val = CX23885_SRC_SEL_PARALLEL_MPEG_VIDEO; | ||
1539 | break; | ||
1540 | case CX23885_BOARD_TEVII_S470: | ||
1541 | case CX23885_BOARD_TEVII_S471: | ||
1542 | case CX23885_BOARD_DVBWORLD_2005: | ||
1543 | ts1->gen_ctrl_val = 0x5; /* Parallel */ | ||
1544 | ts1->ts_clk_en_val = 0x1; /* Enable TS_CLK */ | ||
1545 | ts1->src_sel_val = CX23885_SRC_SEL_PARALLEL_MPEG_VIDEO; | ||
1546 | break; | ||
1547 | case CX23885_BOARD_NETUP_DUAL_DVBS2_CI: | ||
1548 | case CX23885_BOARD_NETUP_DUAL_DVB_T_C_CI_RF: | ||
1549 | case CX23885_BOARD_TERRATEC_CINERGY_T_PCIE_DUAL: | ||
1550 | ts1->gen_ctrl_val = 0xc; /* Serial bus + punctured clock */ | ||
1551 | ts1->ts_clk_en_val = 0x1; /* Enable TS_CLK */ | ||
1552 | ts1->src_sel_val = CX23885_SRC_SEL_PARALLEL_MPEG_VIDEO; | ||
1553 | ts2->gen_ctrl_val = 0xc; /* Serial bus + punctured clock */ | ||
1554 | ts2->ts_clk_en_val = 0x1; /* Enable TS_CLK */ | ||
1555 | ts2->src_sel_val = CX23885_SRC_SEL_PARALLEL_MPEG_VIDEO; | ||
1556 | break; | ||
1557 | case CX23885_BOARD_MYGICA_X8506: | ||
1558 | case CX23885_BOARD_MAGICPRO_PROHDTVE2: | ||
1559 | ts1->gen_ctrl_val = 0x5; /* Parallel */ | ||
1560 | ts1->ts_clk_en_val = 0x1; /* Enable TS_CLK */ | ||
1561 | ts1->src_sel_val = CX23885_SRC_SEL_PARALLEL_MPEG_VIDEO; | ||
1562 | break; | ||
1563 | case CX23885_BOARD_MYGICA_X8558PRO: | ||
1564 | ts1->gen_ctrl_val = 0x5; /* Parallel */ | ||
1565 | ts1->ts_clk_en_val = 0x1; /* Enable TS_CLK */ | ||
1566 | ts1->src_sel_val = CX23885_SRC_SEL_PARALLEL_MPEG_VIDEO; | ||
1567 | ts2->gen_ctrl_val = 0xc; /* Serial bus + punctured clock */ | ||
1568 | ts2->ts_clk_en_val = 0x1; /* Enable TS_CLK */ | ||
1569 | ts2->src_sel_val = CX23885_SRC_SEL_PARALLEL_MPEG_VIDEO; | ||
1570 | break; | ||
1571 | case CX23885_BOARD_HAUPPAUGE_HVR1250: | ||
1572 | case CX23885_BOARD_HAUPPAUGE_HVR1500: | ||
1573 | case CX23885_BOARD_HAUPPAUGE_HVR1500Q: | ||
1574 | case CX23885_BOARD_HAUPPAUGE_HVR1800lp: | ||
1575 | case CX23885_BOARD_HAUPPAUGE_HVR1200: | ||
1576 | case CX23885_BOARD_HAUPPAUGE_HVR1700: | ||
1577 | case CX23885_BOARD_HAUPPAUGE_HVR1400: | ||
1578 | case CX23885_BOARD_LEADTEK_WINFAST_PXDVR3200_H: | ||
1579 | case CX23885_BOARD_LEADTEK_WINFAST_PXDVR3200_H_XC4000: | ||
1580 | case CX23885_BOARD_COMPRO_VIDEOMATE_E650F: | ||
1581 | case CX23885_BOARD_HAUPPAUGE_HVR1270: | ||
1582 | case CX23885_BOARD_HAUPPAUGE_HVR1275: | ||
1583 | case CX23885_BOARD_HAUPPAUGE_HVR1255: | ||
1584 | case CX23885_BOARD_HAUPPAUGE_HVR1255_22111: | ||
1585 | case CX23885_BOARD_HAUPPAUGE_HVR1210: | ||
1586 | case CX23885_BOARD_COMPRO_VIDEOMATE_E800: | ||
1587 | case CX23885_BOARD_HAUPPAUGE_HVR1290: | ||
1588 | case CX23885_BOARD_GOTVIEW_X5_3D_HYBRID: | ||
1589 | default: | ||
1590 | ts2->gen_ctrl_val = 0xc; /* Serial bus + punctured clock */ | ||
1591 | ts2->ts_clk_en_val = 0x1; /* Enable TS_CLK */ | ||
1592 | ts2->src_sel_val = CX23885_SRC_SEL_PARALLEL_MPEG_VIDEO; | ||
1593 | } | ||
1594 | |||
1595 | /* Certain boards support analog, or require the avcore to be | ||
1596 | * loaded, ensure this happens. | ||
1597 | */ | ||
1598 | switch (dev->board) { | ||
1599 | case CX23885_BOARD_TEVII_S470: | ||
1600 | /* Currently only enabled for the integrated IR controller */ | ||
1601 | if (!enable_885_ir) | ||
1602 | break; | ||
1603 | case CX23885_BOARD_HAUPPAUGE_HVR1250: | ||
1604 | case CX23885_BOARD_HAUPPAUGE_HVR1800: | ||
1605 | case CX23885_BOARD_HAUPPAUGE_HVR1800lp: | ||
1606 | case CX23885_BOARD_HAUPPAUGE_HVR1700: | ||
1607 | case CX23885_BOARD_LEADTEK_WINFAST_PXDVR3200_H: | ||
1608 | case CX23885_BOARD_LEADTEK_WINFAST_PXDVR3200_H_XC4000: | ||
1609 | case CX23885_BOARD_COMPRO_VIDEOMATE_E650F: | ||
1610 | case CX23885_BOARD_NETUP_DUAL_DVBS2_CI: | ||
1611 | case CX23885_BOARD_NETUP_DUAL_DVB_T_C_CI_RF: | ||
1612 | case CX23885_BOARD_COMPRO_VIDEOMATE_E800: | ||
1613 | case CX23885_BOARD_HAUPPAUGE_HVR1255: | ||
1614 | case CX23885_BOARD_HAUPPAUGE_HVR1255_22111: | ||
1615 | case CX23885_BOARD_HAUPPAUGE_HVR1270: | ||
1616 | case CX23885_BOARD_HAUPPAUGE_HVR1850: | ||
1617 | case CX23885_BOARD_MYGICA_X8506: | ||
1618 | case CX23885_BOARD_MAGICPRO_PROHDTVE2: | ||
1619 | case CX23885_BOARD_HAUPPAUGE_HVR1290: | ||
1620 | case CX23885_BOARD_LEADTEK_WINFAST_PXTV1200: | ||
1621 | case CX23885_BOARD_GOTVIEW_X5_3D_HYBRID: | ||
1622 | case CX23885_BOARD_HAUPPAUGE_HVR1500: | ||
1623 | case CX23885_BOARD_MPX885: | ||
1624 | case CX23885_BOARD_MYGICA_X8507: | ||
1625 | case CX23885_BOARD_TERRATEC_CINERGY_T_PCIE_DUAL: | ||
1626 | dev->sd_cx25840 = v4l2_i2c_new_subdev(&dev->v4l2_dev, | ||
1627 | &dev->i2c_bus[2].i2c_adap, | ||
1628 | "cx25840", 0x88 >> 1, NULL); | ||
1629 | if (dev->sd_cx25840) { | ||
1630 | dev->sd_cx25840->grp_id = CX23885_HW_AV_CORE; | ||
1631 | v4l2_subdev_call(dev->sd_cx25840, core, load_fw); | ||
1632 | } | ||
1633 | break; | ||
1634 | } | ||
1635 | |||
1636 | /* AUX-PLL 27MHz CLK */ | ||
1637 | switch (dev->board) { | ||
1638 | case CX23885_BOARD_NETUP_DUAL_DVBS2_CI: | ||
1639 | netup_initialize(dev); | ||
1640 | break; | ||
1641 | case CX23885_BOARD_NETUP_DUAL_DVB_T_C_CI_RF: { | ||
1642 | int ret; | ||
1643 | const struct firmware *fw; | ||
1644 | const char *filename = "dvb-netup-altera-01.fw"; | ||
1645 | char *action = "configure"; | ||
1646 | static struct netup_card_info cinfo; | ||
1647 | struct altera_config netup_config = { | ||
1648 | .dev = dev, | ||
1649 | .action = action, | ||
1650 | .jtag_io = netup_jtag_io, | ||
1651 | }; | ||
1652 | |||
1653 | netup_initialize(dev); | ||
1654 | |||
1655 | netup_get_card_info(&dev->i2c_bus[0].i2c_adap, &cinfo); | ||
1656 | if (netup_card_rev) | ||
1657 | cinfo.rev = netup_card_rev; | ||
1658 | |||
1659 | switch (cinfo.rev) { | ||
1660 | case 0x4: | ||
1661 | filename = "dvb-netup-altera-04.fw"; | ||
1662 | break; | ||
1663 | default: | ||
1664 | filename = "dvb-netup-altera-01.fw"; | ||
1665 | break; | ||
1666 | } | ||
1667 | printk(KERN_INFO "NetUP card rev=0x%x fw_filename=%s\n", | ||
1668 | cinfo.rev, filename); | ||
1669 | |||
1670 | ret = request_firmware(&fw, filename, &dev->pci->dev); | ||
1671 | if (ret != 0) | ||
1672 | printk(KERN_ERR "did not find the firmware file. (%s) " | ||
1673 | "Please see linux/Documentation/dvb/ for more details " | ||
1674 | "on firmware-problems.", filename); | ||
1675 | else | ||
1676 | altera_init(&netup_config, fw); | ||
1677 | |||
1678 | release_firmware(fw); | ||
1679 | break; | ||
1680 | } | ||
1681 | } | ||
1682 | } | ||
1683 | |||
1684 | /* ------------------------------------------------------------------ */ | ||
diff --git a/drivers/media/pci/cx23885/cx23885-core.c b/drivers/media/pci/cx23885/cx23885-core.c new file mode 100644 index 000000000000..697728f09430 --- /dev/null +++ b/drivers/media/pci/cx23885/cx23885-core.c | |||
@@ -0,0 +1,2234 @@ | |||
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: " 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 = "TV Audio", | ||
159 | .cmds_start = 0x10190, | ||
160 | .ctrl_start = 0x10480, | ||
161 | .cdt = 0x10a00, | ||
162 | .fifo_start = 0x7000, | ||
163 | .fifo_size = 0x1000, | ||
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 = "VID A (VBI)", | ||
210 | .cmds_start = 0x10050, | ||
211 | .ctrl_start = 0x105F0, | ||
212 | .cdt = 0x10810, | ||
213 | .fifo_start = 0x3000, | ||
214 | .fifo_size = 0x1000, | ||
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 = "TV Audio", | ||
270 | .cmds_start = 0x10190, | ||
271 | .ctrl_start = 0x106B0, | ||
272 | .cdt = 0x10930, | ||
273 | .fifo_start = 0x7000, | ||
274 | .fifo_size = 0x1000, | ||
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 | switch (dev->board) { | ||
1050 | case CX23885_BOARD_TEVII_S470: | ||
1051 | case CX23885_BOARD_TEVII_S471: | ||
1052 | cx_clear(RDR_RDRCTL1, 1 << 8); | ||
1053 | break; | ||
1054 | } | ||
1055 | |||
1056 | return 0; | ||
1057 | } | ||
1058 | |||
1059 | static void cx23885_dev_unregister(struct cx23885_dev *dev) | ||
1060 | { | ||
1061 | release_mem_region(pci_resource_start(dev->pci, 0), | ||
1062 | pci_resource_len(dev->pci, 0)); | ||
1063 | |||
1064 | if (!atomic_dec_and_test(&dev->refcount)) | ||
1065 | return; | ||
1066 | |||
1067 | if (cx23885_boards[dev->board].porta == CX23885_ANALOG_VIDEO) | ||
1068 | cx23885_video_unregister(dev); | ||
1069 | |||
1070 | if (cx23885_boards[dev->board].portb == CX23885_MPEG_DVB) | ||
1071 | cx23885_dvb_unregister(&dev->ts1); | ||
1072 | |||
1073 | if (cx23885_boards[dev->board].portb == CX23885_MPEG_ENCODER) | ||
1074 | cx23885_417_unregister(dev); | ||
1075 | |||
1076 | if (cx23885_boards[dev->board].portc == CX23885_MPEG_DVB) | ||
1077 | cx23885_dvb_unregister(&dev->ts2); | ||
1078 | |||
1079 | if (cx23885_boards[dev->board].portc == CX23885_MPEG_ENCODER) | ||
1080 | cx23885_417_unregister(dev); | ||
1081 | |||
1082 | cx23885_i2c_unregister(&dev->i2c_bus[2]); | ||
1083 | cx23885_i2c_unregister(&dev->i2c_bus[1]); | ||
1084 | cx23885_i2c_unregister(&dev->i2c_bus[0]); | ||
1085 | |||
1086 | iounmap(dev->lmmio); | ||
1087 | } | ||
1088 | |||
1089 | static __le32 *cx23885_risc_field(__le32 *rp, struct scatterlist *sglist, | ||
1090 | unsigned int offset, u32 sync_line, | ||
1091 | unsigned int bpl, unsigned int padding, | ||
1092 | unsigned int lines, unsigned int lpi) | ||
1093 | { | ||
1094 | struct scatterlist *sg; | ||
1095 | unsigned int line, todo, sol; | ||
1096 | |||
1097 | /* sync instruction */ | ||
1098 | if (sync_line != NO_SYNC_LINE) | ||
1099 | *(rp++) = cpu_to_le32(RISC_RESYNC | sync_line); | ||
1100 | |||
1101 | /* scan lines */ | ||
1102 | sg = sglist; | ||
1103 | for (line = 0; line < lines; line++) { | ||
1104 | while (offset && offset >= sg_dma_len(sg)) { | ||
1105 | offset -= sg_dma_len(sg); | ||
1106 | sg++; | ||
1107 | } | ||
1108 | |||
1109 | if (lpi && line > 0 && !(line % lpi)) | ||
1110 | sol = RISC_SOL | RISC_IRQ1 | RISC_CNT_INC; | ||
1111 | else | ||
1112 | sol = RISC_SOL; | ||
1113 | |||
1114 | if (bpl <= sg_dma_len(sg)-offset) { | ||
1115 | /* fits into current chunk */ | ||
1116 | *(rp++) = cpu_to_le32(RISC_WRITE|sol|RISC_EOL|bpl); | ||
1117 | *(rp++) = cpu_to_le32(sg_dma_address(sg)+offset); | ||
1118 | *(rp++) = cpu_to_le32(0); /* bits 63-32 */ | ||
1119 | offset += bpl; | ||
1120 | } else { | ||
1121 | /* scanline needs to be split */ | ||
1122 | todo = bpl; | ||
1123 | *(rp++) = cpu_to_le32(RISC_WRITE|sol| | ||
1124 | (sg_dma_len(sg)-offset)); | ||
1125 | *(rp++) = cpu_to_le32(sg_dma_address(sg)+offset); | ||
1126 | *(rp++) = cpu_to_le32(0); /* bits 63-32 */ | ||
1127 | todo -= (sg_dma_len(sg)-offset); | ||
1128 | offset = 0; | ||
1129 | sg++; | ||
1130 | while (todo > sg_dma_len(sg)) { | ||
1131 | *(rp++) = cpu_to_le32(RISC_WRITE| | ||
1132 | sg_dma_len(sg)); | ||
1133 | *(rp++) = cpu_to_le32(sg_dma_address(sg)); | ||
1134 | *(rp++) = cpu_to_le32(0); /* bits 63-32 */ | ||
1135 | todo -= sg_dma_len(sg); | ||
1136 | sg++; | ||
1137 | } | ||
1138 | *(rp++) = cpu_to_le32(RISC_WRITE|RISC_EOL|todo); | ||
1139 | *(rp++) = cpu_to_le32(sg_dma_address(sg)); | ||
1140 | *(rp++) = cpu_to_le32(0); /* bits 63-32 */ | ||
1141 | offset += todo; | ||
1142 | } | ||
1143 | offset += padding; | ||
1144 | } | ||
1145 | |||
1146 | return rp; | ||
1147 | } | ||
1148 | |||
1149 | int cx23885_risc_buffer(struct pci_dev *pci, struct btcx_riscmem *risc, | ||
1150 | struct scatterlist *sglist, unsigned int top_offset, | ||
1151 | unsigned int bottom_offset, unsigned int bpl, | ||
1152 | unsigned int padding, unsigned int lines) | ||
1153 | { | ||
1154 | u32 instructions, fields; | ||
1155 | __le32 *rp; | ||
1156 | int rc; | ||
1157 | |||
1158 | fields = 0; | ||
1159 | if (UNSET != top_offset) | ||
1160 | fields++; | ||
1161 | if (UNSET != bottom_offset) | ||
1162 | fields++; | ||
1163 | |||
1164 | /* estimate risc mem: worst case is one write per page border + | ||
1165 | one write per scan line + syncs + jump (all 2 dwords). Padding | ||
1166 | can cause next bpl to start close to a page border. First DMA | ||
1167 | region may be smaller than PAGE_SIZE */ | ||
1168 | /* write and jump need and extra dword */ | ||
1169 | instructions = fields * (1 + ((bpl + padding) * lines) | ||
1170 | / PAGE_SIZE + lines); | ||
1171 | instructions += 2; | ||
1172 | rc = btcx_riscmem_alloc(pci, risc, instructions*12); | ||
1173 | if (rc < 0) | ||
1174 | return rc; | ||
1175 | |||
1176 | /* write risc instructions */ | ||
1177 | rp = risc->cpu; | ||
1178 | if (UNSET != top_offset) | ||
1179 | rp = cx23885_risc_field(rp, sglist, top_offset, 0, | ||
1180 | bpl, padding, lines, 0); | ||
1181 | if (UNSET != bottom_offset) | ||
1182 | rp = cx23885_risc_field(rp, sglist, bottom_offset, 0x200, | ||
1183 | bpl, padding, lines, 0); | ||
1184 | |||
1185 | /* save pointer to jmp instruction address */ | ||
1186 | risc->jmp = rp; | ||
1187 | BUG_ON((risc->jmp - risc->cpu + 2) * sizeof(*risc->cpu) > risc->size); | ||
1188 | return 0; | ||
1189 | } | ||
1190 | |||
1191 | int cx23885_risc_databuffer(struct pci_dev *pci, | ||
1192 | struct btcx_riscmem *risc, | ||
1193 | struct scatterlist *sglist, | ||
1194 | unsigned int bpl, | ||
1195 | unsigned int lines, unsigned int lpi) | ||
1196 | { | ||
1197 | u32 instructions; | ||
1198 | __le32 *rp; | ||
1199 | int rc; | ||
1200 | |||
1201 | /* estimate risc mem: worst case is one write per page border + | ||
1202 | one write per scan line + syncs + jump (all 2 dwords). Here | ||
1203 | there is no padding and no sync. First DMA region may be smaller | ||
1204 | than PAGE_SIZE */ | ||
1205 | /* Jump and write need an extra dword */ | ||
1206 | instructions = 1 + (bpl * lines) / PAGE_SIZE + lines; | ||
1207 | instructions += 1; | ||
1208 | |||
1209 | rc = btcx_riscmem_alloc(pci, risc, instructions*12); | ||
1210 | if (rc < 0) | ||
1211 | return rc; | ||
1212 | |||
1213 | /* write risc instructions */ | ||
1214 | rp = risc->cpu; | ||
1215 | rp = cx23885_risc_field(rp, sglist, 0, NO_SYNC_LINE, | ||
1216 | bpl, 0, lines, lpi); | ||
1217 | |||
1218 | /* save pointer to jmp instruction address */ | ||
1219 | risc->jmp = rp; | ||
1220 | BUG_ON((risc->jmp - risc->cpu + 2) * sizeof(*risc->cpu) > risc->size); | ||
1221 | return 0; | ||
1222 | } | ||
1223 | |||
1224 | int cx23885_risc_vbibuffer(struct pci_dev *pci, struct btcx_riscmem *risc, | ||
1225 | struct scatterlist *sglist, unsigned int top_offset, | ||
1226 | unsigned int bottom_offset, unsigned int bpl, | ||
1227 | unsigned int padding, unsigned int lines) | ||
1228 | { | ||
1229 | u32 instructions, fields; | ||
1230 | __le32 *rp; | ||
1231 | int rc; | ||
1232 | |||
1233 | fields = 0; | ||
1234 | if (UNSET != top_offset) | ||
1235 | fields++; | ||
1236 | if (UNSET != bottom_offset) | ||
1237 | fields++; | ||
1238 | |||
1239 | /* estimate risc mem: worst case is one write per page border + | ||
1240 | one write per scan line + syncs + jump (all 2 dwords). Padding | ||
1241 | can cause next bpl to start close to a page border. First DMA | ||
1242 | region may be smaller than PAGE_SIZE */ | ||
1243 | /* write and jump need and extra dword */ | ||
1244 | instructions = fields * (1 + ((bpl + padding) * lines) | ||
1245 | / PAGE_SIZE + lines); | ||
1246 | instructions += 2; | ||
1247 | rc = btcx_riscmem_alloc(pci, risc, instructions*12); | ||
1248 | if (rc < 0) | ||
1249 | return rc; | ||
1250 | /* write risc instructions */ | ||
1251 | rp = risc->cpu; | ||
1252 | |||
1253 | /* Sync to line 6, so US CC line 21 will appear in line '12' | ||
1254 | * in the userland vbi payload */ | ||
1255 | if (UNSET != top_offset) | ||
1256 | rp = cx23885_risc_field(rp, sglist, top_offset, 6, | ||
1257 | bpl, padding, lines, 0); | ||
1258 | |||
1259 | if (UNSET != bottom_offset) | ||
1260 | rp = cx23885_risc_field(rp, sglist, bottom_offset, 0x207, | ||
1261 | bpl, padding, lines, 0); | ||
1262 | |||
1263 | |||
1264 | |||
1265 | /* save pointer to jmp instruction address */ | ||
1266 | risc->jmp = rp; | ||
1267 | BUG_ON((risc->jmp - risc->cpu + 2) * sizeof(*risc->cpu) > risc->size); | ||
1268 | return 0; | ||
1269 | } | ||
1270 | |||
1271 | |||
1272 | int cx23885_risc_stopper(struct pci_dev *pci, struct btcx_riscmem *risc, | ||
1273 | u32 reg, u32 mask, u32 value) | ||
1274 | { | ||
1275 | __le32 *rp; | ||
1276 | int rc; | ||
1277 | |||
1278 | rc = btcx_riscmem_alloc(pci, risc, 4*16); | ||
1279 | if (rc < 0) | ||
1280 | return rc; | ||
1281 | |||
1282 | /* write risc instructions */ | ||
1283 | rp = risc->cpu; | ||
1284 | *(rp++) = cpu_to_le32(RISC_WRITECR | RISC_IRQ2); | ||
1285 | *(rp++) = cpu_to_le32(reg); | ||
1286 | *(rp++) = cpu_to_le32(value); | ||
1287 | *(rp++) = cpu_to_le32(mask); | ||
1288 | *(rp++) = cpu_to_le32(RISC_JUMP); | ||
1289 | *(rp++) = cpu_to_le32(risc->dma); | ||
1290 | *(rp++) = cpu_to_le32(0); /* bits 63-32 */ | ||
1291 | return 0; | ||
1292 | } | ||
1293 | |||
1294 | void cx23885_free_buffer(struct videobuf_queue *q, struct cx23885_buffer *buf) | ||
1295 | { | ||
1296 | struct videobuf_dmabuf *dma = videobuf_to_dma(&buf->vb); | ||
1297 | |||
1298 | BUG_ON(in_interrupt()); | ||
1299 | videobuf_waiton(q, &buf->vb, 0, 0); | ||
1300 | videobuf_dma_unmap(q->dev, dma); | ||
1301 | videobuf_dma_free(dma); | ||
1302 | btcx_riscmem_free(to_pci_dev(q->dev), &buf->risc); | ||
1303 | buf->vb.state = VIDEOBUF_NEEDS_INIT; | ||
1304 | } | ||
1305 | |||
1306 | static void cx23885_tsport_reg_dump(struct cx23885_tsport *port) | ||
1307 | { | ||
1308 | struct cx23885_dev *dev = port->dev; | ||
1309 | |||
1310 | dprintk(1, "%s() Register Dump\n", __func__); | ||
1311 | dprintk(1, "%s() DEV_CNTRL2 0x%08X\n", __func__, | ||
1312 | cx_read(DEV_CNTRL2)); | ||
1313 | dprintk(1, "%s() PCI_INT_MSK 0x%08X\n", __func__, | ||
1314 | cx23885_irq_get_mask(dev)); | ||
1315 | dprintk(1, "%s() AUD_INT_INT_MSK 0x%08X\n", __func__, | ||
1316 | cx_read(AUDIO_INT_INT_MSK)); | ||
1317 | dprintk(1, "%s() AUD_INT_DMA_CTL 0x%08X\n", __func__, | ||
1318 | cx_read(AUD_INT_DMA_CTL)); | ||
1319 | dprintk(1, "%s() AUD_EXT_INT_MSK 0x%08X\n", __func__, | ||
1320 | cx_read(AUDIO_EXT_INT_MSK)); | ||
1321 | dprintk(1, "%s() AUD_EXT_DMA_CTL 0x%08X\n", __func__, | ||
1322 | cx_read(AUD_EXT_DMA_CTL)); | ||
1323 | dprintk(1, "%s() PAD_CTRL 0x%08X\n", __func__, | ||
1324 | cx_read(PAD_CTRL)); | ||
1325 | dprintk(1, "%s() ALT_PIN_OUT_SEL 0x%08X\n", __func__, | ||
1326 | cx_read(ALT_PIN_OUT_SEL)); | ||
1327 | dprintk(1, "%s() GPIO2 0x%08X\n", __func__, | ||
1328 | cx_read(GPIO2)); | ||
1329 | dprintk(1, "%s() gpcnt(0x%08X) 0x%08X\n", __func__, | ||
1330 | port->reg_gpcnt, cx_read(port->reg_gpcnt)); | ||
1331 | dprintk(1, "%s() gpcnt_ctl(0x%08X) 0x%08x\n", __func__, | ||
1332 | port->reg_gpcnt_ctl, cx_read(port->reg_gpcnt_ctl)); | ||
1333 | dprintk(1, "%s() dma_ctl(0x%08X) 0x%08x\n", __func__, | ||
1334 | port->reg_dma_ctl, cx_read(port->reg_dma_ctl)); | ||
1335 | if (port->reg_src_sel) | ||
1336 | dprintk(1, "%s() src_sel(0x%08X) 0x%08x\n", __func__, | ||
1337 | port->reg_src_sel, cx_read(port->reg_src_sel)); | ||
1338 | dprintk(1, "%s() lngth(0x%08X) 0x%08x\n", __func__, | ||
1339 | port->reg_lngth, cx_read(port->reg_lngth)); | ||
1340 | dprintk(1, "%s() hw_sop_ctrl(0x%08X) 0x%08x\n", __func__, | ||
1341 | port->reg_hw_sop_ctrl, cx_read(port->reg_hw_sop_ctrl)); | ||
1342 | dprintk(1, "%s() gen_ctrl(0x%08X) 0x%08x\n", __func__, | ||
1343 | port->reg_gen_ctrl, cx_read(port->reg_gen_ctrl)); | ||
1344 | dprintk(1, "%s() bd_pkt_status(0x%08X) 0x%08x\n", __func__, | ||
1345 | port->reg_bd_pkt_status, cx_read(port->reg_bd_pkt_status)); | ||
1346 | dprintk(1, "%s() sop_status(0x%08X) 0x%08x\n", __func__, | ||
1347 | port->reg_sop_status, cx_read(port->reg_sop_status)); | ||
1348 | dprintk(1, "%s() fifo_ovfl_stat(0x%08X) 0x%08x\n", __func__, | ||
1349 | port->reg_fifo_ovfl_stat, cx_read(port->reg_fifo_ovfl_stat)); | ||
1350 | dprintk(1, "%s() vld_misc(0x%08X) 0x%08x\n", __func__, | ||
1351 | port->reg_vld_misc, cx_read(port->reg_vld_misc)); | ||
1352 | dprintk(1, "%s() ts_clk_en(0x%08X) 0x%08x\n", __func__, | ||
1353 | port->reg_ts_clk_en, cx_read(port->reg_ts_clk_en)); | ||
1354 | dprintk(1, "%s() ts_int_msk(0x%08X) 0x%08x\n", __func__, | ||
1355 | port->reg_ts_int_msk, cx_read(port->reg_ts_int_msk)); | ||
1356 | } | ||
1357 | |||
1358 | static int cx23885_start_dma(struct cx23885_tsport *port, | ||
1359 | struct cx23885_dmaqueue *q, | ||
1360 | struct cx23885_buffer *buf) | ||
1361 | { | ||
1362 | struct cx23885_dev *dev = port->dev; | ||
1363 | u32 reg; | ||
1364 | |||
1365 | dprintk(1, "%s() w: %d, h: %d, f: %d\n", __func__, | ||
1366 | buf->vb.width, buf->vb.height, buf->vb.field); | ||
1367 | |||
1368 | /* Stop the fifo and risc engine for this port */ | ||
1369 | cx_clear(port->reg_dma_ctl, port->dma_ctl_val); | ||
1370 | |||
1371 | /* setup fifo + format */ | ||
1372 | cx23885_sram_channel_setup(dev, | ||
1373 | &dev->sram_channels[port->sram_chno], | ||
1374 | port->ts_packet_size, buf->risc.dma); | ||
1375 | if (debug > 5) { | ||
1376 | cx23885_sram_channel_dump(dev, | ||
1377 | &dev->sram_channels[port->sram_chno]); | ||
1378 | cx23885_risc_disasm(port, &buf->risc); | ||
1379 | } | ||
1380 | |||
1381 | /* write TS length to chip */ | ||
1382 | cx_write(port->reg_lngth, buf->vb.width); | ||
1383 | |||
1384 | if ((!(cx23885_boards[dev->board].portb & CX23885_MPEG_DVB)) && | ||
1385 | (!(cx23885_boards[dev->board].portc & CX23885_MPEG_DVB))) { | ||
1386 | printk("%s() Unsupported .portb/c (0x%08x)/(0x%08x)\n", | ||
1387 | __func__, | ||
1388 | cx23885_boards[dev->board].portb, | ||
1389 | cx23885_boards[dev->board].portc); | ||
1390 | return -EINVAL; | ||
1391 | } | ||
1392 | |||
1393 | if (cx23885_boards[dev->board].portb == CX23885_MPEG_ENCODER) | ||
1394 | cx23885_av_clk(dev, 0); | ||
1395 | |||
1396 | udelay(100); | ||
1397 | |||
1398 | /* If the port supports SRC SELECT, configure it */ | ||
1399 | if (port->reg_src_sel) | ||
1400 | cx_write(port->reg_src_sel, port->src_sel_val); | ||
1401 | |||
1402 | cx_write(port->reg_hw_sop_ctrl, port->hw_sop_ctrl_val); | ||
1403 | cx_write(port->reg_ts_clk_en, port->ts_clk_en_val); | ||
1404 | cx_write(port->reg_vld_misc, port->vld_misc_val); | ||
1405 | cx_write(port->reg_gen_ctrl, port->gen_ctrl_val); | ||
1406 | udelay(100); | ||
1407 | |||
1408 | /* NOTE: this is 2 (reserved) for portb, does it matter? */ | ||
1409 | /* reset counter to zero */ | ||
1410 | cx_write(port->reg_gpcnt_ctl, 3); | ||
1411 | q->count = 1; | ||
1412 | |||
1413 | /* Set VIDB pins to input */ | ||
1414 | if (cx23885_boards[dev->board].portb == CX23885_MPEG_DVB) { | ||
1415 | reg = cx_read(PAD_CTRL); | ||
1416 | reg &= ~0x3; /* Clear TS1_OE & TS1_SOP_OE */ | ||
1417 | cx_write(PAD_CTRL, reg); | ||
1418 | } | ||
1419 | |||
1420 | /* Set VIDC pins to input */ | ||
1421 | if (cx23885_boards[dev->board].portc == CX23885_MPEG_DVB) { | ||
1422 | reg = cx_read(PAD_CTRL); | ||
1423 | reg &= ~0x4; /* Clear TS2_SOP_OE */ | ||
1424 | cx_write(PAD_CTRL, reg); | ||
1425 | } | ||
1426 | |||
1427 | if (cx23885_boards[dev->board].portb == CX23885_MPEG_ENCODER) { | ||
1428 | |||
1429 | reg = cx_read(PAD_CTRL); | ||
1430 | reg = reg & ~0x1; /* Clear TS1_OE */ | ||
1431 | |||
1432 | /* FIXME, bit 2 writing here is questionable */ | ||
1433 | /* set TS1_SOP_OE and TS1_OE_HI */ | ||
1434 | reg = reg | 0xa; | ||
1435 | cx_write(PAD_CTRL, reg); | ||
1436 | |||
1437 | /* FIXME and these two registers should be documented. */ | ||
1438 | cx_write(CLK_DELAY, cx_read(CLK_DELAY) | 0x80000011); | ||
1439 | cx_write(ALT_PIN_OUT_SEL, 0x10100045); | ||
1440 | } | ||
1441 | |||
1442 | switch (dev->bridge) { | ||
1443 | case CX23885_BRIDGE_885: | ||
1444 | case CX23885_BRIDGE_887: | ||
1445 | case CX23885_BRIDGE_888: | ||
1446 | /* enable irqs */ | ||
1447 | dprintk(1, "%s() enabling TS int's and DMA\n", __func__); | ||
1448 | cx_set(port->reg_ts_int_msk, port->ts_int_msk_val); | ||
1449 | cx_set(port->reg_dma_ctl, port->dma_ctl_val); | ||
1450 | cx23885_irq_add(dev, port->pci_irqmask); | ||
1451 | cx23885_irq_enable_all(dev); | ||
1452 | break; | ||
1453 | default: | ||
1454 | BUG(); | ||
1455 | } | ||
1456 | |||
1457 | cx_set(DEV_CNTRL2, (1<<5)); /* Enable RISC controller */ | ||
1458 | |||
1459 | if (cx23885_boards[dev->board].portb == CX23885_MPEG_ENCODER) | ||
1460 | cx23885_av_clk(dev, 1); | ||
1461 | |||
1462 | if (debug > 4) | ||
1463 | cx23885_tsport_reg_dump(port); | ||
1464 | |||
1465 | return 0; | ||
1466 | } | ||
1467 | |||
1468 | static int cx23885_stop_dma(struct cx23885_tsport *port) | ||
1469 | { | ||
1470 | struct cx23885_dev *dev = port->dev; | ||
1471 | u32 reg; | ||
1472 | |||
1473 | dprintk(1, "%s()\n", __func__); | ||
1474 | |||
1475 | /* Stop interrupts and DMA */ | ||
1476 | cx_clear(port->reg_ts_int_msk, port->ts_int_msk_val); | ||
1477 | cx_clear(port->reg_dma_ctl, port->dma_ctl_val); | ||
1478 | |||
1479 | if (cx23885_boards[dev->board].portb == CX23885_MPEG_ENCODER) { | ||
1480 | |||
1481 | reg = cx_read(PAD_CTRL); | ||
1482 | |||
1483 | /* Set TS1_OE */ | ||
1484 | reg = reg | 0x1; | ||
1485 | |||
1486 | /* clear TS1_SOP_OE and TS1_OE_HI */ | ||
1487 | reg = reg & ~0xa; | ||
1488 | cx_write(PAD_CTRL, reg); | ||
1489 | cx_write(port->reg_src_sel, 0); | ||
1490 | cx_write(port->reg_gen_ctrl, 8); | ||
1491 | |||
1492 | } | ||
1493 | |||
1494 | if (cx23885_boards[dev->board].portb == CX23885_MPEG_ENCODER) | ||
1495 | cx23885_av_clk(dev, 0); | ||
1496 | |||
1497 | return 0; | ||
1498 | } | ||
1499 | |||
1500 | int cx23885_restart_queue(struct cx23885_tsport *port, | ||
1501 | struct cx23885_dmaqueue *q) | ||
1502 | { | ||
1503 | struct cx23885_dev *dev = port->dev; | ||
1504 | struct cx23885_buffer *buf; | ||
1505 | |||
1506 | dprintk(5, "%s()\n", __func__); | ||
1507 | if (list_empty(&q->active)) { | ||
1508 | struct cx23885_buffer *prev; | ||
1509 | prev = NULL; | ||
1510 | |||
1511 | dprintk(5, "%s() queue is empty\n", __func__); | ||
1512 | |||
1513 | for (;;) { | ||
1514 | if (list_empty(&q->queued)) | ||
1515 | return 0; | ||
1516 | buf = list_entry(q->queued.next, struct cx23885_buffer, | ||
1517 | vb.queue); | ||
1518 | if (NULL == prev) { | ||
1519 | list_del(&buf->vb.queue); | ||
1520 | list_add_tail(&buf->vb.queue, &q->active); | ||
1521 | cx23885_start_dma(port, q, buf); | ||
1522 | buf->vb.state = VIDEOBUF_ACTIVE; | ||
1523 | buf->count = q->count++; | ||
1524 | mod_timer(&q->timeout, jiffies+BUFFER_TIMEOUT); | ||
1525 | dprintk(5, "[%p/%d] restart_queue - f/active\n", | ||
1526 | buf, buf->vb.i); | ||
1527 | |||
1528 | } else if (prev->vb.width == buf->vb.width && | ||
1529 | prev->vb.height == buf->vb.height && | ||
1530 | prev->fmt == buf->fmt) { | ||
1531 | list_del(&buf->vb.queue); | ||
1532 | list_add_tail(&buf->vb.queue, &q->active); | ||
1533 | buf->vb.state = VIDEOBUF_ACTIVE; | ||
1534 | buf->count = q->count++; | ||
1535 | prev->risc.jmp[1] = cpu_to_le32(buf->risc.dma); | ||
1536 | /* 64 bit bits 63-32 */ | ||
1537 | prev->risc.jmp[2] = cpu_to_le32(0); | ||
1538 | dprintk(5, "[%p/%d] restart_queue - m/active\n", | ||
1539 | buf, buf->vb.i); | ||
1540 | } else { | ||
1541 | return 0; | ||
1542 | } | ||
1543 | prev = buf; | ||
1544 | } | ||
1545 | return 0; | ||
1546 | } | ||
1547 | |||
1548 | buf = list_entry(q->active.next, struct cx23885_buffer, vb.queue); | ||
1549 | dprintk(2, "restart_queue [%p/%d]: restart dma\n", | ||
1550 | buf, buf->vb.i); | ||
1551 | cx23885_start_dma(port, q, buf); | ||
1552 | list_for_each_entry(buf, &q->active, vb.queue) | ||
1553 | buf->count = q->count++; | ||
1554 | mod_timer(&q->timeout, jiffies + BUFFER_TIMEOUT); | ||
1555 | return 0; | ||
1556 | } | ||
1557 | |||
1558 | /* ------------------------------------------------------------------ */ | ||
1559 | |||
1560 | int cx23885_buf_prepare(struct videobuf_queue *q, struct cx23885_tsport *port, | ||
1561 | struct cx23885_buffer *buf, enum v4l2_field field) | ||
1562 | { | ||
1563 | struct cx23885_dev *dev = port->dev; | ||
1564 | int size = port->ts_packet_size * port->ts_packet_count; | ||
1565 | int rc; | ||
1566 | |||
1567 | dprintk(1, "%s: %p\n", __func__, buf); | ||
1568 | if (0 != buf->vb.baddr && buf->vb.bsize < size) | ||
1569 | return -EINVAL; | ||
1570 | |||
1571 | if (VIDEOBUF_NEEDS_INIT == buf->vb.state) { | ||
1572 | buf->vb.width = port->ts_packet_size; | ||
1573 | buf->vb.height = port->ts_packet_count; | ||
1574 | buf->vb.size = size; | ||
1575 | buf->vb.field = field /*V4L2_FIELD_TOP*/; | ||
1576 | |||
1577 | rc = videobuf_iolock(q, &buf->vb, NULL); | ||
1578 | if (0 != rc) | ||
1579 | goto fail; | ||
1580 | cx23885_risc_databuffer(dev->pci, &buf->risc, | ||
1581 | videobuf_to_dma(&buf->vb)->sglist, | ||
1582 | buf->vb.width, buf->vb.height, 0); | ||
1583 | } | ||
1584 | buf->vb.state = VIDEOBUF_PREPARED; | ||
1585 | return 0; | ||
1586 | |||
1587 | fail: | ||
1588 | cx23885_free_buffer(q, buf); | ||
1589 | return rc; | ||
1590 | } | ||
1591 | |||
1592 | void cx23885_buf_queue(struct cx23885_tsport *port, struct cx23885_buffer *buf) | ||
1593 | { | ||
1594 | struct cx23885_buffer *prev; | ||
1595 | struct cx23885_dev *dev = port->dev; | ||
1596 | struct cx23885_dmaqueue *cx88q = &port->mpegq; | ||
1597 | |||
1598 | /* add jump to stopper */ | ||
1599 | buf->risc.jmp[0] = cpu_to_le32(RISC_JUMP | RISC_IRQ1 | RISC_CNT_INC); | ||
1600 | buf->risc.jmp[1] = cpu_to_le32(cx88q->stopper.dma); | ||
1601 | buf->risc.jmp[2] = cpu_to_le32(0); /* bits 63-32 */ | ||
1602 | |||
1603 | if (list_empty(&cx88q->active)) { | ||
1604 | dprintk(1, "queue is empty - first active\n"); | ||
1605 | list_add_tail(&buf->vb.queue, &cx88q->active); | ||
1606 | cx23885_start_dma(port, cx88q, buf); | ||
1607 | buf->vb.state = VIDEOBUF_ACTIVE; | ||
1608 | buf->count = cx88q->count++; | ||
1609 | mod_timer(&cx88q->timeout, jiffies + BUFFER_TIMEOUT); | ||
1610 | dprintk(1, "[%p/%d] %s - first active\n", | ||
1611 | buf, buf->vb.i, __func__); | ||
1612 | } else { | ||
1613 | dprintk(1, "queue is not empty - append to active\n"); | ||
1614 | prev = list_entry(cx88q->active.prev, struct cx23885_buffer, | ||
1615 | vb.queue); | ||
1616 | list_add_tail(&buf->vb.queue, &cx88q->active); | ||
1617 | buf->vb.state = VIDEOBUF_ACTIVE; | ||
1618 | buf->count = cx88q->count++; | ||
1619 | prev->risc.jmp[1] = cpu_to_le32(buf->risc.dma); | ||
1620 | prev->risc.jmp[2] = cpu_to_le32(0); /* 64 bit bits 63-32 */ | ||
1621 | dprintk(1, "[%p/%d] %s - append to active\n", | ||
1622 | buf, buf->vb.i, __func__); | ||
1623 | } | ||
1624 | } | ||
1625 | |||
1626 | /* ----------------------------------------------------------- */ | ||
1627 | |||
1628 | static void do_cancel_buffers(struct cx23885_tsport *port, char *reason, | ||
1629 | int restart) | ||
1630 | { | ||
1631 | struct cx23885_dev *dev = port->dev; | ||
1632 | struct cx23885_dmaqueue *q = &port->mpegq; | ||
1633 | struct cx23885_buffer *buf; | ||
1634 | unsigned long flags; | ||
1635 | |||
1636 | spin_lock_irqsave(&port->slock, flags); | ||
1637 | while (!list_empty(&q->active)) { | ||
1638 | buf = list_entry(q->active.next, struct cx23885_buffer, | ||
1639 | vb.queue); | ||
1640 | list_del(&buf->vb.queue); | ||
1641 | buf->vb.state = VIDEOBUF_ERROR; | ||
1642 | wake_up(&buf->vb.done); | ||
1643 | dprintk(1, "[%p/%d] %s - dma=0x%08lx\n", | ||
1644 | buf, buf->vb.i, reason, (unsigned long)buf->risc.dma); | ||
1645 | } | ||
1646 | if (restart) { | ||
1647 | dprintk(1, "restarting queue\n"); | ||
1648 | cx23885_restart_queue(port, q); | ||
1649 | } | ||
1650 | spin_unlock_irqrestore(&port->slock, flags); | ||
1651 | } | ||
1652 | |||
1653 | void cx23885_cancel_buffers(struct cx23885_tsport *port) | ||
1654 | { | ||
1655 | struct cx23885_dev *dev = port->dev; | ||
1656 | struct cx23885_dmaqueue *q = &port->mpegq; | ||
1657 | |||
1658 | dprintk(1, "%s()\n", __func__); | ||
1659 | del_timer_sync(&q->timeout); | ||
1660 | cx23885_stop_dma(port); | ||
1661 | do_cancel_buffers(port, "cancel", 0); | ||
1662 | } | ||
1663 | |||
1664 | static void cx23885_timeout(unsigned long data) | ||
1665 | { | ||
1666 | struct cx23885_tsport *port = (struct cx23885_tsport *)data; | ||
1667 | struct cx23885_dev *dev = port->dev; | ||
1668 | |||
1669 | dprintk(1, "%s()\n", __func__); | ||
1670 | |||
1671 | if (debug > 5) | ||
1672 | cx23885_sram_channel_dump(dev, | ||
1673 | &dev->sram_channels[port->sram_chno]); | ||
1674 | |||
1675 | cx23885_stop_dma(port); | ||
1676 | do_cancel_buffers(port, "timeout", 1); | ||
1677 | } | ||
1678 | |||
1679 | int cx23885_irq_417(struct cx23885_dev *dev, u32 status) | ||
1680 | { | ||
1681 | /* FIXME: port1 assumption here. */ | ||
1682 | struct cx23885_tsport *port = &dev->ts1; | ||
1683 | int count = 0; | ||
1684 | int handled = 0; | ||
1685 | |||
1686 | if (status == 0) | ||
1687 | return handled; | ||
1688 | |||
1689 | count = cx_read(port->reg_gpcnt); | ||
1690 | dprintk(7, "status: 0x%08x mask: 0x%08x count: 0x%x\n", | ||
1691 | status, cx_read(port->reg_ts_int_msk), count); | ||
1692 | |||
1693 | if ((status & VID_B_MSK_BAD_PKT) || | ||
1694 | (status & VID_B_MSK_OPC_ERR) || | ||
1695 | (status & VID_B_MSK_VBI_OPC_ERR) || | ||
1696 | (status & VID_B_MSK_SYNC) || | ||
1697 | (status & VID_B_MSK_VBI_SYNC) || | ||
1698 | (status & VID_B_MSK_OF) || | ||
1699 | (status & VID_B_MSK_VBI_OF)) { | ||
1700 | printk(KERN_ERR "%s: V4L mpeg risc op code error, status " | ||
1701 | "= 0x%x\n", dev->name, status); | ||
1702 | if (status & VID_B_MSK_BAD_PKT) | ||
1703 | dprintk(1, " VID_B_MSK_BAD_PKT\n"); | ||
1704 | if (status & VID_B_MSK_OPC_ERR) | ||
1705 | dprintk(1, " VID_B_MSK_OPC_ERR\n"); | ||
1706 | if (status & VID_B_MSK_VBI_OPC_ERR) | ||
1707 | dprintk(1, " VID_B_MSK_VBI_OPC_ERR\n"); | ||
1708 | if (status & VID_B_MSK_SYNC) | ||
1709 | dprintk(1, " VID_B_MSK_SYNC\n"); | ||
1710 | if (status & VID_B_MSK_VBI_SYNC) | ||
1711 | dprintk(1, " VID_B_MSK_VBI_SYNC\n"); | ||
1712 | if (status & VID_B_MSK_OF) | ||
1713 | dprintk(1, " VID_B_MSK_OF\n"); | ||
1714 | if (status & VID_B_MSK_VBI_OF) | ||
1715 | dprintk(1, " VID_B_MSK_VBI_OF\n"); | ||
1716 | |||
1717 | cx_clear(port->reg_dma_ctl, port->dma_ctl_val); | ||
1718 | cx23885_sram_channel_dump(dev, | ||
1719 | &dev->sram_channels[port->sram_chno]); | ||
1720 | cx23885_417_check_encoder(dev); | ||
1721 | } else if (status & VID_B_MSK_RISCI1) { | ||
1722 | dprintk(7, " VID_B_MSK_RISCI1\n"); | ||
1723 | spin_lock(&port->slock); | ||
1724 | cx23885_wakeup(port, &port->mpegq, count); | ||
1725 | spin_unlock(&port->slock); | ||
1726 | } else if (status & VID_B_MSK_RISCI2) { | ||
1727 | dprintk(7, " VID_B_MSK_RISCI2\n"); | ||
1728 | spin_lock(&port->slock); | ||
1729 | cx23885_restart_queue(port, &port->mpegq); | ||
1730 | spin_unlock(&port->slock); | ||
1731 | } | ||
1732 | if (status) { | ||
1733 | cx_write(port->reg_ts_int_stat, status); | ||
1734 | handled = 1; | ||
1735 | } | ||
1736 | |||
1737 | return handled; | ||
1738 | } | ||
1739 | |||
1740 | static int cx23885_irq_ts(struct cx23885_tsport *port, u32 status) | ||
1741 | { | ||
1742 | struct cx23885_dev *dev = port->dev; | ||
1743 | int handled = 0; | ||
1744 | u32 count; | ||
1745 | |||
1746 | if ((status & VID_BC_MSK_OPC_ERR) || | ||
1747 | (status & VID_BC_MSK_BAD_PKT) || | ||
1748 | (status & VID_BC_MSK_SYNC) || | ||
1749 | (status & VID_BC_MSK_OF)) { | ||
1750 | |||
1751 | if (status & VID_BC_MSK_OPC_ERR) | ||
1752 | dprintk(7, " (VID_BC_MSK_OPC_ERR 0x%08x)\n", | ||
1753 | VID_BC_MSK_OPC_ERR); | ||
1754 | |||
1755 | if (status & VID_BC_MSK_BAD_PKT) | ||
1756 | dprintk(7, " (VID_BC_MSK_BAD_PKT 0x%08x)\n", | ||
1757 | VID_BC_MSK_BAD_PKT); | ||
1758 | |||
1759 | if (status & VID_BC_MSK_SYNC) | ||
1760 | dprintk(7, " (VID_BC_MSK_SYNC 0x%08x)\n", | ||
1761 | VID_BC_MSK_SYNC); | ||
1762 | |||
1763 | if (status & VID_BC_MSK_OF) | ||
1764 | dprintk(7, " (VID_BC_MSK_OF 0x%08x)\n", | ||
1765 | VID_BC_MSK_OF); | ||
1766 | |||
1767 | printk(KERN_ERR "%s: mpeg risc op code error\n", dev->name); | ||
1768 | |||
1769 | cx_clear(port->reg_dma_ctl, port->dma_ctl_val); | ||
1770 | cx23885_sram_channel_dump(dev, | ||
1771 | &dev->sram_channels[port->sram_chno]); | ||
1772 | |||
1773 | } else if (status & VID_BC_MSK_RISCI1) { | ||
1774 | |||
1775 | dprintk(7, " (RISCI1 0x%08x)\n", VID_BC_MSK_RISCI1); | ||
1776 | |||
1777 | spin_lock(&port->slock); | ||
1778 | count = cx_read(port->reg_gpcnt); | ||
1779 | cx23885_wakeup(port, &port->mpegq, count); | ||
1780 | spin_unlock(&port->slock); | ||
1781 | |||
1782 | } else if (status & VID_BC_MSK_RISCI2) { | ||
1783 | |||
1784 | dprintk(7, " (RISCI2 0x%08x)\n", VID_BC_MSK_RISCI2); | ||
1785 | |||
1786 | spin_lock(&port->slock); | ||
1787 | cx23885_restart_queue(port, &port->mpegq); | ||
1788 | spin_unlock(&port->slock); | ||
1789 | |||
1790 | } | ||
1791 | if (status) { | ||
1792 | cx_write(port->reg_ts_int_stat, status); | ||
1793 | handled = 1; | ||
1794 | } | ||
1795 | |||
1796 | return handled; | ||
1797 | } | ||
1798 | |||
1799 | static irqreturn_t cx23885_irq(int irq, void *dev_id) | ||
1800 | { | ||
1801 | struct cx23885_dev *dev = dev_id; | ||
1802 | struct cx23885_tsport *ts1 = &dev->ts1; | ||
1803 | struct cx23885_tsport *ts2 = &dev->ts2; | ||
1804 | u32 pci_status, pci_mask; | ||
1805 | u32 vida_status, vida_mask; | ||
1806 | u32 audint_status, audint_mask; | ||
1807 | u32 ts1_status, ts1_mask; | ||
1808 | u32 ts2_status, ts2_mask; | ||
1809 | int vida_count = 0, ts1_count = 0, ts2_count = 0, handled = 0; | ||
1810 | int audint_count = 0; | ||
1811 | bool subdev_handled; | ||
1812 | |||
1813 | pci_status = cx_read(PCI_INT_STAT); | ||
1814 | pci_mask = cx23885_irq_get_mask(dev); | ||
1815 | vida_status = cx_read(VID_A_INT_STAT); | ||
1816 | vida_mask = cx_read(VID_A_INT_MSK); | ||
1817 | audint_status = cx_read(AUDIO_INT_INT_STAT); | ||
1818 | audint_mask = cx_read(AUDIO_INT_INT_MSK); | ||
1819 | ts1_status = cx_read(VID_B_INT_STAT); | ||
1820 | ts1_mask = cx_read(VID_B_INT_MSK); | ||
1821 | ts2_status = cx_read(VID_C_INT_STAT); | ||
1822 | ts2_mask = cx_read(VID_C_INT_MSK); | ||
1823 | |||
1824 | if ((pci_status == 0) && (ts2_status == 0) && (ts1_status == 0)) | ||
1825 | goto out; | ||
1826 | |||
1827 | vida_count = cx_read(VID_A_GPCNT); | ||
1828 | audint_count = cx_read(AUD_INT_A_GPCNT); | ||
1829 | ts1_count = cx_read(ts1->reg_gpcnt); | ||
1830 | ts2_count = cx_read(ts2->reg_gpcnt); | ||
1831 | dprintk(7, "pci_status: 0x%08x pci_mask: 0x%08x\n", | ||
1832 | pci_status, pci_mask); | ||
1833 | dprintk(7, "vida_status: 0x%08x vida_mask: 0x%08x count: 0x%x\n", | ||
1834 | vida_status, vida_mask, vida_count); | ||
1835 | dprintk(7, "audint_status: 0x%08x audint_mask: 0x%08x count: 0x%x\n", | ||
1836 | audint_status, audint_mask, audint_count); | ||
1837 | dprintk(7, "ts1_status: 0x%08x ts1_mask: 0x%08x count: 0x%x\n", | ||
1838 | ts1_status, ts1_mask, ts1_count); | ||
1839 | dprintk(7, "ts2_status: 0x%08x ts2_mask: 0x%08x count: 0x%x\n", | ||
1840 | ts2_status, ts2_mask, ts2_count); | ||
1841 | |||
1842 | if (pci_status & (PCI_MSK_RISC_RD | PCI_MSK_RISC_WR | | ||
1843 | PCI_MSK_AL_RD | PCI_MSK_AL_WR | PCI_MSK_APB_DMA | | ||
1844 | PCI_MSK_VID_C | PCI_MSK_VID_B | PCI_MSK_VID_A | | ||
1845 | PCI_MSK_AUD_INT | PCI_MSK_AUD_EXT | | ||
1846 | PCI_MSK_GPIO0 | PCI_MSK_GPIO1 | | ||
1847 | PCI_MSK_AV_CORE | PCI_MSK_IR)) { | ||
1848 | |||
1849 | if (pci_status & PCI_MSK_RISC_RD) | ||
1850 | dprintk(7, " (PCI_MSK_RISC_RD 0x%08x)\n", | ||
1851 | PCI_MSK_RISC_RD); | ||
1852 | |||
1853 | if (pci_status & PCI_MSK_RISC_WR) | ||
1854 | dprintk(7, " (PCI_MSK_RISC_WR 0x%08x)\n", | ||
1855 | PCI_MSK_RISC_WR); | ||
1856 | |||
1857 | if (pci_status & PCI_MSK_AL_RD) | ||
1858 | dprintk(7, " (PCI_MSK_AL_RD 0x%08x)\n", | ||
1859 | PCI_MSK_AL_RD); | ||
1860 | |||
1861 | if (pci_status & PCI_MSK_AL_WR) | ||
1862 | dprintk(7, " (PCI_MSK_AL_WR 0x%08x)\n", | ||
1863 | PCI_MSK_AL_WR); | ||
1864 | |||
1865 | if (pci_status & PCI_MSK_APB_DMA) | ||
1866 | dprintk(7, " (PCI_MSK_APB_DMA 0x%08x)\n", | ||
1867 | PCI_MSK_APB_DMA); | ||
1868 | |||
1869 | if (pci_status & PCI_MSK_VID_C) | ||
1870 | dprintk(7, " (PCI_MSK_VID_C 0x%08x)\n", | ||
1871 | PCI_MSK_VID_C); | ||
1872 | |||
1873 | if (pci_status & PCI_MSK_VID_B) | ||
1874 | dprintk(7, " (PCI_MSK_VID_B 0x%08x)\n", | ||
1875 | PCI_MSK_VID_B); | ||
1876 | |||
1877 | if (pci_status & PCI_MSK_VID_A) | ||
1878 | dprintk(7, " (PCI_MSK_VID_A 0x%08x)\n", | ||
1879 | PCI_MSK_VID_A); | ||
1880 | |||
1881 | if (pci_status & PCI_MSK_AUD_INT) | ||
1882 | dprintk(7, " (PCI_MSK_AUD_INT 0x%08x)\n", | ||
1883 | PCI_MSK_AUD_INT); | ||
1884 | |||
1885 | if (pci_status & PCI_MSK_AUD_EXT) | ||
1886 | dprintk(7, " (PCI_MSK_AUD_EXT 0x%08x)\n", | ||
1887 | PCI_MSK_AUD_EXT); | ||
1888 | |||
1889 | if (pci_status & PCI_MSK_GPIO0) | ||
1890 | dprintk(7, " (PCI_MSK_GPIO0 0x%08x)\n", | ||
1891 | PCI_MSK_GPIO0); | ||
1892 | |||
1893 | if (pci_status & PCI_MSK_GPIO1) | ||
1894 | dprintk(7, " (PCI_MSK_GPIO1 0x%08x)\n", | ||
1895 | PCI_MSK_GPIO1); | ||
1896 | |||
1897 | if (pci_status & PCI_MSK_AV_CORE) | ||
1898 | dprintk(7, " (PCI_MSK_AV_CORE 0x%08x)\n", | ||
1899 | PCI_MSK_AV_CORE); | ||
1900 | |||
1901 | if (pci_status & PCI_MSK_IR) | ||
1902 | dprintk(7, " (PCI_MSK_IR 0x%08x)\n", | ||
1903 | PCI_MSK_IR); | ||
1904 | } | ||
1905 | |||
1906 | if (cx23885_boards[dev->board].ci_type == 1 && | ||
1907 | (pci_status & (PCI_MSK_GPIO1 | PCI_MSK_GPIO0))) | ||
1908 | handled += netup_ci_slot_status(dev, pci_status); | ||
1909 | |||
1910 | if (cx23885_boards[dev->board].ci_type == 2 && | ||
1911 | (pci_status & PCI_MSK_GPIO0)) | ||
1912 | handled += altera_ci_irq(dev); | ||
1913 | |||
1914 | if (ts1_status) { | ||
1915 | if (cx23885_boards[dev->board].portb == CX23885_MPEG_DVB) | ||
1916 | handled += cx23885_irq_ts(ts1, ts1_status); | ||
1917 | else | ||
1918 | if (cx23885_boards[dev->board].portb == CX23885_MPEG_ENCODER) | ||
1919 | handled += cx23885_irq_417(dev, ts1_status); | ||
1920 | } | ||
1921 | |||
1922 | if (ts2_status) { | ||
1923 | if (cx23885_boards[dev->board].portc == CX23885_MPEG_DVB) | ||
1924 | handled += cx23885_irq_ts(ts2, ts2_status); | ||
1925 | else | ||
1926 | if (cx23885_boards[dev->board].portc == CX23885_MPEG_ENCODER) | ||
1927 | handled += cx23885_irq_417(dev, ts2_status); | ||
1928 | } | ||
1929 | |||
1930 | if (vida_status) | ||
1931 | handled += cx23885_video_irq(dev, vida_status); | ||
1932 | |||
1933 | if (audint_status) | ||
1934 | handled += cx23885_audio_irq(dev, audint_status, audint_mask); | ||
1935 | |||
1936 | if (pci_status & PCI_MSK_IR) { | ||
1937 | subdev_handled = false; | ||
1938 | v4l2_subdev_call(dev->sd_ir, core, interrupt_service_routine, | ||
1939 | pci_status, &subdev_handled); | ||
1940 | if (subdev_handled) | ||
1941 | handled++; | ||
1942 | } | ||
1943 | |||
1944 | if ((pci_status & pci_mask) & PCI_MSK_AV_CORE) { | ||
1945 | cx23885_irq_disable(dev, PCI_MSK_AV_CORE); | ||
1946 | if (!schedule_work(&dev->cx25840_work)) | ||
1947 | printk(KERN_ERR "%s: failed to set up deferred work for" | ||
1948 | " AV Core/IR interrupt. Interrupt is disabled" | ||
1949 | " and won't be re-enabled\n", dev->name); | ||
1950 | handled++; | ||
1951 | } | ||
1952 | |||
1953 | if (handled) | ||
1954 | cx_write(PCI_INT_STAT, pci_status); | ||
1955 | out: | ||
1956 | return IRQ_RETVAL(handled); | ||
1957 | } | ||
1958 | |||
1959 | static void cx23885_v4l2_dev_notify(struct v4l2_subdev *sd, | ||
1960 | unsigned int notification, void *arg) | ||
1961 | { | ||
1962 | struct cx23885_dev *dev; | ||
1963 | |||
1964 | if (sd == NULL) | ||
1965 | return; | ||
1966 | |||
1967 | dev = to_cx23885(sd->v4l2_dev); | ||
1968 | |||
1969 | switch (notification) { | ||
1970 | case V4L2_SUBDEV_IR_RX_NOTIFY: /* Possibly called in an IRQ context */ | ||
1971 | if (sd == dev->sd_ir) | ||
1972 | cx23885_ir_rx_v4l2_dev_notify(sd, *(u32 *)arg); | ||
1973 | break; | ||
1974 | case V4L2_SUBDEV_IR_TX_NOTIFY: /* Possibly called in an IRQ context */ | ||
1975 | if (sd == dev->sd_ir) | ||
1976 | cx23885_ir_tx_v4l2_dev_notify(sd, *(u32 *)arg); | ||
1977 | break; | ||
1978 | } | ||
1979 | } | ||
1980 | |||
1981 | static void cx23885_v4l2_dev_notify_init(struct cx23885_dev *dev) | ||
1982 | { | ||
1983 | INIT_WORK(&dev->cx25840_work, cx23885_av_work_handler); | ||
1984 | INIT_WORK(&dev->ir_rx_work, cx23885_ir_rx_work_handler); | ||
1985 | INIT_WORK(&dev->ir_tx_work, cx23885_ir_tx_work_handler); | ||
1986 | dev->v4l2_dev.notify = cx23885_v4l2_dev_notify; | ||
1987 | } | ||
1988 | |||
1989 | static inline int encoder_on_portb(struct cx23885_dev *dev) | ||
1990 | { | ||
1991 | return cx23885_boards[dev->board].portb == CX23885_MPEG_ENCODER; | ||
1992 | } | ||
1993 | |||
1994 | static inline int encoder_on_portc(struct cx23885_dev *dev) | ||
1995 | { | ||
1996 | return cx23885_boards[dev->board].portc == CX23885_MPEG_ENCODER; | ||
1997 | } | ||
1998 | |||
1999 | /* Mask represents 32 different GPIOs, GPIO's are split into multiple | ||
2000 | * registers depending on the board configuration (and whether the | ||
2001 | * 417 encoder (wi it's own GPIO's) are present. Each GPIO bit will | ||
2002 | * be pushed into the correct hardware register, regardless of the | ||
2003 | * physical location. Certain registers are shared so we sanity check | ||
2004 | * and report errors if we think we're tampering with a GPIo that might | ||
2005 | * be assigned to the encoder (and used for the host bus). | ||
2006 | * | ||
2007 | * GPIO 2 thru 0 - On the cx23885 bridge | ||
2008 | * GPIO 18 thru 3 - On the cx23417 host bus interface | ||
2009 | * GPIO 23 thru 19 - On the cx25840 a/v core | ||
2010 | */ | ||
2011 | void cx23885_gpio_set(struct cx23885_dev *dev, u32 mask) | ||
2012 | { | ||
2013 | if (mask & 0x7) | ||
2014 | cx_set(GP0_IO, mask & 0x7); | ||
2015 | |||
2016 | if (mask & 0x0007fff8) { | ||
2017 | if (encoder_on_portb(dev) || encoder_on_portc(dev)) | ||
2018 | printk(KERN_ERR | ||
2019 | "%s: Setting GPIO on encoder ports\n", | ||
2020 | dev->name); | ||
2021 | cx_set(MC417_RWD, (mask & 0x0007fff8) >> 3); | ||
2022 | } | ||
2023 | |||
2024 | /* TODO: 23-19 */ | ||
2025 | if (mask & 0x00f80000) | ||
2026 | printk(KERN_INFO "%s: Unsupported\n", dev->name); | ||
2027 | } | ||
2028 | |||
2029 | void cx23885_gpio_clear(struct cx23885_dev *dev, u32 mask) | ||
2030 | { | ||
2031 | if (mask & 0x00000007) | ||
2032 | cx_clear(GP0_IO, mask & 0x7); | ||
2033 | |||
2034 | if (mask & 0x0007fff8) { | ||
2035 | if (encoder_on_portb(dev) || encoder_on_portc(dev)) | ||
2036 | printk(KERN_ERR | ||
2037 | "%s: Clearing GPIO moving on encoder ports\n", | ||
2038 | dev->name); | ||
2039 | cx_clear(MC417_RWD, (mask & 0x7fff8) >> 3); | ||
2040 | } | ||
2041 | |||
2042 | /* TODO: 23-19 */ | ||
2043 | if (mask & 0x00f80000) | ||
2044 | printk(KERN_INFO "%s: Unsupported\n", dev->name); | ||
2045 | } | ||
2046 | |||
2047 | u32 cx23885_gpio_get(struct cx23885_dev *dev, u32 mask) | ||
2048 | { | ||
2049 | if (mask & 0x00000007) | ||
2050 | return (cx_read(GP0_IO) >> 8) & mask & 0x7; | ||
2051 | |||
2052 | if (mask & 0x0007fff8) { | ||
2053 | if (encoder_on_portb(dev) || encoder_on_portc(dev)) | ||
2054 | printk(KERN_ERR | ||
2055 | "%s: Reading GPIO moving on encoder ports\n", | ||
2056 | dev->name); | ||
2057 | return (cx_read(MC417_RWD) & ((mask & 0x7fff8) >> 3)) << 3; | ||
2058 | } | ||
2059 | |||
2060 | /* TODO: 23-19 */ | ||
2061 | if (mask & 0x00f80000) | ||
2062 | printk(KERN_INFO "%s: Unsupported\n", dev->name); | ||
2063 | |||
2064 | return 0; | ||
2065 | } | ||
2066 | |||
2067 | void cx23885_gpio_enable(struct cx23885_dev *dev, u32 mask, int asoutput) | ||
2068 | { | ||
2069 | if ((mask & 0x00000007) && asoutput) | ||
2070 | cx_set(GP0_IO, (mask & 0x7) << 16); | ||
2071 | else if ((mask & 0x00000007) && !asoutput) | ||
2072 | cx_clear(GP0_IO, (mask & 0x7) << 16); | ||
2073 | |||
2074 | if (mask & 0x0007fff8) { | ||
2075 | if (encoder_on_portb(dev) || encoder_on_portc(dev)) | ||
2076 | printk(KERN_ERR | ||
2077 | "%s: Enabling GPIO on encoder ports\n", | ||
2078 | dev->name); | ||
2079 | } | ||
2080 | |||
2081 | /* MC417_OEN is active low for output, write 1 for an input */ | ||
2082 | if ((mask & 0x0007fff8) && asoutput) | ||
2083 | cx_clear(MC417_OEN, (mask & 0x7fff8) >> 3); | ||
2084 | |||
2085 | else if ((mask & 0x0007fff8) && !asoutput) | ||
2086 | cx_set(MC417_OEN, (mask & 0x7fff8) >> 3); | ||
2087 | |||
2088 | /* TODO: 23-19 */ | ||
2089 | } | ||
2090 | |||
2091 | static int __devinit cx23885_initdev(struct pci_dev *pci_dev, | ||
2092 | const struct pci_device_id *pci_id) | ||
2093 | { | ||
2094 | struct cx23885_dev *dev; | ||
2095 | int err; | ||
2096 | |||
2097 | dev = kzalloc(sizeof(*dev), GFP_KERNEL); | ||
2098 | if (NULL == dev) | ||
2099 | return -ENOMEM; | ||
2100 | |||
2101 | err = v4l2_device_register(&pci_dev->dev, &dev->v4l2_dev); | ||
2102 | if (err < 0) | ||
2103 | goto fail_free; | ||
2104 | |||
2105 | /* Prepare to handle notifications from subdevices */ | ||
2106 | cx23885_v4l2_dev_notify_init(dev); | ||
2107 | |||
2108 | /* pci init */ | ||
2109 | dev->pci = pci_dev; | ||
2110 | if (pci_enable_device(pci_dev)) { | ||
2111 | err = -EIO; | ||
2112 | goto fail_unreg; | ||
2113 | } | ||
2114 | |||
2115 | if (cx23885_dev_setup(dev) < 0) { | ||
2116 | err = -EINVAL; | ||
2117 | goto fail_unreg; | ||
2118 | } | ||
2119 | |||
2120 | /* print pci info */ | ||
2121 | dev->pci_rev = pci_dev->revision; | ||
2122 | pci_read_config_byte(pci_dev, PCI_LATENCY_TIMER, &dev->pci_lat); | ||
2123 | printk(KERN_INFO "%s/0: found at %s, rev: %d, irq: %d, " | ||
2124 | "latency: %d, mmio: 0x%llx\n", dev->name, | ||
2125 | pci_name(pci_dev), dev->pci_rev, pci_dev->irq, | ||
2126 | dev->pci_lat, | ||
2127 | (unsigned long long)pci_resource_start(pci_dev, 0)); | ||
2128 | |||
2129 | pci_set_master(pci_dev); | ||
2130 | if (!pci_dma_supported(pci_dev, 0xffffffff)) { | ||
2131 | printk("%s/0: Oops: no 32bit PCI DMA ???\n", dev->name); | ||
2132 | err = -EIO; | ||
2133 | goto fail_irq; | ||
2134 | } | ||
2135 | |||
2136 | err = request_irq(pci_dev->irq, cx23885_irq, | ||
2137 | IRQF_SHARED | IRQF_DISABLED, dev->name, dev); | ||
2138 | if (err < 0) { | ||
2139 | printk(KERN_ERR "%s: can't get IRQ %d\n", | ||
2140 | dev->name, pci_dev->irq); | ||
2141 | goto fail_irq; | ||
2142 | } | ||
2143 | |||
2144 | switch (dev->board) { | ||
2145 | case CX23885_BOARD_NETUP_DUAL_DVBS2_CI: | ||
2146 | cx23885_irq_add_enable(dev, PCI_MSK_GPIO1 | PCI_MSK_GPIO0); | ||
2147 | break; | ||
2148 | case CX23885_BOARD_NETUP_DUAL_DVB_T_C_CI_RF: | ||
2149 | cx23885_irq_add_enable(dev, PCI_MSK_GPIO0); | ||
2150 | break; | ||
2151 | } | ||
2152 | |||
2153 | /* | ||
2154 | * The CX2388[58] IR controller can start firing interrupts when | ||
2155 | * enabled, so these have to take place after the cx23885_irq() handler | ||
2156 | * is hooked up by the call to request_irq() above. | ||
2157 | */ | ||
2158 | cx23885_ir_pci_int_enable(dev); | ||
2159 | cx23885_input_init(dev); | ||
2160 | |||
2161 | return 0; | ||
2162 | |||
2163 | fail_irq: | ||
2164 | cx23885_dev_unregister(dev); | ||
2165 | fail_unreg: | ||
2166 | v4l2_device_unregister(&dev->v4l2_dev); | ||
2167 | fail_free: | ||
2168 | kfree(dev); | ||
2169 | return err; | ||
2170 | } | ||
2171 | |||
2172 | static void __devexit cx23885_finidev(struct pci_dev *pci_dev) | ||
2173 | { | ||
2174 | struct v4l2_device *v4l2_dev = pci_get_drvdata(pci_dev); | ||
2175 | struct cx23885_dev *dev = to_cx23885(v4l2_dev); | ||
2176 | |||
2177 | cx23885_input_fini(dev); | ||
2178 | cx23885_ir_fini(dev); | ||
2179 | |||
2180 | cx23885_shutdown(dev); | ||
2181 | |||
2182 | pci_disable_device(pci_dev); | ||
2183 | |||
2184 | /* unregister stuff */ | ||
2185 | free_irq(pci_dev->irq, dev); | ||
2186 | |||
2187 | cx23885_dev_unregister(dev); | ||
2188 | v4l2_device_unregister(v4l2_dev); | ||
2189 | kfree(dev); | ||
2190 | } | ||
2191 | |||
2192 | static struct pci_device_id cx23885_pci_tbl[] = { | ||
2193 | { | ||
2194 | /* CX23885 */ | ||
2195 | .vendor = 0x14f1, | ||
2196 | .device = 0x8852, | ||
2197 | .subvendor = PCI_ANY_ID, | ||
2198 | .subdevice = PCI_ANY_ID, | ||
2199 | }, { | ||
2200 | /* CX23887 Rev 2 */ | ||
2201 | .vendor = 0x14f1, | ||
2202 | .device = 0x8880, | ||
2203 | .subvendor = PCI_ANY_ID, | ||
2204 | .subdevice = PCI_ANY_ID, | ||
2205 | }, { | ||
2206 | /* --- end of list --- */ | ||
2207 | } | ||
2208 | }; | ||
2209 | MODULE_DEVICE_TABLE(pci, cx23885_pci_tbl); | ||
2210 | |||
2211 | static struct pci_driver cx23885_pci_driver = { | ||
2212 | .name = "cx23885", | ||
2213 | .id_table = cx23885_pci_tbl, | ||
2214 | .probe = cx23885_initdev, | ||
2215 | .remove = __devexit_p(cx23885_finidev), | ||
2216 | /* TODO */ | ||
2217 | .suspend = NULL, | ||
2218 | .resume = NULL, | ||
2219 | }; | ||
2220 | |||
2221 | static int __init cx23885_init(void) | ||
2222 | { | ||
2223 | printk(KERN_INFO "cx23885 driver version %s loaded\n", | ||
2224 | CX23885_VERSION); | ||
2225 | return pci_register_driver(&cx23885_pci_driver); | ||
2226 | } | ||
2227 | |||
2228 | static void __exit cx23885_fini(void) | ||
2229 | { | ||
2230 | pci_unregister_driver(&cx23885_pci_driver); | ||
2231 | } | ||
2232 | |||
2233 | module_init(cx23885_init); | ||
2234 | module_exit(cx23885_fini); | ||
diff --git a/drivers/media/pci/cx23885/cx23885-dvb.c b/drivers/media/pci/cx23885/cx23885-dvb.c new file mode 100644 index 000000000000..f3202a52d535 --- /dev/null +++ b/drivers/media/pci/cx23885/cx23885-dvb.c | |||
@@ -0,0 +1,1356 @@ | |||
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 | #include "drxk.h" | ||
65 | #include "mt2063.h" | ||
66 | |||
67 | static unsigned int debug; | ||
68 | |||
69 | #define dprintk(level, fmt, arg...)\ | ||
70 | do { if (debug >= level)\ | ||
71 | printk(KERN_DEBUG "%s/0: " fmt, dev->name, ## arg);\ | ||
72 | } while (0) | ||
73 | |||
74 | /* ------------------------------------------------------------------ */ | ||
75 | |||
76 | static unsigned int alt_tuner; | ||
77 | module_param(alt_tuner, int, 0644); | ||
78 | MODULE_PARM_DESC(alt_tuner, "Enable alternate tuner configuration"); | ||
79 | |||
80 | DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr); | ||
81 | |||
82 | /* ------------------------------------------------------------------ */ | ||
83 | |||
84 | static int dvb_buf_setup(struct videobuf_queue *q, | ||
85 | unsigned int *count, unsigned int *size) | ||
86 | { | ||
87 | struct cx23885_tsport *port = q->priv_data; | ||
88 | |||
89 | port->ts_packet_size = 188 * 4; | ||
90 | port->ts_packet_count = 32; | ||
91 | |||
92 | *size = port->ts_packet_size * port->ts_packet_count; | ||
93 | *count = 32; | ||
94 | return 0; | ||
95 | } | ||
96 | |||
97 | static int dvb_buf_prepare(struct videobuf_queue *q, | ||
98 | struct videobuf_buffer *vb, enum v4l2_field field) | ||
99 | { | ||
100 | struct cx23885_tsport *port = q->priv_data; | ||
101 | return cx23885_buf_prepare(q, port, (struct cx23885_buffer *)vb, field); | ||
102 | } | ||
103 | |||
104 | static void dvb_buf_queue(struct videobuf_queue *q, struct videobuf_buffer *vb) | ||
105 | { | ||
106 | struct cx23885_tsport *port = q->priv_data; | ||
107 | cx23885_buf_queue(port, (struct cx23885_buffer *)vb); | ||
108 | } | ||
109 | |||
110 | static void dvb_buf_release(struct videobuf_queue *q, | ||
111 | struct videobuf_buffer *vb) | ||
112 | { | ||
113 | cx23885_free_buffer(q, (struct cx23885_buffer *)vb); | ||
114 | } | ||
115 | |||
116 | static int cx23885_dvb_set_frontend(struct dvb_frontend *fe); | ||
117 | |||
118 | static void cx23885_dvb_gate_ctrl(struct cx23885_tsport *port, int open) | ||
119 | { | ||
120 | struct videobuf_dvb_frontends *f; | ||
121 | struct videobuf_dvb_frontend *fe; | ||
122 | |||
123 | f = &port->frontends; | ||
124 | |||
125 | if (f->gate <= 1) /* undefined or fe0 */ | ||
126 | fe = videobuf_dvb_get_frontend(f, 1); | ||
127 | else | ||
128 | fe = videobuf_dvb_get_frontend(f, f->gate); | ||
129 | |||
130 | if (fe && fe->dvb.frontend && fe->dvb.frontend->ops.i2c_gate_ctrl) | ||
131 | fe->dvb.frontend->ops.i2c_gate_ctrl(fe->dvb.frontend, open); | ||
132 | |||
133 | /* | ||
134 | * FIXME: Improve this path to avoid calling the | ||
135 | * cx23885_dvb_set_frontend() every time it passes here. | ||
136 | */ | ||
137 | cx23885_dvb_set_frontend(fe->dvb.frontend); | ||
138 | } | ||
139 | |||
140 | static struct videobuf_queue_ops dvb_qops = { | ||
141 | .buf_setup = dvb_buf_setup, | ||
142 | .buf_prepare = dvb_buf_prepare, | ||
143 | .buf_queue = dvb_buf_queue, | ||
144 | .buf_release = dvb_buf_release, | ||
145 | }; | ||
146 | |||
147 | static struct s5h1409_config hauppauge_generic_config = { | ||
148 | .demod_address = 0x32 >> 1, | ||
149 | .output_mode = S5H1409_SERIAL_OUTPUT, | ||
150 | .gpio = S5H1409_GPIO_ON, | ||
151 | .qam_if = 44000, | ||
152 | .inversion = S5H1409_INVERSION_OFF, | ||
153 | .status_mode = S5H1409_DEMODLOCKING, | ||
154 | .mpeg_timing = S5H1409_MPEGTIMING_CONTINOUS_NONINVERTING_CLOCK, | ||
155 | }; | ||
156 | |||
157 | static struct tda10048_config hauppauge_hvr1200_config = { | ||
158 | .demod_address = 0x10 >> 1, | ||
159 | .output_mode = TDA10048_SERIAL_OUTPUT, | ||
160 | .fwbulkwritelen = TDA10048_BULKWRITE_200, | ||
161 | .inversion = TDA10048_INVERSION_ON, | ||
162 | .dtv6_if_freq_khz = TDA10048_IF_3300, | ||
163 | .dtv7_if_freq_khz = TDA10048_IF_3800, | ||
164 | .dtv8_if_freq_khz = TDA10048_IF_4300, | ||
165 | .clk_freq_khz = TDA10048_CLK_16000, | ||
166 | }; | ||
167 | |||
168 | static struct tda10048_config hauppauge_hvr1210_config = { | ||
169 | .demod_address = 0x10 >> 1, | ||
170 | .output_mode = TDA10048_SERIAL_OUTPUT, | ||
171 | .fwbulkwritelen = TDA10048_BULKWRITE_200, | ||
172 | .inversion = TDA10048_INVERSION_ON, | ||
173 | .dtv6_if_freq_khz = TDA10048_IF_3300, | ||
174 | .dtv7_if_freq_khz = TDA10048_IF_3500, | ||
175 | .dtv8_if_freq_khz = TDA10048_IF_4000, | ||
176 | .clk_freq_khz = TDA10048_CLK_16000, | ||
177 | }; | ||
178 | |||
179 | static struct s5h1409_config hauppauge_ezqam_config = { | ||
180 | .demod_address = 0x32 >> 1, | ||
181 | .output_mode = S5H1409_SERIAL_OUTPUT, | ||
182 | .gpio = S5H1409_GPIO_OFF, | ||
183 | .qam_if = 4000, | ||
184 | .inversion = S5H1409_INVERSION_ON, | ||
185 | .status_mode = S5H1409_DEMODLOCKING, | ||
186 | .mpeg_timing = S5H1409_MPEGTIMING_CONTINOUS_NONINVERTING_CLOCK, | ||
187 | }; | ||
188 | |||
189 | static struct s5h1409_config hauppauge_hvr1800lp_config = { | ||
190 | .demod_address = 0x32 >> 1, | ||
191 | .output_mode = S5H1409_SERIAL_OUTPUT, | ||
192 | .gpio = S5H1409_GPIO_OFF, | ||
193 | .qam_if = 44000, | ||
194 | .inversion = S5H1409_INVERSION_OFF, | ||
195 | .status_mode = S5H1409_DEMODLOCKING, | ||
196 | .mpeg_timing = S5H1409_MPEGTIMING_CONTINOUS_NONINVERTING_CLOCK, | ||
197 | }; | ||
198 | |||
199 | static struct s5h1409_config hauppauge_hvr1500_config = { | ||
200 | .demod_address = 0x32 >> 1, | ||
201 | .output_mode = S5H1409_SERIAL_OUTPUT, | ||
202 | .gpio = S5H1409_GPIO_OFF, | ||
203 | .inversion = S5H1409_INVERSION_OFF, | ||
204 | .status_mode = S5H1409_DEMODLOCKING, | ||
205 | .mpeg_timing = S5H1409_MPEGTIMING_CONTINOUS_NONINVERTING_CLOCK, | ||
206 | }; | ||
207 | |||
208 | static struct mt2131_config hauppauge_generic_tunerconfig = { | ||
209 | 0x61 | ||
210 | }; | ||
211 | |||
212 | static struct lgdt330x_config fusionhdtv_5_express = { | ||
213 | .demod_address = 0x0e, | ||
214 | .demod_chip = LGDT3303, | ||
215 | .serial_mpeg = 0x40, | ||
216 | }; | ||
217 | |||
218 | static struct s5h1409_config hauppauge_hvr1500q_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 s5h1409_config dvico_s5h1409_config = { | ||
229 | .demod_address = 0x32 >> 1, | ||
230 | .output_mode = S5H1409_SERIAL_OUTPUT, | ||
231 | .gpio = S5H1409_GPIO_ON, | ||
232 | .qam_if = 44000, | ||
233 | .inversion = S5H1409_INVERSION_OFF, | ||
234 | .status_mode = S5H1409_DEMODLOCKING, | ||
235 | .mpeg_timing = S5H1409_MPEGTIMING_CONTINOUS_NONINVERTING_CLOCK, | ||
236 | }; | ||
237 | |||
238 | static struct s5h1411_config dvico_s5h1411_config = { | ||
239 | .output_mode = S5H1411_SERIAL_OUTPUT, | ||
240 | .gpio = S5H1411_GPIO_ON, | ||
241 | .qam_if = S5H1411_IF_44000, | ||
242 | .vsb_if = S5H1411_IF_44000, | ||
243 | .inversion = S5H1411_INVERSION_OFF, | ||
244 | .status_mode = S5H1411_DEMODLOCKING, | ||
245 | .mpeg_timing = S5H1411_MPEGTIMING_CONTINOUS_NONINVERTING_CLOCK, | ||
246 | }; | ||
247 | |||
248 | static struct s5h1411_config hcw_s5h1411_config = { | ||
249 | .output_mode = S5H1411_SERIAL_OUTPUT, | ||
250 | .gpio = S5H1411_GPIO_OFF, | ||
251 | .vsb_if = S5H1411_IF_44000, | ||
252 | .qam_if = S5H1411_IF_4000, | ||
253 | .inversion = S5H1411_INVERSION_ON, | ||
254 | .status_mode = S5H1411_DEMODLOCKING, | ||
255 | .mpeg_timing = S5H1411_MPEGTIMING_CONTINOUS_NONINVERTING_CLOCK, | ||
256 | }; | ||
257 | |||
258 | static struct xc5000_config hauppauge_hvr1500q_tunerconfig = { | ||
259 | .i2c_address = 0x61, | ||
260 | .if_khz = 5380, | ||
261 | }; | ||
262 | |||
263 | static struct xc5000_config dvico_xc5000_tunerconfig = { | ||
264 | .i2c_address = 0x64, | ||
265 | .if_khz = 5380, | ||
266 | }; | ||
267 | |||
268 | static struct tda829x_config tda829x_no_probe = { | ||
269 | .probe_tuner = TDA829X_DONT_PROBE, | ||
270 | }; | ||
271 | |||
272 | static struct tda18271_std_map hauppauge_tda18271_std_map = { | ||
273 | .atsc_6 = { .if_freq = 5380, .agc_mode = 3, .std = 3, | ||
274 | .if_lvl = 6, .rfagc_top = 0x37 }, | ||
275 | .qam_6 = { .if_freq = 4000, .agc_mode = 3, .std = 0, | ||
276 | .if_lvl = 6, .rfagc_top = 0x37 }, | ||
277 | }; | ||
278 | |||
279 | static struct tda18271_std_map hauppauge_hvr1200_tda18271_std_map = { | ||
280 | .dvbt_6 = { .if_freq = 3300, .agc_mode = 3, .std = 4, | ||
281 | .if_lvl = 1, .rfagc_top = 0x37, }, | ||
282 | .dvbt_7 = { .if_freq = 3800, .agc_mode = 3, .std = 5, | ||
283 | .if_lvl = 1, .rfagc_top = 0x37, }, | ||
284 | .dvbt_8 = { .if_freq = 4300, .agc_mode = 3, .std = 6, | ||
285 | .if_lvl = 1, .rfagc_top = 0x37, }, | ||
286 | }; | ||
287 | |||
288 | static struct tda18271_config hauppauge_tda18271_config = { | ||
289 | .std_map = &hauppauge_tda18271_std_map, | ||
290 | .gate = TDA18271_GATE_ANALOG, | ||
291 | .output_opt = TDA18271_OUTPUT_LT_OFF, | ||
292 | }; | ||
293 | |||
294 | static struct tda18271_config hauppauge_hvr1200_tuner_config = { | ||
295 | .std_map = &hauppauge_hvr1200_tda18271_std_map, | ||
296 | .gate = TDA18271_GATE_ANALOG, | ||
297 | .output_opt = TDA18271_OUTPUT_LT_OFF, | ||
298 | }; | ||
299 | |||
300 | static struct tda18271_config hauppauge_hvr1210_tuner_config = { | ||
301 | .gate = TDA18271_GATE_DIGITAL, | ||
302 | .output_opt = TDA18271_OUTPUT_LT_OFF, | ||
303 | }; | ||
304 | |||
305 | static struct tda18271_std_map hauppauge_hvr127x_std_map = { | ||
306 | .atsc_6 = { .if_freq = 3250, .agc_mode = 3, .std = 4, | ||
307 | .if_lvl = 1, .rfagc_top = 0x58 }, | ||
308 | .qam_6 = { .if_freq = 4000, .agc_mode = 3, .std = 5, | ||
309 | .if_lvl = 1, .rfagc_top = 0x58 }, | ||
310 | }; | ||
311 | |||
312 | static struct tda18271_config hauppauge_hvr127x_config = { | ||
313 | .std_map = &hauppauge_hvr127x_std_map, | ||
314 | .output_opt = TDA18271_OUTPUT_LT_OFF, | ||
315 | }; | ||
316 | |||
317 | static struct lgdt3305_config hauppauge_lgdt3305_config = { | ||
318 | .i2c_addr = 0x0e, | ||
319 | .mpeg_mode = LGDT3305_MPEG_SERIAL, | ||
320 | .tpclk_edge = LGDT3305_TPCLK_FALLING_EDGE, | ||
321 | .tpvalid_polarity = LGDT3305_TP_VALID_HIGH, | ||
322 | .deny_i2c_rptr = 1, | ||
323 | .spectral_inversion = 1, | ||
324 | .qam_if_khz = 4000, | ||
325 | .vsb_if_khz = 3250, | ||
326 | }; | ||
327 | |||
328 | static struct dibx000_agc_config xc3028_agc_config = { | ||
329 | BAND_VHF | BAND_UHF, /* band_caps */ | ||
330 | |||
331 | /* P_agc_use_sd_mod1=0, P_agc_use_sd_mod2=0, P_agc_freq_pwm_div=0, | ||
332 | * P_agc_inv_pwm1=0, P_agc_inv_pwm2=0, | ||
333 | * P_agc_inh_dc_rv_est=0, P_agc_time_est=3, P_agc_freeze=0, | ||
334 | * P_agc_nb_est=2, P_agc_write=0 | ||
335 | */ | ||
336 | (0 << 15) | (0 << 14) | (0 << 11) | (0 << 10) | (0 << 9) | (0 << 8) | | ||
337 | (3 << 5) | (0 << 4) | (2 << 1) | (0 << 0), /* setup */ | ||
338 | |||
339 | 712, /* inv_gain */ | ||
340 | 21, /* time_stabiliz */ | ||
341 | |||
342 | 0, /* alpha_level */ | ||
343 | 118, /* thlock */ | ||
344 | |||
345 | 0, /* wbd_inv */ | ||
346 | 2867, /* wbd_ref */ | ||
347 | 0, /* wbd_sel */ | ||
348 | 2, /* wbd_alpha */ | ||
349 | |||
350 | 0, /* agc1_max */ | ||
351 | 0, /* agc1_min */ | ||
352 | 39718, /* agc2_max */ | ||
353 | 9930, /* agc2_min */ | ||
354 | 0, /* agc1_pt1 */ | ||
355 | 0, /* agc1_pt2 */ | ||
356 | 0, /* agc1_pt3 */ | ||
357 | 0, /* agc1_slope1 */ | ||
358 | 0, /* agc1_slope2 */ | ||
359 | 0, /* agc2_pt1 */ | ||
360 | 128, /* agc2_pt2 */ | ||
361 | 29, /* agc2_slope1 */ | ||
362 | 29, /* agc2_slope2 */ | ||
363 | |||
364 | 17, /* alpha_mant */ | ||
365 | 27, /* alpha_exp */ | ||
366 | 23, /* beta_mant */ | ||
367 | 51, /* beta_exp */ | ||
368 | |||
369 | 1, /* perform_agc_softsplit */ | ||
370 | }; | ||
371 | |||
372 | /* PLL Configuration for COFDM BW_MHz = 8.000000 | ||
373 | * With external clock = 30.000000 */ | ||
374 | static struct dibx000_bandwidth_config xc3028_bw_config = { | ||
375 | 60000, /* internal */ | ||
376 | 30000, /* sampling */ | ||
377 | 1, /* pll_cfg: prediv */ | ||
378 | 8, /* pll_cfg: ratio */ | ||
379 | 3, /* pll_cfg: range */ | ||
380 | 1, /* pll_cfg: reset */ | ||
381 | 0, /* pll_cfg: bypass */ | ||
382 | 0, /* misc: refdiv */ | ||
383 | 0, /* misc: bypclk_div */ | ||
384 | 1, /* misc: IO_CLK_en_core */ | ||
385 | 1, /* misc: ADClkSrc */ | ||
386 | 0, /* misc: modulo */ | ||
387 | (3 << 14) | (1 << 12) | (524 << 0), /* sad_cfg: refsel, sel, freq_15k */ | ||
388 | (1 << 25) | 5816102, /* ifreq = 5.200000 MHz */ | ||
389 | 20452225, /* timf */ | ||
390 | 30000000 /* xtal_hz */ | ||
391 | }; | ||
392 | |||
393 | static struct dib7000p_config hauppauge_hvr1400_dib7000_config = { | ||
394 | .output_mpeg2_in_188_bytes = 1, | ||
395 | .hostbus_diversity = 1, | ||
396 | .tuner_is_baseband = 0, | ||
397 | .update_lna = NULL, | ||
398 | |||
399 | .agc_config_count = 1, | ||
400 | .agc = &xc3028_agc_config, | ||
401 | .bw = &xc3028_bw_config, | ||
402 | |||
403 | .gpio_dir = DIB7000P_GPIO_DEFAULT_DIRECTIONS, | ||
404 | .gpio_val = DIB7000P_GPIO_DEFAULT_VALUES, | ||
405 | .gpio_pwm_pos = DIB7000P_GPIO_DEFAULT_PWM_POS, | ||
406 | |||
407 | .pwm_freq_div = 0, | ||
408 | .agc_control = NULL, | ||
409 | .spur_protect = 0, | ||
410 | |||
411 | .output_mode = OUTMODE_MPEG2_SERIAL, | ||
412 | }; | ||
413 | |||
414 | static struct zl10353_config dvico_fusionhdtv_xc3028 = { | ||
415 | .demod_address = 0x0f, | ||
416 | .if2 = 45600, | ||
417 | .no_tuner = 1, | ||
418 | .disable_i2c_gate_ctrl = 1, | ||
419 | }; | ||
420 | |||
421 | static struct stv0900_reg stv0900_ts_regs[] = { | ||
422 | { R0900_TSGENERAL, 0x00 }, | ||
423 | { R0900_P1_TSSPEED, 0x40 }, | ||
424 | { R0900_P2_TSSPEED, 0x40 }, | ||
425 | { R0900_P1_TSCFGM, 0xc0 }, | ||
426 | { R0900_P2_TSCFGM, 0xc0 }, | ||
427 | { R0900_P1_TSCFGH, 0xe0 }, | ||
428 | { R0900_P2_TSCFGH, 0xe0 }, | ||
429 | { R0900_P1_TSCFGL, 0x20 }, | ||
430 | { R0900_P2_TSCFGL, 0x20 }, | ||
431 | { 0xffff, 0xff }, /* terminate */ | ||
432 | }; | ||
433 | |||
434 | static struct stv0900_config netup_stv0900_config = { | ||
435 | .demod_address = 0x68, | ||
436 | .demod_mode = 1, /* dual */ | ||
437 | .xtal = 8000000, | ||
438 | .clkmode = 3,/* 0-CLKI, 2-XTALI, else AUTO */ | ||
439 | .diseqc_mode = 2,/* 2/3 PWM */ | ||
440 | .ts_config_regs = stv0900_ts_regs, | ||
441 | .tun1_maddress = 0,/* 0x60 */ | ||
442 | .tun2_maddress = 3,/* 0x63 */ | ||
443 | .tun1_adc = 1,/* 1 Vpp */ | ||
444 | .tun2_adc = 1,/* 1 Vpp */ | ||
445 | }; | ||
446 | |||
447 | static struct stv6110_config netup_stv6110_tunerconfig_a = { | ||
448 | .i2c_address = 0x60, | ||
449 | .mclk = 16000000, | ||
450 | .clk_div = 1, | ||
451 | .gain = 8, /* +16 dB - maximum gain */ | ||
452 | }; | ||
453 | |||
454 | static struct stv6110_config netup_stv6110_tunerconfig_b = { | ||
455 | .i2c_address = 0x63, | ||
456 | .mclk = 16000000, | ||
457 | .clk_div = 1, | ||
458 | .gain = 8, /* +16 dB - maximum gain */ | ||
459 | }; | ||
460 | |||
461 | static struct cx24116_config tbs_cx24116_config = { | ||
462 | .demod_address = 0x55, | ||
463 | }; | ||
464 | |||
465 | static struct ds3000_config tevii_ds3000_config = { | ||
466 | .demod_address = 0x68, | ||
467 | }; | ||
468 | |||
469 | static struct cx24116_config dvbworld_cx24116_config = { | ||
470 | .demod_address = 0x05, | ||
471 | }; | ||
472 | |||
473 | static struct lgs8gxx_config mygica_x8506_lgs8gl5_config = { | ||
474 | .prod = LGS8GXX_PROD_LGS8GL5, | ||
475 | .demod_address = 0x19, | ||
476 | .serial_ts = 0, | ||
477 | .ts_clk_pol = 1, | ||
478 | .ts_clk_gated = 1, | ||
479 | .if_clk_freq = 30400, /* 30.4 MHz */ | ||
480 | .if_freq = 5380, /* 5.38 MHz */ | ||
481 | .if_neg_center = 1, | ||
482 | .ext_adc = 0, | ||
483 | .adc_signed = 0, | ||
484 | .if_neg_edge = 0, | ||
485 | }; | ||
486 | |||
487 | static struct xc5000_config mygica_x8506_xc5000_config = { | ||
488 | .i2c_address = 0x61, | ||
489 | .if_khz = 5380, | ||
490 | }; | ||
491 | |||
492 | static int cx23885_dvb_set_frontend(struct dvb_frontend *fe) | ||
493 | { | ||
494 | struct dtv_frontend_properties *p = &fe->dtv_property_cache; | ||
495 | struct cx23885_tsport *port = fe->dvb->priv; | ||
496 | struct cx23885_dev *dev = port->dev; | ||
497 | |||
498 | switch (dev->board) { | ||
499 | case CX23885_BOARD_HAUPPAUGE_HVR1275: | ||
500 | switch (p->modulation) { | ||
501 | case VSB_8: | ||
502 | cx23885_gpio_clear(dev, GPIO_5); | ||
503 | break; | ||
504 | case QAM_64: | ||
505 | case QAM_256: | ||
506 | default: | ||
507 | cx23885_gpio_set(dev, GPIO_5); | ||
508 | break; | ||
509 | } | ||
510 | break; | ||
511 | case CX23885_BOARD_MYGICA_X8506: | ||
512 | case CX23885_BOARD_MAGICPRO_PROHDTVE2: | ||
513 | /* Select Digital TV */ | ||
514 | cx23885_gpio_set(dev, GPIO_0); | ||
515 | break; | ||
516 | } | ||
517 | return 0; | ||
518 | } | ||
519 | |||
520 | static struct lgs8gxx_config magicpro_prohdtve2_lgs8g75_config = { | ||
521 | .prod = LGS8GXX_PROD_LGS8G75, | ||
522 | .demod_address = 0x19, | ||
523 | .serial_ts = 0, | ||
524 | .ts_clk_pol = 1, | ||
525 | .ts_clk_gated = 1, | ||
526 | .if_clk_freq = 30400, /* 30.4 MHz */ | ||
527 | .if_freq = 6500, /* 6.50 MHz */ | ||
528 | .if_neg_center = 1, | ||
529 | .ext_adc = 0, | ||
530 | .adc_signed = 1, | ||
531 | .adc_vpp = 2, /* 1.6 Vpp */ | ||
532 | .if_neg_edge = 1, | ||
533 | }; | ||
534 | |||
535 | static struct xc5000_config magicpro_prohdtve2_xc5000_config = { | ||
536 | .i2c_address = 0x61, | ||
537 | .if_khz = 6500, | ||
538 | }; | ||
539 | |||
540 | static struct atbm8830_config mygica_x8558pro_atbm8830_cfg1 = { | ||
541 | .prod = ATBM8830_PROD_8830, | ||
542 | .demod_address = 0x44, | ||
543 | .serial_ts = 0, | ||
544 | .ts_sampling_edge = 1, | ||
545 | .ts_clk_gated = 0, | ||
546 | .osc_clk_freq = 30400, /* in kHz */ | ||
547 | .if_freq = 0, /* zero IF */ | ||
548 | .zif_swap_iq = 1, | ||
549 | .agc_min = 0x2E, | ||
550 | .agc_max = 0xFF, | ||
551 | .agc_hold_loop = 0, | ||
552 | }; | ||
553 | |||
554 | static struct max2165_config mygic_x8558pro_max2165_cfg1 = { | ||
555 | .i2c_address = 0x60, | ||
556 | .osc_clk = 20 | ||
557 | }; | ||
558 | |||
559 | static struct atbm8830_config mygica_x8558pro_atbm8830_cfg2 = { | ||
560 | .prod = ATBM8830_PROD_8830, | ||
561 | .demod_address = 0x44, | ||
562 | .serial_ts = 1, | ||
563 | .ts_sampling_edge = 1, | ||
564 | .ts_clk_gated = 0, | ||
565 | .osc_clk_freq = 30400, /* in kHz */ | ||
566 | .if_freq = 0, /* zero IF */ | ||
567 | .zif_swap_iq = 1, | ||
568 | .agc_min = 0x2E, | ||
569 | .agc_max = 0xFF, | ||
570 | .agc_hold_loop = 0, | ||
571 | }; | ||
572 | |||
573 | static struct max2165_config mygic_x8558pro_max2165_cfg2 = { | ||
574 | .i2c_address = 0x60, | ||
575 | .osc_clk = 20 | ||
576 | }; | ||
577 | static struct stv0367_config netup_stv0367_config[] = { | ||
578 | { | ||
579 | .demod_address = 0x1c, | ||
580 | .xtal = 27000000, | ||
581 | .if_khz = 4500, | ||
582 | .if_iq_mode = 0, | ||
583 | .ts_mode = 1, | ||
584 | .clk_pol = 0, | ||
585 | }, { | ||
586 | .demod_address = 0x1d, | ||
587 | .xtal = 27000000, | ||
588 | .if_khz = 4500, | ||
589 | .if_iq_mode = 0, | ||
590 | .ts_mode = 1, | ||
591 | .clk_pol = 0, | ||
592 | }, | ||
593 | }; | ||
594 | |||
595 | static struct xc5000_config netup_xc5000_config[] = { | ||
596 | { | ||
597 | .i2c_address = 0x61, | ||
598 | .if_khz = 4500, | ||
599 | }, { | ||
600 | .i2c_address = 0x64, | ||
601 | .if_khz = 4500, | ||
602 | }, | ||
603 | }; | ||
604 | |||
605 | static struct drxk_config terratec_drxk_config[] = { | ||
606 | { | ||
607 | .adr = 0x29, | ||
608 | .no_i2c_bridge = 1, | ||
609 | }, { | ||
610 | .adr = 0x2a, | ||
611 | .no_i2c_bridge = 1, | ||
612 | }, | ||
613 | }; | ||
614 | |||
615 | static struct mt2063_config terratec_mt2063_config[] = { | ||
616 | { | ||
617 | .tuner_address = 0x60, | ||
618 | }, { | ||
619 | .tuner_address = 0x67, | ||
620 | }, | ||
621 | }; | ||
622 | |||
623 | int netup_altera_fpga_rw(void *device, int flag, int data, int read) | ||
624 | { | ||
625 | struct cx23885_dev *dev = (struct cx23885_dev *)device; | ||
626 | unsigned long timeout = jiffies + msecs_to_jiffies(1); | ||
627 | uint32_t mem = 0; | ||
628 | |||
629 | mem = cx_read(MC417_RWD); | ||
630 | if (read) | ||
631 | cx_set(MC417_OEN, ALT_DATA); | ||
632 | else { | ||
633 | cx_clear(MC417_OEN, ALT_DATA);/* D0-D7 out */ | ||
634 | mem &= ~ALT_DATA; | ||
635 | mem |= (data & ALT_DATA); | ||
636 | } | ||
637 | |||
638 | if (flag) | ||
639 | mem |= ALT_AD_RG; | ||
640 | else | ||
641 | mem &= ~ALT_AD_RG; | ||
642 | |||
643 | mem &= ~ALT_CS; | ||
644 | if (read) | ||
645 | mem = (mem & ~ALT_RD) | ALT_WR; | ||
646 | else | ||
647 | mem = (mem & ~ALT_WR) | ALT_RD; | ||
648 | |||
649 | cx_write(MC417_RWD, mem); /* start RW cycle */ | ||
650 | |||
651 | for (;;) { | ||
652 | mem = cx_read(MC417_RWD); | ||
653 | if ((mem & ALT_RDY) == 0) | ||
654 | break; | ||
655 | if (time_after(jiffies, timeout)) | ||
656 | break; | ||
657 | udelay(1); | ||
658 | } | ||
659 | |||
660 | cx_set(MC417_RWD, ALT_RD | ALT_WR | ALT_CS); | ||
661 | if (read) | ||
662 | return mem & ALT_DATA; | ||
663 | |||
664 | return 0; | ||
665 | }; | ||
666 | |||
667 | static int dvb_register(struct cx23885_tsport *port) | ||
668 | { | ||
669 | struct cx23885_dev *dev = port->dev; | ||
670 | struct cx23885_i2c *i2c_bus = NULL, *i2c_bus2 = NULL; | ||
671 | struct videobuf_dvb_frontend *fe0, *fe1 = NULL; | ||
672 | int mfe_shared = 0; /* bus not shared by default */ | ||
673 | int ret; | ||
674 | |||
675 | /* Get the first frontend */ | ||
676 | fe0 = videobuf_dvb_get_frontend(&port->frontends, 1); | ||
677 | if (!fe0) | ||
678 | return -EINVAL; | ||
679 | |||
680 | /* init struct videobuf_dvb */ | ||
681 | fe0->dvb.name = dev->name; | ||
682 | |||
683 | /* multi-frontend gate control is undefined or defaults to fe0 */ | ||
684 | port->frontends.gate = 0; | ||
685 | |||
686 | /* Sets the gate control callback to be used by i2c command calls */ | ||
687 | port->gate_ctrl = cx23885_dvb_gate_ctrl; | ||
688 | |||
689 | /* init frontend */ | ||
690 | switch (dev->board) { | ||
691 | case CX23885_BOARD_HAUPPAUGE_HVR1250: | ||
692 | i2c_bus = &dev->i2c_bus[0]; | ||
693 | fe0->dvb.frontend = dvb_attach(s5h1409_attach, | ||
694 | &hauppauge_generic_config, | ||
695 | &i2c_bus->i2c_adap); | ||
696 | if (fe0->dvb.frontend != NULL) { | ||
697 | dvb_attach(mt2131_attach, fe0->dvb.frontend, | ||
698 | &i2c_bus->i2c_adap, | ||
699 | &hauppauge_generic_tunerconfig, 0); | ||
700 | } | ||
701 | break; | ||
702 | case CX23885_BOARD_HAUPPAUGE_HVR1270: | ||
703 | case CX23885_BOARD_HAUPPAUGE_HVR1275: | ||
704 | i2c_bus = &dev->i2c_bus[0]; | ||
705 | fe0->dvb.frontend = dvb_attach(lgdt3305_attach, | ||
706 | &hauppauge_lgdt3305_config, | ||
707 | &i2c_bus->i2c_adap); | ||
708 | if (fe0->dvb.frontend != NULL) { | ||
709 | dvb_attach(tda18271_attach, fe0->dvb.frontend, | ||
710 | 0x60, &dev->i2c_bus[1].i2c_adap, | ||
711 | &hauppauge_hvr127x_config); | ||
712 | } | ||
713 | break; | ||
714 | case CX23885_BOARD_HAUPPAUGE_HVR1255: | ||
715 | case CX23885_BOARD_HAUPPAUGE_HVR1255_22111: | ||
716 | i2c_bus = &dev->i2c_bus[0]; | ||
717 | fe0->dvb.frontend = dvb_attach(s5h1411_attach, | ||
718 | &hcw_s5h1411_config, | ||
719 | &i2c_bus->i2c_adap); | ||
720 | if (fe0->dvb.frontend != NULL) { | ||
721 | dvb_attach(tda18271_attach, fe0->dvb.frontend, | ||
722 | 0x60, &dev->i2c_bus[1].i2c_adap, | ||
723 | &hauppauge_tda18271_config); | ||
724 | } | ||
725 | |||
726 | tda18271_attach(&dev->ts1.analog_fe, | ||
727 | 0x60, &dev->i2c_bus[1].i2c_adap, | ||
728 | &hauppauge_tda18271_config); | ||
729 | |||
730 | break; | ||
731 | case CX23885_BOARD_HAUPPAUGE_HVR1800: | ||
732 | i2c_bus = &dev->i2c_bus[0]; | ||
733 | switch (alt_tuner) { | ||
734 | case 1: | ||
735 | fe0->dvb.frontend = | ||
736 | dvb_attach(s5h1409_attach, | ||
737 | &hauppauge_ezqam_config, | ||
738 | &i2c_bus->i2c_adap); | ||
739 | if (fe0->dvb.frontend != NULL) { | ||
740 | dvb_attach(tda829x_attach, fe0->dvb.frontend, | ||
741 | &dev->i2c_bus[1].i2c_adap, 0x42, | ||
742 | &tda829x_no_probe); | ||
743 | dvb_attach(tda18271_attach, fe0->dvb.frontend, | ||
744 | 0x60, &dev->i2c_bus[1].i2c_adap, | ||
745 | &hauppauge_tda18271_config); | ||
746 | } | ||
747 | break; | ||
748 | case 0: | ||
749 | default: | ||
750 | fe0->dvb.frontend = | ||
751 | dvb_attach(s5h1409_attach, | ||
752 | &hauppauge_generic_config, | ||
753 | &i2c_bus->i2c_adap); | ||
754 | if (fe0->dvb.frontend != NULL) | ||
755 | dvb_attach(mt2131_attach, fe0->dvb.frontend, | ||
756 | &i2c_bus->i2c_adap, | ||
757 | &hauppauge_generic_tunerconfig, 0); | ||
758 | break; | ||
759 | } | ||
760 | break; | ||
761 | case CX23885_BOARD_HAUPPAUGE_HVR1800lp: | ||
762 | i2c_bus = &dev->i2c_bus[0]; | ||
763 | fe0->dvb.frontend = dvb_attach(s5h1409_attach, | ||
764 | &hauppauge_hvr1800lp_config, | ||
765 | &i2c_bus->i2c_adap); | ||
766 | if (fe0->dvb.frontend != NULL) { | ||
767 | dvb_attach(mt2131_attach, fe0->dvb.frontend, | ||
768 | &i2c_bus->i2c_adap, | ||
769 | &hauppauge_generic_tunerconfig, 0); | ||
770 | } | ||
771 | break; | ||
772 | case CX23885_BOARD_DVICO_FUSIONHDTV_5_EXP: | ||
773 | i2c_bus = &dev->i2c_bus[0]; | ||
774 | fe0->dvb.frontend = dvb_attach(lgdt330x_attach, | ||
775 | &fusionhdtv_5_express, | ||
776 | &i2c_bus->i2c_adap); | ||
777 | if (fe0->dvb.frontend != NULL) { | ||
778 | dvb_attach(simple_tuner_attach, fe0->dvb.frontend, | ||
779 | &i2c_bus->i2c_adap, 0x61, | ||
780 | TUNER_LG_TDVS_H06XF); | ||
781 | } | ||
782 | break; | ||
783 | case CX23885_BOARD_HAUPPAUGE_HVR1500Q: | ||
784 | i2c_bus = &dev->i2c_bus[1]; | ||
785 | fe0->dvb.frontend = dvb_attach(s5h1409_attach, | ||
786 | &hauppauge_hvr1500q_config, | ||
787 | &dev->i2c_bus[0].i2c_adap); | ||
788 | if (fe0->dvb.frontend != NULL) | ||
789 | dvb_attach(xc5000_attach, fe0->dvb.frontend, | ||
790 | &i2c_bus->i2c_adap, | ||
791 | &hauppauge_hvr1500q_tunerconfig); | ||
792 | break; | ||
793 | case CX23885_BOARD_HAUPPAUGE_HVR1500: | ||
794 | i2c_bus = &dev->i2c_bus[1]; | ||
795 | fe0->dvb.frontend = dvb_attach(s5h1409_attach, | ||
796 | &hauppauge_hvr1500_config, | ||
797 | &dev->i2c_bus[0].i2c_adap); | ||
798 | if (fe0->dvb.frontend != NULL) { | ||
799 | struct dvb_frontend *fe; | ||
800 | struct xc2028_config cfg = { | ||
801 | .i2c_adap = &i2c_bus->i2c_adap, | ||
802 | .i2c_addr = 0x61, | ||
803 | }; | ||
804 | static struct xc2028_ctrl ctl = { | ||
805 | .fname = XC2028_DEFAULT_FIRMWARE, | ||
806 | .max_len = 64, | ||
807 | .demod = XC3028_FE_OREN538, | ||
808 | }; | ||
809 | |||
810 | fe = dvb_attach(xc2028_attach, | ||
811 | fe0->dvb.frontend, &cfg); | ||
812 | if (fe != NULL && fe->ops.tuner_ops.set_config != NULL) | ||
813 | fe->ops.tuner_ops.set_config(fe, &ctl); | ||
814 | } | ||
815 | break; | ||
816 | case CX23885_BOARD_HAUPPAUGE_HVR1200: | ||
817 | case CX23885_BOARD_HAUPPAUGE_HVR1700: | ||
818 | i2c_bus = &dev->i2c_bus[0]; | ||
819 | fe0->dvb.frontend = dvb_attach(tda10048_attach, | ||
820 | &hauppauge_hvr1200_config, | ||
821 | &i2c_bus->i2c_adap); | ||
822 | if (fe0->dvb.frontend != NULL) { | ||
823 | dvb_attach(tda829x_attach, fe0->dvb.frontend, | ||
824 | &dev->i2c_bus[1].i2c_adap, 0x42, | ||
825 | &tda829x_no_probe); | ||
826 | dvb_attach(tda18271_attach, fe0->dvb.frontend, | ||
827 | 0x60, &dev->i2c_bus[1].i2c_adap, | ||
828 | &hauppauge_hvr1200_tuner_config); | ||
829 | } | ||
830 | break; | ||
831 | case CX23885_BOARD_HAUPPAUGE_HVR1210: | ||
832 | i2c_bus = &dev->i2c_bus[0]; | ||
833 | fe0->dvb.frontend = dvb_attach(tda10048_attach, | ||
834 | &hauppauge_hvr1210_config, | ||
835 | &i2c_bus->i2c_adap); | ||
836 | if (fe0->dvb.frontend != NULL) { | ||
837 | dvb_attach(tda18271_attach, fe0->dvb.frontend, | ||
838 | 0x60, &dev->i2c_bus[1].i2c_adap, | ||
839 | &hauppauge_hvr1210_tuner_config); | ||
840 | } | ||
841 | break; | ||
842 | case CX23885_BOARD_HAUPPAUGE_HVR1400: | ||
843 | i2c_bus = &dev->i2c_bus[0]; | ||
844 | fe0->dvb.frontend = dvb_attach(dib7000p_attach, | ||
845 | &i2c_bus->i2c_adap, | ||
846 | 0x12, &hauppauge_hvr1400_dib7000_config); | ||
847 | if (fe0->dvb.frontend != NULL) { | ||
848 | struct dvb_frontend *fe; | ||
849 | struct xc2028_config cfg = { | ||
850 | .i2c_adap = &dev->i2c_bus[1].i2c_adap, | ||
851 | .i2c_addr = 0x64, | ||
852 | }; | ||
853 | static struct xc2028_ctrl ctl = { | ||
854 | .fname = XC3028L_DEFAULT_FIRMWARE, | ||
855 | .max_len = 64, | ||
856 | .demod = XC3028_FE_DIBCOM52, | ||
857 | /* This is true for all demods with | ||
858 | v36 firmware? */ | ||
859 | .type = XC2028_D2633, | ||
860 | }; | ||
861 | |||
862 | fe = dvb_attach(xc2028_attach, | ||
863 | fe0->dvb.frontend, &cfg); | ||
864 | if (fe != NULL && fe->ops.tuner_ops.set_config != NULL) | ||
865 | fe->ops.tuner_ops.set_config(fe, &ctl); | ||
866 | } | ||
867 | break; | ||
868 | case CX23885_BOARD_DVICO_FUSIONHDTV_7_DUAL_EXP: | ||
869 | i2c_bus = &dev->i2c_bus[port->nr - 1]; | ||
870 | |||
871 | fe0->dvb.frontend = dvb_attach(s5h1409_attach, | ||
872 | &dvico_s5h1409_config, | ||
873 | &i2c_bus->i2c_adap); | ||
874 | if (fe0->dvb.frontend == NULL) | ||
875 | fe0->dvb.frontend = dvb_attach(s5h1411_attach, | ||
876 | &dvico_s5h1411_config, | ||
877 | &i2c_bus->i2c_adap); | ||
878 | if (fe0->dvb.frontend != NULL) | ||
879 | dvb_attach(xc5000_attach, fe0->dvb.frontend, | ||
880 | &i2c_bus->i2c_adap, | ||
881 | &dvico_xc5000_tunerconfig); | ||
882 | break; | ||
883 | case CX23885_BOARD_DVICO_FUSIONHDTV_DVB_T_DUAL_EXP: { | ||
884 | i2c_bus = &dev->i2c_bus[port->nr - 1]; | ||
885 | |||
886 | fe0->dvb.frontend = dvb_attach(zl10353_attach, | ||
887 | &dvico_fusionhdtv_xc3028, | ||
888 | &i2c_bus->i2c_adap); | ||
889 | if (fe0->dvb.frontend != NULL) { | ||
890 | struct dvb_frontend *fe; | ||
891 | struct xc2028_config cfg = { | ||
892 | .i2c_adap = &i2c_bus->i2c_adap, | ||
893 | .i2c_addr = 0x61, | ||
894 | }; | ||
895 | static struct xc2028_ctrl ctl = { | ||
896 | .fname = XC2028_DEFAULT_FIRMWARE, | ||
897 | .max_len = 64, | ||
898 | .demod = XC3028_FE_ZARLINK456, | ||
899 | }; | ||
900 | |||
901 | fe = dvb_attach(xc2028_attach, fe0->dvb.frontend, | ||
902 | &cfg); | ||
903 | if (fe != NULL && fe->ops.tuner_ops.set_config != NULL) | ||
904 | fe->ops.tuner_ops.set_config(fe, &ctl); | ||
905 | } | ||
906 | break; | ||
907 | } | ||
908 | case CX23885_BOARD_LEADTEK_WINFAST_PXDVR3200_H: | ||
909 | case CX23885_BOARD_COMPRO_VIDEOMATE_E650F: | ||
910 | case CX23885_BOARD_COMPRO_VIDEOMATE_E800: | ||
911 | i2c_bus = &dev->i2c_bus[0]; | ||
912 | |||
913 | fe0->dvb.frontend = dvb_attach(zl10353_attach, | ||
914 | &dvico_fusionhdtv_xc3028, | ||
915 | &i2c_bus->i2c_adap); | ||
916 | if (fe0->dvb.frontend != NULL) { | ||
917 | struct dvb_frontend *fe; | ||
918 | struct xc2028_config cfg = { | ||
919 | .i2c_adap = &dev->i2c_bus[1].i2c_adap, | ||
920 | .i2c_addr = 0x61, | ||
921 | }; | ||
922 | static struct xc2028_ctrl ctl = { | ||
923 | .fname = XC2028_DEFAULT_FIRMWARE, | ||
924 | .max_len = 64, | ||
925 | .demod = XC3028_FE_ZARLINK456, | ||
926 | }; | ||
927 | |||
928 | fe = dvb_attach(xc2028_attach, fe0->dvb.frontend, | ||
929 | &cfg); | ||
930 | if (fe != NULL && fe->ops.tuner_ops.set_config != NULL) | ||
931 | fe->ops.tuner_ops.set_config(fe, &ctl); | ||
932 | } | ||
933 | break; | ||
934 | case CX23885_BOARD_LEADTEK_WINFAST_PXDVR3200_H_XC4000: | ||
935 | i2c_bus = &dev->i2c_bus[0]; | ||
936 | |||
937 | fe0->dvb.frontend = dvb_attach(zl10353_attach, | ||
938 | &dvico_fusionhdtv_xc3028, | ||
939 | &i2c_bus->i2c_adap); | ||
940 | if (fe0->dvb.frontend != NULL) { | ||
941 | struct dvb_frontend *fe; | ||
942 | struct xc4000_config cfg = { | ||
943 | .i2c_address = 0x61, | ||
944 | .default_pm = 0, | ||
945 | .dvb_amplitude = 134, | ||
946 | .set_smoothedcvbs = 1, | ||
947 | .if_khz = 4560 | ||
948 | }; | ||
949 | |||
950 | fe = dvb_attach(xc4000_attach, fe0->dvb.frontend, | ||
951 | &dev->i2c_bus[1].i2c_adap, &cfg); | ||
952 | if (!fe) { | ||
953 | printk(KERN_ERR "%s/2: xc4000 attach failed\n", | ||
954 | dev->name); | ||
955 | goto frontend_detach; | ||
956 | } | ||
957 | } | ||
958 | break; | ||
959 | case CX23885_BOARD_TBS_6920: | ||
960 | i2c_bus = &dev->i2c_bus[1]; | ||
961 | |||
962 | fe0->dvb.frontend = dvb_attach(cx24116_attach, | ||
963 | &tbs_cx24116_config, | ||
964 | &i2c_bus->i2c_adap); | ||
965 | if (fe0->dvb.frontend != NULL) | ||
966 | fe0->dvb.frontend->ops.set_voltage = f300_set_voltage; | ||
967 | |||
968 | break; | ||
969 | case CX23885_BOARD_TEVII_S470: | ||
970 | i2c_bus = &dev->i2c_bus[1]; | ||
971 | |||
972 | fe0->dvb.frontend = dvb_attach(ds3000_attach, | ||
973 | &tevii_ds3000_config, | ||
974 | &i2c_bus->i2c_adap); | ||
975 | if (fe0->dvb.frontend != NULL) | ||
976 | fe0->dvb.frontend->ops.set_voltage = f300_set_voltage; | ||
977 | |||
978 | break; | ||
979 | case CX23885_BOARD_DVBWORLD_2005: | ||
980 | i2c_bus = &dev->i2c_bus[1]; | ||
981 | |||
982 | fe0->dvb.frontend = dvb_attach(cx24116_attach, | ||
983 | &dvbworld_cx24116_config, | ||
984 | &i2c_bus->i2c_adap); | ||
985 | break; | ||
986 | case CX23885_BOARD_NETUP_DUAL_DVBS2_CI: | ||
987 | i2c_bus = &dev->i2c_bus[0]; | ||
988 | switch (port->nr) { | ||
989 | /* port B */ | ||
990 | case 1: | ||
991 | fe0->dvb.frontend = dvb_attach(stv0900_attach, | ||
992 | &netup_stv0900_config, | ||
993 | &i2c_bus->i2c_adap, 0); | ||
994 | if (fe0->dvb.frontend != NULL) { | ||
995 | if (dvb_attach(stv6110_attach, | ||
996 | fe0->dvb.frontend, | ||
997 | &netup_stv6110_tunerconfig_a, | ||
998 | &i2c_bus->i2c_adap)) { | ||
999 | if (!dvb_attach(lnbh24_attach, | ||
1000 | fe0->dvb.frontend, | ||
1001 | &i2c_bus->i2c_adap, | ||
1002 | LNBH24_PCL | LNBH24_TTX, | ||
1003 | LNBH24_TEN, 0x09)) | ||
1004 | printk(KERN_ERR | ||
1005 | "No LNBH24 found!\n"); | ||
1006 | |||
1007 | } | ||
1008 | } | ||
1009 | break; | ||
1010 | /* port C */ | ||
1011 | case 2: | ||
1012 | fe0->dvb.frontend = dvb_attach(stv0900_attach, | ||
1013 | &netup_stv0900_config, | ||
1014 | &i2c_bus->i2c_adap, 1); | ||
1015 | if (fe0->dvb.frontend != NULL) { | ||
1016 | if (dvb_attach(stv6110_attach, | ||
1017 | fe0->dvb.frontend, | ||
1018 | &netup_stv6110_tunerconfig_b, | ||
1019 | &i2c_bus->i2c_adap)) { | ||
1020 | if (!dvb_attach(lnbh24_attach, | ||
1021 | fe0->dvb.frontend, | ||
1022 | &i2c_bus->i2c_adap, | ||
1023 | LNBH24_PCL | LNBH24_TTX, | ||
1024 | LNBH24_TEN, 0x0a)) | ||
1025 | printk(KERN_ERR | ||
1026 | "No LNBH24 found!\n"); | ||
1027 | |||
1028 | } | ||
1029 | } | ||
1030 | break; | ||
1031 | } | ||
1032 | break; | ||
1033 | case CX23885_BOARD_MYGICA_X8506: | ||
1034 | i2c_bus = &dev->i2c_bus[0]; | ||
1035 | i2c_bus2 = &dev->i2c_bus[1]; | ||
1036 | fe0->dvb.frontend = dvb_attach(lgs8gxx_attach, | ||
1037 | &mygica_x8506_lgs8gl5_config, | ||
1038 | &i2c_bus->i2c_adap); | ||
1039 | if (fe0->dvb.frontend != NULL) { | ||
1040 | dvb_attach(xc5000_attach, | ||
1041 | fe0->dvb.frontend, | ||
1042 | &i2c_bus2->i2c_adap, | ||
1043 | &mygica_x8506_xc5000_config); | ||
1044 | } | ||
1045 | break; | ||
1046 | case CX23885_BOARD_MAGICPRO_PROHDTVE2: | ||
1047 | i2c_bus = &dev->i2c_bus[0]; | ||
1048 | i2c_bus2 = &dev->i2c_bus[1]; | ||
1049 | fe0->dvb.frontend = dvb_attach(lgs8gxx_attach, | ||
1050 | &magicpro_prohdtve2_lgs8g75_config, | ||
1051 | &i2c_bus->i2c_adap); | ||
1052 | if (fe0->dvb.frontend != NULL) { | ||
1053 | dvb_attach(xc5000_attach, | ||
1054 | fe0->dvb.frontend, | ||
1055 | &i2c_bus2->i2c_adap, | ||
1056 | &magicpro_prohdtve2_xc5000_config); | ||
1057 | } | ||
1058 | break; | ||
1059 | case CX23885_BOARD_HAUPPAUGE_HVR1850: | ||
1060 | i2c_bus = &dev->i2c_bus[0]; | ||
1061 | fe0->dvb.frontend = dvb_attach(s5h1411_attach, | ||
1062 | &hcw_s5h1411_config, | ||
1063 | &i2c_bus->i2c_adap); | ||
1064 | if (fe0->dvb.frontend != NULL) | ||
1065 | dvb_attach(tda18271_attach, fe0->dvb.frontend, | ||
1066 | 0x60, &dev->i2c_bus[0].i2c_adap, | ||
1067 | &hauppauge_tda18271_config); | ||
1068 | |||
1069 | tda18271_attach(&dev->ts1.analog_fe, | ||
1070 | 0x60, &dev->i2c_bus[1].i2c_adap, | ||
1071 | &hauppauge_tda18271_config); | ||
1072 | |||
1073 | break; | ||
1074 | case CX23885_BOARD_HAUPPAUGE_HVR1290: | ||
1075 | i2c_bus = &dev->i2c_bus[0]; | ||
1076 | fe0->dvb.frontend = dvb_attach(s5h1411_attach, | ||
1077 | &hcw_s5h1411_config, | ||
1078 | &i2c_bus->i2c_adap); | ||
1079 | if (fe0->dvb.frontend != NULL) | ||
1080 | dvb_attach(tda18271_attach, fe0->dvb.frontend, | ||
1081 | 0x60, &dev->i2c_bus[0].i2c_adap, | ||
1082 | &hauppauge_tda18271_config); | ||
1083 | break; | ||
1084 | case CX23885_BOARD_MYGICA_X8558PRO: | ||
1085 | switch (port->nr) { | ||
1086 | /* port B */ | ||
1087 | case 1: | ||
1088 | i2c_bus = &dev->i2c_bus[0]; | ||
1089 | fe0->dvb.frontend = dvb_attach(atbm8830_attach, | ||
1090 | &mygica_x8558pro_atbm8830_cfg1, | ||
1091 | &i2c_bus->i2c_adap); | ||
1092 | if (fe0->dvb.frontend != NULL) { | ||
1093 | dvb_attach(max2165_attach, | ||
1094 | fe0->dvb.frontend, | ||
1095 | &i2c_bus->i2c_adap, | ||
1096 | &mygic_x8558pro_max2165_cfg1); | ||
1097 | } | ||
1098 | break; | ||
1099 | /* port C */ | ||
1100 | case 2: | ||
1101 | i2c_bus = &dev->i2c_bus[1]; | ||
1102 | fe0->dvb.frontend = dvb_attach(atbm8830_attach, | ||
1103 | &mygica_x8558pro_atbm8830_cfg2, | ||
1104 | &i2c_bus->i2c_adap); | ||
1105 | if (fe0->dvb.frontend != NULL) { | ||
1106 | dvb_attach(max2165_attach, | ||
1107 | fe0->dvb.frontend, | ||
1108 | &i2c_bus->i2c_adap, | ||
1109 | &mygic_x8558pro_max2165_cfg2); | ||
1110 | } | ||
1111 | break; | ||
1112 | } | ||
1113 | break; | ||
1114 | case CX23885_BOARD_NETUP_DUAL_DVB_T_C_CI_RF: | ||
1115 | i2c_bus = &dev->i2c_bus[0]; | ||
1116 | mfe_shared = 1;/* MFE */ | ||
1117 | port->frontends.gate = 0;/* not clear for me yet */ | ||
1118 | /* ports B, C */ | ||
1119 | /* MFE frontend 1 DVB-T */ | ||
1120 | fe0->dvb.frontend = dvb_attach(stv0367ter_attach, | ||
1121 | &netup_stv0367_config[port->nr - 1], | ||
1122 | &i2c_bus->i2c_adap); | ||
1123 | if (fe0->dvb.frontend != NULL) { | ||
1124 | if (NULL == dvb_attach(xc5000_attach, | ||
1125 | fe0->dvb.frontend, | ||
1126 | &i2c_bus->i2c_adap, | ||
1127 | &netup_xc5000_config[port->nr - 1])) | ||
1128 | goto frontend_detach; | ||
1129 | /* load xc5000 firmware */ | ||
1130 | fe0->dvb.frontend->ops.tuner_ops.init(fe0->dvb.frontend); | ||
1131 | } | ||
1132 | /* MFE frontend 2 */ | ||
1133 | fe1 = videobuf_dvb_get_frontend(&port->frontends, 2); | ||
1134 | if (fe1 == NULL) | ||
1135 | goto frontend_detach; | ||
1136 | /* DVB-C init */ | ||
1137 | fe1->dvb.frontend = dvb_attach(stv0367cab_attach, | ||
1138 | &netup_stv0367_config[port->nr - 1], | ||
1139 | &i2c_bus->i2c_adap); | ||
1140 | if (fe1->dvb.frontend != NULL) { | ||
1141 | fe1->dvb.frontend->id = 1; | ||
1142 | if (NULL == dvb_attach(xc5000_attach, | ||
1143 | fe1->dvb.frontend, | ||
1144 | &i2c_bus->i2c_adap, | ||
1145 | &netup_xc5000_config[port->nr - 1])) | ||
1146 | goto frontend_detach; | ||
1147 | } | ||
1148 | break; | ||
1149 | case CX23885_BOARD_TERRATEC_CINERGY_T_PCIE_DUAL: | ||
1150 | i2c_bus = &dev->i2c_bus[0]; | ||
1151 | i2c_bus2 = &dev->i2c_bus[1]; | ||
1152 | |||
1153 | switch (port->nr) { | ||
1154 | /* port b */ | ||
1155 | case 1: | ||
1156 | fe0->dvb.frontend = dvb_attach(drxk_attach, | ||
1157 | &terratec_drxk_config[0], | ||
1158 | &i2c_bus->i2c_adap); | ||
1159 | if (fe0->dvb.frontend != NULL) { | ||
1160 | if (!dvb_attach(mt2063_attach, | ||
1161 | fe0->dvb.frontend, | ||
1162 | &terratec_mt2063_config[0], | ||
1163 | &i2c_bus2->i2c_adap)) | ||
1164 | goto frontend_detach; | ||
1165 | } | ||
1166 | break; | ||
1167 | /* port c */ | ||
1168 | case 2: | ||
1169 | fe0->dvb.frontend = dvb_attach(drxk_attach, | ||
1170 | &terratec_drxk_config[1], | ||
1171 | &i2c_bus->i2c_adap); | ||
1172 | if (fe0->dvb.frontend != NULL) { | ||
1173 | if (!dvb_attach(mt2063_attach, | ||
1174 | fe0->dvb.frontend, | ||
1175 | &terratec_mt2063_config[1], | ||
1176 | &i2c_bus2->i2c_adap)) | ||
1177 | goto frontend_detach; | ||
1178 | } | ||
1179 | break; | ||
1180 | } | ||
1181 | break; | ||
1182 | case CX23885_BOARD_TEVII_S471: | ||
1183 | i2c_bus = &dev->i2c_bus[1]; | ||
1184 | |||
1185 | fe0->dvb.frontend = dvb_attach(ds3000_attach, | ||
1186 | &tevii_ds3000_config, | ||
1187 | &i2c_bus->i2c_adap); | ||
1188 | break; | ||
1189 | default: | ||
1190 | printk(KERN_INFO "%s: The frontend of your DVB/ATSC card " | ||
1191 | " isn't supported yet\n", | ||
1192 | dev->name); | ||
1193 | break; | ||
1194 | } | ||
1195 | |||
1196 | if ((NULL == fe0->dvb.frontend) || (fe1 && NULL == fe1->dvb.frontend)) { | ||
1197 | printk(KERN_ERR "%s: frontend initialization failed\n", | ||
1198 | dev->name); | ||
1199 | goto frontend_detach; | ||
1200 | } | ||
1201 | |||
1202 | /* define general-purpose callback pointer */ | ||
1203 | fe0->dvb.frontend->callback = cx23885_tuner_callback; | ||
1204 | if (fe1) | ||
1205 | fe1->dvb.frontend->callback = cx23885_tuner_callback; | ||
1206 | #if 0 | ||
1207 | /* Ensure all frontends negotiate bus access */ | ||
1208 | fe0->dvb.frontend->ops.ts_bus_ctrl = cx23885_dvb_bus_ctrl; | ||
1209 | if (fe1) | ||
1210 | fe1->dvb.frontend->ops.ts_bus_ctrl = cx23885_dvb_bus_ctrl; | ||
1211 | #endif | ||
1212 | |||
1213 | /* Put the analog decoder in standby to keep it quiet */ | ||
1214 | call_all(dev, core, s_power, 0); | ||
1215 | |||
1216 | if (fe0->dvb.frontend->ops.analog_ops.standby) | ||
1217 | fe0->dvb.frontend->ops.analog_ops.standby(fe0->dvb.frontend); | ||
1218 | |||
1219 | /* register everything */ | ||
1220 | ret = videobuf_dvb_register_bus(&port->frontends, THIS_MODULE, port, | ||
1221 | &dev->pci->dev, adapter_nr, mfe_shared); | ||
1222 | if (ret) | ||
1223 | goto frontend_detach; | ||
1224 | |||
1225 | /* init CI & MAC */ | ||
1226 | switch (dev->board) { | ||
1227 | case CX23885_BOARD_NETUP_DUAL_DVBS2_CI: { | ||
1228 | static struct netup_card_info cinfo; | ||
1229 | |||
1230 | netup_get_card_info(&dev->i2c_bus[0].i2c_adap, &cinfo); | ||
1231 | memcpy(port->frontends.adapter.proposed_mac, | ||
1232 | cinfo.port[port->nr - 1].mac, 6); | ||
1233 | printk(KERN_INFO "NetUP Dual DVB-S2 CI card port%d MAC=%pM\n", | ||
1234 | port->nr, port->frontends.adapter.proposed_mac); | ||
1235 | |||
1236 | netup_ci_init(port); | ||
1237 | break; | ||
1238 | } | ||
1239 | case CX23885_BOARD_NETUP_DUAL_DVB_T_C_CI_RF: { | ||
1240 | struct altera_ci_config netup_ci_cfg = { | ||
1241 | .dev = dev,/* magic number to identify*/ | ||
1242 | .adapter = &port->frontends.adapter,/* for CI */ | ||
1243 | .demux = &fe0->dvb.demux,/* for hw pid filter */ | ||
1244 | .fpga_rw = netup_altera_fpga_rw, | ||
1245 | }; | ||
1246 | |||
1247 | altera_ci_init(&netup_ci_cfg, port->nr); | ||
1248 | break; | ||
1249 | } | ||
1250 | case CX23885_BOARD_TEVII_S470: { | ||
1251 | u8 eeprom[256]; /* 24C02 i2c eeprom */ | ||
1252 | |||
1253 | if (port->nr != 1) | ||
1254 | break; | ||
1255 | |||
1256 | /* Read entire EEPROM */ | ||
1257 | dev->i2c_bus[0].i2c_client.addr = 0xa0 >> 1; | ||
1258 | tveeprom_read(&dev->i2c_bus[0].i2c_client, eeprom, sizeof(eeprom)); | ||
1259 | printk(KERN_INFO "TeVii S470 MAC= %pM\n", eeprom + 0xa0); | ||
1260 | memcpy(port->frontends.adapter.proposed_mac, eeprom + 0xa0, 6); | ||
1261 | break; | ||
1262 | } | ||
1263 | } | ||
1264 | |||
1265 | return ret; | ||
1266 | |||
1267 | frontend_detach: | ||
1268 | port->gate_ctrl = NULL; | ||
1269 | videobuf_dvb_dealloc_frontends(&port->frontends); | ||
1270 | return -EINVAL; | ||
1271 | } | ||
1272 | |||
1273 | int cx23885_dvb_register(struct cx23885_tsport *port) | ||
1274 | { | ||
1275 | |||
1276 | struct videobuf_dvb_frontend *fe0; | ||
1277 | struct cx23885_dev *dev = port->dev; | ||
1278 | int err, i; | ||
1279 | |||
1280 | /* Here we need to allocate the correct number of frontends, | ||
1281 | * as reflected in the cards struct. The reality is that currently | ||
1282 | * no cx23885 boards support this - yet. But, if we don't modify this | ||
1283 | * code then the second frontend would never be allocated (later) | ||
1284 | * and fail with error before the attach in dvb_register(). | ||
1285 | * Without these changes we risk an OOPS later. The changes here | ||
1286 | * are for safety, and should provide a good foundation for the | ||
1287 | * future addition of any multi-frontend cx23885 based boards. | ||
1288 | */ | ||
1289 | printk(KERN_INFO "%s() allocating %d frontend(s)\n", __func__, | ||
1290 | port->num_frontends); | ||
1291 | |||
1292 | for (i = 1; i <= port->num_frontends; i++) { | ||
1293 | if (videobuf_dvb_alloc_frontend( | ||
1294 | &port->frontends, i) == NULL) { | ||
1295 | printk(KERN_ERR "%s() failed to alloc\n", __func__); | ||
1296 | return -ENOMEM; | ||
1297 | } | ||
1298 | |||
1299 | fe0 = videobuf_dvb_get_frontend(&port->frontends, i); | ||
1300 | if (!fe0) | ||
1301 | err = -EINVAL; | ||
1302 | |||
1303 | dprintk(1, "%s\n", __func__); | ||
1304 | dprintk(1, " ->probed by Card=%d Name=%s, PCI %02x:%02x\n", | ||
1305 | dev->board, | ||
1306 | dev->name, | ||
1307 | dev->pci_bus, | ||
1308 | dev->pci_slot); | ||
1309 | |||
1310 | err = -ENODEV; | ||
1311 | |||
1312 | /* dvb stuff */ | ||
1313 | /* We have to init the queue for each frontend on a port. */ | ||
1314 | printk(KERN_INFO "%s: cx23885 based dvb card\n", dev->name); | ||
1315 | videobuf_queue_sg_init(&fe0->dvb.dvbq, &dvb_qops, | ||
1316 | &dev->pci->dev, &port->slock, | ||
1317 | V4L2_BUF_TYPE_VIDEO_CAPTURE, V4L2_FIELD_TOP, | ||
1318 | sizeof(struct cx23885_buffer), port, NULL); | ||
1319 | } | ||
1320 | err = dvb_register(port); | ||
1321 | if (err != 0) | ||
1322 | printk(KERN_ERR "%s() dvb_register failed err = %d\n", | ||
1323 | __func__, err); | ||
1324 | |||
1325 | return err; | ||
1326 | } | ||
1327 | |||
1328 | int cx23885_dvb_unregister(struct cx23885_tsport *port) | ||
1329 | { | ||
1330 | struct videobuf_dvb_frontend *fe0; | ||
1331 | |||
1332 | /* FIXME: in an error condition where the we have | ||
1333 | * an expected number of frontends (attach problem) | ||
1334 | * then this might not clean up correctly, if 1 | ||
1335 | * is invalid. | ||
1336 | * This comment only applies to future boards IF they | ||
1337 | * implement MFE support. | ||
1338 | */ | ||
1339 | fe0 = videobuf_dvb_get_frontend(&port->frontends, 1); | ||
1340 | if (fe0 && fe0->dvb.frontend) | ||
1341 | videobuf_dvb_unregister_bus(&port->frontends); | ||
1342 | |||
1343 | switch (port->dev->board) { | ||
1344 | case CX23885_BOARD_NETUP_DUAL_DVBS2_CI: | ||
1345 | netup_ci_exit(port); | ||
1346 | break; | ||
1347 | case CX23885_BOARD_NETUP_DUAL_DVB_T_C_CI_RF: | ||
1348 | altera_ci_release(port->dev, port->nr); | ||
1349 | break; | ||
1350 | } | ||
1351 | |||
1352 | port->gate_ctrl = NULL; | ||
1353 | |||
1354 | return 0; | ||
1355 | } | ||
1356 | |||
diff --git a/drivers/media/pci/cx23885/cx23885-f300.c b/drivers/media/pci/cx23885/cx23885-f300.c new file mode 100644 index 000000000000..93998f220986 --- /dev/null +++ b/drivers/media/pci/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/pci/cx23885/cx23885-f300.h b/drivers/media/pci/cx23885/cx23885-f300.h new file mode 100644 index 000000000000..e73344c94963 --- /dev/null +++ b/drivers/media/pci/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/pci/cx23885/cx23885-i2c.c b/drivers/media/pci/cx23885/cx23885-i2c.c new file mode 100644 index 000000000000..4887314339cb --- /dev/null +++ b/drivers/media/pci/cx23885/cx23885-i2c.c | |||
@@ -0,0 +1,396 @@ | |||
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 | [0x98 >> 1] = "flatiron", | ||
291 | [0xa0 >> 1] = "eeprom", | ||
292 | [0xc0 >> 1] = "tuner/mt2131/tda8275", | ||
293 | [0xc2 >> 1] = "tuner/mt2131/tda8275/xc5000/xc3028", | ||
294 | [0xc8 >> 1] = "tuner/xc3028L", | ||
295 | }; | ||
296 | |||
297 | static void do_i2c_scan(char *name, struct i2c_client *c) | ||
298 | { | ||
299 | unsigned char buf; | ||
300 | int i, rc; | ||
301 | |||
302 | for (i = 0; i < 128; i++) { | ||
303 | c->addr = i; | ||
304 | rc = i2c_master_recv(c, &buf, 0); | ||
305 | if (rc < 0) | ||
306 | continue; | ||
307 | printk(KERN_INFO "%s: i2c scan: found device @ 0x%x [%s]\n", | ||
308 | name, i << 1, i2c_devs[i] ? i2c_devs[i] : "???"); | ||
309 | } | ||
310 | } | ||
311 | |||
312 | /* init + register i2c adapter */ | ||
313 | int cx23885_i2c_register(struct cx23885_i2c *bus) | ||
314 | { | ||
315 | struct cx23885_dev *dev = bus->dev; | ||
316 | |||
317 | dprintk(1, "%s(bus = %d)\n", __func__, bus->nr); | ||
318 | |||
319 | bus->i2c_adap = cx23885_i2c_adap_template; | ||
320 | bus->i2c_client = cx23885_i2c_client_template; | ||
321 | bus->i2c_adap.dev.parent = &dev->pci->dev; | ||
322 | |||
323 | strlcpy(bus->i2c_adap.name, bus->dev->name, | ||
324 | sizeof(bus->i2c_adap.name)); | ||
325 | |||
326 | bus->i2c_adap.algo_data = bus; | ||
327 | i2c_set_adapdata(&bus->i2c_adap, &dev->v4l2_dev); | ||
328 | i2c_add_adapter(&bus->i2c_adap); | ||
329 | |||
330 | bus->i2c_client.adapter = &bus->i2c_adap; | ||
331 | |||
332 | if (0 == bus->i2c_rc) { | ||
333 | dprintk(1, "%s: i2c bus %d registered\n", dev->name, bus->nr); | ||
334 | if (i2c_scan) { | ||
335 | printk(KERN_INFO "%s: scan bus %d:\n", | ||
336 | dev->name, bus->nr); | ||
337 | do_i2c_scan(dev->name, &bus->i2c_client); | ||
338 | } | ||
339 | } else | ||
340 | printk(KERN_WARNING "%s: i2c bus %d register FAILED\n", | ||
341 | dev->name, bus->nr); | ||
342 | |||
343 | /* Instantiate the IR receiver device, if present */ | ||
344 | if (0 == bus->i2c_rc) { | ||
345 | struct i2c_board_info info; | ||
346 | const unsigned short addr_list[] = { | ||
347 | 0x6b, I2C_CLIENT_END | ||
348 | }; | ||
349 | |||
350 | memset(&info, 0, sizeof(struct i2c_board_info)); | ||
351 | strlcpy(info.type, "ir_video", I2C_NAME_SIZE); | ||
352 | /* Use quick read command for probe, some IR chips don't | ||
353 | * support writes */ | ||
354 | i2c_new_probed_device(&bus->i2c_adap, &info, addr_list, | ||
355 | i2c_probe_func_quick_read); | ||
356 | } | ||
357 | |||
358 | return bus->i2c_rc; | ||
359 | } | ||
360 | |||
361 | int cx23885_i2c_unregister(struct cx23885_i2c *bus) | ||
362 | { | ||
363 | i2c_del_adapter(&bus->i2c_adap); | ||
364 | return 0; | ||
365 | } | ||
366 | |||
367 | void cx23885_av_clk(struct cx23885_dev *dev, int enable) | ||
368 | { | ||
369 | /* write 0 to bus 2 addr 0x144 via i2x_xfer() */ | ||
370 | char buffer[3]; | ||
371 | struct i2c_msg msg; | ||
372 | dprintk(1, "%s(enabled = %d)\n", __func__, enable); | ||
373 | |||
374 | /* Register 0x144 */ | ||
375 | buffer[0] = 0x01; | ||
376 | buffer[1] = 0x44; | ||
377 | if (enable == 1) | ||
378 | buffer[2] = 0x05; | ||
379 | else | ||
380 | buffer[2] = 0x00; | ||
381 | |||
382 | msg.addr = 0x44; | ||
383 | msg.flags = I2C_M_TEN; | ||
384 | msg.len = 3; | ||
385 | msg.buf = buffer; | ||
386 | |||
387 | i2c_xfer(&dev->i2c_bus[2].i2c_adap, &msg, 1); | ||
388 | } | ||
389 | |||
390 | /* ----------------------------------------------------------------------- */ | ||
391 | |||
392 | /* | ||
393 | * Local variables: | ||
394 | * c-basic-offset: 8 | ||
395 | * End: | ||
396 | */ | ||
diff --git a/drivers/media/pci/cx23885/cx23885-input.c b/drivers/media/pci/cx23885/cx23885-input.c new file mode 100644 index 000000000000..56066721edc1 --- /dev/null +++ b/drivers/media/pci/cx23885/cx23885-input.c | |||
@@ -0,0 +1,365 @@ | |||
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_TERRATEC_CINERGY_T_PCIE_DUAL: | ||
89 | case CX23885_BOARD_TEVII_S470: | ||
90 | case CX23885_BOARD_HAUPPAUGE_HVR1250: | ||
91 | /* | ||
92 | * The only boards we handle right now. However other boards | ||
93 | * using the CX2388x integrated IR controller should be similar | ||
94 | */ | ||
95 | break; | ||
96 | default: | ||
97 | return; | ||
98 | } | ||
99 | |||
100 | overrun = events & (V4L2_SUBDEV_IR_RX_SW_FIFO_OVERRUN | | ||
101 | V4L2_SUBDEV_IR_RX_HW_FIFO_OVERRUN); | ||
102 | |||
103 | data_available = events & (V4L2_SUBDEV_IR_RX_END_OF_RX_DETECTED | | ||
104 | V4L2_SUBDEV_IR_RX_FIFO_SERVICE_REQ); | ||
105 | |||
106 | if (overrun) { | ||
107 | /* If there was a FIFO overrun, stop the device */ | ||
108 | v4l2_subdev_call(dev->sd_ir, ir, rx_g_parameters, ¶ms); | ||
109 | params.enable = false; | ||
110 | /* Mitigate race with cx23885_input_ir_stop() */ | ||
111 | params.shutdown = atomic_read(&dev->ir_input_stopping); | ||
112 | v4l2_subdev_call(dev->sd_ir, ir, rx_s_parameters, ¶ms); | ||
113 | } | ||
114 | |||
115 | if (data_available) | ||
116 | cx23885_input_process_measurements(dev, overrun); | ||
117 | |||
118 | if (overrun) { | ||
119 | /* If there was a FIFO overrun, clear & restart the device */ | ||
120 | params.enable = true; | ||
121 | /* Mitigate race with cx23885_input_ir_stop() */ | ||
122 | params.shutdown = atomic_read(&dev->ir_input_stopping); | ||
123 | v4l2_subdev_call(dev->sd_ir, ir, rx_s_parameters, ¶ms); | ||
124 | } | ||
125 | } | ||
126 | |||
127 | static int cx23885_input_ir_start(struct cx23885_dev *dev) | ||
128 | { | ||
129 | struct v4l2_subdev_ir_parameters params; | ||
130 | |||
131 | if (dev->sd_ir == NULL) | ||
132 | return -ENODEV; | ||
133 | |||
134 | atomic_set(&dev->ir_input_stopping, 0); | ||
135 | |||
136 | v4l2_subdev_call(dev->sd_ir, ir, rx_g_parameters, ¶ms); | ||
137 | switch (dev->board) { | ||
138 | case CX23885_BOARD_HAUPPAUGE_HVR1270: | ||
139 | case CX23885_BOARD_HAUPPAUGE_HVR1850: | ||
140 | case CX23885_BOARD_HAUPPAUGE_HVR1290: | ||
141 | case CX23885_BOARD_HAUPPAUGE_HVR1250: | ||
142 | /* | ||
143 | * The IR controller on this board only returns pulse widths. | ||
144 | * Any other mode setting will fail to set up the device. | ||
145 | */ | ||
146 | params.mode = V4L2_SUBDEV_IR_MODE_PULSE_WIDTH; | ||
147 | params.enable = true; | ||
148 | params.interrupt_enable = true; | ||
149 | params.shutdown = false; | ||
150 | |||
151 | /* Setup for baseband compatible with both RC-5 and RC-6A */ | ||
152 | params.modulation = false; | ||
153 | /* RC-5: 2,222,222 ns = 1/36 kHz * 32 cycles * 2 marks * 1.25*/ | ||
154 | /* RC-6A: 3,333,333 ns = 1/36 kHz * 16 cycles * 6 marks * 1.25*/ | ||
155 | params.max_pulse_width = 3333333; /* ns */ | ||
156 | /* RC-5: 666,667 ns = 1/36 kHz * 32 cycles * 1 mark * 0.75 */ | ||
157 | /* RC-6A: 333,333 ns = 1/36 kHz * 16 cycles * 1 mark * 0.75 */ | ||
158 | params.noise_filter_min_width = 333333; /* ns */ | ||
159 | /* | ||
160 | * This board has inverted receive sense: | ||
161 | * mark is received as low logic level; | ||
162 | * falling edges are detected as rising edges; etc. | ||
163 | */ | ||
164 | params.invert_level = true; | ||
165 | break; | ||
166 | case CX23885_BOARD_TERRATEC_CINERGY_T_PCIE_DUAL: | ||
167 | case CX23885_BOARD_TEVII_S470: | ||
168 | /* | ||
169 | * The IR controller on this board only returns pulse widths. | ||
170 | * Any other mode setting will fail to set up the device. | ||
171 | */ | ||
172 | params.mode = V4L2_SUBDEV_IR_MODE_PULSE_WIDTH; | ||
173 | params.enable = true; | ||
174 | params.interrupt_enable = true; | ||
175 | params.shutdown = false; | ||
176 | |||
177 | /* Setup for a standard NEC protocol */ | ||
178 | params.carrier_freq = 37917; /* Hz, 455 kHz/12 for NEC */ | ||
179 | params.carrier_range_lower = 33000; /* Hz */ | ||
180 | params.carrier_range_upper = 43000; /* Hz */ | ||
181 | params.duty_cycle = 33; /* percent, 33 percent for NEC */ | ||
182 | |||
183 | /* | ||
184 | * NEC max pulse width: (64/3)/(455 kHz/12) * 16 nec_units | ||
185 | * (64/3)/(455 kHz/12) * 16 nec_units * 1.375 = 12378022 ns | ||
186 | */ | ||
187 | params.max_pulse_width = 12378022; /* ns */ | ||
188 | |||
189 | /* | ||
190 | * NEC noise filter min width: (64/3)/(455 kHz/12) * 1 nec_unit | ||
191 | * (64/3)/(455 kHz/12) * 1 nec_units * 0.625 = 351648 ns | ||
192 | */ | ||
193 | params.noise_filter_min_width = 351648; /* ns */ | ||
194 | |||
195 | params.modulation = false; | ||
196 | params.invert_level = true; | ||
197 | break; | ||
198 | } | ||
199 | v4l2_subdev_call(dev->sd_ir, ir, rx_s_parameters, ¶ms); | ||
200 | return 0; | ||
201 | } | ||
202 | |||
203 | static int cx23885_input_ir_open(struct rc_dev *rc) | ||
204 | { | ||
205 | struct cx23885_kernel_ir *kernel_ir = rc->priv; | ||
206 | |||
207 | if (kernel_ir->cx == NULL) | ||
208 | return -ENODEV; | ||
209 | |||
210 | return cx23885_input_ir_start(kernel_ir->cx); | ||
211 | } | ||
212 | |||
213 | static void cx23885_input_ir_stop(struct cx23885_dev *dev) | ||
214 | { | ||
215 | struct v4l2_subdev_ir_parameters params; | ||
216 | |||
217 | if (dev->sd_ir == NULL) | ||
218 | return; | ||
219 | |||
220 | /* | ||
221 | * Stop the sd_ir subdevice from generating notifications and | ||
222 | * scheduling work. | ||
223 | * It is shutdown this way in order to mitigate a race with | ||
224 | * cx23885_input_rx_work_handler() in the overrun case, which could | ||
225 | * re-enable the subdevice. | ||
226 | */ | ||
227 | atomic_set(&dev->ir_input_stopping, 1); | ||
228 | v4l2_subdev_call(dev->sd_ir, ir, rx_g_parameters, ¶ms); | ||
229 | while (params.shutdown == false) { | ||
230 | params.enable = false; | ||
231 | params.interrupt_enable = false; | ||
232 | params.shutdown = true; | ||
233 | v4l2_subdev_call(dev->sd_ir, ir, rx_s_parameters, ¶ms); | ||
234 | v4l2_subdev_call(dev->sd_ir, ir, rx_g_parameters, ¶ms); | ||
235 | } | ||
236 | flush_work_sync(&dev->cx25840_work); | ||
237 | flush_work_sync(&dev->ir_rx_work); | ||
238 | flush_work_sync(&dev->ir_tx_work); | ||
239 | } | ||
240 | |||
241 | static void cx23885_input_ir_close(struct rc_dev *rc) | ||
242 | { | ||
243 | struct cx23885_kernel_ir *kernel_ir = rc->priv; | ||
244 | |||
245 | if (kernel_ir->cx != NULL) | ||
246 | cx23885_input_ir_stop(kernel_ir->cx); | ||
247 | } | ||
248 | |||
249 | int cx23885_input_init(struct cx23885_dev *dev) | ||
250 | { | ||
251 | struct cx23885_kernel_ir *kernel_ir; | ||
252 | struct rc_dev *rc; | ||
253 | char *rc_map; | ||
254 | enum rc_driver_type driver_type; | ||
255 | unsigned long allowed_protos; | ||
256 | |||
257 | int ret; | ||
258 | |||
259 | /* | ||
260 | * If the IR device (hardware registers, chip, GPIO lines, etc.) isn't | ||
261 | * encapsulated in a v4l2_subdev, then I'm not going to deal with it. | ||
262 | */ | ||
263 | if (dev->sd_ir == NULL) | ||
264 | return -ENODEV; | ||
265 | |||
266 | switch (dev->board) { | ||
267 | case CX23885_BOARD_HAUPPAUGE_HVR1270: | ||
268 | case CX23885_BOARD_HAUPPAUGE_HVR1850: | ||
269 | case CX23885_BOARD_HAUPPAUGE_HVR1290: | ||
270 | case CX23885_BOARD_HAUPPAUGE_HVR1250: | ||
271 | /* Integrated CX2388[58] IR controller */ | ||
272 | driver_type = RC_DRIVER_IR_RAW; | ||
273 | allowed_protos = RC_TYPE_ALL; | ||
274 | /* The grey Hauppauge RC-5 remote */ | ||
275 | rc_map = RC_MAP_HAUPPAUGE; | ||
276 | break; | ||
277 | case CX23885_BOARD_TERRATEC_CINERGY_T_PCIE_DUAL: | ||
278 | /* Integrated CX23885 IR controller */ | ||
279 | driver_type = RC_DRIVER_IR_RAW; | ||
280 | allowed_protos = RC_TYPE_NEC; | ||
281 | /* The grey Terratec remote with orange buttons */ | ||
282 | rc_map = RC_MAP_NEC_TERRATEC_CINERGY_XS; | ||
283 | break; | ||
284 | case CX23885_BOARD_TEVII_S470: | ||
285 | /* Integrated CX23885 IR controller */ | ||
286 | driver_type = RC_DRIVER_IR_RAW; | ||
287 | allowed_protos = RC_TYPE_ALL; | ||
288 | /* A guess at the remote */ | ||
289 | rc_map = RC_MAP_TEVII_NEC; | ||
290 | break; | ||
291 | default: | ||
292 | return -ENODEV; | ||
293 | } | ||
294 | |||
295 | /* cx23885 board instance kernel IR state */ | ||
296 | kernel_ir = kzalloc(sizeof(struct cx23885_kernel_ir), GFP_KERNEL); | ||
297 | if (kernel_ir == NULL) | ||
298 | return -ENOMEM; | ||
299 | |||
300 | kernel_ir->cx = dev; | ||
301 | kernel_ir->name = kasprintf(GFP_KERNEL, "cx23885 IR (%s)", | ||
302 | cx23885_boards[dev->board].name); | ||
303 | kernel_ir->phys = kasprintf(GFP_KERNEL, "pci-%s/ir0", | ||
304 | pci_name(dev->pci)); | ||
305 | |||
306 | /* input device */ | ||
307 | rc = rc_allocate_device(); | ||
308 | if (!rc) { | ||
309 | ret = -ENOMEM; | ||
310 | goto err_out_free; | ||
311 | } | ||
312 | |||
313 | kernel_ir->rc = rc; | ||
314 | rc->input_name = kernel_ir->name; | ||
315 | rc->input_phys = kernel_ir->phys; | ||
316 | rc->input_id.bustype = BUS_PCI; | ||
317 | rc->input_id.version = 1; | ||
318 | if (dev->pci->subsystem_vendor) { | ||
319 | rc->input_id.vendor = dev->pci->subsystem_vendor; | ||
320 | rc->input_id.product = dev->pci->subsystem_device; | ||
321 | } else { | ||
322 | rc->input_id.vendor = dev->pci->vendor; | ||
323 | rc->input_id.product = dev->pci->device; | ||
324 | } | ||
325 | rc->dev.parent = &dev->pci->dev; | ||
326 | rc->driver_type = driver_type; | ||
327 | rc->allowed_protos = allowed_protos; | ||
328 | rc->priv = kernel_ir; | ||
329 | rc->open = cx23885_input_ir_open; | ||
330 | rc->close = cx23885_input_ir_close; | ||
331 | rc->map_name = rc_map; | ||
332 | rc->driver_name = MODULE_NAME; | ||
333 | |||
334 | /* Go */ | ||
335 | dev->kernel_ir = kernel_ir; | ||
336 | ret = rc_register_device(rc); | ||
337 | if (ret) | ||
338 | goto err_out_stop; | ||
339 | |||
340 | return 0; | ||
341 | |||
342 | err_out_stop: | ||
343 | cx23885_input_ir_stop(dev); | ||
344 | dev->kernel_ir = NULL; | ||
345 | rc_free_device(rc); | ||
346 | err_out_free: | ||
347 | kfree(kernel_ir->phys); | ||
348 | kfree(kernel_ir->name); | ||
349 | kfree(kernel_ir); | ||
350 | return ret; | ||
351 | } | ||
352 | |||
353 | void cx23885_input_fini(struct cx23885_dev *dev) | ||
354 | { | ||
355 | /* Always stop the IR hardware from generating interrupts */ | ||
356 | cx23885_input_ir_stop(dev); | ||
357 | |||
358 | if (dev->kernel_ir == NULL) | ||
359 | return; | ||
360 | rc_unregister_device(dev->kernel_ir->rc); | ||
361 | kfree(dev->kernel_ir->phys); | ||
362 | kfree(dev->kernel_ir->name); | ||
363 | kfree(dev->kernel_ir); | ||
364 | dev->kernel_ir = NULL; | ||
365 | } | ||
diff --git a/drivers/media/pci/cx23885/cx23885-input.h b/drivers/media/pci/cx23885/cx23885-input.h new file mode 100644 index 000000000000..75ef15d3f523 --- /dev/null +++ b/drivers/media/pci/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/pci/cx23885/cx23885-ioctl.c b/drivers/media/pci/cx23885/cx23885-ioctl.c new file mode 100644 index 000000000000..44812ca78899 --- /dev/null +++ b/drivers/media/pci/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/pci/cx23885/cx23885-ioctl.h b/drivers/media/pci/cx23885/cx23885-ioctl.h new file mode 100644 index 000000000000..315be0ca5a04 --- /dev/null +++ b/drivers/media/pci/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/pci/cx23885/cx23885-ir.c b/drivers/media/pci/cx23885/cx23885-ir.c new file mode 100644 index 000000000000..7125247dd255 --- /dev/null +++ b/drivers/media/pci/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/pci/cx23885/cx23885-ir.h b/drivers/media/pci/cx23885/cx23885-ir.h new file mode 100644 index 000000000000..0c9d8bda9e28 --- /dev/null +++ b/drivers/media/pci/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/pci/cx23885/cx23885-reg.h b/drivers/media/pci/cx23885/cx23885-reg.h new file mode 100644 index 000000000000..a99936e0cbc2 --- /dev/null +++ b/drivers/media/pci/cx23885/cx23885-reg.h | |||
@@ -0,0 +1,452 @@ | |||
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 FLD_CH_SEL (1 << 3) | ||
207 | #define CH_PWR_CTRL2 0x0000000F | ||
208 | #define DSM_STATUS1 0x00000010 | ||
209 | #define DSM_STATUS2 0x00000011 | ||
210 | #define DIG_CTL1 0x00000012 | ||
211 | #define DIG_CTL2 0x00000013 | ||
212 | #define I2S_TX_CFG 0x0000001A | ||
213 | |||
214 | #define DEV_CNTRL2 0x00040000 | ||
215 | |||
216 | #define PCI_MSK_IR (1 << 28) | ||
217 | #define PCI_MSK_AV_CORE (1 << 27) | ||
218 | #define PCI_MSK_GPIO1 (1 << 24) | ||
219 | #define PCI_MSK_GPIO0 (1 << 23) | ||
220 | #define PCI_MSK_APB_DMA (1 << 12) | ||
221 | #define PCI_MSK_AL_WR (1 << 11) | ||
222 | #define PCI_MSK_AL_RD (1 << 10) | ||
223 | #define PCI_MSK_RISC_WR (1 << 9) | ||
224 | #define PCI_MSK_RISC_RD (1 << 8) | ||
225 | #define PCI_MSK_AUD_EXT (1 << 4) | ||
226 | #define PCI_MSK_AUD_INT (1 << 3) | ||
227 | #define PCI_MSK_VID_C (1 << 2) | ||
228 | #define PCI_MSK_VID_B (1 << 1) | ||
229 | #define PCI_MSK_VID_A 1 | ||
230 | #define PCI_INT_MSK 0x00040010 | ||
231 | |||
232 | #define PCI_INT_STAT 0x00040014 | ||
233 | #define PCI_INT_MSTAT 0x00040018 | ||
234 | |||
235 | #define VID_A_INT_MSK 0x00040020 | ||
236 | #define VID_A_INT_STAT 0x00040024 | ||
237 | #define VID_A_INT_MSTAT 0x00040028 | ||
238 | #define VID_A_INT_SSTAT 0x0004002C | ||
239 | |||
240 | #define VID_B_INT_MSK 0x00040030 | ||
241 | #define VID_B_MSK_BAD_PKT (1 << 20) | ||
242 | #define VID_B_MSK_VBI_OPC_ERR (1 << 17) | ||
243 | #define VID_B_MSK_OPC_ERR (1 << 16) | ||
244 | #define VID_B_MSK_VBI_SYNC (1 << 13) | ||
245 | #define VID_B_MSK_SYNC (1 << 12) | ||
246 | #define VID_B_MSK_VBI_OF (1 << 9) | ||
247 | #define VID_B_MSK_OF (1 << 8) | ||
248 | #define VID_B_MSK_VBI_RISCI2 (1 << 5) | ||
249 | #define VID_B_MSK_RISCI2 (1 << 4) | ||
250 | #define VID_B_MSK_VBI_RISCI1 (1 << 1) | ||
251 | #define VID_B_MSK_RISCI1 1 | ||
252 | #define VID_B_INT_STAT 0x00040034 | ||
253 | #define VID_B_INT_MSTAT 0x00040038 | ||
254 | #define VID_B_INT_SSTAT 0x0004003C | ||
255 | |||
256 | #define VID_B_MSK_BAD_PKT (1 << 20) | ||
257 | #define VID_B_MSK_OPC_ERR (1 << 16) | ||
258 | #define VID_B_MSK_SYNC (1 << 12) | ||
259 | #define VID_B_MSK_OF (1 << 8) | ||
260 | #define VID_B_MSK_RISCI2 (1 << 4) | ||
261 | #define VID_B_MSK_RISCI1 1 | ||
262 | |||
263 | #define VID_C_MSK_BAD_PKT (1 << 20) | ||
264 | #define VID_C_MSK_OPC_ERR (1 << 16) | ||
265 | #define VID_C_MSK_SYNC (1 << 12) | ||
266 | #define VID_C_MSK_OF (1 << 8) | ||
267 | #define VID_C_MSK_RISCI2 (1 << 4) | ||
268 | #define VID_C_MSK_RISCI1 1 | ||
269 | |||
270 | /* A superset for testing purposes */ | ||
271 | #define VID_BC_MSK_BAD_PKT (1 << 20) | ||
272 | #define VID_BC_MSK_OPC_ERR (1 << 16) | ||
273 | #define VID_BC_MSK_SYNC (1 << 12) | ||
274 | #define VID_BC_MSK_OF (1 << 8) | ||
275 | #define VID_BC_MSK_VBI_RISCI2 (1 << 5) | ||
276 | #define VID_BC_MSK_RISCI2 (1 << 4) | ||
277 | #define VID_BC_MSK_VBI_RISCI1 (1 << 1) | ||
278 | #define VID_BC_MSK_RISCI1 1 | ||
279 | |||
280 | #define VID_C_INT_MSK 0x00040040 | ||
281 | #define VID_C_INT_STAT 0x00040044 | ||
282 | #define VID_C_INT_MSTAT 0x00040048 | ||
283 | #define VID_C_INT_SSTAT 0x0004004C | ||
284 | |||
285 | #define AUDIO_INT_INT_MSK 0x00040050 | ||
286 | #define AUDIO_INT_INT_STAT 0x00040054 | ||
287 | #define AUDIO_INT_INT_MSTAT 0x00040058 | ||
288 | #define AUDIO_INT_INT_SSTAT 0x0004005C | ||
289 | |||
290 | #define AUDIO_EXT_INT_MSK 0x00040060 | ||
291 | #define AUDIO_EXT_INT_STAT 0x00040064 | ||
292 | #define AUDIO_EXT_INT_MSTAT 0x00040068 | ||
293 | #define AUDIO_EXT_INT_SSTAT 0x0004006C | ||
294 | |||
295 | #define RDR_CFG0 0x00050000 | ||
296 | #define RDR_CFG1 0x00050004 | ||
297 | #define RDR_CFG2 0x00050008 | ||
298 | #define RDR_RDRCTL1 0x0005030c | ||
299 | #define RDR_TLCTL0 0x00050318 | ||
300 | |||
301 | /* APB DMAC Current Buffer Pointer */ | ||
302 | #define DMA1_PTR1 0x00100000 | ||
303 | #define DMA2_PTR1 0x00100004 | ||
304 | #define DMA3_PTR1 0x00100008 | ||
305 | #define DMA4_PTR1 0x0010000C | ||
306 | #define DMA5_PTR1 0x00100010 | ||
307 | #define DMA6_PTR1 0x00100014 | ||
308 | #define DMA7_PTR1 0x00100018 | ||
309 | #define DMA8_PTR1 0x0010001C | ||
310 | |||
311 | /* APB DMAC Current Table Pointer */ | ||
312 | #define DMA1_PTR2 0x00100040 | ||
313 | #define DMA2_PTR2 0x00100044 | ||
314 | #define DMA3_PTR2 0x00100048 | ||
315 | #define DMA4_PTR2 0x0010004C | ||
316 | #define DMA5_PTR2 0x00100050 | ||
317 | #define DMA6_PTR2 0x00100054 | ||
318 | #define DMA7_PTR2 0x00100058 | ||
319 | #define DMA8_PTR2 0x0010005C | ||
320 | |||
321 | /* APB DMAC Buffer Limit */ | ||
322 | #define DMA1_CNT1 0x00100080 | ||
323 | #define DMA2_CNT1 0x00100084 | ||
324 | #define DMA3_CNT1 0x00100088 | ||
325 | #define DMA4_CNT1 0x0010008C | ||
326 | #define DMA5_CNT1 0x00100090 | ||
327 | #define DMA6_CNT1 0x00100094 | ||
328 | #define DMA7_CNT1 0x00100098 | ||
329 | #define DMA8_CNT1 0x0010009C | ||
330 | |||
331 | /* APB DMAC Table Size */ | ||
332 | #define DMA1_CNT2 0x001000C0 | ||
333 | #define DMA2_CNT2 0x001000C4 | ||
334 | #define DMA3_CNT2 0x001000C8 | ||
335 | #define DMA4_CNT2 0x001000CC | ||
336 | #define DMA5_CNT2 0x001000D0 | ||
337 | #define DMA6_CNT2 0x001000D4 | ||
338 | #define DMA7_CNT2 0x001000D8 | ||
339 | #define DMA8_CNT2 0x001000DC | ||
340 | |||
341 | /* Timer Counters */ | ||
342 | #define TM_CNT_LDW 0x00110000 | ||
343 | #define TM_CNT_UW 0x00110004 | ||
344 | #define TM_LMT_LDW 0x00110008 | ||
345 | #define TM_LMT_UW 0x0011000C | ||
346 | |||
347 | /* GPIO */ | ||
348 | #define GP0_IO 0x00110010 | ||
349 | #define GPIO_ISM 0x00110014 | ||
350 | #define SOFT_RESET 0x0011001C | ||
351 | |||
352 | /* GPIO (417 Microsoftcontroller) RW Data */ | ||
353 | #define MC417_RWD 0x00110020 | ||
354 | |||
355 | /* GPIO (417 Microsoftcontroller) Output Enable, Low Active */ | ||
356 | #define MC417_OEN 0x00110024 | ||
357 | #define MC417_CTL 0x00110028 | ||
358 | #define ALT_PIN_OUT_SEL 0x0011002C | ||
359 | #define CLK_DELAY 0x00110048 | ||
360 | #define PAD_CTRL 0x0011004C | ||
361 | |||
362 | /* Video A Interface */ | ||
363 | #define VID_A_GPCNT 0x00130020 | ||
364 | #define VBI_A_GPCNT 0x00130024 | ||
365 | #define VID_A_GPCNT_CTL 0x00130030 | ||
366 | #define VBI_A_GPCNT_CTL 0x00130034 | ||
367 | #define VID_A_DMA_CTL 0x00130040 | ||
368 | #define VID_A_VIP_CTRL 0x00130080 | ||
369 | #define VID_A_PIXEL_FRMT 0x00130084 | ||
370 | #define VID_A_VBI_CTRL 0x00130088 | ||
371 | |||
372 | /* Video B Interface */ | ||
373 | #define VID_B_DMA 0x00130100 | ||
374 | #define VBI_B_DMA 0x00130108 | ||
375 | #define VID_B_GPCNT 0x00130120 | ||
376 | #define VBI_B_GPCNT 0x00130124 | ||
377 | #define VID_B_GPCNT_CTL 0x00130134 | ||
378 | #define VBI_B_GPCNT_CTL 0x00130138 | ||
379 | #define VID_B_DMA_CTL 0x00130140 | ||
380 | #define VID_B_SRC_SEL 0x00130144 | ||
381 | #define VID_B_LNGTH 0x00130150 | ||
382 | #define VID_B_HW_SOP_CTL 0x00130154 | ||
383 | #define VID_B_GEN_CTL 0x00130158 | ||
384 | #define VID_B_BD_PKT_STATUS 0x0013015C | ||
385 | #define VID_B_SOP_STATUS 0x00130160 | ||
386 | #define VID_B_FIFO_OVFL_STAT 0x00130164 | ||
387 | #define VID_B_VLD_MISC 0x00130168 | ||
388 | #define VID_B_TS_CLK_EN 0x0013016C | ||
389 | #define VID_B_VIP_CTRL 0x00130180 | ||
390 | #define VID_B_PIXEL_FRMT 0x00130184 | ||
391 | |||
392 | /* Video C Interface */ | ||
393 | #define VID_C_GPCNT 0x00130220 | ||
394 | #define VID_C_GPCNT_CTL 0x00130230 | ||
395 | #define VBI_C_GPCNT_CTL 0x00130234 | ||
396 | #define VID_C_DMA_CTL 0x00130240 | ||
397 | #define VID_C_LNGTH 0x00130250 | ||
398 | #define VID_C_HW_SOP_CTL 0x00130254 | ||
399 | #define VID_C_GEN_CTL 0x00130258 | ||
400 | #define VID_C_BD_PKT_STATUS 0x0013025C | ||
401 | #define VID_C_SOP_STATUS 0x00130260 | ||
402 | #define VID_C_FIFO_OVFL_STAT 0x00130264 | ||
403 | #define VID_C_VLD_MISC 0x00130268 | ||
404 | #define VID_C_TS_CLK_EN 0x0013026C | ||
405 | |||
406 | /* Internal Audio Interface */ | ||
407 | #define AUD_INT_A_GPCNT 0x00140020 | ||
408 | #define AUD_INT_B_GPCNT 0x00140024 | ||
409 | #define AUD_INT_A_GPCNT_CTL 0x00140030 | ||
410 | #define AUD_INT_B_GPCNT_CTL 0x00140034 | ||
411 | #define AUD_INT_DMA_CTL 0x00140040 | ||
412 | #define AUD_INT_A_LNGTH 0x00140050 | ||
413 | #define AUD_INT_B_LNGTH 0x00140054 | ||
414 | #define AUD_INT_A_MODE 0x00140058 | ||
415 | #define AUD_INT_B_MODE 0x0014005C | ||
416 | |||
417 | /* External Audio Interface */ | ||
418 | #define AUD_EXT_DMA 0x00140100 | ||
419 | #define AUD_EXT_GPCNT 0x00140120 | ||
420 | #define AUD_EXT_GPCNT_CTL 0x00140130 | ||
421 | #define AUD_EXT_DMA_CTL 0x00140140 | ||
422 | #define AUD_EXT_LNGTH 0x00140150 | ||
423 | #define AUD_EXT_A_MODE 0x00140158 | ||
424 | |||
425 | /* I2C Bus 1 */ | ||
426 | #define I2C1_ADDR 0x00180000 | ||
427 | #define I2C1_WDATA 0x00180004 | ||
428 | #define I2C1_CTRL 0x00180008 | ||
429 | #define I2C1_RDATA 0x0018000C | ||
430 | #define I2C1_STAT 0x00180010 | ||
431 | |||
432 | /* I2C Bus 2 */ | ||
433 | #define I2C2_ADDR 0x00190000 | ||
434 | #define I2C2_WDATA 0x00190004 | ||
435 | #define I2C2_CTRL 0x00190008 | ||
436 | #define I2C2_RDATA 0x0019000C | ||
437 | #define I2C2_STAT 0x00190010 | ||
438 | |||
439 | /* I2C Bus 3 */ | ||
440 | #define I2C3_ADDR 0x001A0000 | ||
441 | #define I2C3_WDATA 0x001A0004 | ||
442 | #define I2C3_CTRL 0x001A0008 | ||
443 | #define I2C3_RDATA 0x001A000C | ||
444 | #define I2C3_STAT 0x001A0010 | ||
445 | |||
446 | /* UART */ | ||
447 | #define UART_CTL 0x001B0000 | ||
448 | #define UART_BRD 0x001B0004 | ||
449 | #define UART_ISR 0x001B000C | ||
450 | #define UART_CNT 0x001B0010 | ||
451 | |||
452 | #endif /* _CX23885_REG_H_ */ | ||
diff --git a/drivers/media/pci/cx23885/cx23885-vbi.c b/drivers/media/pci/cx23885/cx23885-vbi.c new file mode 100644 index 000000000000..a1154f035bc1 --- /dev/null +++ b/drivers/media/pci/cx23885/cx23885-vbi.c | |||
@@ -0,0 +1,295 @@ | |||
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 | #define VBI_LINE_LENGTH 1440 | ||
45 | #define NTSC_VBI_START_LINE 10 /* line 10 - 21 */ | ||
46 | #define NTSC_VBI_END_LINE 21 | ||
47 | #define NTSC_VBI_LINES (NTSC_VBI_END_LINE - NTSC_VBI_START_LINE + 1) | ||
48 | |||
49 | |||
50 | int cx23885_vbi_fmt(struct file *file, void *priv, | ||
51 | struct v4l2_format *f) | ||
52 | { | ||
53 | struct cx23885_fh *fh = priv; | ||
54 | struct cx23885_dev *dev = fh->dev; | ||
55 | |||
56 | if (dev->tvnorm & V4L2_STD_525_60) { | ||
57 | /* ntsc */ | ||
58 | f->fmt.vbi.samples_per_line = VBI_LINE_LENGTH; | ||
59 | f->fmt.vbi.sampling_rate = 27000000; | ||
60 | f->fmt.vbi.sample_format = V4L2_PIX_FMT_GREY; | ||
61 | f->fmt.vbi.offset = 0; | ||
62 | f->fmt.vbi.flags = 0; | ||
63 | f->fmt.vbi.start[0] = 10; | ||
64 | f->fmt.vbi.count[0] = 17; | ||
65 | f->fmt.vbi.start[1] = 263 + 10 + 1; | ||
66 | f->fmt.vbi.count[1] = 17; | ||
67 | } else if (dev->tvnorm & V4L2_STD_625_50) { | ||
68 | /* pal */ | ||
69 | f->fmt.vbi.sampling_rate = 35468950; | ||
70 | f->fmt.vbi.start[0] = 7 - 1; | ||
71 | f->fmt.vbi.start[1] = 319 - 1; | ||
72 | } | ||
73 | |||
74 | return 0; | ||
75 | } | ||
76 | |||
77 | /* We're given the Video Interrupt status register. | ||
78 | * The cx23885_video_irq() func has already validated | ||
79 | * the potential error bits, we just need to | ||
80 | * deal with vbi payload and return indication if | ||
81 | * we actually processed any payload. | ||
82 | */ | ||
83 | int cx23885_vbi_irq(struct cx23885_dev *dev, u32 status) | ||
84 | { | ||
85 | u32 count; | ||
86 | int handled = 0; | ||
87 | |||
88 | if (status & VID_BC_MSK_VBI_RISCI1) { | ||
89 | dprintk(1, "%s() VID_BC_MSK_VBI_RISCI1\n", __func__); | ||
90 | spin_lock(&dev->slock); | ||
91 | count = cx_read(VID_A_GPCNT); | ||
92 | cx23885_video_wakeup(dev, &dev->vbiq, count); | ||
93 | spin_unlock(&dev->slock); | ||
94 | handled++; | ||
95 | } | ||
96 | |||
97 | if (status & VID_BC_MSK_VBI_RISCI2) { | ||
98 | dprintk(1, "%s() VID_BC_MSK_VBI_RISCI2\n", __func__); | ||
99 | dprintk(2, "stopper vbi\n"); | ||
100 | spin_lock(&dev->slock); | ||
101 | cx23885_restart_vbi_queue(dev, &dev->vbiq); | ||
102 | spin_unlock(&dev->slock); | ||
103 | handled++; | ||
104 | } | ||
105 | |||
106 | return handled; | ||
107 | } | ||
108 | |||
109 | static int cx23885_start_vbi_dma(struct cx23885_dev *dev, | ||
110 | struct cx23885_dmaqueue *q, | ||
111 | struct cx23885_buffer *buf) | ||
112 | { | ||
113 | dprintk(1, "%s()\n", __func__); | ||
114 | |||
115 | /* setup fifo + format */ | ||
116 | cx23885_sram_channel_setup(dev, &dev->sram_channels[SRAM_CH02], | ||
117 | buf->vb.width, buf->risc.dma); | ||
118 | |||
119 | /* reset counter */ | ||
120 | cx_write(VID_A_GPCNT_CTL, 3); | ||
121 | cx_write(VID_A_VBI_CTRL, 3); | ||
122 | cx_write(VBI_A_GPCNT_CTL, 3); | ||
123 | q->count = 1; | ||
124 | |||
125 | /* enable irq */ | ||
126 | cx23885_irq_add_enable(dev, 0x01); | ||
127 | cx_set(VID_A_INT_MSK, 0x000022); | ||
128 | |||
129 | /* start dma */ | ||
130 | cx_set(DEV_CNTRL2, (1<<5)); | ||
131 | cx_set(VID_A_DMA_CTL, 0x22); /* FIFO and RISC enable */ | ||
132 | |||
133 | return 0; | ||
134 | } | ||
135 | |||
136 | |||
137 | int cx23885_restart_vbi_queue(struct cx23885_dev *dev, | ||
138 | struct cx23885_dmaqueue *q) | ||
139 | { | ||
140 | struct cx23885_buffer *buf; | ||
141 | struct list_head *item; | ||
142 | |||
143 | if (list_empty(&q->active)) | ||
144 | return 0; | ||
145 | |||
146 | buf = list_entry(q->active.next, struct cx23885_buffer, vb.queue); | ||
147 | dprintk(2, "restart_queue [%p/%d]: restart dma\n", | ||
148 | buf, buf->vb.i); | ||
149 | cx23885_start_vbi_dma(dev, q, buf); | ||
150 | list_for_each(item, &q->active) { | ||
151 | buf = list_entry(item, struct cx23885_buffer, vb.queue); | ||
152 | buf->count = q->count++; | ||
153 | } | ||
154 | mod_timer(&q->timeout, jiffies + (BUFFER_TIMEOUT / 30)); | ||
155 | return 0; | ||
156 | } | ||
157 | |||
158 | void cx23885_vbi_timeout(unsigned long data) | ||
159 | { | ||
160 | struct cx23885_dev *dev = (struct cx23885_dev *)data; | ||
161 | struct cx23885_dmaqueue *q = &dev->vbiq; | ||
162 | struct cx23885_buffer *buf; | ||
163 | unsigned long flags; | ||
164 | |||
165 | /* Stop the VBI engine */ | ||
166 | cx_clear(VID_A_DMA_CTL, 0x22); | ||
167 | |||
168 | spin_lock_irqsave(&dev->slock, flags); | ||
169 | while (!list_empty(&q->active)) { | ||
170 | buf = list_entry(q->active.next, struct cx23885_buffer, | ||
171 | vb.queue); | ||
172 | list_del(&buf->vb.queue); | ||
173 | buf->vb.state = VIDEOBUF_ERROR; | ||
174 | wake_up(&buf->vb.done); | ||
175 | printk("%s/0: [%p/%d] timeout - dma=0x%08lx\n", dev->name, | ||
176 | buf, buf->vb.i, (unsigned long)buf->risc.dma); | ||
177 | } | ||
178 | cx23885_restart_vbi_queue(dev, q); | ||
179 | spin_unlock_irqrestore(&dev->slock, flags); | ||
180 | } | ||
181 | |||
182 | /* ------------------------------------------------------------------ */ | ||
183 | #define VBI_LINE_LENGTH 1440 | ||
184 | #define VBI_LINE_COUNT 17 | ||
185 | |||
186 | static int | ||
187 | vbi_setup(struct videobuf_queue *q, unsigned int *count, unsigned int *size) | ||
188 | { | ||
189 | *size = VBI_LINE_COUNT * VBI_LINE_LENGTH * 2; | ||
190 | if (0 == *count) | ||
191 | *count = vbibufs; | ||
192 | if (*count < 2) | ||
193 | *count = 2; | ||
194 | if (*count > 32) | ||
195 | *count = 32; | ||
196 | return 0; | ||
197 | } | ||
198 | |||
199 | static int | ||
200 | vbi_prepare(struct videobuf_queue *q, struct videobuf_buffer *vb, | ||
201 | enum v4l2_field field) | ||
202 | { | ||
203 | struct cx23885_fh *fh = q->priv_data; | ||
204 | struct cx23885_dev *dev = fh->dev; | ||
205 | struct cx23885_buffer *buf = container_of(vb, | ||
206 | struct cx23885_buffer, vb); | ||
207 | struct videobuf_dmabuf *dma = videobuf_to_dma(&buf->vb); | ||
208 | unsigned int size; | ||
209 | int rc; | ||
210 | |||
211 | size = VBI_LINE_COUNT * VBI_LINE_LENGTH * 2; | ||
212 | if (0 != buf->vb.baddr && buf->vb.bsize < size) | ||
213 | return -EINVAL; | ||
214 | |||
215 | if (VIDEOBUF_NEEDS_INIT == buf->vb.state) { | ||
216 | buf->vb.width = VBI_LINE_LENGTH; | ||
217 | buf->vb.height = VBI_LINE_COUNT; | ||
218 | buf->vb.size = size; | ||
219 | buf->vb.field = V4L2_FIELD_SEQ_TB; | ||
220 | |||
221 | rc = videobuf_iolock(q, &buf->vb, NULL); | ||
222 | if (0 != rc) | ||
223 | goto fail; | ||
224 | cx23885_risc_vbibuffer(dev->pci, &buf->risc, | ||
225 | dma->sglist, | ||
226 | 0, buf->vb.width * buf->vb.height, | ||
227 | buf->vb.width, 0, | ||
228 | buf->vb.height); | ||
229 | } | ||
230 | buf->vb.state = VIDEOBUF_PREPARED; | ||
231 | return 0; | ||
232 | |||
233 | fail: | ||
234 | cx23885_free_buffer(q, buf); | ||
235 | return rc; | ||
236 | } | ||
237 | |||
238 | static void | ||
239 | vbi_queue(struct videobuf_queue *vq, struct videobuf_buffer *vb) | ||
240 | { | ||
241 | struct cx23885_buffer *buf = | ||
242 | container_of(vb, struct cx23885_buffer, vb); | ||
243 | struct cx23885_buffer *prev; | ||
244 | struct cx23885_fh *fh = vq->priv_data; | ||
245 | struct cx23885_dev *dev = fh->dev; | ||
246 | struct cx23885_dmaqueue *q = &dev->vbiq; | ||
247 | |||
248 | /* add jump to stopper */ | ||
249 | buf->risc.jmp[0] = cpu_to_le32(RISC_JUMP | RISC_IRQ1 | RISC_CNT_INC); | ||
250 | buf->risc.jmp[1] = cpu_to_le32(q->stopper.dma); | ||
251 | buf->risc.jmp[2] = cpu_to_le32(0); /* bits 63-32 */ | ||
252 | |||
253 | if (list_empty(&q->active)) { | ||
254 | list_add_tail(&buf->vb.queue, &q->active); | ||
255 | cx23885_start_vbi_dma(dev, q, buf); | ||
256 | buf->vb.state = VIDEOBUF_ACTIVE; | ||
257 | buf->count = q->count++; | ||
258 | mod_timer(&q->timeout, jiffies + (BUFFER_TIMEOUT / 30)); | ||
259 | dprintk(2, "[%p/%d] vbi_queue - first active\n", | ||
260 | buf, buf->vb.i); | ||
261 | |||
262 | } else { | ||
263 | prev = list_entry(q->active.prev, struct cx23885_buffer, | ||
264 | vb.queue); | ||
265 | list_add_tail(&buf->vb.queue, &q->active); | ||
266 | buf->vb.state = VIDEOBUF_ACTIVE; | ||
267 | buf->count = q->count++; | ||
268 | prev->risc.jmp[1] = cpu_to_le32(buf->risc.dma); | ||
269 | prev->risc.jmp[2] = cpu_to_le32(0); /* Bits 63-32 */ | ||
270 | dprintk(2, "[%p/%d] buffer_queue - append to active\n", | ||
271 | buf, buf->vb.i); | ||
272 | } | ||
273 | } | ||
274 | |||
275 | static void vbi_release(struct videobuf_queue *q, struct videobuf_buffer *vb) | ||
276 | { | ||
277 | struct cx23885_buffer *buf = | ||
278 | container_of(vb, struct cx23885_buffer, vb); | ||
279 | |||
280 | cx23885_free_buffer(q, buf); | ||
281 | } | ||
282 | |||
283 | struct videobuf_queue_ops cx23885_vbi_qops = { | ||
284 | .buf_setup = vbi_setup, | ||
285 | .buf_prepare = vbi_prepare, | ||
286 | .buf_queue = vbi_queue, | ||
287 | .buf_release = vbi_release, | ||
288 | }; | ||
289 | |||
290 | /* ------------------------------------------------------------------ */ | ||
291 | /* | ||
292 | * Local variables: | ||
293 | * c-basic-offset: 8 | ||
294 | * End: | ||
295 | */ | ||
diff --git a/drivers/media/pci/cx23885/cx23885-video.c b/drivers/media/pci/cx23885/cx23885-video.c new file mode 100644 index 000000000000..22f8e7fbd665 --- /dev/null +++ b/drivers/media/pci/cx23885/cx23885-video.c | |||
@@ -0,0 +1,1926 @@ | |||
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 | #include <media/cx25840.h> | ||
41 | |||
42 | MODULE_DESCRIPTION("v4l2 driver module for cx23885 based TV cards"); | ||
43 | MODULE_AUTHOR("Steven Toth <stoth@linuxtv.org>"); | ||
44 | MODULE_LICENSE("GPL"); | ||
45 | |||
46 | /* ------------------------------------------------------------------ */ | ||
47 | |||
48 | static unsigned int video_nr[] = {[0 ... (CX23885_MAXBOARDS - 1)] = UNSET }; | ||
49 | static unsigned int vbi_nr[] = {[0 ... (CX23885_MAXBOARDS - 1)] = UNSET }; | ||
50 | static unsigned int radio_nr[] = {[0 ... (CX23885_MAXBOARDS - 1)] = UNSET }; | ||
51 | |||
52 | module_param_array(video_nr, int, NULL, 0444); | ||
53 | module_param_array(vbi_nr, int, NULL, 0444); | ||
54 | module_param_array(radio_nr, int, NULL, 0444); | ||
55 | |||
56 | MODULE_PARM_DESC(video_nr, "video device numbers"); | ||
57 | MODULE_PARM_DESC(vbi_nr, "vbi device numbers"); | ||
58 | MODULE_PARM_DESC(radio_nr, "radio device numbers"); | ||
59 | |||
60 | static unsigned int video_debug; | ||
61 | module_param(video_debug, int, 0644); | ||
62 | MODULE_PARM_DESC(video_debug, "enable debug messages [video]"); | ||
63 | |||
64 | static unsigned int irq_debug; | ||
65 | module_param(irq_debug, int, 0644); | ||
66 | MODULE_PARM_DESC(irq_debug, "enable debug messages [IRQ handler]"); | ||
67 | |||
68 | static unsigned int vid_limit = 16; | ||
69 | module_param(vid_limit, int, 0644); | ||
70 | MODULE_PARM_DESC(vid_limit, "capture memory limit in megabytes"); | ||
71 | |||
72 | #define dprintk(level, fmt, arg...)\ | ||
73 | do { if (video_debug >= level)\ | ||
74 | printk(KERN_DEBUG "%s: " fmt, dev->name, ## arg);\ | ||
75 | } while (0) | ||
76 | |||
77 | /* ------------------------------------------------------------------- */ | ||
78 | /* static data */ | ||
79 | |||
80 | #define FORMAT_FLAGS_PACKED 0x01 | ||
81 | #if 0 | ||
82 | static struct cx23885_fmt formats[] = { | ||
83 | { | ||
84 | .name = "8 bpp, gray", | ||
85 | .fourcc = V4L2_PIX_FMT_GREY, | ||
86 | .depth = 8, | ||
87 | .flags = FORMAT_FLAGS_PACKED, | ||
88 | }, { | ||
89 | .name = "15 bpp RGB, le", | ||
90 | .fourcc = V4L2_PIX_FMT_RGB555, | ||
91 | .depth = 16, | ||
92 | .flags = FORMAT_FLAGS_PACKED, | ||
93 | }, { | ||
94 | .name = "15 bpp RGB, be", | ||
95 | .fourcc = V4L2_PIX_FMT_RGB555X, | ||
96 | .depth = 16, | ||
97 | .flags = FORMAT_FLAGS_PACKED, | ||
98 | }, { | ||
99 | .name = "16 bpp RGB, le", | ||
100 | .fourcc = V4L2_PIX_FMT_RGB565, | ||
101 | .depth = 16, | ||
102 | .flags = FORMAT_FLAGS_PACKED, | ||
103 | }, { | ||
104 | .name = "16 bpp RGB, be", | ||
105 | .fourcc = V4L2_PIX_FMT_RGB565X, | ||
106 | .depth = 16, | ||
107 | .flags = FORMAT_FLAGS_PACKED, | ||
108 | }, { | ||
109 | .name = "24 bpp RGB, le", | ||
110 | .fourcc = V4L2_PIX_FMT_BGR24, | ||
111 | .depth = 24, | ||
112 | .flags = FORMAT_FLAGS_PACKED, | ||
113 | }, { | ||
114 | .name = "32 bpp RGB, le", | ||
115 | .fourcc = V4L2_PIX_FMT_BGR32, | ||
116 | .depth = 32, | ||
117 | .flags = FORMAT_FLAGS_PACKED, | ||
118 | }, { | ||
119 | .name = "32 bpp RGB, be", | ||
120 | .fourcc = V4L2_PIX_FMT_RGB32, | ||
121 | .depth = 32, | ||
122 | .flags = FORMAT_FLAGS_PACKED, | ||
123 | }, { | ||
124 | .name = "4:2:2, packed, YUYV", | ||
125 | .fourcc = V4L2_PIX_FMT_YUYV, | ||
126 | .depth = 16, | ||
127 | .flags = FORMAT_FLAGS_PACKED, | ||
128 | }, { | ||
129 | .name = "4:2:2, packed, UYVY", | ||
130 | .fourcc = V4L2_PIX_FMT_UYVY, | ||
131 | .depth = 16, | ||
132 | .flags = FORMAT_FLAGS_PACKED, | ||
133 | }, | ||
134 | }; | ||
135 | #else | ||
136 | static struct cx23885_fmt formats[] = { | ||
137 | { | ||
138 | #if 0 | ||
139 | .name = "4:2:2, packed, UYVY", | ||
140 | .fourcc = V4L2_PIX_FMT_UYVY, | ||
141 | .depth = 16, | ||
142 | .flags = FORMAT_FLAGS_PACKED, | ||
143 | }, { | ||
144 | #endif | ||
145 | .name = "4:2:2, packed, YUYV", | ||
146 | .fourcc = V4L2_PIX_FMT_YUYV, | ||
147 | .depth = 16, | ||
148 | .flags = FORMAT_FLAGS_PACKED, | ||
149 | } | ||
150 | }; | ||
151 | #endif | ||
152 | |||
153 | static struct cx23885_fmt *format_by_fourcc(unsigned int fourcc) | ||
154 | { | ||
155 | unsigned int i; | ||
156 | |||
157 | for (i = 0; i < ARRAY_SIZE(formats); i++) | ||
158 | if (formats[i].fourcc == fourcc) | ||
159 | return formats+i; | ||
160 | |||
161 | printk(KERN_ERR "%s(%c%c%c%c) NOT FOUND\n", __func__, | ||
162 | (fourcc & 0xff), | ||
163 | ((fourcc >> 8) & 0xff), | ||
164 | ((fourcc >> 16) & 0xff), | ||
165 | ((fourcc >> 24) & 0xff) | ||
166 | ); | ||
167 | return NULL; | ||
168 | } | ||
169 | |||
170 | /* ------------------------------------------------------------------- */ | ||
171 | |||
172 | static const struct v4l2_queryctrl no_ctl = { | ||
173 | .name = "42", | ||
174 | .flags = V4L2_CTRL_FLAG_DISABLED, | ||
175 | }; | ||
176 | |||
177 | static struct cx23885_ctrl cx23885_ctls[] = { | ||
178 | /* --- video --- */ | ||
179 | { | ||
180 | .v = { | ||
181 | .id = V4L2_CID_BRIGHTNESS, | ||
182 | .name = "Brightness", | ||
183 | .minimum = 0x00, | ||
184 | .maximum = 0xff, | ||
185 | .step = 1, | ||
186 | .default_value = 0x7f, | ||
187 | .type = V4L2_CTRL_TYPE_INTEGER, | ||
188 | }, | ||
189 | .off = 128, | ||
190 | .reg = LUMA_CTRL, | ||
191 | .mask = 0x00ff, | ||
192 | .shift = 0, | ||
193 | }, { | ||
194 | .v = { | ||
195 | .id = V4L2_CID_CONTRAST, | ||
196 | .name = "Contrast", | ||
197 | .minimum = 0, | ||
198 | .maximum = 0x7f, | ||
199 | .step = 1, | ||
200 | .default_value = 0x3f, | ||
201 | .type = V4L2_CTRL_TYPE_INTEGER, | ||
202 | }, | ||
203 | .off = 0, | ||
204 | .reg = LUMA_CTRL, | ||
205 | .mask = 0xff00, | ||
206 | .shift = 8, | ||
207 | }, { | ||
208 | .v = { | ||
209 | .id = V4L2_CID_HUE, | ||
210 | .name = "Hue", | ||
211 | .minimum = -127, | ||
212 | .maximum = 128, | ||
213 | .step = 1, | ||
214 | .default_value = 0x0, | ||
215 | .type = V4L2_CTRL_TYPE_INTEGER, | ||
216 | }, | ||
217 | .off = 128, | ||
218 | .reg = CHROMA_CTRL, | ||
219 | .mask = 0xff0000, | ||
220 | .shift = 16, | ||
221 | }, { | ||
222 | /* strictly, this only describes only U saturation. | ||
223 | * V saturation is handled specially through code. | ||
224 | */ | ||
225 | .v = { | ||
226 | .id = V4L2_CID_SATURATION, | ||
227 | .name = "Saturation", | ||
228 | .minimum = 0, | ||
229 | .maximum = 0x7f, | ||
230 | .step = 1, | ||
231 | .default_value = 0x3f, | ||
232 | .type = V4L2_CTRL_TYPE_INTEGER, | ||
233 | }, | ||
234 | .off = 0, | ||
235 | .reg = CHROMA_CTRL, | ||
236 | .mask = 0x00ff, | ||
237 | .shift = 0, | ||
238 | }, { | ||
239 | /* --- audio --- */ | ||
240 | .v = { | ||
241 | .id = V4L2_CID_AUDIO_MUTE, | ||
242 | .name = "Mute", | ||
243 | .minimum = 0, | ||
244 | .maximum = 1, | ||
245 | .default_value = 1, | ||
246 | .type = V4L2_CTRL_TYPE_BOOLEAN, | ||
247 | }, | ||
248 | .reg = PATH1_CTL1, | ||
249 | .mask = (0x1f << 24), | ||
250 | .shift = 24, | ||
251 | }, { | ||
252 | .v = { | ||
253 | .id = V4L2_CID_AUDIO_VOLUME, | ||
254 | .name = "Volume", | ||
255 | .minimum = 0, | ||
256 | .maximum = 65535, | ||
257 | .step = 65535 / 100, | ||
258 | .default_value = 65535, | ||
259 | .type = V4L2_CTRL_TYPE_INTEGER, | ||
260 | }, | ||
261 | .reg = PATH1_VOL_CTL, | ||
262 | .mask = 0xff, | ||
263 | .shift = 0, | ||
264 | } | ||
265 | }; | ||
266 | static const int CX23885_CTLS = ARRAY_SIZE(cx23885_ctls); | ||
267 | |||
268 | /* Must be sorted from low to high control ID! */ | ||
269 | static const u32 cx23885_user_ctrls[] = { | ||
270 | V4L2_CID_USER_CLASS, | ||
271 | V4L2_CID_BRIGHTNESS, | ||
272 | V4L2_CID_CONTRAST, | ||
273 | V4L2_CID_SATURATION, | ||
274 | V4L2_CID_HUE, | ||
275 | V4L2_CID_AUDIO_VOLUME, | ||
276 | V4L2_CID_AUDIO_MUTE, | ||
277 | 0 | ||
278 | }; | ||
279 | |||
280 | static const u32 *ctrl_classes[] = { | ||
281 | cx23885_user_ctrls, | ||
282 | NULL | ||
283 | }; | ||
284 | |||
285 | void cx23885_video_wakeup(struct cx23885_dev *dev, | ||
286 | struct cx23885_dmaqueue *q, u32 count) | ||
287 | { | ||
288 | struct cx23885_buffer *buf; | ||
289 | int bc; | ||
290 | |||
291 | for (bc = 0;; bc++) { | ||
292 | if (list_empty(&q->active)) | ||
293 | break; | ||
294 | buf = list_entry(q->active.next, | ||
295 | struct cx23885_buffer, vb.queue); | ||
296 | |||
297 | /* count comes from the hw and is is 16bit wide -- | ||
298 | * this trick handles wrap-arounds correctly for | ||
299 | * up to 32767 buffers in flight... */ | ||
300 | if ((s16) (count - buf->count) < 0) | ||
301 | break; | ||
302 | |||
303 | do_gettimeofday(&buf->vb.ts); | ||
304 | dprintk(2, "[%p/%d] wakeup reg=%d buf=%d\n", buf, buf->vb.i, | ||
305 | count, buf->count); | ||
306 | buf->vb.state = VIDEOBUF_DONE; | ||
307 | list_del(&buf->vb.queue); | ||
308 | wake_up(&buf->vb.done); | ||
309 | } | ||
310 | if (list_empty(&q->active)) | ||
311 | del_timer(&q->timeout); | ||
312 | else | ||
313 | mod_timer(&q->timeout, jiffies+BUFFER_TIMEOUT); | ||
314 | if (bc != 1) | ||
315 | printk(KERN_ERR "%s: %d buffers handled (should be 1)\n", | ||
316 | __func__, bc); | ||
317 | } | ||
318 | |||
319 | int cx23885_set_tvnorm(struct cx23885_dev *dev, v4l2_std_id norm) | ||
320 | { | ||
321 | dprintk(1, "%s(norm = 0x%08x) name: [%s]\n", | ||
322 | __func__, | ||
323 | (unsigned int)norm, | ||
324 | v4l2_norm_to_name(norm)); | ||
325 | |||
326 | dev->tvnorm = norm; | ||
327 | |||
328 | call_all(dev, core, s_std, norm); | ||
329 | |||
330 | return 0; | ||
331 | } | ||
332 | |||
333 | static struct video_device *cx23885_vdev_init(struct cx23885_dev *dev, | ||
334 | struct pci_dev *pci, | ||
335 | struct video_device *template, | ||
336 | char *type) | ||
337 | { | ||
338 | struct video_device *vfd; | ||
339 | dprintk(1, "%s()\n", __func__); | ||
340 | |||
341 | vfd = video_device_alloc(); | ||
342 | if (NULL == vfd) | ||
343 | return NULL; | ||
344 | *vfd = *template; | ||
345 | vfd->v4l2_dev = &dev->v4l2_dev; | ||
346 | vfd->release = video_device_release; | ||
347 | snprintf(vfd->name, sizeof(vfd->name), "%s (%s)", | ||
348 | cx23885_boards[dev->board].name, type); | ||
349 | video_set_drvdata(vfd, dev); | ||
350 | return vfd; | ||
351 | } | ||
352 | |||
353 | static int cx23885_ctrl_query(struct v4l2_queryctrl *qctrl) | ||
354 | { | ||
355 | int i; | ||
356 | |||
357 | if (qctrl->id < V4L2_CID_BASE || | ||
358 | qctrl->id >= V4L2_CID_LASTP1) | ||
359 | return -EINVAL; | ||
360 | for (i = 0; i < CX23885_CTLS; i++) | ||
361 | if (cx23885_ctls[i].v.id == qctrl->id) | ||
362 | break; | ||
363 | if (i == CX23885_CTLS) { | ||
364 | *qctrl = no_ctl; | ||
365 | return 0; | ||
366 | } | ||
367 | *qctrl = cx23885_ctls[i].v; | ||
368 | return 0; | ||
369 | } | ||
370 | |||
371 | /* ------------------------------------------------------------------- */ | ||
372 | /* resource management */ | ||
373 | |||
374 | static int res_get(struct cx23885_dev *dev, struct cx23885_fh *fh, | ||
375 | unsigned int bit) | ||
376 | { | ||
377 | dprintk(1, "%s()\n", __func__); | ||
378 | if (fh->resources & bit) | ||
379 | /* have it already allocated */ | ||
380 | return 1; | ||
381 | |||
382 | /* is it free? */ | ||
383 | mutex_lock(&dev->lock); | ||
384 | if (dev->resources & bit) { | ||
385 | /* no, someone else uses it */ | ||
386 | mutex_unlock(&dev->lock); | ||
387 | return 0; | ||
388 | } | ||
389 | /* it's free, grab it */ | ||
390 | fh->resources |= bit; | ||
391 | dev->resources |= bit; | ||
392 | dprintk(1, "res: get %d\n", bit); | ||
393 | mutex_unlock(&dev->lock); | ||
394 | return 1; | ||
395 | } | ||
396 | |||
397 | static int res_check(struct cx23885_fh *fh, unsigned int bit) | ||
398 | { | ||
399 | return fh->resources & bit; | ||
400 | } | ||
401 | |||
402 | static int res_locked(struct cx23885_dev *dev, unsigned int bit) | ||
403 | { | ||
404 | return dev->resources & bit; | ||
405 | } | ||
406 | |||
407 | static void res_free(struct cx23885_dev *dev, struct cx23885_fh *fh, | ||
408 | unsigned int bits) | ||
409 | { | ||
410 | BUG_ON((fh->resources & bits) != bits); | ||
411 | dprintk(1, "%s()\n", __func__); | ||
412 | |||
413 | mutex_lock(&dev->lock); | ||
414 | fh->resources &= ~bits; | ||
415 | dev->resources &= ~bits; | ||
416 | dprintk(1, "res: put %d\n", bits); | ||
417 | mutex_unlock(&dev->lock); | ||
418 | } | ||
419 | |||
420 | static int cx23885_flatiron_write(struct cx23885_dev *dev, u8 reg, u8 data) | ||
421 | { | ||
422 | /* 8 bit registers, 8 bit values */ | ||
423 | u8 buf[] = { reg, data }; | ||
424 | |||
425 | struct i2c_msg msg = { .addr = 0x98 >> 1, | ||
426 | .flags = 0, .buf = buf, .len = 2 }; | ||
427 | |||
428 | return i2c_transfer(&dev->i2c_bus[2].i2c_adap, &msg, 1); | ||
429 | } | ||
430 | |||
431 | static u8 cx23885_flatiron_read(struct cx23885_dev *dev, u8 reg) | ||
432 | { | ||
433 | /* 8 bit registers, 8 bit values */ | ||
434 | int ret; | ||
435 | u8 b0[] = { reg }; | ||
436 | u8 b1[] = { 0 }; | ||
437 | |||
438 | struct i2c_msg msg[] = { | ||
439 | { .addr = 0x98 >> 1, .flags = 0, .buf = b0, .len = 1 }, | ||
440 | { .addr = 0x98 >> 1, .flags = I2C_M_RD, .buf = b1, .len = 1 } | ||
441 | }; | ||
442 | |||
443 | ret = i2c_transfer(&dev->i2c_bus[2].i2c_adap, &msg[0], 2); | ||
444 | if (ret != 2) | ||
445 | printk(KERN_ERR "%s() error\n", __func__); | ||
446 | |||
447 | return b1[0]; | ||
448 | } | ||
449 | |||
450 | static void cx23885_flatiron_dump(struct cx23885_dev *dev) | ||
451 | { | ||
452 | int i; | ||
453 | dprintk(1, "Flatiron dump\n"); | ||
454 | for (i = 0; i < 0x24; i++) { | ||
455 | dprintk(1, "FI[%02x] = %02x\n", i, | ||
456 | cx23885_flatiron_read(dev, i)); | ||
457 | } | ||
458 | } | ||
459 | |||
460 | static int cx23885_flatiron_mux(struct cx23885_dev *dev, int input) | ||
461 | { | ||
462 | u8 val; | ||
463 | dprintk(1, "%s(input = %d)\n", __func__, input); | ||
464 | |||
465 | if (input == 1) | ||
466 | val = cx23885_flatiron_read(dev, CH_PWR_CTRL1) & ~FLD_CH_SEL; | ||
467 | else if (input == 2) | ||
468 | val = cx23885_flatiron_read(dev, CH_PWR_CTRL1) | FLD_CH_SEL; | ||
469 | else | ||
470 | return -EINVAL; | ||
471 | |||
472 | val |= 0x20; /* Enable clock to delta-sigma and dec filter */ | ||
473 | |||
474 | cx23885_flatiron_write(dev, CH_PWR_CTRL1, val); | ||
475 | |||
476 | /* Wake up */ | ||
477 | cx23885_flatiron_write(dev, CH_PWR_CTRL2, 0); | ||
478 | |||
479 | if (video_debug) | ||
480 | cx23885_flatiron_dump(dev); | ||
481 | |||
482 | return 0; | ||
483 | } | ||
484 | |||
485 | static int cx23885_video_mux(struct cx23885_dev *dev, unsigned int input) | ||
486 | { | ||
487 | dprintk(1, "%s() video_mux: %d [vmux=%d, gpio=0x%x,0x%x,0x%x,0x%x]\n", | ||
488 | __func__, | ||
489 | input, INPUT(input)->vmux, | ||
490 | INPUT(input)->gpio0, INPUT(input)->gpio1, | ||
491 | INPUT(input)->gpio2, INPUT(input)->gpio3); | ||
492 | dev->input = input; | ||
493 | |||
494 | if (dev->board == CX23885_BOARD_MYGICA_X8506 || | ||
495 | dev->board == CX23885_BOARD_MAGICPRO_PROHDTVE2 || | ||
496 | dev->board == CX23885_BOARD_MYGICA_X8507) { | ||
497 | /* Select Analog TV */ | ||
498 | if (INPUT(input)->type == CX23885_VMUX_TELEVISION) | ||
499 | cx23885_gpio_clear(dev, GPIO_0); | ||
500 | } | ||
501 | |||
502 | /* Tell the internal A/V decoder */ | ||
503 | v4l2_subdev_call(dev->sd_cx25840, video, s_routing, | ||
504 | INPUT(input)->vmux, 0, 0); | ||
505 | |||
506 | if ((dev->board == CX23885_BOARD_HAUPPAUGE_HVR1800) || | ||
507 | (dev->board == CX23885_BOARD_MPX885) || | ||
508 | (dev->board == CX23885_BOARD_HAUPPAUGE_HVR1250) || | ||
509 | (dev->board == CX23885_BOARD_HAUPPAUGE_HVR1255) || | ||
510 | (dev->board == CX23885_BOARD_HAUPPAUGE_HVR1255_22111) || | ||
511 | (dev->board == CX23885_BOARD_HAUPPAUGE_HVR1850)) { | ||
512 | /* Configure audio routing */ | ||
513 | v4l2_subdev_call(dev->sd_cx25840, audio, s_routing, | ||
514 | INPUT(input)->amux, 0, 0); | ||
515 | |||
516 | if (INPUT(input)->amux == CX25840_AUDIO7) | ||
517 | cx23885_flatiron_mux(dev, 1); | ||
518 | else if (INPUT(input)->amux == CX25840_AUDIO6) | ||
519 | cx23885_flatiron_mux(dev, 2); | ||
520 | } | ||
521 | |||
522 | return 0; | ||
523 | } | ||
524 | |||
525 | static int cx23885_audio_mux(struct cx23885_dev *dev, unsigned int input) | ||
526 | { | ||
527 | dprintk(1, "%s(input=%d)\n", __func__, input); | ||
528 | |||
529 | /* The baseband video core of the cx23885 has two audio inputs. | ||
530 | * LR1 and LR2. In almost every single case so far only HVR1xxx | ||
531 | * cards we've only ever supported LR1. Time to support LR2, | ||
532 | * which is available via the optional white breakout header on | ||
533 | * the board. | ||
534 | * We'll use a could of existing enums in the card struct to allow | ||
535 | * devs to specify which baseband input they need, or just default | ||
536 | * to what we've always used. | ||
537 | */ | ||
538 | if (INPUT(input)->amux == CX25840_AUDIO7) | ||
539 | cx23885_flatiron_mux(dev, 1); | ||
540 | else if (INPUT(input)->amux == CX25840_AUDIO6) | ||
541 | cx23885_flatiron_mux(dev, 2); | ||
542 | else { | ||
543 | /* Not specifically defined, assume the default. */ | ||
544 | cx23885_flatiron_mux(dev, 1); | ||
545 | } | ||
546 | |||
547 | return 0; | ||
548 | } | ||
549 | |||
550 | /* ------------------------------------------------------------------ */ | ||
551 | static int cx23885_start_video_dma(struct cx23885_dev *dev, | ||
552 | struct cx23885_dmaqueue *q, | ||
553 | struct cx23885_buffer *buf) | ||
554 | { | ||
555 | dprintk(1, "%s()\n", __func__); | ||
556 | |||
557 | /* Stop the dma/fifo before we tamper with it's risc programs */ | ||
558 | cx_clear(VID_A_DMA_CTL, 0x11); | ||
559 | |||
560 | /* setup fifo + format */ | ||
561 | cx23885_sram_channel_setup(dev, &dev->sram_channels[SRAM_CH01], | ||
562 | buf->bpl, buf->risc.dma); | ||
563 | |||
564 | /* reset counter */ | ||
565 | cx_write(VID_A_GPCNT_CTL, 3); | ||
566 | q->count = 1; | ||
567 | |||
568 | /* enable irq */ | ||
569 | cx23885_irq_add_enable(dev, 0x01); | ||
570 | cx_set(VID_A_INT_MSK, 0x000011); | ||
571 | |||
572 | /* start dma */ | ||
573 | cx_set(DEV_CNTRL2, (1<<5)); | ||
574 | cx_set(VID_A_DMA_CTL, 0x11); /* FIFO and RISC enable */ | ||
575 | |||
576 | return 0; | ||
577 | } | ||
578 | |||
579 | |||
580 | static int cx23885_restart_video_queue(struct cx23885_dev *dev, | ||
581 | struct cx23885_dmaqueue *q) | ||
582 | { | ||
583 | struct cx23885_buffer *buf, *prev; | ||
584 | struct list_head *item; | ||
585 | dprintk(1, "%s()\n", __func__); | ||
586 | |||
587 | if (!list_empty(&q->active)) { | ||
588 | buf = list_entry(q->active.next, struct cx23885_buffer, | ||
589 | vb.queue); | ||
590 | dprintk(2, "restart_queue [%p/%d]: restart dma\n", | ||
591 | buf, buf->vb.i); | ||
592 | cx23885_start_video_dma(dev, q, buf); | ||
593 | list_for_each(item, &q->active) { | ||
594 | buf = list_entry(item, struct cx23885_buffer, | ||
595 | vb.queue); | ||
596 | buf->count = q->count++; | ||
597 | } | ||
598 | mod_timer(&q->timeout, jiffies+BUFFER_TIMEOUT); | ||
599 | return 0; | ||
600 | } | ||
601 | |||
602 | prev = NULL; | ||
603 | for (;;) { | ||
604 | if (list_empty(&q->queued)) | ||
605 | return 0; | ||
606 | buf = list_entry(q->queued.next, struct cx23885_buffer, | ||
607 | vb.queue); | ||
608 | if (NULL == prev) { | ||
609 | list_move_tail(&buf->vb.queue, &q->active); | ||
610 | cx23885_start_video_dma(dev, q, buf); | ||
611 | buf->vb.state = VIDEOBUF_ACTIVE; | ||
612 | buf->count = q->count++; | ||
613 | mod_timer(&q->timeout, jiffies+BUFFER_TIMEOUT); | ||
614 | dprintk(2, "[%p/%d] restart_queue - first active\n", | ||
615 | buf, buf->vb.i); | ||
616 | |||
617 | } else if (prev->vb.width == buf->vb.width && | ||
618 | prev->vb.height == buf->vb.height && | ||
619 | prev->fmt == buf->fmt) { | ||
620 | list_move_tail(&buf->vb.queue, &q->active); | ||
621 | buf->vb.state = VIDEOBUF_ACTIVE; | ||
622 | buf->count = q->count++; | ||
623 | prev->risc.jmp[1] = cpu_to_le32(buf->risc.dma); | ||
624 | prev->risc.jmp[2] = cpu_to_le32(0); /* Bits 63 - 32 */ | ||
625 | dprintk(2, "[%p/%d] restart_queue - move to active\n", | ||
626 | buf, buf->vb.i); | ||
627 | } else { | ||
628 | return 0; | ||
629 | } | ||
630 | prev = buf; | ||
631 | } | ||
632 | } | ||
633 | |||
634 | static int buffer_setup(struct videobuf_queue *q, unsigned int *count, | ||
635 | unsigned int *size) | ||
636 | { | ||
637 | struct cx23885_fh *fh = q->priv_data; | ||
638 | |||
639 | *size = fh->fmt->depth*fh->width*fh->height >> 3; | ||
640 | if (0 == *count) | ||
641 | *count = 32; | ||
642 | if (*size * *count > vid_limit * 1024 * 1024) | ||
643 | *count = (vid_limit * 1024 * 1024) / *size; | ||
644 | return 0; | ||
645 | } | ||
646 | |||
647 | static int buffer_prepare(struct videobuf_queue *q, struct videobuf_buffer *vb, | ||
648 | enum v4l2_field field) | ||
649 | { | ||
650 | struct cx23885_fh *fh = q->priv_data; | ||
651 | struct cx23885_dev *dev = fh->dev; | ||
652 | struct cx23885_buffer *buf = | ||
653 | container_of(vb, struct cx23885_buffer, vb); | ||
654 | int rc, init_buffer = 0; | ||
655 | u32 line0_offset, line1_offset; | ||
656 | struct videobuf_dmabuf *dma = videobuf_to_dma(&buf->vb); | ||
657 | int field_tff; | ||
658 | |||
659 | BUG_ON(NULL == fh->fmt); | ||
660 | if (fh->width < 48 || fh->width > norm_maxw(dev->tvnorm) || | ||
661 | fh->height < 32 || fh->height > norm_maxh(dev->tvnorm)) | ||
662 | return -EINVAL; | ||
663 | buf->vb.size = (fh->width * fh->height * fh->fmt->depth) >> 3; | ||
664 | if (0 != buf->vb.baddr && buf->vb.bsize < buf->vb.size) | ||
665 | return -EINVAL; | ||
666 | |||
667 | if (buf->fmt != fh->fmt || | ||
668 | buf->vb.width != fh->width || | ||
669 | buf->vb.height != fh->height || | ||
670 | buf->vb.field != field) { | ||
671 | buf->fmt = fh->fmt; | ||
672 | buf->vb.width = fh->width; | ||
673 | buf->vb.height = fh->height; | ||
674 | buf->vb.field = field; | ||
675 | init_buffer = 1; | ||
676 | } | ||
677 | |||
678 | if (VIDEOBUF_NEEDS_INIT == buf->vb.state) { | ||
679 | init_buffer = 1; | ||
680 | rc = videobuf_iolock(q, &buf->vb, NULL); | ||
681 | if (0 != rc) | ||
682 | goto fail; | ||
683 | } | ||
684 | |||
685 | if (init_buffer) { | ||
686 | buf->bpl = buf->vb.width * buf->fmt->depth >> 3; | ||
687 | switch (buf->vb.field) { | ||
688 | case V4L2_FIELD_TOP: | ||
689 | cx23885_risc_buffer(dev->pci, &buf->risc, | ||
690 | dma->sglist, 0, UNSET, | ||
691 | buf->bpl, 0, buf->vb.height); | ||
692 | break; | ||
693 | case V4L2_FIELD_BOTTOM: | ||
694 | cx23885_risc_buffer(dev->pci, &buf->risc, | ||
695 | dma->sglist, UNSET, 0, | ||
696 | buf->bpl, 0, buf->vb.height); | ||
697 | break; | ||
698 | case V4L2_FIELD_INTERLACED: | ||
699 | if (dev->tvnorm & V4L2_STD_NTSC) | ||
700 | /* NTSC or */ | ||
701 | field_tff = 1; | ||
702 | else | ||
703 | field_tff = 0; | ||
704 | |||
705 | if (cx23885_boards[dev->board].force_bff) | ||
706 | /* PAL / SECAM OR 888 in NTSC MODE */ | ||
707 | field_tff = 0; | ||
708 | |||
709 | if (field_tff) { | ||
710 | /* cx25840 transmits NTSC bottom field first */ | ||
711 | dprintk(1, "%s() Creating TFF/NTSC risc\n", | ||
712 | __func__); | ||
713 | line0_offset = buf->bpl; | ||
714 | line1_offset = 0; | ||
715 | } else { | ||
716 | /* All other formats are top field first */ | ||
717 | dprintk(1, "%s() Creating BFF/PAL/SECAM risc\n", | ||
718 | __func__); | ||
719 | line0_offset = 0; | ||
720 | line1_offset = buf->bpl; | ||
721 | } | ||
722 | cx23885_risc_buffer(dev->pci, &buf->risc, | ||
723 | dma->sglist, line0_offset, | ||
724 | line1_offset, | ||
725 | buf->bpl, buf->bpl, | ||
726 | buf->vb.height >> 1); | ||
727 | break; | ||
728 | case V4L2_FIELD_SEQ_TB: | ||
729 | cx23885_risc_buffer(dev->pci, &buf->risc, | ||
730 | dma->sglist, | ||
731 | 0, buf->bpl * (buf->vb.height >> 1), | ||
732 | buf->bpl, 0, | ||
733 | buf->vb.height >> 1); | ||
734 | break; | ||
735 | case V4L2_FIELD_SEQ_BT: | ||
736 | cx23885_risc_buffer(dev->pci, &buf->risc, | ||
737 | dma->sglist, | ||
738 | buf->bpl * (buf->vb.height >> 1), 0, | ||
739 | buf->bpl, 0, | ||
740 | buf->vb.height >> 1); | ||
741 | break; | ||
742 | default: | ||
743 | BUG(); | ||
744 | } | ||
745 | } | ||
746 | dprintk(2, "[%p/%d] buffer_prep - %dx%d %dbpp \"%s\" - dma=0x%08lx\n", | ||
747 | buf, buf->vb.i, | ||
748 | fh->width, fh->height, fh->fmt->depth, fh->fmt->name, | ||
749 | (unsigned long)buf->risc.dma); | ||
750 | |||
751 | buf->vb.state = VIDEOBUF_PREPARED; | ||
752 | return 0; | ||
753 | |||
754 | fail: | ||
755 | cx23885_free_buffer(q, buf); | ||
756 | return rc; | ||
757 | } | ||
758 | |||
759 | static void buffer_queue(struct videobuf_queue *vq, struct videobuf_buffer *vb) | ||
760 | { | ||
761 | struct cx23885_buffer *buf = container_of(vb, | ||
762 | struct cx23885_buffer, vb); | ||
763 | struct cx23885_buffer *prev; | ||
764 | struct cx23885_fh *fh = vq->priv_data; | ||
765 | struct cx23885_dev *dev = fh->dev; | ||
766 | struct cx23885_dmaqueue *q = &dev->vidq; | ||
767 | |||
768 | /* add jump to stopper */ | ||
769 | buf->risc.jmp[0] = cpu_to_le32(RISC_JUMP | RISC_IRQ1 | RISC_CNT_INC); | ||
770 | buf->risc.jmp[1] = cpu_to_le32(q->stopper.dma); | ||
771 | buf->risc.jmp[2] = cpu_to_le32(0); /* bits 63-32 */ | ||
772 | |||
773 | if (!list_empty(&q->queued)) { | ||
774 | list_add_tail(&buf->vb.queue, &q->queued); | ||
775 | buf->vb.state = VIDEOBUF_QUEUED; | ||
776 | dprintk(2, "[%p/%d] buffer_queue - append to queued\n", | ||
777 | buf, buf->vb.i); | ||
778 | |||
779 | } else if (list_empty(&q->active)) { | ||
780 | list_add_tail(&buf->vb.queue, &q->active); | ||
781 | cx23885_start_video_dma(dev, q, buf); | ||
782 | buf->vb.state = VIDEOBUF_ACTIVE; | ||
783 | buf->count = q->count++; | ||
784 | mod_timer(&q->timeout, jiffies+BUFFER_TIMEOUT); | ||
785 | dprintk(2, "[%p/%d] buffer_queue - first active\n", | ||
786 | buf, buf->vb.i); | ||
787 | |||
788 | } else { | ||
789 | prev = list_entry(q->active.prev, struct cx23885_buffer, | ||
790 | vb.queue); | ||
791 | if (prev->vb.width == buf->vb.width && | ||
792 | prev->vb.height == buf->vb.height && | ||
793 | prev->fmt == buf->fmt) { | ||
794 | list_add_tail(&buf->vb.queue, &q->active); | ||
795 | buf->vb.state = VIDEOBUF_ACTIVE; | ||
796 | buf->count = q->count++; | ||
797 | prev->risc.jmp[1] = cpu_to_le32(buf->risc.dma); | ||
798 | /* 64 bit bits 63-32 */ | ||
799 | prev->risc.jmp[2] = cpu_to_le32(0); | ||
800 | dprintk(2, "[%p/%d] buffer_queue - append to active\n", | ||
801 | buf, buf->vb.i); | ||
802 | |||
803 | } else { | ||
804 | list_add_tail(&buf->vb.queue, &q->queued); | ||
805 | buf->vb.state = VIDEOBUF_QUEUED; | ||
806 | dprintk(2, "[%p/%d] buffer_queue - first queued\n", | ||
807 | buf, buf->vb.i); | ||
808 | } | ||
809 | } | ||
810 | } | ||
811 | |||
812 | static void buffer_release(struct videobuf_queue *q, | ||
813 | struct videobuf_buffer *vb) | ||
814 | { | ||
815 | struct cx23885_buffer *buf = container_of(vb, | ||
816 | struct cx23885_buffer, vb); | ||
817 | |||
818 | cx23885_free_buffer(q, buf); | ||
819 | } | ||
820 | |||
821 | static struct videobuf_queue_ops cx23885_video_qops = { | ||
822 | .buf_setup = buffer_setup, | ||
823 | .buf_prepare = buffer_prepare, | ||
824 | .buf_queue = buffer_queue, | ||
825 | .buf_release = buffer_release, | ||
826 | }; | ||
827 | |||
828 | static struct videobuf_queue *get_queue(struct cx23885_fh *fh) | ||
829 | { | ||
830 | switch (fh->type) { | ||
831 | case V4L2_BUF_TYPE_VIDEO_CAPTURE: | ||
832 | return &fh->vidq; | ||
833 | case V4L2_BUF_TYPE_VBI_CAPTURE: | ||
834 | return &fh->vbiq; | ||
835 | default: | ||
836 | BUG(); | ||
837 | return NULL; | ||
838 | } | ||
839 | } | ||
840 | |||
841 | static int get_resource(struct cx23885_fh *fh) | ||
842 | { | ||
843 | switch (fh->type) { | ||
844 | case V4L2_BUF_TYPE_VIDEO_CAPTURE: | ||
845 | return RESOURCE_VIDEO; | ||
846 | case V4L2_BUF_TYPE_VBI_CAPTURE: | ||
847 | return RESOURCE_VBI; | ||
848 | default: | ||
849 | BUG(); | ||
850 | return 0; | ||
851 | } | ||
852 | } | ||
853 | |||
854 | static int video_open(struct file *file) | ||
855 | { | ||
856 | struct video_device *vdev = video_devdata(file); | ||
857 | struct cx23885_dev *dev = video_drvdata(file); | ||
858 | struct cx23885_fh *fh; | ||
859 | enum v4l2_buf_type type = 0; | ||
860 | int radio = 0; | ||
861 | |||
862 | switch (vdev->vfl_type) { | ||
863 | case VFL_TYPE_GRABBER: | ||
864 | type = V4L2_BUF_TYPE_VIDEO_CAPTURE; | ||
865 | break; | ||
866 | case VFL_TYPE_VBI: | ||
867 | type = V4L2_BUF_TYPE_VBI_CAPTURE; | ||
868 | break; | ||
869 | case VFL_TYPE_RADIO: | ||
870 | radio = 1; | ||
871 | break; | ||
872 | } | ||
873 | |||
874 | dprintk(1, "open dev=%s radio=%d type=%s\n", | ||
875 | video_device_node_name(vdev), radio, v4l2_type_names[type]); | ||
876 | |||
877 | /* allocate + initialize per filehandle data */ | ||
878 | fh = kzalloc(sizeof(*fh), GFP_KERNEL); | ||
879 | if (NULL == fh) | ||
880 | return -ENOMEM; | ||
881 | |||
882 | file->private_data = fh; | ||
883 | fh->dev = dev; | ||
884 | fh->radio = radio; | ||
885 | fh->type = type; | ||
886 | fh->width = 320; | ||
887 | fh->height = 240; | ||
888 | fh->fmt = format_by_fourcc(V4L2_PIX_FMT_YUYV); | ||
889 | |||
890 | videobuf_queue_sg_init(&fh->vidq, &cx23885_video_qops, | ||
891 | &dev->pci->dev, &dev->slock, | ||
892 | V4L2_BUF_TYPE_VIDEO_CAPTURE, | ||
893 | V4L2_FIELD_INTERLACED, | ||
894 | sizeof(struct cx23885_buffer), | ||
895 | fh, NULL); | ||
896 | |||
897 | videobuf_queue_sg_init(&fh->vbiq, &cx23885_vbi_qops, | ||
898 | &dev->pci->dev, &dev->slock, | ||
899 | V4L2_BUF_TYPE_VBI_CAPTURE, | ||
900 | V4L2_FIELD_SEQ_TB, | ||
901 | sizeof(struct cx23885_buffer), | ||
902 | fh, NULL); | ||
903 | |||
904 | |||
905 | dprintk(1, "post videobuf_queue_init()\n"); | ||
906 | |||
907 | return 0; | ||
908 | } | ||
909 | |||
910 | static ssize_t video_read(struct file *file, char __user *data, | ||
911 | size_t count, loff_t *ppos) | ||
912 | { | ||
913 | struct cx23885_fh *fh = file->private_data; | ||
914 | |||
915 | switch (fh->type) { | ||
916 | case V4L2_BUF_TYPE_VIDEO_CAPTURE: | ||
917 | if (res_locked(fh->dev, RESOURCE_VIDEO)) | ||
918 | return -EBUSY; | ||
919 | return videobuf_read_one(&fh->vidq, data, count, ppos, | ||
920 | file->f_flags & O_NONBLOCK); | ||
921 | case V4L2_BUF_TYPE_VBI_CAPTURE: | ||
922 | if (!res_get(fh->dev, fh, RESOURCE_VBI)) | ||
923 | return -EBUSY; | ||
924 | return videobuf_read_stream(&fh->vbiq, data, count, ppos, 1, | ||
925 | file->f_flags & O_NONBLOCK); | ||
926 | default: | ||
927 | BUG(); | ||
928 | return 0; | ||
929 | } | ||
930 | } | ||
931 | |||
932 | static unsigned int video_poll(struct file *file, | ||
933 | struct poll_table_struct *wait) | ||
934 | { | ||
935 | struct cx23885_fh *fh = file->private_data; | ||
936 | struct cx23885_buffer *buf; | ||
937 | unsigned int rc = POLLERR; | ||
938 | |||
939 | if (V4L2_BUF_TYPE_VBI_CAPTURE == fh->type) { | ||
940 | if (!res_get(fh->dev, fh, RESOURCE_VBI)) | ||
941 | return POLLERR; | ||
942 | return videobuf_poll_stream(file, &fh->vbiq, wait); | ||
943 | } | ||
944 | |||
945 | mutex_lock(&fh->vidq.vb_lock); | ||
946 | if (res_check(fh, RESOURCE_VIDEO)) { | ||
947 | /* streaming capture */ | ||
948 | if (list_empty(&fh->vidq.stream)) | ||
949 | goto done; | ||
950 | buf = list_entry(fh->vidq.stream.next, | ||
951 | struct cx23885_buffer, vb.stream); | ||
952 | } else { | ||
953 | /* read() capture */ | ||
954 | buf = (struct cx23885_buffer *)fh->vidq.read_buf; | ||
955 | if (NULL == buf) | ||
956 | goto done; | ||
957 | } | ||
958 | poll_wait(file, &buf->vb.done, wait); | ||
959 | if (buf->vb.state == VIDEOBUF_DONE || | ||
960 | buf->vb.state == VIDEOBUF_ERROR) | ||
961 | rc = POLLIN|POLLRDNORM; | ||
962 | else | ||
963 | rc = 0; | ||
964 | done: | ||
965 | mutex_unlock(&fh->vidq.vb_lock); | ||
966 | return rc; | ||
967 | } | ||
968 | |||
969 | static int video_release(struct file *file) | ||
970 | { | ||
971 | struct cx23885_fh *fh = file->private_data; | ||
972 | struct cx23885_dev *dev = fh->dev; | ||
973 | |||
974 | /* turn off overlay */ | ||
975 | if (res_check(fh, RESOURCE_OVERLAY)) { | ||
976 | /* FIXME */ | ||
977 | res_free(dev, fh, RESOURCE_OVERLAY); | ||
978 | } | ||
979 | |||
980 | /* stop video capture */ | ||
981 | if (res_check(fh, RESOURCE_VIDEO)) { | ||
982 | videobuf_queue_cancel(&fh->vidq); | ||
983 | res_free(dev, fh, RESOURCE_VIDEO); | ||
984 | } | ||
985 | if (fh->vidq.read_buf) { | ||
986 | buffer_release(&fh->vidq, fh->vidq.read_buf); | ||
987 | kfree(fh->vidq.read_buf); | ||
988 | } | ||
989 | |||
990 | /* stop vbi capture */ | ||
991 | if (res_check(fh, RESOURCE_VBI)) { | ||
992 | if (fh->vbiq.streaming) | ||
993 | videobuf_streamoff(&fh->vbiq); | ||
994 | if (fh->vbiq.reading) | ||
995 | videobuf_read_stop(&fh->vbiq); | ||
996 | res_free(dev, fh, RESOURCE_VBI); | ||
997 | } | ||
998 | |||
999 | videobuf_mmap_free(&fh->vidq); | ||
1000 | videobuf_mmap_free(&fh->vbiq); | ||
1001 | |||
1002 | file->private_data = NULL; | ||
1003 | kfree(fh); | ||
1004 | |||
1005 | /* We are not putting the tuner to sleep here on exit, because | ||
1006 | * we want to use the mpeg encoder in another session to capture | ||
1007 | * tuner video. Closing this will result in no video to the encoder. | ||
1008 | */ | ||
1009 | |||
1010 | return 0; | ||
1011 | } | ||
1012 | |||
1013 | static int video_mmap(struct file *file, struct vm_area_struct *vma) | ||
1014 | { | ||
1015 | struct cx23885_fh *fh = file->private_data; | ||
1016 | |||
1017 | return videobuf_mmap_mapper(get_queue(fh), vma); | ||
1018 | } | ||
1019 | |||
1020 | /* ------------------------------------------------------------------ */ | ||
1021 | /* VIDEO CTRL IOCTLS */ | ||
1022 | |||
1023 | int cx23885_get_control(struct cx23885_dev *dev, | ||
1024 | struct v4l2_control *ctl) | ||
1025 | { | ||
1026 | dprintk(1, "%s() calling cx25840(VIDIOC_G_CTRL)\n", __func__); | ||
1027 | call_all(dev, core, g_ctrl, ctl); | ||
1028 | return 0; | ||
1029 | } | ||
1030 | |||
1031 | int cx23885_set_control(struct cx23885_dev *dev, | ||
1032 | struct v4l2_control *ctl) | ||
1033 | { | ||
1034 | dprintk(1, "%s() calling cx25840(VIDIOC_S_CTRL)\n", __func__); | ||
1035 | call_all(dev, core, s_ctrl, ctl); | ||
1036 | |||
1037 | return 0; | ||
1038 | } | ||
1039 | |||
1040 | static void init_controls(struct cx23885_dev *dev) | ||
1041 | { | ||
1042 | struct v4l2_control ctrl; | ||
1043 | int i; | ||
1044 | |||
1045 | for (i = 0; i < CX23885_CTLS; i++) { | ||
1046 | ctrl.id = cx23885_ctls[i].v.id; | ||
1047 | ctrl.value = cx23885_ctls[i].v.default_value; | ||
1048 | |||
1049 | cx23885_set_control(dev, &ctrl); | ||
1050 | } | ||
1051 | } | ||
1052 | |||
1053 | /* ------------------------------------------------------------------ */ | ||
1054 | /* VIDEO IOCTLS */ | ||
1055 | |||
1056 | static int vidioc_g_fmt_vid_cap(struct file *file, void *priv, | ||
1057 | struct v4l2_format *f) | ||
1058 | { | ||
1059 | struct cx23885_fh *fh = priv; | ||
1060 | |||
1061 | f->fmt.pix.width = fh->width; | ||
1062 | f->fmt.pix.height = fh->height; | ||
1063 | f->fmt.pix.field = fh->vidq.field; | ||
1064 | f->fmt.pix.pixelformat = fh->fmt->fourcc; | ||
1065 | f->fmt.pix.bytesperline = | ||
1066 | (f->fmt.pix.width * fh->fmt->depth) >> 3; | ||
1067 | f->fmt.pix.sizeimage = | ||
1068 | f->fmt.pix.height * f->fmt.pix.bytesperline; | ||
1069 | |||
1070 | return 0; | ||
1071 | } | ||
1072 | |||
1073 | static int vidioc_try_fmt_vid_cap(struct file *file, void *priv, | ||
1074 | struct v4l2_format *f) | ||
1075 | { | ||
1076 | struct cx23885_dev *dev = ((struct cx23885_fh *)priv)->dev; | ||
1077 | struct cx23885_fmt *fmt; | ||
1078 | enum v4l2_field field; | ||
1079 | unsigned int maxw, maxh; | ||
1080 | |||
1081 | fmt = format_by_fourcc(f->fmt.pix.pixelformat); | ||
1082 | if (NULL == fmt) | ||
1083 | return -EINVAL; | ||
1084 | |||
1085 | field = f->fmt.pix.field; | ||
1086 | maxw = norm_maxw(dev->tvnorm); | ||
1087 | maxh = norm_maxh(dev->tvnorm); | ||
1088 | |||
1089 | if (V4L2_FIELD_ANY == field) { | ||
1090 | field = (f->fmt.pix.height > maxh/2) | ||
1091 | ? V4L2_FIELD_INTERLACED | ||
1092 | : V4L2_FIELD_BOTTOM; | ||
1093 | } | ||
1094 | |||
1095 | switch (field) { | ||
1096 | case V4L2_FIELD_TOP: | ||
1097 | case V4L2_FIELD_BOTTOM: | ||
1098 | maxh = maxh / 2; | ||
1099 | break; | ||
1100 | case V4L2_FIELD_INTERLACED: | ||
1101 | break; | ||
1102 | default: | ||
1103 | return -EINVAL; | ||
1104 | } | ||
1105 | |||
1106 | f->fmt.pix.field = field; | ||
1107 | v4l_bound_align_image(&f->fmt.pix.width, 48, maxw, 2, | ||
1108 | &f->fmt.pix.height, 32, maxh, 0, 0); | ||
1109 | f->fmt.pix.bytesperline = | ||
1110 | (f->fmt.pix.width * fmt->depth) >> 3; | ||
1111 | f->fmt.pix.sizeimage = | ||
1112 | f->fmt.pix.height * f->fmt.pix.bytesperline; | ||
1113 | |||
1114 | return 0; | ||
1115 | } | ||
1116 | |||
1117 | static int vidioc_s_fmt_vid_cap(struct file *file, void *priv, | ||
1118 | struct v4l2_format *f) | ||
1119 | { | ||
1120 | struct cx23885_fh *fh = priv; | ||
1121 | struct cx23885_dev *dev = ((struct cx23885_fh *)priv)->dev; | ||
1122 | struct v4l2_mbus_framefmt mbus_fmt; | ||
1123 | int err; | ||
1124 | |||
1125 | dprintk(2, "%s()\n", __func__); | ||
1126 | err = vidioc_try_fmt_vid_cap(file, priv, f); | ||
1127 | |||
1128 | if (0 != err) | ||
1129 | return err; | ||
1130 | fh->fmt = format_by_fourcc(f->fmt.pix.pixelformat); | ||
1131 | fh->width = f->fmt.pix.width; | ||
1132 | fh->height = f->fmt.pix.height; | ||
1133 | fh->vidq.field = f->fmt.pix.field; | ||
1134 | dprintk(2, "%s() width=%d height=%d field=%d\n", __func__, | ||
1135 | fh->width, fh->height, fh->vidq.field); | ||
1136 | v4l2_fill_mbus_format(&mbus_fmt, &f->fmt.pix, V4L2_MBUS_FMT_FIXED); | ||
1137 | call_all(dev, video, s_mbus_fmt, &mbus_fmt); | ||
1138 | v4l2_fill_pix_format(&f->fmt.pix, &mbus_fmt); | ||
1139 | return 0; | ||
1140 | } | ||
1141 | |||
1142 | static int vidioc_querycap(struct file *file, void *priv, | ||
1143 | struct v4l2_capability *cap) | ||
1144 | { | ||
1145 | struct cx23885_dev *dev = ((struct cx23885_fh *)priv)->dev; | ||
1146 | |||
1147 | strcpy(cap->driver, "cx23885"); | ||
1148 | strlcpy(cap->card, cx23885_boards[dev->board].name, | ||
1149 | sizeof(cap->card)); | ||
1150 | sprintf(cap->bus_info, "PCIe:%s", pci_name(dev->pci)); | ||
1151 | cap->capabilities = | ||
1152 | V4L2_CAP_VIDEO_CAPTURE | | ||
1153 | V4L2_CAP_READWRITE | | ||
1154 | V4L2_CAP_STREAMING | | ||
1155 | V4L2_CAP_VBI_CAPTURE; | ||
1156 | if (UNSET != dev->tuner_type) | ||
1157 | cap->capabilities |= V4L2_CAP_TUNER; | ||
1158 | return 0; | ||
1159 | } | ||
1160 | |||
1161 | static int vidioc_enum_fmt_vid_cap(struct file *file, void *priv, | ||
1162 | struct v4l2_fmtdesc *f) | ||
1163 | { | ||
1164 | if (unlikely(f->index >= ARRAY_SIZE(formats))) | ||
1165 | return -EINVAL; | ||
1166 | |||
1167 | strlcpy(f->description, formats[f->index].name, | ||
1168 | sizeof(f->description)); | ||
1169 | f->pixelformat = formats[f->index].fourcc; | ||
1170 | |||
1171 | return 0; | ||
1172 | } | ||
1173 | |||
1174 | static int vidioc_reqbufs(struct file *file, void *priv, | ||
1175 | struct v4l2_requestbuffers *p) | ||
1176 | { | ||
1177 | struct cx23885_fh *fh = priv; | ||
1178 | return videobuf_reqbufs(get_queue(fh), p); | ||
1179 | } | ||
1180 | |||
1181 | static int vidioc_querybuf(struct file *file, void *priv, | ||
1182 | struct v4l2_buffer *p) | ||
1183 | { | ||
1184 | struct cx23885_fh *fh = priv; | ||
1185 | return videobuf_querybuf(get_queue(fh), p); | ||
1186 | } | ||
1187 | |||
1188 | static int vidioc_qbuf(struct file *file, void *priv, | ||
1189 | struct v4l2_buffer *p) | ||
1190 | { | ||
1191 | struct cx23885_fh *fh = priv; | ||
1192 | return videobuf_qbuf(get_queue(fh), p); | ||
1193 | } | ||
1194 | |||
1195 | static int vidioc_dqbuf(struct file *file, void *priv, | ||
1196 | struct v4l2_buffer *p) | ||
1197 | { | ||
1198 | struct cx23885_fh *fh = priv; | ||
1199 | return videobuf_dqbuf(get_queue(fh), p, | ||
1200 | file->f_flags & O_NONBLOCK); | ||
1201 | } | ||
1202 | |||
1203 | static int vidioc_streamon(struct file *file, void *priv, | ||
1204 | enum v4l2_buf_type i) | ||
1205 | { | ||
1206 | struct cx23885_fh *fh = priv; | ||
1207 | struct cx23885_dev *dev = fh->dev; | ||
1208 | dprintk(1, "%s()\n", __func__); | ||
1209 | |||
1210 | if ((fh->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) && | ||
1211 | (fh->type != V4L2_BUF_TYPE_VBI_CAPTURE)) | ||
1212 | return -EINVAL; | ||
1213 | if (unlikely(i != fh->type)) | ||
1214 | return -EINVAL; | ||
1215 | |||
1216 | if (unlikely(!res_get(dev, fh, get_resource(fh)))) | ||
1217 | return -EBUSY; | ||
1218 | |||
1219 | /* Don't start VBI streaming unless vida streaming | ||
1220 | * has already started. | ||
1221 | */ | ||
1222 | if ((fh->type == V4L2_BUF_TYPE_VBI_CAPTURE) && | ||
1223 | ((cx_read(VID_A_DMA_CTL) & 0x11) == 0)) | ||
1224 | return -EINVAL; | ||
1225 | |||
1226 | return videobuf_streamon(get_queue(fh)); | ||
1227 | } | ||
1228 | |||
1229 | static int vidioc_streamoff(struct file *file, void *priv, enum v4l2_buf_type i) | ||
1230 | { | ||
1231 | struct cx23885_fh *fh = priv; | ||
1232 | struct cx23885_dev *dev = fh->dev; | ||
1233 | int err, res; | ||
1234 | dprintk(1, "%s()\n", __func__); | ||
1235 | |||
1236 | if ((fh->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) && | ||
1237 | (fh->type != V4L2_BUF_TYPE_VBI_CAPTURE)) | ||
1238 | return -EINVAL; | ||
1239 | if (i != fh->type) | ||
1240 | return -EINVAL; | ||
1241 | |||
1242 | res = get_resource(fh); | ||
1243 | err = videobuf_streamoff(get_queue(fh)); | ||
1244 | if (err < 0) | ||
1245 | return err; | ||
1246 | res_free(dev, fh, res); | ||
1247 | return 0; | ||
1248 | } | ||
1249 | |||
1250 | static int vidioc_g_std(struct file *file, void *priv, v4l2_std_id *id) | ||
1251 | { | ||
1252 | struct cx23885_dev *dev = ((struct cx23885_fh *)priv)->dev; | ||
1253 | dprintk(1, "%s()\n", __func__); | ||
1254 | |||
1255 | call_all(dev, core, g_std, id); | ||
1256 | |||
1257 | return 0; | ||
1258 | } | ||
1259 | |||
1260 | static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id *tvnorms) | ||
1261 | { | ||
1262 | struct cx23885_dev *dev = ((struct cx23885_fh *)priv)->dev; | ||
1263 | dprintk(1, "%s()\n", __func__); | ||
1264 | |||
1265 | mutex_lock(&dev->lock); | ||
1266 | cx23885_set_tvnorm(dev, *tvnorms); | ||
1267 | mutex_unlock(&dev->lock); | ||
1268 | |||
1269 | return 0; | ||
1270 | } | ||
1271 | |||
1272 | int cx23885_enum_input(struct cx23885_dev *dev, struct v4l2_input *i) | ||
1273 | { | ||
1274 | static const char *iname[] = { | ||
1275 | [CX23885_VMUX_COMPOSITE1] = "Composite1", | ||
1276 | [CX23885_VMUX_COMPOSITE2] = "Composite2", | ||
1277 | [CX23885_VMUX_COMPOSITE3] = "Composite3", | ||
1278 | [CX23885_VMUX_COMPOSITE4] = "Composite4", | ||
1279 | [CX23885_VMUX_SVIDEO] = "S-Video", | ||
1280 | [CX23885_VMUX_COMPONENT] = "Component", | ||
1281 | [CX23885_VMUX_TELEVISION] = "Television", | ||
1282 | [CX23885_VMUX_CABLE] = "Cable TV", | ||
1283 | [CX23885_VMUX_DVB] = "DVB", | ||
1284 | [CX23885_VMUX_DEBUG] = "for debug only", | ||
1285 | }; | ||
1286 | unsigned int n; | ||
1287 | dprintk(1, "%s()\n", __func__); | ||
1288 | |||
1289 | n = i->index; | ||
1290 | if (n >= MAX_CX23885_INPUT) | ||
1291 | return -EINVAL; | ||
1292 | |||
1293 | if (0 == INPUT(n)->type) | ||
1294 | return -EINVAL; | ||
1295 | |||
1296 | i->index = n; | ||
1297 | i->type = V4L2_INPUT_TYPE_CAMERA; | ||
1298 | strcpy(i->name, iname[INPUT(n)->type]); | ||
1299 | if ((CX23885_VMUX_TELEVISION == INPUT(n)->type) || | ||
1300 | (CX23885_VMUX_CABLE == INPUT(n)->type)) { | ||
1301 | i->type = V4L2_INPUT_TYPE_TUNER; | ||
1302 | i->std = CX23885_NORMS; | ||
1303 | } | ||
1304 | |||
1305 | /* Two selectable audio inputs for non-tv inputs */ | ||
1306 | if (INPUT(n)->type != CX23885_VMUX_TELEVISION) | ||
1307 | i->audioset = 0x3; | ||
1308 | |||
1309 | if (dev->input == n) { | ||
1310 | /* enum'd input matches our configured input. | ||
1311 | * Ask the video decoder to process the call | ||
1312 | * and give it an oppertunity to update the | ||
1313 | * status field. | ||
1314 | */ | ||
1315 | call_all(dev, video, g_input_status, &i->status); | ||
1316 | } | ||
1317 | |||
1318 | return 0; | ||
1319 | } | ||
1320 | |||
1321 | static int vidioc_enum_input(struct file *file, void *priv, | ||
1322 | struct v4l2_input *i) | ||
1323 | { | ||
1324 | struct cx23885_dev *dev = ((struct cx23885_fh *)priv)->dev; | ||
1325 | dprintk(1, "%s()\n", __func__); | ||
1326 | return cx23885_enum_input(dev, i); | ||
1327 | } | ||
1328 | |||
1329 | int cx23885_get_input(struct file *file, void *priv, unsigned int *i) | ||
1330 | { | ||
1331 | struct cx23885_dev *dev = ((struct cx23885_fh *)priv)->dev; | ||
1332 | |||
1333 | *i = dev->input; | ||
1334 | dprintk(1, "%s() returns %d\n", __func__, *i); | ||
1335 | return 0; | ||
1336 | } | ||
1337 | |||
1338 | static int vidioc_g_input(struct file *file, void *priv, unsigned int *i) | ||
1339 | { | ||
1340 | return cx23885_get_input(file, priv, i); | ||
1341 | } | ||
1342 | |||
1343 | int cx23885_set_input(struct file *file, void *priv, unsigned int i) | ||
1344 | { | ||
1345 | struct cx23885_dev *dev = ((struct cx23885_fh *)priv)->dev; | ||
1346 | |||
1347 | dprintk(1, "%s(%d)\n", __func__, i); | ||
1348 | |||
1349 | if (i >= MAX_CX23885_INPUT) { | ||
1350 | dprintk(1, "%s() -EINVAL\n", __func__); | ||
1351 | return -EINVAL; | ||
1352 | } | ||
1353 | |||
1354 | if (INPUT(i)->type == 0) | ||
1355 | return -EINVAL; | ||
1356 | |||
1357 | mutex_lock(&dev->lock); | ||
1358 | cx23885_video_mux(dev, i); | ||
1359 | |||
1360 | /* By default establish the default audio input for the card also */ | ||
1361 | /* Caller is free to use VIDIOC_S_AUDIO to override afterwards */ | ||
1362 | cx23885_audio_mux(dev, i); | ||
1363 | mutex_unlock(&dev->lock); | ||
1364 | return 0; | ||
1365 | } | ||
1366 | |||
1367 | static int vidioc_s_input(struct file *file, void *priv, unsigned int i) | ||
1368 | { | ||
1369 | return cx23885_set_input(file, priv, i); | ||
1370 | } | ||
1371 | |||
1372 | static int vidioc_log_status(struct file *file, void *priv) | ||
1373 | { | ||
1374 | struct cx23885_fh *fh = priv; | ||
1375 | struct cx23885_dev *dev = fh->dev; | ||
1376 | |||
1377 | printk(KERN_INFO | ||
1378 | "%s/0: ============ START LOG STATUS ============\n", | ||
1379 | dev->name); | ||
1380 | call_all(dev, core, log_status); | ||
1381 | printk(KERN_INFO | ||
1382 | "%s/0: ============= END LOG STATUS =============\n", | ||
1383 | dev->name); | ||
1384 | return 0; | ||
1385 | } | ||
1386 | |||
1387 | static int cx23885_query_audinput(struct file *file, void *priv, | ||
1388 | struct v4l2_audio *i) | ||
1389 | { | ||
1390 | struct cx23885_dev *dev = ((struct cx23885_fh *)priv)->dev; | ||
1391 | static const char *iname[] = { | ||
1392 | [0] = "Baseband L/R 1", | ||
1393 | [1] = "Baseband L/R 2", | ||
1394 | }; | ||
1395 | unsigned int n; | ||
1396 | dprintk(1, "%s()\n", __func__); | ||
1397 | |||
1398 | n = i->index; | ||
1399 | if (n >= 2) | ||
1400 | return -EINVAL; | ||
1401 | |||
1402 | memset(i, 0, sizeof(*i)); | ||
1403 | i->index = n; | ||
1404 | strcpy(i->name, iname[n]); | ||
1405 | i->capability = V4L2_AUDCAP_STEREO; | ||
1406 | i->mode = V4L2_AUDMODE_AVL; | ||
1407 | return 0; | ||
1408 | |||
1409 | } | ||
1410 | |||
1411 | static int vidioc_enum_audinput(struct file *file, void *priv, | ||
1412 | struct v4l2_audio *i) | ||
1413 | { | ||
1414 | return cx23885_query_audinput(file, priv, i); | ||
1415 | } | ||
1416 | |||
1417 | static int vidioc_g_audinput(struct file *file, void *priv, | ||
1418 | struct v4l2_audio *i) | ||
1419 | { | ||
1420 | struct cx23885_dev *dev = ((struct cx23885_fh *)priv)->dev; | ||
1421 | |||
1422 | i->index = dev->audinput; | ||
1423 | dprintk(1, "%s(input=%d)\n", __func__, i->index); | ||
1424 | |||
1425 | return cx23885_query_audinput(file, priv, i); | ||
1426 | } | ||
1427 | |||
1428 | static int vidioc_s_audinput(struct file *file, void *priv, | ||
1429 | struct v4l2_audio *i) | ||
1430 | { | ||
1431 | struct cx23885_dev *dev = ((struct cx23885_fh *)priv)->dev; | ||
1432 | if (i->index >= 2) | ||
1433 | return -EINVAL; | ||
1434 | |||
1435 | dprintk(1, "%s(%d)\n", __func__, i->index); | ||
1436 | |||
1437 | dev->audinput = i->index; | ||
1438 | |||
1439 | /* Skip the audio defaults from the cards struct, caller wants | ||
1440 | * directly touch the audio mux hardware. */ | ||
1441 | cx23885_flatiron_mux(dev, dev->audinput + 1); | ||
1442 | return 0; | ||
1443 | } | ||
1444 | |||
1445 | static int vidioc_queryctrl(struct file *file, void *priv, | ||
1446 | struct v4l2_queryctrl *qctrl) | ||
1447 | { | ||
1448 | qctrl->id = v4l2_ctrl_next(ctrl_classes, qctrl->id); | ||
1449 | if (unlikely(qctrl->id == 0)) | ||
1450 | return -EINVAL; | ||
1451 | return cx23885_ctrl_query(qctrl); | ||
1452 | } | ||
1453 | |||
1454 | static int vidioc_g_ctrl(struct file *file, void *priv, | ||
1455 | struct v4l2_control *ctl) | ||
1456 | { | ||
1457 | struct cx23885_dev *dev = ((struct cx23885_fh *)priv)->dev; | ||
1458 | |||
1459 | return cx23885_get_control(dev, ctl); | ||
1460 | } | ||
1461 | |||
1462 | static int vidioc_s_ctrl(struct file *file, void *priv, | ||
1463 | struct v4l2_control *ctl) | ||
1464 | { | ||
1465 | struct cx23885_dev *dev = ((struct cx23885_fh *)priv)->dev; | ||
1466 | |||
1467 | return cx23885_set_control(dev, ctl); | ||
1468 | } | ||
1469 | |||
1470 | static int vidioc_g_tuner(struct file *file, void *priv, | ||
1471 | struct v4l2_tuner *t) | ||
1472 | { | ||
1473 | struct cx23885_dev *dev = ((struct cx23885_fh *)priv)->dev; | ||
1474 | |||
1475 | if (unlikely(UNSET == dev->tuner_type)) | ||
1476 | return -EINVAL; | ||
1477 | if (0 != t->index) | ||
1478 | return -EINVAL; | ||
1479 | |||
1480 | strcpy(t->name, "Television"); | ||
1481 | |||
1482 | call_all(dev, tuner, g_tuner, t); | ||
1483 | return 0; | ||
1484 | } | ||
1485 | |||
1486 | static int vidioc_s_tuner(struct file *file, void *priv, | ||
1487 | struct v4l2_tuner *t) | ||
1488 | { | ||
1489 | struct cx23885_dev *dev = ((struct cx23885_fh *)priv)->dev; | ||
1490 | |||
1491 | if (UNSET == dev->tuner_type) | ||
1492 | return -EINVAL; | ||
1493 | if (0 != t->index) | ||
1494 | return -EINVAL; | ||
1495 | /* Update the A/V core */ | ||
1496 | call_all(dev, tuner, s_tuner, t); | ||
1497 | |||
1498 | return 0; | ||
1499 | } | ||
1500 | |||
1501 | static int vidioc_g_frequency(struct file *file, void *priv, | ||
1502 | struct v4l2_frequency *f) | ||
1503 | { | ||
1504 | struct cx23885_fh *fh = priv; | ||
1505 | struct cx23885_dev *dev = fh->dev; | ||
1506 | |||
1507 | if (unlikely(UNSET == dev->tuner_type)) | ||
1508 | return -EINVAL; | ||
1509 | |||
1510 | /* f->type = fh->radio ? V4L2_TUNER_RADIO : V4L2_TUNER_ANALOG_TV; */ | ||
1511 | f->type = fh->radio ? V4L2_TUNER_RADIO : V4L2_TUNER_ANALOG_TV; | ||
1512 | f->frequency = dev->freq; | ||
1513 | |||
1514 | call_all(dev, tuner, g_frequency, f); | ||
1515 | |||
1516 | return 0; | ||
1517 | } | ||
1518 | |||
1519 | static int cx23885_set_freq(struct cx23885_dev *dev, struct v4l2_frequency *f) | ||
1520 | { | ||
1521 | struct v4l2_control ctrl; | ||
1522 | |||
1523 | if (unlikely(UNSET == dev->tuner_type)) | ||
1524 | return -EINVAL; | ||
1525 | if (unlikely(f->tuner != 0)) | ||
1526 | return -EINVAL; | ||
1527 | |||
1528 | mutex_lock(&dev->lock); | ||
1529 | dev->freq = f->frequency; | ||
1530 | |||
1531 | /* I need to mute audio here */ | ||
1532 | ctrl.id = V4L2_CID_AUDIO_MUTE; | ||
1533 | ctrl.value = 1; | ||
1534 | cx23885_set_control(dev, &ctrl); | ||
1535 | |||
1536 | call_all(dev, tuner, s_frequency, f); | ||
1537 | |||
1538 | /* When changing channels it is required to reset TVAUDIO */ | ||
1539 | msleep(100); | ||
1540 | |||
1541 | /* I need to unmute audio here */ | ||
1542 | ctrl.value = 0; | ||
1543 | cx23885_set_control(dev, &ctrl); | ||
1544 | |||
1545 | mutex_unlock(&dev->lock); | ||
1546 | |||
1547 | return 0; | ||
1548 | } | ||
1549 | |||
1550 | static int cx23885_set_freq_via_ops(struct cx23885_dev *dev, | ||
1551 | struct v4l2_frequency *f) | ||
1552 | { | ||
1553 | struct v4l2_control ctrl; | ||
1554 | struct videobuf_dvb_frontend *vfe; | ||
1555 | struct dvb_frontend *fe; | ||
1556 | |||
1557 | struct analog_parameters params = { | ||
1558 | .mode = V4L2_TUNER_ANALOG_TV, | ||
1559 | .audmode = V4L2_TUNER_MODE_STEREO, | ||
1560 | .std = dev->tvnorm, | ||
1561 | .frequency = f->frequency | ||
1562 | }; | ||
1563 | |||
1564 | mutex_lock(&dev->lock); | ||
1565 | dev->freq = f->frequency; | ||
1566 | |||
1567 | /* I need to mute audio here */ | ||
1568 | ctrl.id = V4L2_CID_AUDIO_MUTE; | ||
1569 | ctrl.value = 1; | ||
1570 | cx23885_set_control(dev, &ctrl); | ||
1571 | |||
1572 | /* If HVR1850 */ | ||
1573 | dprintk(1, "%s() frequency=%d tuner=%d std=0x%llx\n", __func__, | ||
1574 | params.frequency, f->tuner, params.std); | ||
1575 | |||
1576 | vfe = videobuf_dvb_get_frontend(&dev->ts2.frontends, 1); | ||
1577 | if (!vfe) { | ||
1578 | mutex_unlock(&dev->lock); | ||
1579 | return -EINVAL; | ||
1580 | } | ||
1581 | |||
1582 | fe = vfe->dvb.frontend; | ||
1583 | |||
1584 | if ((dev->board == CX23885_BOARD_HAUPPAUGE_HVR1850) || | ||
1585 | (dev->board == CX23885_BOARD_HAUPPAUGE_HVR1255) || | ||
1586 | (dev->board == CX23885_BOARD_HAUPPAUGE_HVR1255_22111)) | ||
1587 | fe = &dev->ts1.analog_fe; | ||
1588 | |||
1589 | if (fe && fe->ops.tuner_ops.set_analog_params) { | ||
1590 | call_all(dev, core, s_std, dev->tvnorm); | ||
1591 | fe->ops.tuner_ops.set_analog_params(fe, ¶ms); | ||
1592 | } | ||
1593 | else | ||
1594 | printk(KERN_ERR "%s() No analog tuner, aborting\n", __func__); | ||
1595 | |||
1596 | /* When changing channels it is required to reset TVAUDIO */ | ||
1597 | msleep(100); | ||
1598 | |||
1599 | /* I need to unmute audio here */ | ||
1600 | ctrl.value = 0; | ||
1601 | cx23885_set_control(dev, &ctrl); | ||
1602 | |||
1603 | mutex_unlock(&dev->lock); | ||
1604 | |||
1605 | return 0; | ||
1606 | } | ||
1607 | |||
1608 | int cx23885_set_frequency(struct file *file, void *priv, | ||
1609 | struct v4l2_frequency *f) | ||
1610 | { | ||
1611 | struct cx23885_fh *fh = priv; | ||
1612 | struct cx23885_dev *dev = fh->dev; | ||
1613 | int ret; | ||
1614 | |||
1615 | switch (dev->board) { | ||
1616 | case CX23885_BOARD_HAUPPAUGE_HVR1255: | ||
1617 | case CX23885_BOARD_HAUPPAUGE_HVR1255_22111: | ||
1618 | case CX23885_BOARD_HAUPPAUGE_HVR1850: | ||
1619 | ret = cx23885_set_freq_via_ops(dev, f); | ||
1620 | break; | ||
1621 | default: | ||
1622 | ret = cx23885_set_freq(dev, f); | ||
1623 | } | ||
1624 | |||
1625 | return ret; | ||
1626 | } | ||
1627 | |||
1628 | static int vidioc_s_frequency(struct file *file, void *priv, | ||
1629 | struct v4l2_frequency *f) | ||
1630 | { | ||
1631 | return cx23885_set_frequency(file, priv, f); | ||
1632 | } | ||
1633 | |||
1634 | /* ----------------------------------------------------------- */ | ||
1635 | |||
1636 | static void cx23885_vid_timeout(unsigned long data) | ||
1637 | { | ||
1638 | struct cx23885_dev *dev = (struct cx23885_dev *)data; | ||
1639 | struct cx23885_dmaqueue *q = &dev->vidq; | ||
1640 | struct cx23885_buffer *buf; | ||
1641 | unsigned long flags; | ||
1642 | |||
1643 | spin_lock_irqsave(&dev->slock, flags); | ||
1644 | while (!list_empty(&q->active)) { | ||
1645 | buf = list_entry(q->active.next, | ||
1646 | struct cx23885_buffer, vb.queue); | ||
1647 | list_del(&buf->vb.queue); | ||
1648 | buf->vb.state = VIDEOBUF_ERROR; | ||
1649 | wake_up(&buf->vb.done); | ||
1650 | printk(KERN_ERR "%s: [%p/%d] timeout - dma=0x%08lx\n", | ||
1651 | dev->name, buf, buf->vb.i, | ||
1652 | (unsigned long)buf->risc.dma); | ||
1653 | } | ||
1654 | cx23885_restart_video_queue(dev, q); | ||
1655 | spin_unlock_irqrestore(&dev->slock, flags); | ||
1656 | } | ||
1657 | |||
1658 | int cx23885_video_irq(struct cx23885_dev *dev, u32 status) | ||
1659 | { | ||
1660 | u32 mask, count; | ||
1661 | int handled = 0; | ||
1662 | |||
1663 | mask = cx_read(VID_A_INT_MSK); | ||
1664 | if (0 == (status & mask)) | ||
1665 | return handled; | ||
1666 | |||
1667 | cx_write(VID_A_INT_STAT, status); | ||
1668 | |||
1669 | /* risc op code error, fifo overflow or line sync detection error */ | ||
1670 | if ((status & VID_BC_MSK_OPC_ERR) || | ||
1671 | (status & VID_BC_MSK_SYNC) || | ||
1672 | (status & VID_BC_MSK_OF)) { | ||
1673 | |||
1674 | if (status & VID_BC_MSK_OPC_ERR) { | ||
1675 | dprintk(7, " (VID_BC_MSK_OPC_ERR 0x%08x)\n", | ||
1676 | VID_BC_MSK_OPC_ERR); | ||
1677 | printk(KERN_WARNING "%s: video risc op code error\n", | ||
1678 | dev->name); | ||
1679 | cx23885_sram_channel_dump(dev, | ||
1680 | &dev->sram_channels[SRAM_CH01]); | ||
1681 | } | ||
1682 | |||
1683 | if (status & VID_BC_MSK_SYNC) | ||
1684 | dprintk(7, " (VID_BC_MSK_SYNC 0x%08x) " | ||
1685 | "video lines miss-match\n", | ||
1686 | VID_BC_MSK_SYNC); | ||
1687 | |||
1688 | if (status & VID_BC_MSK_OF) | ||
1689 | dprintk(7, " (VID_BC_MSK_OF 0x%08x) fifo overflow\n", | ||
1690 | VID_BC_MSK_OF); | ||
1691 | |||
1692 | } | ||
1693 | |||
1694 | /* Video */ | ||
1695 | if (status & VID_BC_MSK_RISCI1) { | ||
1696 | spin_lock(&dev->slock); | ||
1697 | count = cx_read(VID_A_GPCNT); | ||
1698 | cx23885_video_wakeup(dev, &dev->vidq, count); | ||
1699 | spin_unlock(&dev->slock); | ||
1700 | handled++; | ||
1701 | } | ||
1702 | if (status & VID_BC_MSK_RISCI2) { | ||
1703 | dprintk(2, "stopper video\n"); | ||
1704 | spin_lock(&dev->slock); | ||
1705 | cx23885_restart_video_queue(dev, &dev->vidq); | ||
1706 | spin_unlock(&dev->slock); | ||
1707 | handled++; | ||
1708 | } | ||
1709 | |||
1710 | /* Allow the VBI framework to process it's payload */ | ||
1711 | handled += cx23885_vbi_irq(dev, status); | ||
1712 | |||
1713 | return handled; | ||
1714 | } | ||
1715 | |||
1716 | /* ----------------------------------------------------------- */ | ||
1717 | /* exported stuff */ | ||
1718 | |||
1719 | static const struct v4l2_file_operations video_fops = { | ||
1720 | .owner = THIS_MODULE, | ||
1721 | .open = video_open, | ||
1722 | .release = video_release, | ||
1723 | .read = video_read, | ||
1724 | .poll = video_poll, | ||
1725 | .mmap = video_mmap, | ||
1726 | .ioctl = video_ioctl2, | ||
1727 | }; | ||
1728 | |||
1729 | static const struct v4l2_ioctl_ops video_ioctl_ops = { | ||
1730 | .vidioc_querycap = vidioc_querycap, | ||
1731 | .vidioc_enum_fmt_vid_cap = vidioc_enum_fmt_vid_cap, | ||
1732 | .vidioc_g_fmt_vid_cap = vidioc_g_fmt_vid_cap, | ||
1733 | .vidioc_try_fmt_vid_cap = vidioc_try_fmt_vid_cap, | ||
1734 | .vidioc_s_fmt_vid_cap = vidioc_s_fmt_vid_cap, | ||
1735 | .vidioc_g_fmt_vbi_cap = cx23885_vbi_fmt, | ||
1736 | .vidioc_try_fmt_vbi_cap = cx23885_vbi_fmt, | ||
1737 | .vidioc_s_fmt_vbi_cap = cx23885_vbi_fmt, | ||
1738 | .vidioc_reqbufs = vidioc_reqbufs, | ||
1739 | .vidioc_querybuf = vidioc_querybuf, | ||
1740 | .vidioc_qbuf = vidioc_qbuf, | ||
1741 | .vidioc_dqbuf = vidioc_dqbuf, | ||
1742 | .vidioc_s_std = vidioc_s_std, | ||
1743 | .vidioc_g_std = vidioc_g_std, | ||
1744 | .vidioc_querystd = vidioc_g_std, | ||
1745 | .vidioc_enum_input = vidioc_enum_input, | ||
1746 | .vidioc_g_input = vidioc_g_input, | ||
1747 | .vidioc_s_input = vidioc_s_input, | ||
1748 | .vidioc_log_status = vidioc_log_status, | ||
1749 | .vidioc_queryctrl = vidioc_queryctrl, | ||
1750 | .vidioc_g_ctrl = vidioc_g_ctrl, | ||
1751 | .vidioc_s_ctrl = vidioc_s_ctrl, | ||
1752 | .vidioc_streamon = vidioc_streamon, | ||
1753 | .vidioc_streamoff = vidioc_streamoff, | ||
1754 | .vidioc_g_tuner = vidioc_g_tuner, | ||
1755 | .vidioc_s_tuner = vidioc_s_tuner, | ||
1756 | .vidioc_g_frequency = vidioc_g_frequency, | ||
1757 | .vidioc_s_frequency = vidioc_s_frequency, | ||
1758 | .vidioc_g_chip_ident = cx23885_g_chip_ident, | ||
1759 | #ifdef CONFIG_VIDEO_ADV_DEBUG | ||
1760 | .vidioc_g_register = cx23885_g_register, | ||
1761 | .vidioc_s_register = cx23885_s_register, | ||
1762 | #endif | ||
1763 | .vidioc_enumaudio = vidioc_enum_audinput, | ||
1764 | .vidioc_g_audio = vidioc_g_audinput, | ||
1765 | .vidioc_s_audio = vidioc_s_audinput, | ||
1766 | }; | ||
1767 | |||
1768 | static struct video_device cx23885_vbi_template; | ||
1769 | static struct video_device cx23885_video_template = { | ||
1770 | .name = "cx23885-video", | ||
1771 | .fops = &video_fops, | ||
1772 | .ioctl_ops = &video_ioctl_ops, | ||
1773 | .tvnorms = CX23885_NORMS, | ||
1774 | .current_norm = V4L2_STD_NTSC_M, | ||
1775 | }; | ||
1776 | |||
1777 | static const struct v4l2_file_operations radio_fops = { | ||
1778 | .owner = THIS_MODULE, | ||
1779 | .open = video_open, | ||
1780 | .release = video_release, | ||
1781 | .ioctl = video_ioctl2, | ||
1782 | }; | ||
1783 | |||
1784 | |||
1785 | void cx23885_video_unregister(struct cx23885_dev *dev) | ||
1786 | { | ||
1787 | dprintk(1, "%s()\n", __func__); | ||
1788 | cx23885_irq_remove(dev, 0x01); | ||
1789 | |||
1790 | if (dev->vbi_dev) { | ||
1791 | if (video_is_registered(dev->vbi_dev)) | ||
1792 | video_unregister_device(dev->vbi_dev); | ||
1793 | else | ||
1794 | video_device_release(dev->vbi_dev); | ||
1795 | dev->vbi_dev = NULL; | ||
1796 | btcx_riscmem_free(dev->pci, &dev->vbiq.stopper); | ||
1797 | } | ||
1798 | if (dev->video_dev) { | ||
1799 | if (video_is_registered(dev->video_dev)) | ||
1800 | video_unregister_device(dev->video_dev); | ||
1801 | else | ||
1802 | video_device_release(dev->video_dev); | ||
1803 | dev->video_dev = NULL; | ||
1804 | |||
1805 | btcx_riscmem_free(dev->pci, &dev->vidq.stopper); | ||
1806 | } | ||
1807 | |||
1808 | if (dev->audio_dev) | ||
1809 | cx23885_audio_unregister(dev); | ||
1810 | } | ||
1811 | |||
1812 | int cx23885_video_register(struct cx23885_dev *dev) | ||
1813 | { | ||
1814 | int err; | ||
1815 | |||
1816 | dprintk(1, "%s()\n", __func__); | ||
1817 | spin_lock_init(&dev->slock); | ||
1818 | |||
1819 | /* Initialize VBI template */ | ||
1820 | memcpy(&cx23885_vbi_template, &cx23885_video_template, | ||
1821 | sizeof(cx23885_vbi_template)); | ||
1822 | strcpy(cx23885_vbi_template.name, "cx23885-vbi"); | ||
1823 | |||
1824 | dev->tvnorm = cx23885_video_template.current_norm; | ||
1825 | |||
1826 | /* init video dma queues */ | ||
1827 | INIT_LIST_HEAD(&dev->vidq.active); | ||
1828 | INIT_LIST_HEAD(&dev->vidq.queued); | ||
1829 | dev->vidq.timeout.function = cx23885_vid_timeout; | ||
1830 | dev->vidq.timeout.data = (unsigned long)dev; | ||
1831 | init_timer(&dev->vidq.timeout); | ||
1832 | cx23885_risc_stopper(dev->pci, &dev->vidq.stopper, | ||
1833 | VID_A_DMA_CTL, 0x11, 0x00); | ||
1834 | |||
1835 | /* init vbi dma queues */ | ||
1836 | INIT_LIST_HEAD(&dev->vbiq.active); | ||
1837 | INIT_LIST_HEAD(&dev->vbiq.queued); | ||
1838 | dev->vbiq.timeout.function = cx23885_vbi_timeout; | ||
1839 | dev->vbiq.timeout.data = (unsigned long)dev; | ||
1840 | init_timer(&dev->vbiq.timeout); | ||
1841 | cx23885_risc_stopper(dev->pci, &dev->vbiq.stopper, | ||
1842 | VID_A_DMA_CTL, 0x22, 0x00); | ||
1843 | |||
1844 | cx23885_irq_add_enable(dev, 0x01); | ||
1845 | |||
1846 | if ((TUNER_ABSENT != dev->tuner_type) && | ||
1847 | ((dev->tuner_bus == 0) || (dev->tuner_bus == 1))) { | ||
1848 | struct v4l2_subdev *sd = NULL; | ||
1849 | |||
1850 | if (dev->tuner_addr) | ||
1851 | sd = v4l2_i2c_new_subdev(&dev->v4l2_dev, | ||
1852 | &dev->i2c_bus[dev->tuner_bus].i2c_adap, | ||
1853 | "tuner", dev->tuner_addr, NULL); | ||
1854 | else | ||
1855 | sd = v4l2_i2c_new_subdev(&dev->v4l2_dev, | ||
1856 | &dev->i2c_bus[dev->tuner_bus].i2c_adap, | ||
1857 | "tuner", 0, v4l2_i2c_tuner_addrs(ADDRS_TV)); | ||
1858 | if (sd) { | ||
1859 | struct tuner_setup tun_setup; | ||
1860 | |||
1861 | memset(&tun_setup, 0, sizeof(tun_setup)); | ||
1862 | tun_setup.mode_mask = T_ANALOG_TV; | ||
1863 | tun_setup.type = dev->tuner_type; | ||
1864 | tun_setup.addr = v4l2_i2c_subdev_addr(sd); | ||
1865 | tun_setup.tuner_callback = cx23885_tuner_callback; | ||
1866 | |||
1867 | v4l2_subdev_call(sd, tuner, s_type_addr, &tun_setup); | ||
1868 | |||
1869 | if (dev->board == CX23885_BOARD_LEADTEK_WINFAST_PXTV1200) { | ||
1870 | struct xc2028_ctrl ctrl = { | ||
1871 | .fname = XC2028_DEFAULT_FIRMWARE, | ||
1872 | .max_len = 64 | ||
1873 | }; | ||
1874 | struct v4l2_priv_tun_config cfg = { | ||
1875 | .tuner = dev->tuner_type, | ||
1876 | .priv = &ctrl | ||
1877 | }; | ||
1878 | v4l2_subdev_call(sd, tuner, s_config, &cfg); | ||
1879 | } | ||
1880 | } | ||
1881 | } | ||
1882 | |||
1883 | /* register Video device */ | ||
1884 | dev->video_dev = cx23885_vdev_init(dev, dev->pci, | ||
1885 | &cx23885_video_template, "video"); | ||
1886 | err = video_register_device(dev->video_dev, VFL_TYPE_GRABBER, | ||
1887 | video_nr[dev->nr]); | ||
1888 | if (err < 0) { | ||
1889 | printk(KERN_INFO "%s: can't register video device\n", | ||
1890 | dev->name); | ||
1891 | goto fail_unreg; | ||
1892 | } | ||
1893 | printk(KERN_INFO "%s: registered device %s [v4l2]\n", | ||
1894 | dev->name, video_device_node_name(dev->video_dev)); | ||
1895 | |||
1896 | /* register VBI device */ | ||
1897 | dev->vbi_dev = cx23885_vdev_init(dev, dev->pci, | ||
1898 | &cx23885_vbi_template, "vbi"); | ||
1899 | err = video_register_device(dev->vbi_dev, VFL_TYPE_VBI, | ||
1900 | vbi_nr[dev->nr]); | ||
1901 | if (err < 0) { | ||
1902 | printk(KERN_INFO "%s: can't register vbi device\n", | ||
1903 | dev->name); | ||
1904 | goto fail_unreg; | ||
1905 | } | ||
1906 | printk(KERN_INFO "%s: registered device %s\n", | ||
1907 | dev->name, video_device_node_name(dev->vbi_dev)); | ||
1908 | |||
1909 | /* Register ALSA audio device */ | ||
1910 | dev->audio_dev = cx23885_audio_register(dev); | ||
1911 | |||
1912 | /* initial device configuration */ | ||
1913 | mutex_lock(&dev->lock); | ||
1914 | cx23885_set_tvnorm(dev, dev->tvnorm); | ||
1915 | init_controls(dev); | ||
1916 | cx23885_video_mux(dev, 0); | ||
1917 | cx23885_audio_mux(dev, 0); | ||
1918 | mutex_unlock(&dev->lock); | ||
1919 | |||
1920 | return 0; | ||
1921 | |||
1922 | fail_unreg: | ||
1923 | cx23885_video_unregister(dev); | ||
1924 | return err; | ||
1925 | } | ||
1926 | |||
diff --git a/drivers/media/pci/cx23885/cx23885.h b/drivers/media/pci/cx23885/cx23885.h new file mode 100644 index 000000000000..5d560c747e09 --- /dev/null +++ b/drivers/media/pci/cx23885/cx23885.h | |||
@@ -0,0 +1,653 @@ | |||
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/kdev_t.h> | ||
25 | #include <linux/slab.h> | ||
26 | |||
27 | #include <media/v4l2-device.h> | ||
28 | #include <media/tuner.h> | ||
29 | #include <media/tveeprom.h> | ||
30 | #include <media/videobuf-dma-sg.h> | ||
31 | #include <media/videobuf-dvb.h> | ||
32 | #include <media/rc-core.h> | ||
33 | |||
34 | #include "btcx-risc.h" | ||
35 | #include "cx23885-reg.h" | ||
36 | #include "media/cx2341x.h" | ||
37 | |||
38 | #include <linux/mutex.h> | ||
39 | |||
40 | #define CX23885_VERSION "0.0.3" | ||
41 | |||
42 | #define UNSET (-1U) | ||
43 | |||
44 | #define CX23885_MAXBOARDS 8 | ||
45 | |||
46 | /* Max number of inputs by card */ | ||
47 | #define MAX_CX23885_INPUT 8 | ||
48 | #define INPUT(nr) (&cx23885_boards[dev->board].input[nr]) | ||
49 | #define RESOURCE_OVERLAY 1 | ||
50 | #define RESOURCE_VIDEO 2 | ||
51 | #define RESOURCE_VBI 4 | ||
52 | |||
53 | #define BUFFER_TIMEOUT (HZ) /* 0.5 seconds */ | ||
54 | |||
55 | #define CX23885_BOARD_NOAUTO UNSET | ||
56 | #define CX23885_BOARD_UNKNOWN 0 | ||
57 | #define CX23885_BOARD_HAUPPAUGE_HVR1800lp 1 | ||
58 | #define CX23885_BOARD_HAUPPAUGE_HVR1800 2 | ||
59 | #define CX23885_BOARD_HAUPPAUGE_HVR1250 3 | ||
60 | #define CX23885_BOARD_DVICO_FUSIONHDTV_5_EXP 4 | ||
61 | #define CX23885_BOARD_HAUPPAUGE_HVR1500Q 5 | ||
62 | #define CX23885_BOARD_HAUPPAUGE_HVR1500 6 | ||
63 | #define CX23885_BOARD_HAUPPAUGE_HVR1200 7 | ||
64 | #define CX23885_BOARD_HAUPPAUGE_HVR1700 8 | ||
65 | #define CX23885_BOARD_HAUPPAUGE_HVR1400 9 | ||
66 | #define CX23885_BOARD_DVICO_FUSIONHDTV_7_DUAL_EXP 10 | ||
67 | #define CX23885_BOARD_DVICO_FUSIONHDTV_DVB_T_DUAL_EXP 11 | ||
68 | #define CX23885_BOARD_LEADTEK_WINFAST_PXDVR3200_H 12 | ||
69 | #define CX23885_BOARD_COMPRO_VIDEOMATE_E650F 13 | ||
70 | #define CX23885_BOARD_TBS_6920 14 | ||
71 | #define CX23885_BOARD_TEVII_S470 15 | ||
72 | #define CX23885_BOARD_DVBWORLD_2005 16 | ||
73 | #define CX23885_BOARD_NETUP_DUAL_DVBS2_CI 17 | ||
74 | #define CX23885_BOARD_HAUPPAUGE_HVR1270 18 | ||
75 | #define CX23885_BOARD_HAUPPAUGE_HVR1275 19 | ||
76 | #define CX23885_BOARD_HAUPPAUGE_HVR1255 20 | ||
77 | #define CX23885_BOARD_HAUPPAUGE_HVR1210 21 | ||
78 | #define CX23885_BOARD_MYGICA_X8506 22 | ||
79 | #define CX23885_BOARD_MAGICPRO_PROHDTVE2 23 | ||
80 | #define CX23885_BOARD_HAUPPAUGE_HVR1850 24 | ||
81 | #define CX23885_BOARD_COMPRO_VIDEOMATE_E800 25 | ||
82 | #define CX23885_BOARD_HAUPPAUGE_HVR1290 26 | ||
83 | #define CX23885_BOARD_MYGICA_X8558PRO 27 | ||
84 | #define CX23885_BOARD_LEADTEK_WINFAST_PXTV1200 28 | ||
85 | #define CX23885_BOARD_GOTVIEW_X5_3D_HYBRID 29 | ||
86 | #define CX23885_BOARD_NETUP_DUAL_DVB_T_C_CI_RF 30 | ||
87 | #define CX23885_BOARD_LEADTEK_WINFAST_PXDVR3200_H_XC4000 31 | ||
88 | #define CX23885_BOARD_MPX885 32 | ||
89 | #define CX23885_BOARD_MYGICA_X8507 33 | ||
90 | #define CX23885_BOARD_TERRATEC_CINERGY_T_PCIE_DUAL 34 | ||
91 | #define CX23885_BOARD_TEVII_S471 35 | ||
92 | #define CX23885_BOARD_HAUPPAUGE_HVR1255_22111 36 | ||
93 | |||
94 | #define GPIO_0 0x00000001 | ||
95 | #define GPIO_1 0x00000002 | ||
96 | #define GPIO_2 0x00000004 | ||
97 | #define GPIO_3 0x00000008 | ||
98 | #define GPIO_4 0x00000010 | ||
99 | #define GPIO_5 0x00000020 | ||
100 | #define GPIO_6 0x00000040 | ||
101 | #define GPIO_7 0x00000080 | ||
102 | #define GPIO_8 0x00000100 | ||
103 | #define GPIO_9 0x00000200 | ||
104 | #define GPIO_10 0x00000400 | ||
105 | #define GPIO_11 0x00000800 | ||
106 | #define GPIO_12 0x00001000 | ||
107 | #define GPIO_13 0x00002000 | ||
108 | #define GPIO_14 0x00004000 | ||
109 | #define GPIO_15 0x00008000 | ||
110 | |||
111 | /* Currently unsupported by the driver: PAL/H, NTSC/Kr, SECAM B/G/H/LC */ | ||
112 | #define CX23885_NORMS (\ | ||
113 | V4L2_STD_NTSC_M | V4L2_STD_NTSC_M_JP | V4L2_STD_NTSC_443 | \ | ||
114 | V4L2_STD_PAL_BG | V4L2_STD_PAL_DK | V4L2_STD_PAL_I | \ | ||
115 | V4L2_STD_PAL_M | V4L2_STD_PAL_N | V4L2_STD_PAL_Nc | \ | ||
116 | V4L2_STD_PAL_60 | V4L2_STD_SECAM_L | V4L2_STD_SECAM_DK) | ||
117 | |||
118 | struct cx23885_fmt { | ||
119 | char *name; | ||
120 | u32 fourcc; /* v4l2 format id */ | ||
121 | int depth; | ||
122 | int flags; | ||
123 | u32 cxformat; | ||
124 | }; | ||
125 | |||
126 | struct cx23885_ctrl { | ||
127 | struct v4l2_queryctrl v; | ||
128 | u32 off; | ||
129 | u32 reg; | ||
130 | u32 mask; | ||
131 | u32 shift; | ||
132 | }; | ||
133 | |||
134 | struct cx23885_tvnorm { | ||
135 | char *name; | ||
136 | v4l2_std_id id; | ||
137 | u32 cxiformat; | ||
138 | u32 cxoformat; | ||
139 | }; | ||
140 | |||
141 | struct cx23885_fh { | ||
142 | struct cx23885_dev *dev; | ||
143 | enum v4l2_buf_type type; | ||
144 | int radio; | ||
145 | u32 resources; | ||
146 | |||
147 | /* video overlay */ | ||
148 | struct v4l2_window win; | ||
149 | struct v4l2_clip *clips; | ||
150 | unsigned int nclips; | ||
151 | |||
152 | /* video capture */ | ||
153 | struct cx23885_fmt *fmt; | ||
154 | unsigned int width, height; | ||
155 | |||
156 | /* vbi capture */ | ||
157 | struct videobuf_queue vidq; | ||
158 | struct videobuf_queue vbiq; | ||
159 | |||
160 | /* MPEG Encoder specifics ONLY */ | ||
161 | struct videobuf_queue mpegq; | ||
162 | atomic_t v4l_reading; | ||
163 | }; | ||
164 | |||
165 | enum cx23885_itype { | ||
166 | CX23885_VMUX_COMPOSITE1 = 1, | ||
167 | CX23885_VMUX_COMPOSITE2, | ||
168 | CX23885_VMUX_COMPOSITE3, | ||
169 | CX23885_VMUX_COMPOSITE4, | ||
170 | CX23885_VMUX_SVIDEO, | ||
171 | CX23885_VMUX_COMPONENT, | ||
172 | CX23885_VMUX_TELEVISION, | ||
173 | CX23885_VMUX_CABLE, | ||
174 | CX23885_VMUX_DVB, | ||
175 | CX23885_VMUX_DEBUG, | ||
176 | CX23885_RADIO, | ||
177 | }; | ||
178 | |||
179 | enum cx23885_src_sel_type { | ||
180 | CX23885_SRC_SEL_EXT_656_VIDEO = 0, | ||
181 | CX23885_SRC_SEL_PARALLEL_MPEG_VIDEO | ||
182 | }; | ||
183 | |||
184 | /* buffer for one video frame */ | ||
185 | struct cx23885_buffer { | ||
186 | /* common v4l buffer stuff -- must be first */ | ||
187 | struct videobuf_buffer vb; | ||
188 | |||
189 | /* cx23885 specific */ | ||
190 | unsigned int bpl; | ||
191 | struct btcx_riscmem risc; | ||
192 | struct cx23885_fmt *fmt; | ||
193 | u32 count; | ||
194 | }; | ||
195 | |||
196 | struct cx23885_input { | ||
197 | enum cx23885_itype type; | ||
198 | unsigned int vmux; | ||
199 | unsigned int amux; | ||
200 | u32 gpio0, gpio1, gpio2, gpio3; | ||
201 | }; | ||
202 | |||
203 | typedef enum { | ||
204 | CX23885_MPEG_UNDEFINED = 0, | ||
205 | CX23885_MPEG_DVB, | ||
206 | CX23885_ANALOG_VIDEO, | ||
207 | CX23885_MPEG_ENCODER, | ||
208 | } port_t; | ||
209 | |||
210 | struct cx23885_board { | ||
211 | char *name; | ||
212 | port_t porta, portb, portc; | ||
213 | int num_fds_portb, num_fds_portc; | ||
214 | unsigned int tuner_type; | ||
215 | unsigned int radio_type; | ||
216 | unsigned char tuner_addr; | ||
217 | unsigned char radio_addr; | ||
218 | unsigned int tuner_bus; | ||
219 | |||
220 | /* Vendors can and do run the PCIe bridge at different | ||
221 | * clock rates, driven physically by crystals on the PCBs. | ||
222 | * The core has to accommodate this. This allows the user | ||
223 | * to add new boards with new frequencys. The value is | ||
224 | * expressed in Hz. | ||
225 | * | ||
226 | * The core framework will default this value based on | ||
227 | * current designs, but it can vary. | ||
228 | */ | ||
229 | u32 clk_freq; | ||
230 | struct cx23885_input input[MAX_CX23885_INPUT]; | ||
231 | int ci_type; /* for NetUP */ | ||
232 | /* Force bottom field first during DMA (888 workaround) */ | ||
233 | u32 force_bff; | ||
234 | }; | ||
235 | |||
236 | struct cx23885_subid { | ||
237 | u16 subvendor; | ||
238 | u16 subdevice; | ||
239 | u32 card; | ||
240 | }; | ||
241 | |||
242 | struct cx23885_i2c { | ||
243 | struct cx23885_dev *dev; | ||
244 | |||
245 | int nr; | ||
246 | |||
247 | /* i2c i/o */ | ||
248 | struct i2c_adapter i2c_adap; | ||
249 | struct i2c_client i2c_client; | ||
250 | u32 i2c_rc; | ||
251 | |||
252 | /* 885 registers used for raw addess */ | ||
253 | u32 i2c_period; | ||
254 | u32 reg_ctrl; | ||
255 | u32 reg_stat; | ||
256 | u32 reg_addr; | ||
257 | u32 reg_rdata; | ||
258 | u32 reg_wdata; | ||
259 | }; | ||
260 | |||
261 | struct cx23885_dmaqueue { | ||
262 | struct list_head active; | ||
263 | struct list_head queued; | ||
264 | struct timer_list timeout; | ||
265 | struct btcx_riscmem stopper; | ||
266 | u32 count; | ||
267 | }; | ||
268 | |||
269 | struct cx23885_tsport { | ||
270 | struct cx23885_dev *dev; | ||
271 | |||
272 | int nr; | ||
273 | int sram_chno; | ||
274 | |||
275 | struct videobuf_dvb_frontends frontends; | ||
276 | |||
277 | /* dma queues */ | ||
278 | struct cx23885_dmaqueue mpegq; | ||
279 | u32 ts_packet_size; | ||
280 | u32 ts_packet_count; | ||
281 | |||
282 | int width; | ||
283 | int height; | ||
284 | |||
285 | spinlock_t slock; | ||
286 | |||
287 | /* registers */ | ||
288 | u32 reg_gpcnt; | ||
289 | u32 reg_gpcnt_ctl; | ||
290 | u32 reg_dma_ctl; | ||
291 | u32 reg_lngth; | ||
292 | u32 reg_hw_sop_ctrl; | ||
293 | u32 reg_gen_ctrl; | ||
294 | u32 reg_bd_pkt_status; | ||
295 | u32 reg_sop_status; | ||
296 | u32 reg_fifo_ovfl_stat; | ||
297 | u32 reg_vld_misc; | ||
298 | u32 reg_ts_clk_en; | ||
299 | u32 reg_ts_int_msk; | ||
300 | u32 reg_ts_int_stat; | ||
301 | u32 reg_src_sel; | ||
302 | |||
303 | /* Default register vals */ | ||
304 | int pci_irqmask; | ||
305 | u32 dma_ctl_val; | ||
306 | u32 ts_int_msk_val; | ||
307 | u32 gen_ctrl_val; | ||
308 | u32 ts_clk_en_val; | ||
309 | u32 src_sel_val; | ||
310 | u32 vld_misc_val; | ||
311 | u32 hw_sop_ctrl_val; | ||
312 | |||
313 | /* Allow a single tsport to have multiple frontends */ | ||
314 | u32 num_frontends; | ||
315 | void (*gate_ctrl)(struct cx23885_tsport *port, int open); | ||
316 | void *port_priv; | ||
317 | |||
318 | /* Workaround for a temp dvb_frontend that the tuner can attached to */ | ||
319 | struct dvb_frontend analog_fe; | ||
320 | }; | ||
321 | |||
322 | struct cx23885_kernel_ir { | ||
323 | struct cx23885_dev *cx; | ||
324 | char *name; | ||
325 | char *phys; | ||
326 | |||
327 | struct rc_dev *rc; | ||
328 | }; | ||
329 | |||
330 | struct cx23885_audio_buffer { | ||
331 | unsigned int bpl; | ||
332 | struct btcx_riscmem risc; | ||
333 | struct videobuf_dmabuf dma; | ||
334 | }; | ||
335 | |||
336 | struct cx23885_audio_dev { | ||
337 | struct cx23885_dev *dev; | ||
338 | |||
339 | struct pci_dev *pci; | ||
340 | |||
341 | struct snd_card *card; | ||
342 | |||
343 | spinlock_t lock; | ||
344 | |||
345 | atomic_t count; | ||
346 | |||
347 | unsigned int dma_size; | ||
348 | unsigned int period_size; | ||
349 | unsigned int num_periods; | ||
350 | |||
351 | struct videobuf_dmabuf *dma_risc; | ||
352 | |||
353 | struct cx23885_audio_buffer *buf; | ||
354 | |||
355 | struct snd_pcm_substream *substream; | ||
356 | }; | ||
357 | |||
358 | struct cx23885_dev { | ||
359 | atomic_t refcount; | ||
360 | struct v4l2_device v4l2_dev; | ||
361 | |||
362 | /* pci stuff */ | ||
363 | struct pci_dev *pci; | ||
364 | unsigned char pci_rev, pci_lat; | ||
365 | int pci_bus, pci_slot; | ||
366 | u32 __iomem *lmmio; | ||
367 | u8 __iomem *bmmio; | ||
368 | int pci_irqmask; | ||
369 | spinlock_t pci_irqmask_lock; /* protects mask reg too */ | ||
370 | int hwrevision; | ||
371 | |||
372 | /* This valud is board specific and is used to configure the | ||
373 | * AV core so we see nice clean and stable video and audio. */ | ||
374 | u32 clk_freq; | ||
375 | |||
376 | /* I2C adapters: Master 1 & 2 (External) & Master 3 (Internal only) */ | ||
377 | struct cx23885_i2c i2c_bus[3]; | ||
378 | |||
379 | int nr; | ||
380 | struct mutex lock; | ||
381 | struct mutex gpio_lock; | ||
382 | |||
383 | /* board details */ | ||
384 | unsigned int board; | ||
385 | char name[32]; | ||
386 | |||
387 | struct cx23885_tsport ts1, ts2; | ||
388 | |||
389 | /* sram configuration */ | ||
390 | struct sram_channel *sram_channels; | ||
391 | |||
392 | enum { | ||
393 | CX23885_BRIDGE_UNDEFINED = 0, | ||
394 | CX23885_BRIDGE_885 = 885, | ||
395 | CX23885_BRIDGE_887 = 887, | ||
396 | CX23885_BRIDGE_888 = 888, | ||
397 | } bridge; | ||
398 | |||
399 | /* Analog video */ | ||
400 | u32 resources; | ||
401 | unsigned int input; | ||
402 | unsigned int audinput; /* Selectable audio input */ | ||
403 | u32 tvaudio; | ||
404 | v4l2_std_id tvnorm; | ||
405 | unsigned int tuner_type; | ||
406 | unsigned char tuner_addr; | ||
407 | unsigned int tuner_bus; | ||
408 | unsigned int radio_type; | ||
409 | unsigned char radio_addr; | ||
410 | unsigned int has_radio; | ||
411 | struct v4l2_subdev *sd_cx25840; | ||
412 | struct work_struct cx25840_work; | ||
413 | |||
414 | /* Infrared */ | ||
415 | struct v4l2_subdev *sd_ir; | ||
416 | struct work_struct ir_rx_work; | ||
417 | unsigned long ir_rx_notifications; | ||
418 | struct work_struct ir_tx_work; | ||
419 | unsigned long ir_tx_notifications; | ||
420 | |||
421 | struct cx23885_kernel_ir *kernel_ir; | ||
422 | atomic_t ir_input_stopping; | ||
423 | |||
424 | /* V4l */ | ||
425 | u32 freq; | ||
426 | struct video_device *video_dev; | ||
427 | struct video_device *vbi_dev; | ||
428 | struct video_device *radio_dev; | ||
429 | |||
430 | struct cx23885_dmaqueue vidq; | ||
431 | struct cx23885_dmaqueue vbiq; | ||
432 | spinlock_t slock; | ||
433 | |||
434 | /* MPEG Encoder ONLY settings */ | ||
435 | u32 cx23417_mailbox; | ||
436 | struct cx2341x_mpeg_params mpeg_params; | ||
437 | struct video_device *v4l_device; | ||
438 | atomic_t v4l_reader_count; | ||
439 | struct cx23885_tvnorm encodernorm; | ||
440 | |||
441 | /* Analog raw audio */ | ||
442 | struct cx23885_audio_dev *audio_dev; | ||
443 | |||
444 | }; | ||
445 | |||
446 | static inline struct cx23885_dev *to_cx23885(struct v4l2_device *v4l2_dev) | ||
447 | { | ||
448 | return container_of(v4l2_dev, struct cx23885_dev, v4l2_dev); | ||
449 | } | ||
450 | |||
451 | #define call_all(dev, o, f, args...) \ | ||
452 | v4l2_device_call_all(&dev->v4l2_dev, 0, o, f, ##args) | ||
453 | |||
454 | #define CX23885_HW_888_IR (1 << 0) | ||
455 | #define CX23885_HW_AV_CORE (1 << 1) | ||
456 | |||
457 | #define call_hw(dev, grpid, o, f, args...) \ | ||
458 | v4l2_device_call_all(&dev->v4l2_dev, grpid, o, f, ##args) | ||
459 | |||
460 | extern struct v4l2_subdev *cx23885_find_hw(struct cx23885_dev *dev, u32 hw); | ||
461 | |||
462 | #define SRAM_CH01 0 /* Video A */ | ||
463 | #define SRAM_CH02 1 /* VBI A */ | ||
464 | #define SRAM_CH03 2 /* Video B */ | ||
465 | #define SRAM_CH04 3 /* Transport via B */ | ||
466 | #define SRAM_CH05 4 /* VBI B */ | ||
467 | #define SRAM_CH06 5 /* Video C */ | ||
468 | #define SRAM_CH07 6 /* Transport via C */ | ||
469 | #define SRAM_CH08 7 /* Audio Internal A */ | ||
470 | #define SRAM_CH09 8 /* Audio Internal B */ | ||
471 | #define SRAM_CH10 9 /* Audio External */ | ||
472 | #define SRAM_CH11 10 /* COMB_3D_N */ | ||
473 | #define SRAM_CH12 11 /* Comb 3D N1 */ | ||
474 | #define SRAM_CH13 12 /* Comb 3D N2 */ | ||
475 | #define SRAM_CH14 13 /* MOE Vid */ | ||
476 | #define SRAM_CH15 14 /* MOE RSLT */ | ||
477 | |||
478 | struct sram_channel { | ||
479 | char *name; | ||
480 | u32 cmds_start; | ||
481 | u32 ctrl_start; | ||
482 | u32 cdt; | ||
483 | u32 fifo_start; | ||
484 | u32 fifo_size; | ||
485 | u32 ptr1_reg; | ||
486 | u32 ptr2_reg; | ||
487 | u32 cnt1_reg; | ||
488 | u32 cnt2_reg; | ||
489 | u32 jumponly; | ||
490 | }; | ||
491 | |||
492 | /* ----------------------------------------------------------- */ | ||
493 | |||
494 | #define cx_read(reg) readl(dev->lmmio + ((reg)>>2)) | ||
495 | #define cx_write(reg, value) writel((value), dev->lmmio + ((reg)>>2)) | ||
496 | |||
497 | #define cx_andor(reg, mask, value) \ | ||
498 | writel((readl(dev->lmmio+((reg)>>2)) & ~(mask)) |\ | ||
499 | ((value) & (mask)), dev->lmmio+((reg)>>2)) | ||
500 | |||
501 | #define cx_set(reg, bit) cx_andor((reg), (bit), (bit)) | ||
502 | #define cx_clear(reg, bit) cx_andor((reg), (bit), 0) | ||
503 | |||
504 | /* ----------------------------------------------------------- */ | ||
505 | /* cx23885-core.c */ | ||
506 | |||
507 | extern int cx23885_sram_channel_setup(struct cx23885_dev *dev, | ||
508 | struct sram_channel *ch, | ||
509 | unsigned int bpl, u32 risc); | ||
510 | |||
511 | extern void cx23885_sram_channel_dump(struct cx23885_dev *dev, | ||
512 | struct sram_channel *ch); | ||
513 | |||
514 | extern int cx23885_risc_stopper(struct pci_dev *pci, struct btcx_riscmem *risc, | ||
515 | u32 reg, u32 mask, u32 value); | ||
516 | |||
517 | extern int cx23885_risc_buffer(struct pci_dev *pci, struct btcx_riscmem *risc, | ||
518 | struct scatterlist *sglist, | ||
519 | unsigned int top_offset, unsigned int bottom_offset, | ||
520 | unsigned int bpl, unsigned int padding, unsigned int lines); | ||
521 | |||
522 | extern int cx23885_risc_vbibuffer(struct pci_dev *pci, | ||
523 | struct btcx_riscmem *risc, struct scatterlist *sglist, | ||
524 | unsigned int top_offset, unsigned int bottom_offset, | ||
525 | unsigned int bpl, unsigned int padding, unsigned int lines); | ||
526 | |||
527 | void cx23885_cancel_buffers(struct cx23885_tsport *port); | ||
528 | |||
529 | extern int cx23885_restart_queue(struct cx23885_tsport *port, | ||
530 | struct cx23885_dmaqueue *q); | ||
531 | |||
532 | extern void cx23885_wakeup(struct cx23885_tsport *port, | ||
533 | struct cx23885_dmaqueue *q, u32 count); | ||
534 | |||
535 | extern void cx23885_gpio_set(struct cx23885_dev *dev, u32 mask); | ||
536 | extern void cx23885_gpio_clear(struct cx23885_dev *dev, u32 mask); | ||
537 | extern u32 cx23885_gpio_get(struct cx23885_dev *dev, u32 mask); | ||
538 | extern void cx23885_gpio_enable(struct cx23885_dev *dev, u32 mask, | ||
539 | int asoutput); | ||
540 | |||
541 | extern void cx23885_irq_add_enable(struct cx23885_dev *dev, u32 mask); | ||
542 | extern void cx23885_irq_enable(struct cx23885_dev *dev, u32 mask); | ||
543 | extern void cx23885_irq_disable(struct cx23885_dev *dev, u32 mask); | ||
544 | extern void cx23885_irq_remove(struct cx23885_dev *dev, u32 mask); | ||
545 | |||
546 | /* ----------------------------------------------------------- */ | ||
547 | /* cx23885-cards.c */ | ||
548 | extern struct cx23885_board cx23885_boards[]; | ||
549 | extern const unsigned int cx23885_bcount; | ||
550 | |||
551 | extern struct cx23885_subid cx23885_subids[]; | ||
552 | extern const unsigned int cx23885_idcount; | ||
553 | |||
554 | extern int cx23885_tuner_callback(void *priv, int component, | ||
555 | int command, int arg); | ||
556 | extern void cx23885_card_list(struct cx23885_dev *dev); | ||
557 | extern int cx23885_ir_init(struct cx23885_dev *dev); | ||
558 | extern void cx23885_ir_pci_int_enable(struct cx23885_dev *dev); | ||
559 | extern void cx23885_ir_fini(struct cx23885_dev *dev); | ||
560 | extern void cx23885_gpio_setup(struct cx23885_dev *dev); | ||
561 | extern void cx23885_card_setup(struct cx23885_dev *dev); | ||
562 | extern void cx23885_card_setup_pre_i2c(struct cx23885_dev *dev); | ||
563 | |||
564 | extern int cx23885_dvb_register(struct cx23885_tsport *port); | ||
565 | extern int cx23885_dvb_unregister(struct cx23885_tsport *port); | ||
566 | |||
567 | extern int cx23885_buf_prepare(struct videobuf_queue *q, | ||
568 | struct cx23885_tsport *port, | ||
569 | struct cx23885_buffer *buf, | ||
570 | enum v4l2_field field); | ||
571 | extern void cx23885_buf_queue(struct cx23885_tsport *port, | ||
572 | struct cx23885_buffer *buf); | ||
573 | extern void cx23885_free_buffer(struct videobuf_queue *q, | ||
574 | struct cx23885_buffer *buf); | ||
575 | |||
576 | /* ----------------------------------------------------------- */ | ||
577 | /* cx23885-video.c */ | ||
578 | /* Video */ | ||
579 | extern int cx23885_video_register(struct cx23885_dev *dev); | ||
580 | extern void cx23885_video_unregister(struct cx23885_dev *dev); | ||
581 | extern int cx23885_video_irq(struct cx23885_dev *dev, u32 status); | ||
582 | extern void cx23885_video_wakeup(struct cx23885_dev *dev, | ||
583 | struct cx23885_dmaqueue *q, u32 count); | ||
584 | int cx23885_enum_input(struct cx23885_dev *dev, struct v4l2_input *i); | ||
585 | int cx23885_set_input(struct file *file, void *priv, unsigned int i); | ||
586 | int cx23885_get_input(struct file *file, void *priv, unsigned int *i); | ||
587 | int cx23885_set_frequency(struct file *file, void *priv, struct v4l2_frequency *f); | ||
588 | int cx23885_set_control(struct cx23885_dev *dev, struct v4l2_control *ctl); | ||
589 | int cx23885_get_control(struct cx23885_dev *dev, struct v4l2_control *ctl); | ||
590 | int cx23885_set_tvnorm(struct cx23885_dev *dev, v4l2_std_id norm); | ||
591 | |||
592 | /* ----------------------------------------------------------- */ | ||
593 | /* cx23885-vbi.c */ | ||
594 | extern int cx23885_vbi_fmt(struct file *file, void *priv, | ||
595 | struct v4l2_format *f); | ||
596 | extern void cx23885_vbi_timeout(unsigned long data); | ||
597 | extern struct videobuf_queue_ops cx23885_vbi_qops; | ||
598 | extern int cx23885_restart_vbi_queue(struct cx23885_dev *dev, | ||
599 | struct cx23885_dmaqueue *q); | ||
600 | extern int cx23885_vbi_irq(struct cx23885_dev *dev, u32 status); | ||
601 | |||
602 | /* cx23885-i2c.c */ | ||
603 | extern int cx23885_i2c_register(struct cx23885_i2c *bus); | ||
604 | extern int cx23885_i2c_unregister(struct cx23885_i2c *bus); | ||
605 | extern void cx23885_av_clk(struct cx23885_dev *dev, int enable); | ||
606 | |||
607 | /* ----------------------------------------------------------- */ | ||
608 | /* cx23885-417.c */ | ||
609 | extern int cx23885_417_register(struct cx23885_dev *dev); | ||
610 | extern void cx23885_417_unregister(struct cx23885_dev *dev); | ||
611 | extern int cx23885_irq_417(struct cx23885_dev *dev, u32 status); | ||
612 | extern void cx23885_417_check_encoder(struct cx23885_dev *dev); | ||
613 | extern void cx23885_mc417_init(struct cx23885_dev *dev); | ||
614 | extern int mc417_memory_read(struct cx23885_dev *dev, u32 address, u32 *value); | ||
615 | extern int mc417_memory_write(struct cx23885_dev *dev, u32 address, u32 value); | ||
616 | extern int mc417_register_read(struct cx23885_dev *dev, | ||
617 | u16 address, u32 *value); | ||
618 | extern int mc417_register_write(struct cx23885_dev *dev, | ||
619 | u16 address, u32 value); | ||
620 | extern void mc417_gpio_set(struct cx23885_dev *dev, u32 mask); | ||
621 | extern void mc417_gpio_clear(struct cx23885_dev *dev, u32 mask); | ||
622 | extern void mc417_gpio_enable(struct cx23885_dev *dev, u32 mask, int asoutput); | ||
623 | |||
624 | /* ----------------------------------------------------------- */ | ||
625 | /* cx23885-alsa.c */ | ||
626 | extern struct cx23885_audio_dev *cx23885_audio_register( | ||
627 | struct cx23885_dev *dev); | ||
628 | extern void cx23885_audio_unregister(struct cx23885_dev *dev); | ||
629 | extern int cx23885_audio_irq(struct cx23885_dev *dev, u32 status, u32 mask); | ||
630 | extern int cx23885_risc_databuffer(struct pci_dev *pci, | ||
631 | struct btcx_riscmem *risc, | ||
632 | struct scatterlist *sglist, | ||
633 | unsigned int bpl, | ||
634 | unsigned int lines, | ||
635 | unsigned int lpi); | ||
636 | |||
637 | /* ----------------------------------------------------------- */ | ||
638 | /* tv norms */ | ||
639 | |||
640 | static inline unsigned int norm_maxw(v4l2_std_id norm) | ||
641 | { | ||
642 | return (norm & (V4L2_STD_MN & ~V4L2_STD_PAL_Nc)) ? 720 : 768; | ||
643 | } | ||
644 | |||
645 | static inline unsigned int norm_maxh(v4l2_std_id norm) | ||
646 | { | ||
647 | return (norm & V4L2_STD_625_50) ? 576 : 480; | ||
648 | } | ||
649 | |||
650 | static inline unsigned int norm_swidth(v4l2_std_id norm) | ||
651 | { | ||
652 | return (norm & (V4L2_STD_MN & ~V4L2_STD_PAL_Nc)) ? 754 : 922; | ||
653 | } | ||
diff --git a/drivers/media/pci/cx23885/cx23888-ir.c b/drivers/media/pci/cx23885/cx23888-ir.c new file mode 100644 index 000000000000..c2bc39c58f82 --- /dev/null +++ b/drivers/media/pci/cx23885/cx23888-ir.c | |||
@@ -0,0 +1,1271 @@ | |||
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 | do_div(count, (FIFO_RXTX << 2) | 0x3); | ||
335 | |||
336 | /* net result needs to be rounded down and decremented by 1 */ | ||
337 | if (count > RXCLK_RCD + 1) | ||
338 | count = RXCLK_RCD; | ||
339 | else if (count < 2) | ||
340 | count = 1; | ||
341 | else | ||
342 | count--; | ||
343 | return (u16) count; | ||
344 | } | ||
345 | |||
346 | /* | ||
347 | * IR Control Register helpers | ||
348 | */ | ||
349 | enum tx_fifo_watermark { | ||
350 | TX_FIFO_HALF_EMPTY = 0, | ||
351 | TX_FIFO_EMPTY = CNTRL_TIC, | ||
352 | }; | ||
353 | |||
354 | enum rx_fifo_watermark { | ||
355 | RX_FIFO_HALF_FULL = 0, | ||
356 | RX_FIFO_NOT_EMPTY = CNTRL_RIC, | ||
357 | }; | ||
358 | |||
359 | static inline void control_tx_irq_watermark(struct cx23885_dev *dev, | ||
360 | enum tx_fifo_watermark level) | ||
361 | { | ||
362 | cx23888_ir_and_or4(dev, CX23888_IR_CNTRL_REG, ~CNTRL_TIC, level); | ||
363 | } | ||
364 | |||
365 | static inline void control_rx_irq_watermark(struct cx23885_dev *dev, | ||
366 | enum rx_fifo_watermark level) | ||
367 | { | ||
368 | cx23888_ir_and_or4(dev, CX23888_IR_CNTRL_REG, ~CNTRL_RIC, level); | ||
369 | } | ||
370 | |||
371 | static inline void control_tx_enable(struct cx23885_dev *dev, bool enable) | ||
372 | { | ||
373 | cx23888_ir_and_or4(dev, CX23888_IR_CNTRL_REG, ~(CNTRL_TXE | CNTRL_TFE), | ||
374 | enable ? (CNTRL_TXE | CNTRL_TFE) : 0); | ||
375 | } | ||
376 | |||
377 | static inline void control_rx_enable(struct cx23885_dev *dev, bool enable) | ||
378 | { | ||
379 | cx23888_ir_and_or4(dev, CX23888_IR_CNTRL_REG, ~(CNTRL_RXE | CNTRL_RFE), | ||
380 | enable ? (CNTRL_RXE | CNTRL_RFE) : 0); | ||
381 | } | ||
382 | |||
383 | static inline void control_tx_modulation_enable(struct cx23885_dev *dev, | ||
384 | bool enable) | ||
385 | { | ||
386 | cx23888_ir_and_or4(dev, CX23888_IR_CNTRL_REG, ~CNTRL_MOD, | ||
387 | enable ? CNTRL_MOD : 0); | ||
388 | } | ||
389 | |||
390 | static inline void control_rx_demodulation_enable(struct cx23885_dev *dev, | ||
391 | bool enable) | ||
392 | { | ||
393 | cx23888_ir_and_or4(dev, CX23888_IR_CNTRL_REG, ~CNTRL_DMD, | ||
394 | enable ? CNTRL_DMD : 0); | ||
395 | } | ||
396 | |||
397 | static inline void control_rx_s_edge_detection(struct cx23885_dev *dev, | ||
398 | u32 edge_types) | ||
399 | { | ||
400 | cx23888_ir_and_or4(dev, CX23888_IR_CNTRL_REG, ~CNTRL_EDG_BOTH, | ||
401 | edge_types & CNTRL_EDG_BOTH); | ||
402 | } | ||
403 | |||
404 | static void control_rx_s_carrier_window(struct cx23885_dev *dev, | ||
405 | unsigned int carrier, | ||
406 | unsigned int *carrier_range_low, | ||
407 | unsigned int *carrier_range_high) | ||
408 | { | ||
409 | u32 v; | ||
410 | unsigned int c16 = carrier * 16; | ||
411 | |||
412 | if (*carrier_range_low < DIV_ROUND_CLOSEST(c16, 16 + 3)) { | ||
413 | v = CNTRL_WIN_3_4; | ||
414 | *carrier_range_low = DIV_ROUND_CLOSEST(c16, 16 + 4); | ||
415 | } else { | ||
416 | v = CNTRL_WIN_3_3; | ||
417 | *carrier_range_low = DIV_ROUND_CLOSEST(c16, 16 + 3); | ||
418 | } | ||
419 | |||
420 | if (*carrier_range_high > DIV_ROUND_CLOSEST(c16, 16 - 3)) { | ||
421 | v |= CNTRL_WIN_4_3; | ||
422 | *carrier_range_high = DIV_ROUND_CLOSEST(c16, 16 - 4); | ||
423 | } else { | ||
424 | v |= CNTRL_WIN_3_3; | ||
425 | *carrier_range_high = DIV_ROUND_CLOSEST(c16, 16 - 3); | ||
426 | } | ||
427 | cx23888_ir_and_or4(dev, CX23888_IR_CNTRL_REG, ~CNTRL_WIN, v); | ||
428 | } | ||
429 | |||
430 | static inline void control_tx_polarity_invert(struct cx23885_dev *dev, | ||
431 | bool invert) | ||
432 | { | ||
433 | cx23888_ir_and_or4(dev, CX23888_IR_CNTRL_REG, ~CNTRL_CPL, | ||
434 | invert ? CNTRL_CPL : 0); | ||
435 | } | ||
436 | |||
437 | static inline void control_tx_level_invert(struct cx23885_dev *dev, | ||
438 | bool invert) | ||
439 | { | ||
440 | cx23888_ir_and_or4(dev, CX23888_IR_CNTRL_REG, ~CNTRL_IVO, | ||
441 | invert ? CNTRL_IVO : 0); | ||
442 | } | ||
443 | |||
444 | /* | ||
445 | * IR Rx & Tx Clock Register helpers | ||
446 | */ | ||
447 | static unsigned int txclk_tx_s_carrier(struct cx23885_dev *dev, | ||
448 | unsigned int freq, | ||
449 | u16 *divider) | ||
450 | { | ||
451 | *divider = carrier_freq_to_clock_divider(freq); | ||
452 | cx23888_ir_write4(dev, CX23888_IR_TXCLK_REG, *divider); | ||
453 | return clock_divider_to_carrier_freq(*divider); | ||
454 | } | ||
455 | |||
456 | static unsigned int rxclk_rx_s_carrier(struct cx23885_dev *dev, | ||
457 | unsigned int freq, | ||
458 | u16 *divider) | ||
459 | { | ||
460 | *divider = carrier_freq_to_clock_divider(freq); | ||
461 | cx23888_ir_write4(dev, CX23888_IR_RXCLK_REG, *divider); | ||
462 | return clock_divider_to_carrier_freq(*divider); | ||
463 | } | ||
464 | |||
465 | static u32 txclk_tx_s_max_pulse_width(struct cx23885_dev *dev, u32 ns, | ||
466 | u16 *divider) | ||
467 | { | ||
468 | u64 pulse_clocks; | ||
469 | |||
470 | if (ns > IR_MAX_DURATION) | ||
471 | ns = IR_MAX_DURATION; | ||
472 | pulse_clocks = ns_to_pulse_clocks(ns); | ||
473 | *divider = pulse_clocks_to_clock_divider(pulse_clocks); | ||
474 | cx23888_ir_write4(dev, CX23888_IR_TXCLK_REG, *divider); | ||
475 | return (u32) pulse_width_count_to_ns(FIFO_RXTX, *divider); | ||
476 | } | ||
477 | |||
478 | static u32 rxclk_rx_s_max_pulse_width(struct cx23885_dev *dev, u32 ns, | ||
479 | u16 *divider) | ||
480 | { | ||
481 | u64 pulse_clocks; | ||
482 | |||
483 | if (ns > IR_MAX_DURATION) | ||
484 | ns = IR_MAX_DURATION; | ||
485 | pulse_clocks = ns_to_pulse_clocks(ns); | ||
486 | *divider = pulse_clocks_to_clock_divider(pulse_clocks); | ||
487 | cx23888_ir_write4(dev, CX23888_IR_RXCLK_REG, *divider); | ||
488 | return (u32) pulse_width_count_to_ns(FIFO_RXTX, *divider); | ||
489 | } | ||
490 | |||
491 | /* | ||
492 | * IR Tx Carrier Duty Cycle register helpers | ||
493 | */ | ||
494 | static unsigned int cduty_tx_s_duty_cycle(struct cx23885_dev *dev, | ||
495 | unsigned int duty_cycle) | ||
496 | { | ||
497 | u32 n; | ||
498 | n = DIV_ROUND_CLOSEST(duty_cycle * 100, 625); /* 16ths of 100% */ | ||
499 | if (n != 0) | ||
500 | n--; | ||
501 | if (n > 15) | ||
502 | n = 15; | ||
503 | cx23888_ir_write4(dev, CX23888_IR_CDUTY_REG, n); | ||
504 | return DIV_ROUND_CLOSEST((n + 1) * 100, 16); | ||
505 | } | ||
506 | |||
507 | /* | ||
508 | * IR Filter Register helpers | ||
509 | */ | ||
510 | static u32 filter_rx_s_min_width(struct cx23885_dev *dev, u32 min_width_ns) | ||
511 | { | ||
512 | u32 count = ns_to_lpf_count(min_width_ns); | ||
513 | cx23888_ir_write4(dev, CX23888_IR_FILTR_REG, count); | ||
514 | return lpf_count_to_ns(count); | ||
515 | } | ||
516 | |||
517 | /* | ||
518 | * IR IRQ Enable Register helpers | ||
519 | */ | ||
520 | static inline void irqenable_rx(struct cx23885_dev *dev, u32 mask) | ||
521 | { | ||
522 | mask &= (IRQEN_RTE | IRQEN_ROE | IRQEN_RSE); | ||
523 | cx23888_ir_and_or4(dev, CX23888_IR_IRQEN_REG, | ||
524 | ~(IRQEN_RTE | IRQEN_ROE | IRQEN_RSE), mask); | ||
525 | } | ||
526 | |||
527 | static inline void irqenable_tx(struct cx23885_dev *dev, u32 mask) | ||
528 | { | ||
529 | mask &= IRQEN_TSE; | ||
530 | cx23888_ir_and_or4(dev, CX23888_IR_IRQEN_REG, ~IRQEN_TSE, mask); | ||
531 | } | ||
532 | |||
533 | /* | ||
534 | * V4L2 Subdevice IR Ops | ||
535 | */ | ||
536 | static int cx23888_ir_irq_handler(struct v4l2_subdev *sd, u32 status, | ||
537 | bool *handled) | ||
538 | { | ||
539 | struct cx23888_ir_state *state = to_state(sd); | ||
540 | struct cx23885_dev *dev = state->dev; | ||
541 | unsigned long flags; | ||
542 | |||
543 | u32 cntrl = cx23888_ir_read4(dev, CX23888_IR_CNTRL_REG); | ||
544 | u32 irqen = cx23888_ir_read4(dev, CX23888_IR_IRQEN_REG); | ||
545 | u32 stats = cx23888_ir_read4(dev, CX23888_IR_STATS_REG); | ||
546 | |||
547 | union cx23888_ir_fifo_rec rx_data[FIFO_RX_DEPTH]; | ||
548 | unsigned int i, j, k; | ||
549 | u32 events, v; | ||
550 | int tsr, rsr, rto, ror, tse, rse, rte, roe, kror; | ||
551 | |||
552 | tsr = stats & STATS_TSR; /* Tx FIFO Service Request */ | ||
553 | rsr = stats & STATS_RSR; /* Rx FIFO Service Request */ | ||
554 | rto = stats & STATS_RTO; /* Rx Pulse Width Timer Time Out */ | ||
555 | ror = stats & STATS_ROR; /* Rx FIFO Over Run */ | ||
556 | |||
557 | tse = irqen & IRQEN_TSE; /* Tx FIFO Service Request IRQ Enable */ | ||
558 | rse = irqen & IRQEN_RSE; /* Rx FIFO Service Reuqest IRQ Enable */ | ||
559 | rte = irqen & IRQEN_RTE; /* Rx Pulse Width Timer Time Out IRQ Enable */ | ||
560 | roe = irqen & IRQEN_ROE; /* Rx FIFO Over Run IRQ Enable */ | ||
561 | |||
562 | *handled = false; | ||
563 | v4l2_dbg(2, ir_888_debug, sd, "IRQ Status: %s %s %s %s %s %s\n", | ||
564 | tsr ? "tsr" : " ", rsr ? "rsr" : " ", | ||
565 | rto ? "rto" : " ", ror ? "ror" : " ", | ||
566 | stats & STATS_TBY ? "tby" : " ", | ||
567 | stats & STATS_RBY ? "rby" : " "); | ||
568 | |||
569 | v4l2_dbg(2, ir_888_debug, sd, "IRQ Enables: %s %s %s %s\n", | ||
570 | tse ? "tse" : " ", rse ? "rse" : " ", | ||
571 | rte ? "rte" : " ", roe ? "roe" : " "); | ||
572 | |||
573 | /* | ||
574 | * Transmitter interrupt service | ||
575 | */ | ||
576 | if (tse && tsr) { | ||
577 | /* | ||
578 | * TODO: | ||
579 | * Check the watermark threshold setting | ||
580 | * Pull FIFO_TX_DEPTH or FIFO_TX_DEPTH/2 entries from tx_kfifo | ||
581 | * Push the data to the hardware FIFO. | ||
582 | * If there was nothing more to send in the tx_kfifo, disable | ||
583 | * the TSR IRQ and notify the v4l2_device. | ||
584 | * If there was something in the tx_kfifo, check the tx_kfifo | ||
585 | * level and notify the v4l2_device, if it is low. | ||
586 | */ | ||
587 | /* For now, inhibit TSR interrupt until Tx is implemented */ | ||
588 | irqenable_tx(dev, 0); | ||
589 | events = V4L2_SUBDEV_IR_TX_FIFO_SERVICE_REQ; | ||
590 | v4l2_subdev_notify(sd, V4L2_SUBDEV_IR_TX_NOTIFY, &events); | ||
591 | *handled = true; | ||
592 | } | ||
593 | |||
594 | /* | ||
595 | * Receiver interrupt service | ||
596 | */ | ||
597 | kror = 0; | ||
598 | if ((rse && rsr) || (rte && rto)) { | ||
599 | /* | ||
600 | * Receive data on RSR to clear the STATS_RSR. | ||
601 | * Receive data on RTO, since we may not have yet hit the RSR | ||
602 | * watermark when we receive the RTO. | ||
603 | */ | ||
604 | for (i = 0, v = FIFO_RX_NDV; | ||
605 | (v & FIFO_RX_NDV) && !kror; i = 0) { | ||
606 | for (j = 0; | ||
607 | (v & FIFO_RX_NDV) && j < FIFO_RX_DEPTH; j++) { | ||
608 | v = cx23888_ir_read4(dev, CX23888_IR_FIFO_REG); | ||
609 | rx_data[i].hw_fifo_data = v & ~FIFO_RX_NDV; | ||
610 | i++; | ||
611 | } | ||
612 | if (i == 0) | ||
613 | break; | ||
614 | j = i * sizeof(union cx23888_ir_fifo_rec); | ||
615 | k = kfifo_in_locked(&state->rx_kfifo, | ||
616 | (unsigned char *) rx_data, j, | ||
617 | &state->rx_kfifo_lock); | ||
618 | if (k != j) | ||
619 | kror++; /* rx_kfifo over run */ | ||
620 | } | ||
621 | *handled = true; | ||
622 | } | ||
623 | |||
624 | events = 0; | ||
625 | v = 0; | ||
626 | if (kror) { | ||
627 | events |= V4L2_SUBDEV_IR_RX_SW_FIFO_OVERRUN; | ||
628 | v4l2_err(sd, "IR receiver software FIFO overrun\n"); | ||
629 | } | ||
630 | if (roe && ror) { | ||
631 | /* | ||
632 | * The RX FIFO Enable (CNTRL_RFE) must be toggled to clear | ||
633 | * the Rx FIFO Over Run status (STATS_ROR) | ||
634 | */ | ||
635 | v |= CNTRL_RFE; | ||
636 | events |= V4L2_SUBDEV_IR_RX_HW_FIFO_OVERRUN; | ||
637 | v4l2_err(sd, "IR receiver hardware FIFO overrun\n"); | ||
638 | } | ||
639 | if (rte && rto) { | ||
640 | /* | ||
641 | * The IR Receiver Enable (CNTRL_RXE) must be toggled to clear | ||
642 | * the Rx Pulse Width Timer Time Out (STATS_RTO) | ||
643 | */ | ||
644 | v |= CNTRL_RXE; | ||
645 | events |= V4L2_SUBDEV_IR_RX_END_OF_RX_DETECTED; | ||
646 | } | ||
647 | if (v) { | ||
648 | /* Clear STATS_ROR & STATS_RTO as needed by reseting hardware */ | ||
649 | cx23888_ir_write4(dev, CX23888_IR_CNTRL_REG, cntrl & ~v); | ||
650 | cx23888_ir_write4(dev, CX23888_IR_CNTRL_REG, cntrl); | ||
651 | *handled = true; | ||
652 | } | ||
653 | |||
654 | spin_lock_irqsave(&state->rx_kfifo_lock, flags); | ||
655 | if (kfifo_len(&state->rx_kfifo) >= CX23888_IR_RX_KFIFO_SIZE / 2) | ||
656 | events |= V4L2_SUBDEV_IR_RX_FIFO_SERVICE_REQ; | ||
657 | spin_unlock_irqrestore(&state->rx_kfifo_lock, flags); | ||
658 | |||
659 | if (events) | ||
660 | v4l2_subdev_notify(sd, V4L2_SUBDEV_IR_RX_NOTIFY, &events); | ||
661 | return 0; | ||
662 | } | ||
663 | |||
664 | /* Receiver */ | ||
665 | static int cx23888_ir_rx_read(struct v4l2_subdev *sd, u8 *buf, size_t count, | ||
666 | ssize_t *num) | ||
667 | { | ||
668 | struct cx23888_ir_state *state = to_state(sd); | ||
669 | bool invert = (bool) atomic_read(&state->rx_invert); | ||
670 | u16 divider = (u16) atomic_read(&state->rxclk_divider); | ||
671 | |||
672 | unsigned int i, n; | ||
673 | union cx23888_ir_fifo_rec *p; | ||
674 | unsigned u, v, w; | ||
675 | |||
676 | n = count / sizeof(union cx23888_ir_fifo_rec) | ||
677 | * sizeof(union cx23888_ir_fifo_rec); | ||
678 | if (n == 0) { | ||
679 | *num = 0; | ||
680 | return 0; | ||
681 | } | ||
682 | |||
683 | n = kfifo_out_locked(&state->rx_kfifo, buf, n, &state->rx_kfifo_lock); | ||
684 | |||
685 | n /= sizeof(union cx23888_ir_fifo_rec); | ||
686 | *num = n * sizeof(union cx23888_ir_fifo_rec); | ||
687 | |||
688 | for (p = (union cx23888_ir_fifo_rec *) buf, i = 0; i < n; p++, i++) { | ||
689 | |||
690 | if ((p->hw_fifo_data & FIFO_RXTX_RTO) == FIFO_RXTX_RTO) { | ||
691 | /* Assume RTO was because of no IR light input */ | ||
692 | u = 0; | ||
693 | w = 1; | ||
694 | } else { | ||
695 | u = (p->hw_fifo_data & FIFO_RXTX_LVL) ? 1 : 0; | ||
696 | if (invert) | ||
697 | u = u ? 0 : 1; | ||
698 | w = 0; | ||
699 | } | ||
700 | |||
701 | v = (unsigned) pulse_width_count_to_ns( | ||
702 | (u16) (p->hw_fifo_data & FIFO_RXTX), divider); | ||
703 | if (v > IR_MAX_DURATION) | ||
704 | v = IR_MAX_DURATION; | ||
705 | |||
706 | init_ir_raw_event(&p->ir_core_data); | ||
707 | p->ir_core_data.pulse = u; | ||
708 | p->ir_core_data.duration = v; | ||
709 | p->ir_core_data.timeout = w; | ||
710 | |||
711 | v4l2_dbg(2, ir_888_debug, sd, "rx read: %10u ns %s %s\n", | ||
712 | v, u ? "mark" : "space", w ? "(timed out)" : ""); | ||
713 | if (w) | ||
714 | v4l2_dbg(2, ir_888_debug, sd, "rx read: end of rx\n"); | ||
715 | } | ||
716 | return 0; | ||
717 | } | ||
718 | |||
719 | static int cx23888_ir_rx_g_parameters(struct v4l2_subdev *sd, | ||
720 | struct v4l2_subdev_ir_parameters *p) | ||
721 | { | ||
722 | struct cx23888_ir_state *state = to_state(sd); | ||
723 | mutex_lock(&state->rx_params_lock); | ||
724 | memcpy(p, &state->rx_params, sizeof(struct v4l2_subdev_ir_parameters)); | ||
725 | mutex_unlock(&state->rx_params_lock); | ||
726 | return 0; | ||
727 | } | ||
728 | |||
729 | static int cx23888_ir_rx_shutdown(struct v4l2_subdev *sd) | ||
730 | { | ||
731 | struct cx23888_ir_state *state = to_state(sd); | ||
732 | struct cx23885_dev *dev = state->dev; | ||
733 | |||
734 | mutex_lock(&state->rx_params_lock); | ||
735 | |||
736 | /* Disable or slow down all IR Rx circuits and counters */ | ||
737 | irqenable_rx(dev, 0); | ||
738 | control_rx_enable(dev, false); | ||
739 | control_rx_demodulation_enable(dev, false); | ||
740 | control_rx_s_edge_detection(dev, CNTRL_EDG_NONE); | ||
741 | filter_rx_s_min_width(dev, 0); | ||
742 | cx23888_ir_write4(dev, CX23888_IR_RXCLK_REG, RXCLK_RCD); | ||
743 | |||
744 | state->rx_params.shutdown = true; | ||
745 | |||
746 | mutex_unlock(&state->rx_params_lock); | ||
747 | return 0; | ||
748 | } | ||
749 | |||
750 | static int cx23888_ir_rx_s_parameters(struct v4l2_subdev *sd, | ||
751 | struct v4l2_subdev_ir_parameters *p) | ||
752 | { | ||
753 | struct cx23888_ir_state *state = to_state(sd); | ||
754 | struct cx23885_dev *dev = state->dev; | ||
755 | struct v4l2_subdev_ir_parameters *o = &state->rx_params; | ||
756 | u16 rxclk_divider; | ||
757 | |||
758 | if (p->shutdown) | ||
759 | return cx23888_ir_rx_shutdown(sd); | ||
760 | |||
761 | if (p->mode != V4L2_SUBDEV_IR_MODE_PULSE_WIDTH) | ||
762 | return -ENOSYS; | ||
763 | |||
764 | mutex_lock(&state->rx_params_lock); | ||
765 | |||
766 | o->shutdown = p->shutdown; | ||
767 | |||
768 | o->mode = p->mode = V4L2_SUBDEV_IR_MODE_PULSE_WIDTH; | ||
769 | |||
770 | o->bytes_per_data_element = p->bytes_per_data_element | ||
771 | = sizeof(union cx23888_ir_fifo_rec); | ||
772 | |||
773 | /* Before we tweak the hardware, we have to disable the receiver */ | ||
774 | irqenable_rx(dev, 0); | ||
775 | control_rx_enable(dev, false); | ||
776 | |||
777 | control_rx_demodulation_enable(dev, p->modulation); | ||
778 | o->modulation = p->modulation; | ||
779 | |||
780 | if (p->modulation) { | ||
781 | p->carrier_freq = rxclk_rx_s_carrier(dev, p->carrier_freq, | ||
782 | &rxclk_divider); | ||
783 | |||
784 | o->carrier_freq = p->carrier_freq; | ||
785 | |||
786 | o->duty_cycle = p->duty_cycle = 50; | ||
787 | |||
788 | control_rx_s_carrier_window(dev, p->carrier_freq, | ||
789 | &p->carrier_range_lower, | ||
790 | &p->carrier_range_upper); | ||
791 | o->carrier_range_lower = p->carrier_range_lower; | ||
792 | o->carrier_range_upper = p->carrier_range_upper; | ||
793 | |||
794 | p->max_pulse_width = | ||
795 | (u32) pulse_width_count_to_ns(FIFO_RXTX, rxclk_divider); | ||
796 | } else { | ||
797 | p->max_pulse_width = | ||
798 | rxclk_rx_s_max_pulse_width(dev, p->max_pulse_width, | ||
799 | &rxclk_divider); | ||
800 | } | ||
801 | o->max_pulse_width = p->max_pulse_width; | ||
802 | atomic_set(&state->rxclk_divider, rxclk_divider); | ||
803 | |||
804 | p->noise_filter_min_width = | ||
805 | filter_rx_s_min_width(dev, p->noise_filter_min_width); | ||
806 | o->noise_filter_min_width = p->noise_filter_min_width; | ||
807 | |||
808 | p->resolution = clock_divider_to_resolution(rxclk_divider); | ||
809 | o->resolution = p->resolution; | ||
810 | |||
811 | /* FIXME - make this dependent on resolution for better performance */ | ||
812 | control_rx_irq_watermark(dev, RX_FIFO_HALF_FULL); | ||
813 | |||
814 | control_rx_s_edge_detection(dev, CNTRL_EDG_BOTH); | ||
815 | |||
816 | o->invert_level = p->invert_level; | ||
817 | atomic_set(&state->rx_invert, p->invert_level); | ||
818 | |||
819 | o->interrupt_enable = p->interrupt_enable; | ||
820 | o->enable = p->enable; | ||
821 | if (p->enable) { | ||
822 | unsigned long flags; | ||
823 | |||
824 | spin_lock_irqsave(&state->rx_kfifo_lock, flags); | ||
825 | kfifo_reset(&state->rx_kfifo); | ||
826 | /* reset tx_fifo too if there is one... */ | ||
827 | spin_unlock_irqrestore(&state->rx_kfifo_lock, flags); | ||
828 | if (p->interrupt_enable) | ||
829 | irqenable_rx(dev, IRQEN_RSE | IRQEN_RTE | IRQEN_ROE); | ||
830 | control_rx_enable(dev, p->enable); | ||
831 | } | ||
832 | |||
833 | mutex_unlock(&state->rx_params_lock); | ||
834 | return 0; | ||
835 | } | ||
836 | |||
837 | /* Transmitter */ | ||
838 | static int cx23888_ir_tx_write(struct v4l2_subdev *sd, u8 *buf, size_t count, | ||
839 | ssize_t *num) | ||
840 | { | ||
841 | struct cx23888_ir_state *state = to_state(sd); | ||
842 | struct cx23885_dev *dev = state->dev; | ||
843 | /* For now enable the Tx FIFO Service interrupt & pretend we did work */ | ||
844 | irqenable_tx(dev, IRQEN_TSE); | ||
845 | *num = count; | ||
846 | return 0; | ||
847 | } | ||
848 | |||
849 | static int cx23888_ir_tx_g_parameters(struct v4l2_subdev *sd, | ||
850 | struct v4l2_subdev_ir_parameters *p) | ||
851 | { | ||
852 | struct cx23888_ir_state *state = to_state(sd); | ||
853 | mutex_lock(&state->tx_params_lock); | ||
854 | memcpy(p, &state->tx_params, sizeof(struct v4l2_subdev_ir_parameters)); | ||
855 | mutex_unlock(&state->tx_params_lock); | ||
856 | return 0; | ||
857 | } | ||
858 | |||
859 | static int cx23888_ir_tx_shutdown(struct v4l2_subdev *sd) | ||
860 | { | ||
861 | struct cx23888_ir_state *state = to_state(sd); | ||
862 | struct cx23885_dev *dev = state->dev; | ||
863 | |||
864 | mutex_lock(&state->tx_params_lock); | ||
865 | |||
866 | /* Disable or slow down all IR Tx circuits and counters */ | ||
867 | irqenable_tx(dev, 0); | ||
868 | control_tx_enable(dev, false); | ||
869 | control_tx_modulation_enable(dev, false); | ||
870 | cx23888_ir_write4(dev, CX23888_IR_TXCLK_REG, TXCLK_TCD); | ||
871 | |||
872 | state->tx_params.shutdown = true; | ||
873 | |||
874 | mutex_unlock(&state->tx_params_lock); | ||
875 | return 0; | ||
876 | } | ||
877 | |||
878 | static int cx23888_ir_tx_s_parameters(struct v4l2_subdev *sd, | ||
879 | struct v4l2_subdev_ir_parameters *p) | ||
880 | { | ||
881 | struct cx23888_ir_state *state = to_state(sd); | ||
882 | struct cx23885_dev *dev = state->dev; | ||
883 | struct v4l2_subdev_ir_parameters *o = &state->tx_params; | ||
884 | u16 txclk_divider; | ||
885 | |||
886 | if (p->shutdown) | ||
887 | return cx23888_ir_tx_shutdown(sd); | ||
888 | |||
889 | if (p->mode != V4L2_SUBDEV_IR_MODE_PULSE_WIDTH) | ||
890 | return -ENOSYS; | ||
891 | |||
892 | mutex_lock(&state->tx_params_lock); | ||
893 | |||
894 | o->shutdown = p->shutdown; | ||
895 | |||
896 | o->mode = p->mode = V4L2_SUBDEV_IR_MODE_PULSE_WIDTH; | ||
897 | |||
898 | o->bytes_per_data_element = p->bytes_per_data_element | ||
899 | = sizeof(union cx23888_ir_fifo_rec); | ||
900 | |||
901 | /* Before we tweak the hardware, we have to disable the transmitter */ | ||
902 | irqenable_tx(dev, 0); | ||
903 | control_tx_enable(dev, false); | ||
904 | |||
905 | control_tx_modulation_enable(dev, p->modulation); | ||
906 | o->modulation = p->modulation; | ||
907 | |||
908 | if (p->modulation) { | ||
909 | p->carrier_freq = txclk_tx_s_carrier(dev, p->carrier_freq, | ||
910 | &txclk_divider); | ||
911 | o->carrier_freq = p->carrier_freq; | ||
912 | |||
913 | p->duty_cycle = cduty_tx_s_duty_cycle(dev, p->duty_cycle); | ||
914 | o->duty_cycle = p->duty_cycle; | ||
915 | |||
916 | p->max_pulse_width = | ||
917 | (u32) pulse_width_count_to_ns(FIFO_RXTX, txclk_divider); | ||
918 | } else { | ||
919 | p->max_pulse_width = | ||
920 | txclk_tx_s_max_pulse_width(dev, p->max_pulse_width, | ||
921 | &txclk_divider); | ||
922 | } | ||
923 | o->max_pulse_width = p->max_pulse_width; | ||
924 | atomic_set(&state->txclk_divider, txclk_divider); | ||
925 | |||
926 | p->resolution = clock_divider_to_resolution(txclk_divider); | ||
927 | o->resolution = p->resolution; | ||
928 | |||
929 | /* FIXME - make this dependent on resolution for better performance */ | ||
930 | control_tx_irq_watermark(dev, TX_FIFO_HALF_EMPTY); | ||
931 | |||
932 | control_tx_polarity_invert(dev, p->invert_carrier_sense); | ||
933 | o->invert_carrier_sense = p->invert_carrier_sense; | ||
934 | |||
935 | control_tx_level_invert(dev, p->invert_level); | ||
936 | o->invert_level = p->invert_level; | ||
937 | |||
938 | o->interrupt_enable = p->interrupt_enable; | ||
939 | o->enable = p->enable; | ||
940 | if (p->enable) { | ||
941 | if (p->interrupt_enable) | ||
942 | irqenable_tx(dev, IRQEN_TSE); | ||
943 | control_tx_enable(dev, p->enable); | ||
944 | } | ||
945 | |||
946 | mutex_unlock(&state->tx_params_lock); | ||
947 | return 0; | ||
948 | } | ||
949 | |||
950 | |||
951 | /* | ||
952 | * V4L2 Subdevice Core Ops | ||
953 | */ | ||
954 | static int cx23888_ir_log_status(struct v4l2_subdev *sd) | ||
955 | { | ||
956 | struct cx23888_ir_state *state = to_state(sd); | ||
957 | struct cx23885_dev *dev = state->dev; | ||
958 | char *s; | ||
959 | int i, j; | ||
960 | |||
961 | u32 cntrl = cx23888_ir_read4(dev, CX23888_IR_CNTRL_REG); | ||
962 | u32 txclk = cx23888_ir_read4(dev, CX23888_IR_TXCLK_REG) & TXCLK_TCD; | ||
963 | u32 rxclk = cx23888_ir_read4(dev, CX23888_IR_RXCLK_REG) & RXCLK_RCD; | ||
964 | u32 cduty = cx23888_ir_read4(dev, CX23888_IR_CDUTY_REG) & CDUTY_CDC; | ||
965 | u32 stats = cx23888_ir_read4(dev, CX23888_IR_STATS_REG); | ||
966 | u32 irqen = cx23888_ir_read4(dev, CX23888_IR_IRQEN_REG); | ||
967 | u32 filtr = cx23888_ir_read4(dev, CX23888_IR_FILTR_REG) & FILTR_LPF; | ||
968 | |||
969 | v4l2_info(sd, "IR Receiver:\n"); | ||
970 | v4l2_info(sd, "\tEnabled: %s\n", | ||
971 | cntrl & CNTRL_RXE ? "yes" : "no"); | ||
972 | v4l2_info(sd, "\tDemodulation from a carrier: %s\n", | ||
973 | cntrl & CNTRL_DMD ? "enabled" : "disabled"); | ||
974 | v4l2_info(sd, "\tFIFO: %s\n", | ||
975 | cntrl & CNTRL_RFE ? "enabled" : "disabled"); | ||
976 | switch (cntrl & CNTRL_EDG) { | ||
977 | case CNTRL_EDG_NONE: | ||
978 | s = "disabled"; | ||
979 | break; | ||
980 | case CNTRL_EDG_FALL: | ||
981 | s = "falling edge"; | ||
982 | break; | ||
983 | case CNTRL_EDG_RISE: | ||
984 | s = "rising edge"; | ||
985 | break; | ||
986 | case CNTRL_EDG_BOTH: | ||
987 | s = "rising & falling edges"; | ||
988 | break; | ||
989 | default: | ||
990 | s = "??? edge"; | ||
991 | break; | ||
992 | } | ||
993 | v4l2_info(sd, "\tPulse timers' start/stop trigger: %s\n", s); | ||
994 | v4l2_info(sd, "\tFIFO data on pulse timer overflow: %s\n", | ||
995 | cntrl & CNTRL_R ? "not loaded" : "overflow marker"); | ||
996 | v4l2_info(sd, "\tFIFO interrupt watermark: %s\n", | ||
997 | cntrl & CNTRL_RIC ? "not empty" : "half full or greater"); | ||
998 | v4l2_info(sd, "\tLoopback mode: %s\n", | ||
999 | cntrl & CNTRL_LBM ? "loopback active" : "normal receive"); | ||
1000 | if (cntrl & CNTRL_DMD) { | ||
1001 | v4l2_info(sd, "\tExpected carrier (16 clocks): %u Hz\n", | ||
1002 | clock_divider_to_carrier_freq(rxclk)); | ||
1003 | switch (cntrl & CNTRL_WIN) { | ||
1004 | case CNTRL_WIN_3_3: | ||
1005 | i = 3; | ||
1006 | j = 3; | ||
1007 | break; | ||
1008 | case CNTRL_WIN_4_3: | ||
1009 | i = 4; | ||
1010 | j = 3; | ||
1011 | break; | ||
1012 | case CNTRL_WIN_3_4: | ||
1013 | i = 3; | ||
1014 | j = 4; | ||
1015 | break; | ||
1016 | case CNTRL_WIN_4_4: | ||
1017 | i = 4; | ||
1018 | j = 4; | ||
1019 | break; | ||
1020 | default: | ||
1021 | i = 0; | ||
1022 | j = 0; | ||
1023 | break; | ||
1024 | } | ||
1025 | v4l2_info(sd, "\tNext carrier edge window: 16 clocks " | ||
1026 | "-%1d/+%1d, %u to %u Hz\n", i, j, | ||
1027 | clock_divider_to_freq(rxclk, 16 + j), | ||
1028 | clock_divider_to_freq(rxclk, 16 - i)); | ||
1029 | } | ||
1030 | v4l2_info(sd, "\tMax measurable pulse width: %u us, %llu ns\n", | ||
1031 | pulse_width_count_to_us(FIFO_RXTX, rxclk), | ||
1032 | pulse_width_count_to_ns(FIFO_RXTX, rxclk)); | ||
1033 | v4l2_info(sd, "\tLow pass filter: %s\n", | ||
1034 | filtr ? "enabled" : "disabled"); | ||
1035 | if (filtr) | ||
1036 | v4l2_info(sd, "\tMin acceptable pulse width (LPF): %u us, " | ||
1037 | "%u ns\n", | ||
1038 | lpf_count_to_us(filtr), | ||
1039 | lpf_count_to_ns(filtr)); | ||
1040 | v4l2_info(sd, "\tPulse width timer timed-out: %s\n", | ||
1041 | stats & STATS_RTO ? "yes" : "no"); | ||
1042 | v4l2_info(sd, "\tPulse width timer time-out intr: %s\n", | ||
1043 | irqen & IRQEN_RTE ? "enabled" : "disabled"); | ||
1044 | v4l2_info(sd, "\tFIFO overrun: %s\n", | ||
1045 | stats & STATS_ROR ? "yes" : "no"); | ||
1046 | v4l2_info(sd, "\tFIFO overrun interrupt: %s\n", | ||
1047 | irqen & IRQEN_ROE ? "enabled" : "disabled"); | ||
1048 | v4l2_info(sd, "\tBusy: %s\n", | ||
1049 | stats & STATS_RBY ? "yes" : "no"); | ||
1050 | v4l2_info(sd, "\tFIFO service requested: %s\n", | ||
1051 | stats & STATS_RSR ? "yes" : "no"); | ||
1052 | v4l2_info(sd, "\tFIFO service request interrupt: %s\n", | ||
1053 | irqen & IRQEN_RSE ? "enabled" : "disabled"); | ||
1054 | |||
1055 | v4l2_info(sd, "IR Transmitter:\n"); | ||
1056 | v4l2_info(sd, "\tEnabled: %s\n", | ||
1057 | cntrl & CNTRL_TXE ? "yes" : "no"); | ||
1058 | v4l2_info(sd, "\tModulation onto a carrier: %s\n", | ||
1059 | cntrl & CNTRL_MOD ? "enabled" : "disabled"); | ||
1060 | v4l2_info(sd, "\tFIFO: %s\n", | ||
1061 | cntrl & CNTRL_TFE ? "enabled" : "disabled"); | ||
1062 | v4l2_info(sd, "\tFIFO interrupt watermark: %s\n", | ||
1063 | cntrl & CNTRL_TIC ? "not empty" : "half full or less"); | ||
1064 | v4l2_info(sd, "\tOutput pin level inversion %s\n", | ||
1065 | cntrl & CNTRL_IVO ? "yes" : "no"); | ||
1066 | v4l2_info(sd, "\tCarrier polarity: %s\n", | ||
1067 | cntrl & CNTRL_CPL ? "space:burst mark:noburst" | ||
1068 | : "space:noburst mark:burst"); | ||
1069 | if (cntrl & CNTRL_MOD) { | ||
1070 | v4l2_info(sd, "\tCarrier (16 clocks): %u Hz\n", | ||
1071 | clock_divider_to_carrier_freq(txclk)); | ||
1072 | v4l2_info(sd, "\tCarrier duty cycle: %2u/16\n", | ||
1073 | cduty + 1); | ||
1074 | } | ||
1075 | v4l2_info(sd, "\tMax pulse width: %u us, %llu ns\n", | ||
1076 | pulse_width_count_to_us(FIFO_RXTX, txclk), | ||
1077 | pulse_width_count_to_ns(FIFO_RXTX, txclk)); | ||
1078 | v4l2_info(sd, "\tBusy: %s\n", | ||
1079 | stats & STATS_TBY ? "yes" : "no"); | ||
1080 | v4l2_info(sd, "\tFIFO service requested: %s\n", | ||
1081 | stats & STATS_TSR ? "yes" : "no"); | ||
1082 | v4l2_info(sd, "\tFIFO service request interrupt: %s\n", | ||
1083 | irqen & IRQEN_TSE ? "enabled" : "disabled"); | ||
1084 | |||
1085 | return 0; | ||
1086 | } | ||
1087 | |||
1088 | static inline int cx23888_ir_dbg_match(const struct v4l2_dbg_match *match) | ||
1089 | { | ||
1090 | return match->type == V4L2_CHIP_MATCH_HOST && match->addr == 2; | ||
1091 | } | ||
1092 | |||
1093 | static int cx23888_ir_g_chip_ident(struct v4l2_subdev *sd, | ||
1094 | struct v4l2_dbg_chip_ident *chip) | ||
1095 | { | ||
1096 | struct cx23888_ir_state *state = to_state(sd); | ||
1097 | |||
1098 | if (cx23888_ir_dbg_match(&chip->match)) { | ||
1099 | chip->ident = state->id; | ||
1100 | chip->revision = state->rev; | ||
1101 | } | ||
1102 | return 0; | ||
1103 | } | ||
1104 | |||
1105 | #ifdef CONFIG_VIDEO_ADV_DEBUG | ||
1106 | static int cx23888_ir_g_register(struct v4l2_subdev *sd, | ||
1107 | struct v4l2_dbg_register *reg) | ||
1108 | { | ||
1109 | struct cx23888_ir_state *state = to_state(sd); | ||
1110 | u32 addr = CX23888_IR_REG_BASE + (u32) reg->reg; | ||
1111 | |||
1112 | if (!cx23888_ir_dbg_match(®->match)) | ||
1113 | return -EINVAL; | ||
1114 | if ((addr & 0x3) != 0) | ||
1115 | return -EINVAL; | ||
1116 | if (addr < CX23888_IR_CNTRL_REG || addr > CX23888_IR_LEARN_REG) | ||
1117 | return -EINVAL; | ||
1118 | if (!capable(CAP_SYS_ADMIN)) | ||
1119 | return -EPERM; | ||
1120 | reg->size = 4; | ||
1121 | reg->val = cx23888_ir_read4(state->dev, addr); | ||
1122 | return 0; | ||
1123 | } | ||
1124 | |||
1125 | static int cx23888_ir_s_register(struct v4l2_subdev *sd, | ||
1126 | struct v4l2_dbg_register *reg) | ||
1127 | { | ||
1128 | struct cx23888_ir_state *state = to_state(sd); | ||
1129 | u32 addr = CX23888_IR_REG_BASE + (u32) reg->reg; | ||
1130 | |||
1131 | if (!cx23888_ir_dbg_match(®->match)) | ||
1132 | return -EINVAL; | ||
1133 | if ((addr & 0x3) != 0) | ||
1134 | return -EINVAL; | ||
1135 | if (addr < CX23888_IR_CNTRL_REG || addr > CX23888_IR_LEARN_REG) | ||
1136 | return -EINVAL; | ||
1137 | if (!capable(CAP_SYS_ADMIN)) | ||
1138 | return -EPERM; | ||
1139 | cx23888_ir_write4(state->dev, addr, reg->val); | ||
1140 | return 0; | ||
1141 | } | ||
1142 | #endif | ||
1143 | |||
1144 | static const struct v4l2_subdev_core_ops cx23888_ir_core_ops = { | ||
1145 | .g_chip_ident = cx23888_ir_g_chip_ident, | ||
1146 | .log_status = cx23888_ir_log_status, | ||
1147 | #ifdef CONFIG_VIDEO_ADV_DEBUG | ||
1148 | .g_register = cx23888_ir_g_register, | ||
1149 | .s_register = cx23888_ir_s_register, | ||
1150 | #endif | ||
1151 | .interrupt_service_routine = cx23888_ir_irq_handler, | ||
1152 | }; | ||
1153 | |||
1154 | static const struct v4l2_subdev_ir_ops cx23888_ir_ir_ops = { | ||
1155 | .rx_read = cx23888_ir_rx_read, | ||
1156 | .rx_g_parameters = cx23888_ir_rx_g_parameters, | ||
1157 | .rx_s_parameters = cx23888_ir_rx_s_parameters, | ||
1158 | |||
1159 | .tx_write = cx23888_ir_tx_write, | ||
1160 | .tx_g_parameters = cx23888_ir_tx_g_parameters, | ||
1161 | .tx_s_parameters = cx23888_ir_tx_s_parameters, | ||
1162 | }; | ||
1163 | |||
1164 | static const struct v4l2_subdev_ops cx23888_ir_controller_ops = { | ||
1165 | .core = &cx23888_ir_core_ops, | ||
1166 | .ir = &cx23888_ir_ir_ops, | ||
1167 | }; | ||
1168 | |||
1169 | static const struct v4l2_subdev_ir_parameters default_rx_params = { | ||
1170 | .bytes_per_data_element = sizeof(union cx23888_ir_fifo_rec), | ||
1171 | .mode = V4L2_SUBDEV_IR_MODE_PULSE_WIDTH, | ||
1172 | |||
1173 | .enable = false, | ||
1174 | .interrupt_enable = false, | ||
1175 | .shutdown = true, | ||
1176 | |||
1177 | .modulation = true, | ||
1178 | .carrier_freq = 36000, /* 36 kHz - RC-5, RC-6, and RC-6A carrier */ | ||
1179 | |||
1180 | /* RC-5: 666,667 ns = 1/36 kHz * 32 cycles * 1 mark * 0.75 */ | ||
1181 | /* RC-6A: 333,333 ns = 1/36 kHz * 16 cycles * 1 mark * 0.75 */ | ||
1182 | .noise_filter_min_width = 333333, /* ns */ | ||
1183 | .carrier_range_lower = 35000, | ||
1184 | .carrier_range_upper = 37000, | ||
1185 | .invert_level = false, | ||
1186 | }; | ||
1187 | |||
1188 | static const struct v4l2_subdev_ir_parameters default_tx_params = { | ||
1189 | .bytes_per_data_element = sizeof(union cx23888_ir_fifo_rec), | ||
1190 | .mode = V4L2_SUBDEV_IR_MODE_PULSE_WIDTH, | ||
1191 | |||
1192 | .enable = false, | ||
1193 | .interrupt_enable = false, | ||
1194 | .shutdown = true, | ||
1195 | |||
1196 | .modulation = true, | ||
1197 | .carrier_freq = 36000, /* 36 kHz - RC-5 carrier */ | ||
1198 | .duty_cycle = 25, /* 25 % - RC-5 carrier */ | ||
1199 | .invert_level = false, | ||
1200 | .invert_carrier_sense = false, | ||
1201 | }; | ||
1202 | |||
1203 | int cx23888_ir_probe(struct cx23885_dev *dev) | ||
1204 | { | ||
1205 | struct cx23888_ir_state *state; | ||
1206 | struct v4l2_subdev *sd; | ||
1207 | struct v4l2_subdev_ir_parameters default_params; | ||
1208 | int ret; | ||
1209 | |||
1210 | state = kzalloc(sizeof(struct cx23888_ir_state), GFP_KERNEL); | ||
1211 | if (state == NULL) | ||
1212 | return -ENOMEM; | ||
1213 | |||
1214 | spin_lock_init(&state->rx_kfifo_lock); | ||
1215 | if (kfifo_alloc(&state->rx_kfifo, CX23888_IR_RX_KFIFO_SIZE, GFP_KERNEL)) | ||
1216 | return -ENOMEM; | ||
1217 | |||
1218 | state->dev = dev; | ||
1219 | state->id = V4L2_IDENT_CX23888_IR; | ||
1220 | state->rev = 0; | ||
1221 | sd = &state->sd; | ||
1222 | |||
1223 | v4l2_subdev_init(sd, &cx23888_ir_controller_ops); | ||
1224 | v4l2_set_subdevdata(sd, state); | ||
1225 | /* FIXME - fix the formatting of dev->v4l2_dev.name and use it */ | ||
1226 | snprintf(sd->name, sizeof(sd->name), "%s/888-ir", dev->name); | ||
1227 | sd->grp_id = CX23885_HW_888_IR; | ||
1228 | |||
1229 | ret = v4l2_device_register_subdev(&dev->v4l2_dev, sd); | ||
1230 | if (ret == 0) { | ||
1231 | /* | ||
1232 | * Ensure no interrupts arrive from '888 specific conditions, | ||
1233 | * since we ignore them in this driver to have commonality with | ||
1234 | * similar IR controller cores. | ||
1235 | */ | ||
1236 | cx23888_ir_write4(dev, CX23888_IR_IRQEN_REG, 0); | ||
1237 | |||
1238 | mutex_init(&state->rx_params_lock); | ||
1239 | memcpy(&default_params, &default_rx_params, | ||
1240 | sizeof(struct v4l2_subdev_ir_parameters)); | ||
1241 | v4l2_subdev_call(sd, ir, rx_s_parameters, &default_params); | ||
1242 | |||
1243 | mutex_init(&state->tx_params_lock); | ||
1244 | memcpy(&default_params, &default_tx_params, | ||
1245 | sizeof(struct v4l2_subdev_ir_parameters)); | ||
1246 | v4l2_subdev_call(sd, ir, tx_s_parameters, &default_params); | ||
1247 | } else { | ||
1248 | kfifo_free(&state->rx_kfifo); | ||
1249 | } | ||
1250 | return ret; | ||
1251 | } | ||
1252 | |||
1253 | int cx23888_ir_remove(struct cx23885_dev *dev) | ||
1254 | { | ||
1255 | struct v4l2_subdev *sd; | ||
1256 | struct cx23888_ir_state *state; | ||
1257 | |||
1258 | sd = cx23885_find_hw(dev, CX23885_HW_888_IR); | ||
1259 | if (sd == NULL) | ||
1260 | return -ENODEV; | ||
1261 | |||
1262 | cx23888_ir_rx_shutdown(sd); | ||
1263 | cx23888_ir_tx_shutdown(sd); | ||
1264 | |||
1265 | state = to_state(sd); | ||
1266 | v4l2_device_unregister_subdev(sd); | ||
1267 | kfifo_free(&state->rx_kfifo); | ||
1268 | kfree(state); | ||
1269 | /* Nothing more to free() as state held the actual v4l2_subdev object */ | ||
1270 | return 0; | ||
1271 | } | ||
diff --git a/drivers/media/pci/cx23885/cx23888-ir.h b/drivers/media/pci/cx23885/cx23888-ir.h new file mode 100644 index 000000000000..d2de41caaf1d --- /dev/null +++ b/drivers/media/pci/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/pci/cx23885/netup-eeprom.c b/drivers/media/pci/cx23885/netup-eeprom.c new file mode 100644 index 000000000000..98a48f500684 --- /dev/null +++ b/drivers/media/pci/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/pci/cx23885/netup-eeprom.h b/drivers/media/pci/cx23885/netup-eeprom.h new file mode 100644 index 000000000000..13926e18feba --- /dev/null +++ b/drivers/media/pci/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/pci/cx23885/netup-init.c b/drivers/media/pci/cx23885/netup-init.c new file mode 100644 index 000000000000..f4893e69cd89 --- /dev/null +++ b/drivers/media/pci/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/pci/cx23885/netup-init.h b/drivers/media/pci/cx23885/netup-init.h new file mode 100644 index 000000000000..d26ae4b1590e --- /dev/null +++ b/drivers/media/pci/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); | ||