1c942fddfSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later
2b285192aSMauro Carvalho Chehab /*
3b285192aSMauro Carvalho Chehab * cx18 driver initialization and card probing
4b285192aSMauro Carvalho Chehab *
5b285192aSMauro Carvalho Chehab * Derived from ivtv-driver.c
6b285192aSMauro Carvalho Chehab *
7b285192aSMauro Carvalho Chehab * Copyright (C) 2007 Hans Verkuil <hverkuil@xs4all.nl>
8b285192aSMauro Carvalho Chehab * Copyright (C) 2008 Andy Walls <awalls@md.metrocast.net>
9b285192aSMauro Carvalho Chehab */
10b285192aSMauro Carvalho Chehab
11b285192aSMauro Carvalho Chehab #include "cx18-driver.h"
12b285192aSMauro Carvalho Chehab #include "cx18-io.h"
13b285192aSMauro Carvalho Chehab #include "cx18-version.h"
14b285192aSMauro Carvalho Chehab #include "cx18-cards.h"
15b285192aSMauro Carvalho Chehab #include "cx18-i2c.h"
16b285192aSMauro Carvalho Chehab #include "cx18-irq.h"
17b285192aSMauro Carvalho Chehab #include "cx18-gpio.h"
18b285192aSMauro Carvalho Chehab #include "cx18-firmware.h"
19b285192aSMauro Carvalho Chehab #include "cx18-queue.h"
20b285192aSMauro Carvalho Chehab #include "cx18-streams.h"
21b285192aSMauro Carvalho Chehab #include "cx18-av-core.h"
22b285192aSMauro Carvalho Chehab #include "cx18-scb.h"
23b285192aSMauro Carvalho Chehab #include "cx18-mailbox.h"
24b285192aSMauro Carvalho Chehab #include "cx18-ioctl.h"
25b285192aSMauro Carvalho Chehab #include "cx18-controls.h"
26d76231e4SMauro Carvalho Chehab #include "xc2028.h"
27b285192aSMauro Carvalho Chehab #include <linux/dma-mapping.h>
28b285192aSMauro Carvalho Chehab #include <media/tveeprom.h>
29b285192aSMauro Carvalho Chehab
30b285192aSMauro Carvalho Chehab /* If you have already X v4l cards, then set this to X. This way
31b285192aSMauro Carvalho Chehab the device numbers stay matched. Example: you have a WinTV card
32b285192aSMauro Carvalho Chehab without radio and a Compro H900 with. Normally this would give a
33b285192aSMauro Carvalho Chehab video1 device together with a radio0 device for the Compro. By
34b285192aSMauro Carvalho Chehab setting this to 1 you ensure that radio0 is now also radio1. */
35b285192aSMauro Carvalho Chehab int cx18_first_minor;
36b285192aSMauro Carvalho Chehab
37b285192aSMauro Carvalho Chehab /* Callback for registering extensions */
38b285192aSMauro Carvalho Chehab int (*cx18_ext_init)(struct cx18 *);
39b285192aSMauro Carvalho Chehab EXPORT_SYMBOL(cx18_ext_init);
40b285192aSMauro Carvalho Chehab
41b285192aSMauro Carvalho Chehab /* add your revision and whatnot here */
421482ccdaSArvind Yadav static const struct pci_device_id cx18_pci_tbl[] = {
43b285192aSMauro Carvalho Chehab {PCI_VENDOR_ID_CX, PCI_DEVICE_ID_CX23418,
44b285192aSMauro Carvalho Chehab PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
45b285192aSMauro Carvalho Chehab {0,}
46b285192aSMauro Carvalho Chehab };
47b285192aSMauro Carvalho Chehab
48b285192aSMauro Carvalho Chehab MODULE_DEVICE_TABLE(pci, cx18_pci_tbl);
49b285192aSMauro Carvalho Chehab
50b285192aSMauro Carvalho Chehab static atomic_t cx18_instance = ATOMIC_INIT(0);
51b285192aSMauro Carvalho Chehab
52b285192aSMauro Carvalho Chehab /* Parameter declarations */
53b285192aSMauro Carvalho Chehab static int cardtype[CX18_MAX_CARDS];
54b285192aSMauro Carvalho Chehab static int tuner[CX18_MAX_CARDS] = { -1, -1, -1, -1, -1, -1, -1, -1,
55b285192aSMauro Carvalho Chehab -1, -1, -1, -1, -1, -1, -1, -1,
56b285192aSMauro Carvalho Chehab -1, -1, -1, -1, -1, -1, -1, -1,
57b285192aSMauro Carvalho Chehab -1, -1, -1, -1, -1, -1, -1, -1 };
58b285192aSMauro Carvalho Chehab static int radio[CX18_MAX_CARDS] = { -1, -1, -1, -1, -1, -1, -1, -1,
59b285192aSMauro Carvalho Chehab -1, -1, -1, -1, -1, -1, -1, -1,
60b285192aSMauro Carvalho Chehab -1, -1, -1, -1, -1, -1, -1, -1,
61b285192aSMauro Carvalho Chehab -1, -1, -1, -1, -1, -1, -1, -1 };
62b285192aSMauro Carvalho Chehab static unsigned cardtype_c = 1;
63b285192aSMauro Carvalho Chehab static unsigned tuner_c = 1;
64b285192aSMauro Carvalho Chehab static unsigned radio_c = 1;
65b285192aSMauro Carvalho Chehab static char pal[] = "--";
66b285192aSMauro Carvalho Chehab static char secam[] = "--";
67b285192aSMauro Carvalho Chehab static char ntsc[] = "-";
68b285192aSMauro Carvalho Chehab
69b285192aSMauro Carvalho Chehab /* Buffers */
70b285192aSMauro Carvalho Chehab static int enc_ts_buffers = CX18_DEFAULT_ENC_TS_BUFFERS;
71b285192aSMauro Carvalho Chehab static int enc_mpg_buffers = CX18_DEFAULT_ENC_MPG_BUFFERS;
72b285192aSMauro Carvalho Chehab static int enc_idx_buffers = CX18_DEFAULT_ENC_IDX_BUFFERS;
73b285192aSMauro Carvalho Chehab static int enc_yuv_buffers = CX18_DEFAULT_ENC_YUV_BUFFERS;
74b285192aSMauro Carvalho Chehab static int enc_vbi_buffers = CX18_DEFAULT_ENC_VBI_BUFFERS;
75b285192aSMauro Carvalho Chehab static int enc_pcm_buffers = CX18_DEFAULT_ENC_PCM_BUFFERS;
76b285192aSMauro Carvalho Chehab
77b285192aSMauro Carvalho Chehab static int enc_ts_bufsize = CX18_DEFAULT_ENC_TS_BUFSIZE;
78b285192aSMauro Carvalho Chehab static int enc_mpg_bufsize = CX18_DEFAULT_ENC_MPG_BUFSIZE;
79b285192aSMauro Carvalho Chehab static int enc_idx_bufsize = CX18_DEFAULT_ENC_IDX_BUFSIZE;
80b285192aSMauro Carvalho Chehab static int enc_yuv_bufsize = CX18_DEFAULT_ENC_YUV_BUFSIZE;
81b285192aSMauro Carvalho Chehab static int enc_pcm_bufsize = CX18_DEFAULT_ENC_PCM_BUFSIZE;
82b285192aSMauro Carvalho Chehab
83b285192aSMauro Carvalho Chehab static int enc_ts_bufs = -1;
84b285192aSMauro Carvalho Chehab static int enc_mpg_bufs = -1;
85b285192aSMauro Carvalho Chehab static int enc_idx_bufs = CX18_MAX_FW_MDLS_PER_STREAM;
86b285192aSMauro Carvalho Chehab static int enc_yuv_bufs = -1;
87b285192aSMauro Carvalho Chehab static int enc_vbi_bufs = -1;
88b285192aSMauro Carvalho Chehab static int enc_pcm_bufs = -1;
89b285192aSMauro Carvalho Chehab
90b285192aSMauro Carvalho Chehab
91b285192aSMauro Carvalho Chehab static int cx18_pci_latency = 1;
92b285192aSMauro Carvalho Chehab
93b285192aSMauro Carvalho Chehab static int mmio_ndelay;
94b285192aSMauro Carvalho Chehab static int retry_mmio = 1;
95b285192aSMauro Carvalho Chehab
96b285192aSMauro Carvalho Chehab int cx18_debug;
97b285192aSMauro Carvalho Chehab
98b285192aSMauro Carvalho Chehab module_param_array(tuner, int, &tuner_c, 0644);
99b285192aSMauro Carvalho Chehab module_param_array(radio, int, &radio_c, 0644);
100b285192aSMauro Carvalho Chehab module_param_array(cardtype, int, &cardtype_c, 0644);
101b285192aSMauro Carvalho Chehab module_param_string(pal, pal, sizeof(pal), 0644);
102b285192aSMauro Carvalho Chehab module_param_string(secam, secam, sizeof(secam), 0644);
103b285192aSMauro Carvalho Chehab module_param_string(ntsc, ntsc, sizeof(ntsc), 0644);
104b285192aSMauro Carvalho Chehab module_param_named(debug, cx18_debug, int, 0644);
105b285192aSMauro Carvalho Chehab module_param(mmio_ndelay, int, 0644);
106b285192aSMauro Carvalho Chehab module_param(retry_mmio, int, 0644);
107b285192aSMauro Carvalho Chehab module_param(cx18_pci_latency, int, 0644);
108b285192aSMauro Carvalho Chehab module_param(cx18_first_minor, int, 0644);
109b285192aSMauro Carvalho Chehab
110b285192aSMauro Carvalho Chehab module_param(enc_ts_buffers, int, 0644);
111b285192aSMauro Carvalho Chehab module_param(enc_mpg_buffers, int, 0644);
112b285192aSMauro Carvalho Chehab module_param(enc_idx_buffers, int, 0644);
113b285192aSMauro Carvalho Chehab module_param(enc_yuv_buffers, int, 0644);
114b285192aSMauro Carvalho Chehab module_param(enc_vbi_buffers, int, 0644);
115b285192aSMauro Carvalho Chehab module_param(enc_pcm_buffers, int, 0644);
116b285192aSMauro Carvalho Chehab
117b285192aSMauro Carvalho Chehab module_param(enc_ts_bufsize, int, 0644);
118b285192aSMauro Carvalho Chehab module_param(enc_mpg_bufsize, int, 0644);
119b285192aSMauro Carvalho Chehab module_param(enc_idx_bufsize, int, 0644);
120b285192aSMauro Carvalho Chehab module_param(enc_yuv_bufsize, int, 0644);
121b285192aSMauro Carvalho Chehab module_param(enc_pcm_bufsize, int, 0644);
122b285192aSMauro Carvalho Chehab
123b285192aSMauro Carvalho Chehab module_param(enc_ts_bufs, int, 0644);
124b285192aSMauro Carvalho Chehab module_param(enc_mpg_bufs, int, 0644);
125b285192aSMauro Carvalho Chehab module_param(enc_idx_bufs, int, 0644);
126b285192aSMauro Carvalho Chehab module_param(enc_yuv_bufs, int, 0644);
127b285192aSMauro Carvalho Chehab module_param(enc_vbi_bufs, int, 0644);
128b285192aSMauro Carvalho Chehab module_param(enc_pcm_bufs, int, 0644);
129b285192aSMauro Carvalho Chehab
130b285192aSMauro Carvalho Chehab MODULE_PARM_DESC(tuner, "Tuner type selection,\n"
131b285192aSMauro Carvalho Chehab "\t\t\tsee tuner.h for values");
132b285192aSMauro Carvalho Chehab MODULE_PARM_DESC(radio,
133b285192aSMauro Carvalho Chehab "Enable or disable the radio. Use only if autodetection\n"
134b285192aSMauro Carvalho Chehab "\t\t\tfails. 0 = disable, 1 = enable");
135b285192aSMauro Carvalho Chehab MODULE_PARM_DESC(cardtype,
136b285192aSMauro Carvalho Chehab "Only use this option if your card is not detected properly.\n"
137b285192aSMauro Carvalho Chehab "\t\tSpecify card type:\n"
138b285192aSMauro Carvalho Chehab "\t\t\t 1 = Hauppauge HVR 1600 (ESMT memory)\n"
139b285192aSMauro Carvalho Chehab "\t\t\t 2 = Hauppauge HVR 1600 (Samsung memory)\n"
140b285192aSMauro Carvalho Chehab "\t\t\t 3 = Compro VideoMate H900\n"
141b285192aSMauro Carvalho Chehab "\t\t\t 4 = Yuan MPC718\n"
142b285192aSMauro Carvalho Chehab "\t\t\t 5 = Conexant Raptor PAL/SECAM\n"
143b285192aSMauro Carvalho Chehab "\t\t\t 6 = Toshiba Qosmio DVB-T/Analog\n"
144b285192aSMauro Carvalho Chehab "\t\t\t 7 = Leadtek WinFast PVR2100\n"
145b285192aSMauro Carvalho Chehab "\t\t\t 8 = Leadtek WinFast DVR3100 H\n"
146b285192aSMauro Carvalho Chehab "\t\t\t 9 = GoTView PCI DVD3 Hybrid\n"
147b285192aSMauro Carvalho Chehab "\t\t\t 10 = Hauppauge HVR 1600 (S5H1411)\n"
148b285192aSMauro Carvalho Chehab "\t\t\t 0 = Autodetect (default)\n"
149b285192aSMauro Carvalho Chehab "\t\t\t-1 = Ignore this card\n\t\t");
150b285192aSMauro Carvalho Chehab MODULE_PARM_DESC(pal, "Set PAL standard: B, G, H, D, K, I, M, N, Nc, 60");
151b285192aSMauro Carvalho Chehab MODULE_PARM_DESC(secam, "Set SECAM standard: B, G, H, D, K, L, LC");
152b285192aSMauro Carvalho Chehab MODULE_PARM_DESC(ntsc, "Set NTSC standard: M, J, K");
153b285192aSMauro Carvalho Chehab MODULE_PARM_DESC(debug,
154b285192aSMauro Carvalho Chehab "Debug level (bitmask). Default: 0\n"
155b285192aSMauro Carvalho Chehab "\t\t\t 1/0x0001: warning\n"
156b285192aSMauro Carvalho Chehab "\t\t\t 2/0x0002: info\n"
157b285192aSMauro Carvalho Chehab "\t\t\t 4/0x0004: mailbox\n"
158b285192aSMauro Carvalho Chehab "\t\t\t 8/0x0008: dma\n"
159b285192aSMauro Carvalho Chehab "\t\t\t 16/0x0010: ioctl\n"
160b285192aSMauro Carvalho Chehab "\t\t\t 32/0x0020: file\n"
161b285192aSMauro Carvalho Chehab "\t\t\t 64/0x0040: i2c\n"
162b285192aSMauro Carvalho Chehab "\t\t\t128/0x0080: irq\n"
163b285192aSMauro Carvalho Chehab "\t\t\t256/0x0100: high volume\n");
164b285192aSMauro Carvalho Chehab MODULE_PARM_DESC(cx18_pci_latency,
165b285192aSMauro Carvalho Chehab "Change the PCI latency to 64 if lower: 0 = No, 1 = Yes,\n"
166b285192aSMauro Carvalho Chehab "\t\t\tDefault: Yes");
167b285192aSMauro Carvalho Chehab MODULE_PARM_DESC(retry_mmio,
168b285192aSMauro Carvalho Chehab "(Deprecated) MMIO writes are now always checked and retried\n"
169b285192aSMauro Carvalho Chehab "\t\t\tEffectively: 1 [Yes]");
170b285192aSMauro Carvalho Chehab MODULE_PARM_DESC(mmio_ndelay,
171b285192aSMauro Carvalho Chehab "(Deprecated) MMIO accesses are now never purposely delayed\n"
172b285192aSMauro Carvalho Chehab "\t\t\tEffectively: 0 ns");
173b285192aSMauro Carvalho Chehab MODULE_PARM_DESC(enc_ts_buffers,
174b285192aSMauro Carvalho Chehab "Encoder TS buffer memory (MB). (enc_ts_bufs can override)\n"
175b285192aSMauro Carvalho Chehab "\t\t\tDefault: " __stringify(CX18_DEFAULT_ENC_TS_BUFFERS));
176b285192aSMauro Carvalho Chehab MODULE_PARM_DESC(enc_ts_bufsize,
177b285192aSMauro Carvalho Chehab "Size of an encoder TS buffer (kB)\n"
178b285192aSMauro Carvalho Chehab "\t\t\tDefault: " __stringify(CX18_DEFAULT_ENC_TS_BUFSIZE));
179b285192aSMauro Carvalho Chehab MODULE_PARM_DESC(enc_ts_bufs,
180b285192aSMauro Carvalho Chehab "Number of encoder TS buffers\n"
181b285192aSMauro Carvalho Chehab "\t\t\tDefault is computed from other enc_ts_* parameters");
182b285192aSMauro Carvalho Chehab MODULE_PARM_DESC(enc_mpg_buffers,
183b285192aSMauro Carvalho Chehab "Encoder MPG buffer memory (MB). (enc_mpg_bufs can override)\n"
184b285192aSMauro Carvalho Chehab "\t\t\tDefault: " __stringify(CX18_DEFAULT_ENC_MPG_BUFFERS));
185b285192aSMauro Carvalho Chehab MODULE_PARM_DESC(enc_mpg_bufsize,
186b285192aSMauro Carvalho Chehab "Size of an encoder MPG buffer (kB)\n"
187b285192aSMauro Carvalho Chehab "\t\t\tDefault: " __stringify(CX18_DEFAULT_ENC_MPG_BUFSIZE));
188b285192aSMauro Carvalho Chehab MODULE_PARM_DESC(enc_mpg_bufs,
189b285192aSMauro Carvalho Chehab "Number of encoder MPG buffers\n"
190b285192aSMauro Carvalho Chehab "\t\t\tDefault is computed from other enc_mpg_* parameters");
191b285192aSMauro Carvalho Chehab MODULE_PARM_DESC(enc_idx_buffers,
192b285192aSMauro Carvalho Chehab "(Deprecated) Encoder IDX buffer memory (MB)\n"
193b285192aSMauro Carvalho Chehab "\t\t\tIgnored, except 0 disables IDX buffer allocations\n"
194b285192aSMauro Carvalho Chehab "\t\t\tDefault: 1 [Enabled]");
195b285192aSMauro Carvalho Chehab MODULE_PARM_DESC(enc_idx_bufsize,
196b285192aSMauro Carvalho Chehab "Size of an encoder IDX buffer (kB)\n"
197b285192aSMauro Carvalho Chehab "\t\t\tAllowed values are multiples of 1.5 kB rounded up\n"
198b285192aSMauro Carvalho Chehab "\t\t\t(multiples of size required for 64 index entries)\n"
199b285192aSMauro Carvalho Chehab "\t\t\tDefault: 2");
200b285192aSMauro Carvalho Chehab MODULE_PARM_DESC(enc_idx_bufs,
201b285192aSMauro Carvalho Chehab "Number of encoder IDX buffers\n"
202b285192aSMauro Carvalho Chehab "\t\t\tDefault: " __stringify(CX18_MAX_FW_MDLS_PER_STREAM));
203b285192aSMauro Carvalho Chehab MODULE_PARM_DESC(enc_yuv_buffers,
204b285192aSMauro Carvalho Chehab "Encoder YUV buffer memory (MB). (enc_yuv_bufs can override)\n"
205b285192aSMauro Carvalho Chehab "\t\t\tDefault: " __stringify(CX18_DEFAULT_ENC_YUV_BUFFERS));
206b285192aSMauro Carvalho Chehab MODULE_PARM_DESC(enc_yuv_bufsize,
207b285192aSMauro Carvalho Chehab "Size of an encoder YUV buffer (kB)\n"
208b285192aSMauro Carvalho Chehab "\t\t\tAllowed values are multiples of 33.75 kB rounded up\n"
209b285192aSMauro Carvalho Chehab "\t\t\t(multiples of size required for 32 screen lines)\n"
210b285192aSMauro Carvalho Chehab "\t\t\tDefault: 102");
211b285192aSMauro Carvalho Chehab MODULE_PARM_DESC(enc_yuv_bufs,
212b285192aSMauro Carvalho Chehab "Number of encoder YUV buffers\n"
213b285192aSMauro Carvalho Chehab "\t\t\tDefault is computed from other enc_yuv_* parameters");
214b285192aSMauro Carvalho Chehab MODULE_PARM_DESC(enc_vbi_buffers,
215b285192aSMauro Carvalho Chehab "Encoder VBI buffer memory (MB). (enc_vbi_bufs can override)\n"
216b285192aSMauro Carvalho Chehab "\t\t\tDefault: " __stringify(CX18_DEFAULT_ENC_VBI_BUFFERS));
217b285192aSMauro Carvalho Chehab MODULE_PARM_DESC(enc_vbi_bufs,
218b285192aSMauro Carvalho Chehab "Number of encoder VBI buffers\n"
219b285192aSMauro Carvalho Chehab "\t\t\tDefault is computed from enc_vbi_buffers");
220b285192aSMauro Carvalho Chehab MODULE_PARM_DESC(enc_pcm_buffers,
221b285192aSMauro Carvalho Chehab "Encoder PCM buffer memory (MB). (enc_pcm_bufs can override)\n"
222b285192aSMauro Carvalho Chehab "\t\t\tDefault: " __stringify(CX18_DEFAULT_ENC_PCM_BUFFERS));
223b285192aSMauro Carvalho Chehab MODULE_PARM_DESC(enc_pcm_bufsize,
224b285192aSMauro Carvalho Chehab "Size of an encoder PCM buffer (kB)\n"
225b285192aSMauro Carvalho Chehab "\t\t\tDefault: " __stringify(CX18_DEFAULT_ENC_PCM_BUFSIZE));
226b285192aSMauro Carvalho Chehab MODULE_PARM_DESC(enc_pcm_bufs,
227b285192aSMauro Carvalho Chehab "Number of encoder PCM buffers\n"
228b285192aSMauro Carvalho Chehab "\t\t\tDefault is computed from other enc_pcm_* parameters");
229b285192aSMauro Carvalho Chehab
230b285192aSMauro Carvalho Chehab MODULE_PARM_DESC(cx18_first_minor,
231b285192aSMauro Carvalho Chehab "Set device node number assigned to first card");
232b285192aSMauro Carvalho Chehab
233b285192aSMauro Carvalho Chehab MODULE_AUTHOR("Hans Verkuil");
234b285192aSMauro Carvalho Chehab MODULE_DESCRIPTION("CX23418 driver");
235b285192aSMauro Carvalho Chehab MODULE_LICENSE("GPL");
236b285192aSMauro Carvalho Chehab
237b285192aSMauro Carvalho Chehab MODULE_VERSION(CX18_VERSION);
238b285192aSMauro Carvalho Chehab
239b285192aSMauro Carvalho Chehab #if defined(CONFIG_MODULES) && defined(MODULE)
request_module_async(struct work_struct * work)240b285192aSMauro Carvalho Chehab static void request_module_async(struct work_struct *work)
241b285192aSMauro Carvalho Chehab {
242b285192aSMauro Carvalho Chehab struct cx18 *dev = container_of(work, struct cx18, request_module_wk);
243b285192aSMauro Carvalho Chehab
244b285192aSMauro Carvalho Chehab /* Make sure cx18-alsa module is loaded */
245b285192aSMauro Carvalho Chehab request_module("cx18-alsa");
246b285192aSMauro Carvalho Chehab
247b285192aSMauro Carvalho Chehab /* Initialize cx18-alsa for this instance of the cx18 device */
248af28c996SMarkus Elfring if (cx18_ext_init)
249b285192aSMauro Carvalho Chehab cx18_ext_init(dev);
250b285192aSMauro Carvalho Chehab }
251b285192aSMauro Carvalho Chehab
request_modules(struct cx18 * dev)252b285192aSMauro Carvalho Chehab static void request_modules(struct cx18 *dev)
253b285192aSMauro Carvalho Chehab {
254b285192aSMauro Carvalho Chehab INIT_WORK(&dev->request_module_wk, request_module_async);
255b285192aSMauro Carvalho Chehab schedule_work(&dev->request_module_wk);
256b285192aSMauro Carvalho Chehab }
257b285192aSMauro Carvalho Chehab
flush_request_modules(struct cx18 * dev)258b285192aSMauro Carvalho Chehab static void flush_request_modules(struct cx18 *dev)
259b285192aSMauro Carvalho Chehab {
2600b8e74c6SLinus Torvalds flush_work(&dev->request_module_wk);
261b285192aSMauro Carvalho Chehab }
262b285192aSMauro Carvalho Chehab #else
263b285192aSMauro Carvalho Chehab #define request_modules(dev)
264b285192aSMauro Carvalho Chehab #define flush_request_modules(dev)
265b285192aSMauro Carvalho Chehab #endif /* CONFIG_MODULES */
266b285192aSMauro Carvalho Chehab
267b285192aSMauro Carvalho Chehab /* Generic utility functions */
cx18_msleep_timeout(unsigned int msecs,int intr)268b285192aSMauro Carvalho Chehab int cx18_msleep_timeout(unsigned int msecs, int intr)
269b285192aSMauro Carvalho Chehab {
270b285192aSMauro Carvalho Chehab long int timeout = msecs_to_jiffies(msecs);
271b285192aSMauro Carvalho Chehab int sig;
272b285192aSMauro Carvalho Chehab
273b285192aSMauro Carvalho Chehab do {
274b285192aSMauro Carvalho Chehab set_current_state(intr ? TASK_INTERRUPTIBLE : TASK_UNINTERRUPTIBLE);
275b285192aSMauro Carvalho Chehab timeout = schedule_timeout(timeout);
276b285192aSMauro Carvalho Chehab sig = intr ? signal_pending(current) : 0;
277b285192aSMauro Carvalho Chehab } while (!sig && timeout);
278b285192aSMauro Carvalho Chehab return sig;
279b285192aSMauro Carvalho Chehab }
280b285192aSMauro Carvalho Chehab
281b285192aSMauro Carvalho Chehab /* Release ioremapped memory */
cx18_iounmap(struct cx18 * cx)282b285192aSMauro Carvalho Chehab static void cx18_iounmap(struct cx18 *cx)
283b285192aSMauro Carvalho Chehab {
284af28c996SMarkus Elfring if (!cx)
285b285192aSMauro Carvalho Chehab return;
286b285192aSMauro Carvalho Chehab
287b285192aSMauro Carvalho Chehab /* Release io memory */
288af28c996SMarkus Elfring if (cx->enc_mem) {
289b285192aSMauro Carvalho Chehab CX18_DEBUG_INFO("releasing enc_mem\n");
290b285192aSMauro Carvalho Chehab iounmap(cx->enc_mem);
291b285192aSMauro Carvalho Chehab cx->enc_mem = NULL;
292b285192aSMauro Carvalho Chehab }
293b285192aSMauro Carvalho Chehab }
294b285192aSMauro Carvalho Chehab
cx18_eeprom_dump(struct cx18 * cx,unsigned char * eedata,int len)295b285192aSMauro Carvalho Chehab static void cx18_eeprom_dump(struct cx18 *cx, unsigned char *eedata, int len)
296b285192aSMauro Carvalho Chehab {
297b285192aSMauro Carvalho Chehab int i;
298b285192aSMauro Carvalho Chehab
299b285192aSMauro Carvalho Chehab CX18_INFO("eeprom dump:\n");
300b285192aSMauro Carvalho Chehab for (i = 0; i < len; i++) {
301b285192aSMauro Carvalho Chehab if (0 == (i % 16))
302b285192aSMauro Carvalho Chehab CX18_INFO("eeprom %02x:", i);
303b285192aSMauro Carvalho Chehab printk(KERN_CONT " %02x", eedata[i]);
304b285192aSMauro Carvalho Chehab if (15 == (i % 16))
305b285192aSMauro Carvalho Chehab printk(KERN_CONT "\n");
306b285192aSMauro Carvalho Chehab }
307b285192aSMauro Carvalho Chehab }
308b285192aSMauro Carvalho Chehab
309b285192aSMauro Carvalho Chehab /* Hauppauge card? get values from tveeprom */
cx18_read_eeprom(struct cx18 * cx,struct tveeprom * tv)310b285192aSMauro Carvalho Chehab void cx18_read_eeprom(struct cx18 *cx, struct tveeprom *tv)
311b285192aSMauro Carvalho Chehab {
3121d212cf0SMauro Carvalho Chehab struct i2c_client *c;
313b285192aSMauro Carvalho Chehab u8 eedata[256];
314b285192aSMauro Carvalho Chehab
315e351bf25SDan Carpenter memset(tv, 0, sizeof(*tv));
316e351bf25SDan Carpenter
3171d212cf0SMauro Carvalho Chehab c = kzalloc(sizeof(*c), GFP_KERNEL);
318e351bf25SDan Carpenter if (!c)
319e351bf25SDan Carpenter return;
3201d212cf0SMauro Carvalho Chehab
321c0decac1SMauro Carvalho Chehab strscpy(c->name, "cx18 tveeprom tmp", sizeof(c->name));
3221d212cf0SMauro Carvalho Chehab c->adapter = &cx->i2c_adap[0];
3231d212cf0SMauro Carvalho Chehab c->addr = 0xa0 >> 1;
324b285192aSMauro Carvalho Chehab
3251d212cf0SMauro Carvalho Chehab if (tveeprom_read(c, eedata, sizeof(eedata)))
3261d212cf0SMauro Carvalho Chehab goto ret;
327b285192aSMauro Carvalho Chehab
328b285192aSMauro Carvalho Chehab switch (cx->card->type) {
329b285192aSMauro Carvalho Chehab case CX18_CARD_HVR_1600_ESMT:
330b285192aSMauro Carvalho Chehab case CX18_CARD_HVR_1600_SAMSUNG:
331b285192aSMauro Carvalho Chehab case CX18_CARD_HVR_1600_S5H1411:
332446aba66SMauro Carvalho Chehab tveeprom_hauppauge_analog(tv, eedata);
333b285192aSMauro Carvalho Chehab break;
334b285192aSMauro Carvalho Chehab case CX18_CARD_YUAN_MPC718:
335b285192aSMauro Carvalho Chehab case CX18_CARD_GOTVIEW_PCI_DVD3:
336b285192aSMauro Carvalho Chehab tv->model = 0x718;
337b285192aSMauro Carvalho Chehab cx18_eeprom_dump(cx, eedata, sizeof(eedata));
338b285192aSMauro Carvalho Chehab CX18_INFO("eeprom PCI ID: %02x%02x:%02x%02x\n",
339b285192aSMauro Carvalho Chehab eedata[2], eedata[1], eedata[4], eedata[3]);
340b285192aSMauro Carvalho Chehab break;
341b285192aSMauro Carvalho Chehab default:
342b285192aSMauro Carvalho Chehab tv->model = 0xffffffff;
343b285192aSMauro Carvalho Chehab cx18_eeprom_dump(cx, eedata, sizeof(eedata));
344b285192aSMauro Carvalho Chehab break;
345b285192aSMauro Carvalho Chehab }
3461d212cf0SMauro Carvalho Chehab
3471d212cf0SMauro Carvalho Chehab ret:
3481d212cf0SMauro Carvalho Chehab kfree(c);
349b285192aSMauro Carvalho Chehab }
350b285192aSMauro Carvalho Chehab
cx18_process_eeprom(struct cx18 * cx)351b285192aSMauro Carvalho Chehab static void cx18_process_eeprom(struct cx18 *cx)
352b285192aSMauro Carvalho Chehab {
353b285192aSMauro Carvalho Chehab struct tveeprom tv;
354b285192aSMauro Carvalho Chehab
355b285192aSMauro Carvalho Chehab cx18_read_eeprom(cx, &tv);
356b285192aSMauro Carvalho Chehab
357b285192aSMauro Carvalho Chehab /* Many thanks to Steven Toth from Hauppauge for providing the
358b285192aSMauro Carvalho Chehab model numbers */
359b285192aSMauro Carvalho Chehab /* Note: the Samsung memory models cannot be reliably determined
360b285192aSMauro Carvalho Chehab from the model number. Use the cardtype module option if you
361b285192aSMauro Carvalho Chehab have one of these preproduction models. */
362b285192aSMauro Carvalho Chehab switch (tv.model) {
363b285192aSMauro Carvalho Chehab case 74301: /* Retail models */
364b285192aSMauro Carvalho Chehab case 74321:
365b285192aSMauro Carvalho Chehab case 74351: /* OEM models */
366b285192aSMauro Carvalho Chehab case 74361:
367b285192aSMauro Carvalho Chehab /* Digital side is s5h1411/tda18271 */
368b285192aSMauro Carvalho Chehab cx->card = cx18_get_card(CX18_CARD_HVR_1600_S5H1411);
369b285192aSMauro Carvalho Chehab break;
370b285192aSMauro Carvalho Chehab case 74021: /* Retail models */
371b285192aSMauro Carvalho Chehab case 74031:
372b285192aSMauro Carvalho Chehab case 74041:
373b285192aSMauro Carvalho Chehab case 74141:
374b285192aSMauro Carvalho Chehab case 74541: /* OEM models */
375b285192aSMauro Carvalho Chehab case 74551:
376b285192aSMauro Carvalho Chehab case 74591:
377b285192aSMauro Carvalho Chehab case 74651:
378b285192aSMauro Carvalho Chehab case 74691:
379b285192aSMauro Carvalho Chehab case 74751:
380b285192aSMauro Carvalho Chehab case 74891:
381b285192aSMauro Carvalho Chehab /* Digital side is s5h1409/mxl5005s */
382b285192aSMauro Carvalho Chehab cx->card = cx18_get_card(CX18_CARD_HVR_1600_ESMT);
383b285192aSMauro Carvalho Chehab break;
384b285192aSMauro Carvalho Chehab case 0x718:
385b285192aSMauro Carvalho Chehab return;
386b285192aSMauro Carvalho Chehab case 0xffffffff:
387b285192aSMauro Carvalho Chehab CX18_INFO("Unknown EEPROM encoding\n");
388b285192aSMauro Carvalho Chehab return;
389b285192aSMauro Carvalho Chehab case 0:
390b285192aSMauro Carvalho Chehab CX18_ERR("Invalid EEPROM\n");
391b285192aSMauro Carvalho Chehab return;
392b285192aSMauro Carvalho Chehab default:
3936beb1388SMauro Carvalho Chehab CX18_ERR("Unknown model %d, defaulting to original HVR-1600 (cardtype=1)\n",
3946beb1388SMauro Carvalho Chehab tv.model);
395b285192aSMauro Carvalho Chehab cx->card = cx18_get_card(CX18_CARD_HVR_1600_ESMT);
396b285192aSMauro Carvalho Chehab break;
397b285192aSMauro Carvalho Chehab }
398b285192aSMauro Carvalho Chehab
399b285192aSMauro Carvalho Chehab cx->v4l2_cap = cx->card->v4l2_capabilities;
400b285192aSMauro Carvalho Chehab cx->card_name = cx->card->name;
401b285192aSMauro Carvalho Chehab cx->card_i2c = cx->card->i2c;
402b285192aSMauro Carvalho Chehab
403b285192aSMauro Carvalho Chehab CX18_INFO("Autodetected %s\n", cx->card_name);
404b285192aSMauro Carvalho Chehab
405b285192aSMauro Carvalho Chehab if (tv.tuner_type == TUNER_ABSENT)
406b285192aSMauro Carvalho Chehab CX18_ERR("tveeprom cannot autodetect tuner!\n");
407b285192aSMauro Carvalho Chehab
408b285192aSMauro Carvalho Chehab if (cx->options.tuner == -1)
409b285192aSMauro Carvalho Chehab cx->options.tuner = tv.tuner_type;
410b285192aSMauro Carvalho Chehab if (cx->options.radio == -1)
411b285192aSMauro Carvalho Chehab cx->options.radio = (tv.has_radio != 0);
412b285192aSMauro Carvalho Chehab
413b285192aSMauro Carvalho Chehab if (cx->std != 0)
414b285192aSMauro Carvalho Chehab /* user specified tuner standard */
415b285192aSMauro Carvalho Chehab return;
416b285192aSMauro Carvalho Chehab
417b285192aSMauro Carvalho Chehab /* autodetect tuner standard */
418b285192aSMauro Carvalho Chehab #define TVEEPROM_TUNER_FORMAT_ALL (V4L2_STD_B | V4L2_STD_GH | \
419b285192aSMauro Carvalho Chehab V4L2_STD_MN | \
420b285192aSMauro Carvalho Chehab V4L2_STD_PAL_I | \
421b285192aSMauro Carvalho Chehab V4L2_STD_SECAM_L | V4L2_STD_SECAM_LC | \
422b285192aSMauro Carvalho Chehab V4L2_STD_DK)
423b285192aSMauro Carvalho Chehab if ((tv.tuner_formats & TVEEPROM_TUNER_FORMAT_ALL)
424b285192aSMauro Carvalho Chehab == TVEEPROM_TUNER_FORMAT_ALL) {
425b285192aSMauro Carvalho Chehab CX18_DEBUG_INFO("Worldwide tuner detected\n");
426b285192aSMauro Carvalho Chehab cx->std = V4L2_STD_ALL;
427b285192aSMauro Carvalho Chehab } else if (tv.tuner_formats & V4L2_STD_PAL) {
428b285192aSMauro Carvalho Chehab CX18_DEBUG_INFO("PAL tuner detected\n");
429b285192aSMauro Carvalho Chehab cx->std |= V4L2_STD_PAL_BG | V4L2_STD_PAL_H;
430b285192aSMauro Carvalho Chehab } else if (tv.tuner_formats & V4L2_STD_NTSC) {
431b285192aSMauro Carvalho Chehab CX18_DEBUG_INFO("NTSC tuner detected\n");
432b285192aSMauro Carvalho Chehab cx->std |= V4L2_STD_NTSC_M;
433b285192aSMauro Carvalho Chehab } else if (tv.tuner_formats & V4L2_STD_SECAM) {
434b285192aSMauro Carvalho Chehab CX18_DEBUG_INFO("SECAM tuner detected\n");
435b285192aSMauro Carvalho Chehab cx->std |= V4L2_STD_SECAM_L;
436b285192aSMauro Carvalho Chehab } else {
437b285192aSMauro Carvalho Chehab CX18_INFO("No tuner detected, default to NTSC-M\n");
438b285192aSMauro Carvalho Chehab cx->std |= V4L2_STD_NTSC_M;
439b285192aSMauro Carvalho Chehab }
440b285192aSMauro Carvalho Chehab }
441b285192aSMauro Carvalho Chehab
cx18_parse_std(struct cx18 * cx)442b285192aSMauro Carvalho Chehab static v4l2_std_id cx18_parse_std(struct cx18 *cx)
443b285192aSMauro Carvalho Chehab {
444b285192aSMauro Carvalho Chehab switch (pal[0]) {
445b285192aSMauro Carvalho Chehab case '6':
446b285192aSMauro Carvalho Chehab return V4L2_STD_PAL_60;
447b285192aSMauro Carvalho Chehab case 'b':
448b285192aSMauro Carvalho Chehab case 'B':
449b285192aSMauro Carvalho Chehab case 'g':
450b285192aSMauro Carvalho Chehab case 'G':
451b285192aSMauro Carvalho Chehab return V4L2_STD_PAL_BG;
452b285192aSMauro Carvalho Chehab case 'h':
453b285192aSMauro Carvalho Chehab case 'H':
454b285192aSMauro Carvalho Chehab return V4L2_STD_PAL_H;
455b285192aSMauro Carvalho Chehab case 'n':
456b285192aSMauro Carvalho Chehab case 'N':
457b285192aSMauro Carvalho Chehab if (pal[1] == 'c' || pal[1] == 'C')
458b285192aSMauro Carvalho Chehab return V4L2_STD_PAL_Nc;
459b285192aSMauro Carvalho Chehab return V4L2_STD_PAL_N;
460b285192aSMauro Carvalho Chehab case 'i':
461b285192aSMauro Carvalho Chehab case 'I':
462b285192aSMauro Carvalho Chehab return V4L2_STD_PAL_I;
463b285192aSMauro Carvalho Chehab case 'd':
464b285192aSMauro Carvalho Chehab case 'D':
465b285192aSMauro Carvalho Chehab case 'k':
466b285192aSMauro Carvalho Chehab case 'K':
467b285192aSMauro Carvalho Chehab return V4L2_STD_PAL_DK;
468b285192aSMauro Carvalho Chehab case 'M':
469b285192aSMauro Carvalho Chehab case 'm':
470b285192aSMauro Carvalho Chehab return V4L2_STD_PAL_M;
471b285192aSMauro Carvalho Chehab case '-':
472b285192aSMauro Carvalho Chehab break;
473b285192aSMauro Carvalho Chehab default:
474b285192aSMauro Carvalho Chehab CX18_WARN("pal= argument not recognised\n");
475b285192aSMauro Carvalho Chehab return 0;
476b285192aSMauro Carvalho Chehab }
477b285192aSMauro Carvalho Chehab
478b285192aSMauro Carvalho Chehab switch (secam[0]) {
479b285192aSMauro Carvalho Chehab case 'b':
480b285192aSMauro Carvalho Chehab case 'B':
481b285192aSMauro Carvalho Chehab case 'g':
482b285192aSMauro Carvalho Chehab case 'G':
483b285192aSMauro Carvalho Chehab case 'h':
484b285192aSMauro Carvalho Chehab case 'H':
485b285192aSMauro Carvalho Chehab return V4L2_STD_SECAM_B | V4L2_STD_SECAM_G | V4L2_STD_SECAM_H;
486b285192aSMauro Carvalho Chehab case 'd':
487b285192aSMauro Carvalho Chehab case 'D':
488b285192aSMauro Carvalho Chehab case 'k':
489b285192aSMauro Carvalho Chehab case 'K':
490b285192aSMauro Carvalho Chehab return V4L2_STD_SECAM_DK;
491b285192aSMauro Carvalho Chehab case 'l':
492b285192aSMauro Carvalho Chehab case 'L':
493b285192aSMauro Carvalho Chehab if (secam[1] == 'C' || secam[1] == 'c')
494b285192aSMauro Carvalho Chehab return V4L2_STD_SECAM_LC;
495b285192aSMauro Carvalho Chehab return V4L2_STD_SECAM_L;
496b285192aSMauro Carvalho Chehab case '-':
497b285192aSMauro Carvalho Chehab break;
498b285192aSMauro Carvalho Chehab default:
499b285192aSMauro Carvalho Chehab CX18_WARN("secam= argument not recognised\n");
500b285192aSMauro Carvalho Chehab return 0;
501b285192aSMauro Carvalho Chehab }
502b285192aSMauro Carvalho Chehab
503b285192aSMauro Carvalho Chehab switch (ntsc[0]) {
504b285192aSMauro Carvalho Chehab case 'm':
505b285192aSMauro Carvalho Chehab case 'M':
506b285192aSMauro Carvalho Chehab return V4L2_STD_NTSC_M;
507b285192aSMauro Carvalho Chehab case 'j':
508b285192aSMauro Carvalho Chehab case 'J':
509b285192aSMauro Carvalho Chehab return V4L2_STD_NTSC_M_JP;
510b285192aSMauro Carvalho Chehab case 'k':
511b285192aSMauro Carvalho Chehab case 'K':
512b285192aSMauro Carvalho Chehab return V4L2_STD_NTSC_M_KR;
513b285192aSMauro Carvalho Chehab case '-':
514b285192aSMauro Carvalho Chehab break;
515b285192aSMauro Carvalho Chehab default:
516b285192aSMauro Carvalho Chehab CX18_WARN("ntsc= argument not recognised\n");
517b285192aSMauro Carvalho Chehab return 0;
518b285192aSMauro Carvalho Chehab }
519b285192aSMauro Carvalho Chehab
520b285192aSMauro Carvalho Chehab /* no match found */
521b285192aSMauro Carvalho Chehab return 0;
522b285192aSMauro Carvalho Chehab }
523b285192aSMauro Carvalho Chehab
cx18_process_options(struct cx18 * cx)524b285192aSMauro Carvalho Chehab static void cx18_process_options(struct cx18 *cx)
525b285192aSMauro Carvalho Chehab {
526b285192aSMauro Carvalho Chehab int i, j;
527b285192aSMauro Carvalho Chehab
528b285192aSMauro Carvalho Chehab cx->options.megabytes[CX18_ENC_STREAM_TYPE_TS] = enc_ts_buffers;
529b285192aSMauro Carvalho Chehab cx->options.megabytes[CX18_ENC_STREAM_TYPE_MPG] = enc_mpg_buffers;
530b285192aSMauro Carvalho Chehab cx->options.megabytes[CX18_ENC_STREAM_TYPE_IDX] = enc_idx_buffers;
531b285192aSMauro Carvalho Chehab cx->options.megabytes[CX18_ENC_STREAM_TYPE_YUV] = enc_yuv_buffers;
532b285192aSMauro Carvalho Chehab cx->options.megabytes[CX18_ENC_STREAM_TYPE_VBI] = enc_vbi_buffers;
533b285192aSMauro Carvalho Chehab cx->options.megabytes[CX18_ENC_STREAM_TYPE_PCM] = enc_pcm_buffers;
534b285192aSMauro Carvalho Chehab cx->options.megabytes[CX18_ENC_STREAM_TYPE_RAD] = 0; /* control only */
535b285192aSMauro Carvalho Chehab
536b285192aSMauro Carvalho Chehab cx->stream_buffers[CX18_ENC_STREAM_TYPE_TS] = enc_ts_bufs;
537b285192aSMauro Carvalho Chehab cx->stream_buffers[CX18_ENC_STREAM_TYPE_MPG] = enc_mpg_bufs;
538b285192aSMauro Carvalho Chehab cx->stream_buffers[CX18_ENC_STREAM_TYPE_IDX] = enc_idx_bufs;
539b285192aSMauro Carvalho Chehab cx->stream_buffers[CX18_ENC_STREAM_TYPE_YUV] = enc_yuv_bufs;
540b285192aSMauro Carvalho Chehab cx->stream_buffers[CX18_ENC_STREAM_TYPE_VBI] = enc_vbi_bufs;
541b285192aSMauro Carvalho Chehab cx->stream_buffers[CX18_ENC_STREAM_TYPE_PCM] = enc_pcm_bufs;
542b285192aSMauro Carvalho Chehab cx->stream_buffers[CX18_ENC_STREAM_TYPE_RAD] = 0; /* control, no data */
543b285192aSMauro Carvalho Chehab
544b285192aSMauro Carvalho Chehab cx->stream_buf_size[CX18_ENC_STREAM_TYPE_TS] = enc_ts_bufsize;
545b285192aSMauro Carvalho Chehab cx->stream_buf_size[CX18_ENC_STREAM_TYPE_MPG] = enc_mpg_bufsize;
546b285192aSMauro Carvalho Chehab cx->stream_buf_size[CX18_ENC_STREAM_TYPE_IDX] = enc_idx_bufsize;
547b285192aSMauro Carvalho Chehab cx->stream_buf_size[CX18_ENC_STREAM_TYPE_YUV] = enc_yuv_bufsize;
548318de791SMauro Carvalho Chehab cx->stream_buf_size[CX18_ENC_STREAM_TYPE_VBI] = VBI_ACTIVE_SAMPLES * 36;
549b285192aSMauro Carvalho Chehab cx->stream_buf_size[CX18_ENC_STREAM_TYPE_PCM] = enc_pcm_bufsize;
550b285192aSMauro Carvalho Chehab cx->stream_buf_size[CX18_ENC_STREAM_TYPE_RAD] = 0; /* control no data */
551b285192aSMauro Carvalho Chehab
552b285192aSMauro Carvalho Chehab /* Ensure stream_buffers & stream_buf_size are valid */
553b285192aSMauro Carvalho Chehab for (i = 0; i < CX18_MAX_STREAMS; i++) {
554b285192aSMauro Carvalho Chehab if (cx->stream_buffers[i] == 0 || /* User said 0 buffers */
555b285192aSMauro Carvalho Chehab cx->options.megabytes[i] <= 0 || /* User said 0 MB total */
556b285192aSMauro Carvalho Chehab cx->stream_buf_size[i] <= 0) { /* User said buf size 0 */
557b285192aSMauro Carvalho Chehab cx->options.megabytes[i] = 0;
558b285192aSMauro Carvalho Chehab cx->stream_buffers[i] = 0;
559b285192aSMauro Carvalho Chehab cx->stream_buf_size[i] = 0;
560b285192aSMauro Carvalho Chehab continue;
561b285192aSMauro Carvalho Chehab }
562b285192aSMauro Carvalho Chehab /*
563b285192aSMauro Carvalho Chehab * YUV is a special case where the stream_buf_size needs to be
564b285192aSMauro Carvalho Chehab * an integral multiple of 33.75 kB (storage for 32 screens
565b285192aSMauro Carvalho Chehab * lines to maintain alignment in case of lost buffers).
566b285192aSMauro Carvalho Chehab *
567b285192aSMauro Carvalho Chehab * IDX is a special case where the stream_buf_size should be
568b285192aSMauro Carvalho Chehab * an integral multiple of 1.5 kB (storage for 64 index entries
569b285192aSMauro Carvalho Chehab * to maintain alignment in case of lost buffers).
570b285192aSMauro Carvalho Chehab *
571b285192aSMauro Carvalho Chehab */
572b285192aSMauro Carvalho Chehab if (i == CX18_ENC_STREAM_TYPE_YUV) {
573b285192aSMauro Carvalho Chehab cx->stream_buf_size[i] *= 1024;
574b285192aSMauro Carvalho Chehab cx->stream_buf_size[i] -=
575b285192aSMauro Carvalho Chehab (cx->stream_buf_size[i] % CX18_UNIT_ENC_YUV_BUFSIZE);
576b285192aSMauro Carvalho Chehab
577b285192aSMauro Carvalho Chehab if (cx->stream_buf_size[i] < CX18_UNIT_ENC_YUV_BUFSIZE)
578b285192aSMauro Carvalho Chehab cx->stream_buf_size[i] =
579b285192aSMauro Carvalho Chehab CX18_UNIT_ENC_YUV_BUFSIZE;
580b285192aSMauro Carvalho Chehab } else if (i == CX18_ENC_STREAM_TYPE_IDX) {
581b285192aSMauro Carvalho Chehab cx->stream_buf_size[i] *= 1024;
582b285192aSMauro Carvalho Chehab cx->stream_buf_size[i] -=
583b285192aSMauro Carvalho Chehab (cx->stream_buf_size[i] % CX18_UNIT_ENC_IDX_BUFSIZE);
584b285192aSMauro Carvalho Chehab
585b285192aSMauro Carvalho Chehab if (cx->stream_buf_size[i] < CX18_UNIT_ENC_IDX_BUFSIZE)
586b285192aSMauro Carvalho Chehab cx->stream_buf_size[i] =
587b285192aSMauro Carvalho Chehab CX18_UNIT_ENC_IDX_BUFSIZE;
588b285192aSMauro Carvalho Chehab }
589b285192aSMauro Carvalho Chehab /*
590b285192aSMauro Carvalho Chehab * YUV and IDX are special cases where the stream_buf_size is
591b285192aSMauro Carvalho Chehab * now in bytes.
592b285192aSMauro Carvalho Chehab * VBI is a special case where the stream_buf_size is fixed
593b285192aSMauro Carvalho Chehab * and already in bytes
594b285192aSMauro Carvalho Chehab */
595b285192aSMauro Carvalho Chehab if (i == CX18_ENC_STREAM_TYPE_VBI ||
596b285192aSMauro Carvalho Chehab i == CX18_ENC_STREAM_TYPE_YUV ||
597b285192aSMauro Carvalho Chehab i == CX18_ENC_STREAM_TYPE_IDX) {
598b285192aSMauro Carvalho Chehab if (cx->stream_buffers[i] < 0) {
599b285192aSMauro Carvalho Chehab cx->stream_buffers[i] =
600b285192aSMauro Carvalho Chehab cx->options.megabytes[i] * 1024 * 1024
601b285192aSMauro Carvalho Chehab / cx->stream_buf_size[i];
602b285192aSMauro Carvalho Chehab } else {
603b285192aSMauro Carvalho Chehab /* N.B. This might round down to 0 */
604b285192aSMauro Carvalho Chehab cx->options.megabytes[i] =
605b285192aSMauro Carvalho Chehab cx->stream_buffers[i]
606b285192aSMauro Carvalho Chehab * cx->stream_buf_size[i]/(1024 * 1024);
607b285192aSMauro Carvalho Chehab }
608b285192aSMauro Carvalho Chehab } else {
609b285192aSMauro Carvalho Chehab /* All other streams have stream_buf_size in kB here */
610b285192aSMauro Carvalho Chehab if (cx->stream_buffers[i] < 0) {
611b285192aSMauro Carvalho Chehab cx->stream_buffers[i] =
612b285192aSMauro Carvalho Chehab cx->options.megabytes[i] * 1024
613b285192aSMauro Carvalho Chehab / cx->stream_buf_size[i];
614b285192aSMauro Carvalho Chehab } else {
615b285192aSMauro Carvalho Chehab /* N.B. This might round down to 0 */
616b285192aSMauro Carvalho Chehab cx->options.megabytes[i] =
617b285192aSMauro Carvalho Chehab cx->stream_buffers[i]
618b285192aSMauro Carvalho Chehab * cx->stream_buf_size[i] / 1024;
619b285192aSMauro Carvalho Chehab }
620b285192aSMauro Carvalho Chehab /* convert from kB to bytes */
621b285192aSMauro Carvalho Chehab cx->stream_buf_size[i] *= 1024;
622b285192aSMauro Carvalho Chehab }
6236beb1388SMauro Carvalho Chehab CX18_DEBUG_INFO("Stream type %d options: %d MB, %d buffers, %d bytes\n",
6246beb1388SMauro Carvalho Chehab i, cx->options.megabytes[i],
625b285192aSMauro Carvalho Chehab cx->stream_buffers[i], cx->stream_buf_size[i]);
626b285192aSMauro Carvalho Chehab }
627b285192aSMauro Carvalho Chehab
628b285192aSMauro Carvalho Chehab cx->options.cardtype = cardtype[cx->instance];
629b285192aSMauro Carvalho Chehab cx->options.tuner = tuner[cx->instance];
630b285192aSMauro Carvalho Chehab cx->options.radio = radio[cx->instance];
631b285192aSMauro Carvalho Chehab
632b285192aSMauro Carvalho Chehab cx->std = cx18_parse_std(cx);
633b285192aSMauro Carvalho Chehab if (cx->options.cardtype == -1) {
634b285192aSMauro Carvalho Chehab CX18_INFO("Ignore card\n");
635b285192aSMauro Carvalho Chehab return;
636b285192aSMauro Carvalho Chehab }
637b285192aSMauro Carvalho Chehab cx->card = cx18_get_card(cx->options.cardtype - 1);
638b285192aSMauro Carvalho Chehab if (cx->card)
639b285192aSMauro Carvalho Chehab CX18_INFO("User specified %s card\n", cx->card->name);
640b285192aSMauro Carvalho Chehab else if (cx->options.cardtype != 0)
641b285192aSMauro Carvalho Chehab CX18_ERR("Unknown user specified type, trying to autodetect card\n");
642af28c996SMarkus Elfring if (!cx->card) {
643b285192aSMauro Carvalho Chehab if (cx->pci_dev->subsystem_vendor == CX18_PCI_ID_HAUPPAUGE) {
644b285192aSMauro Carvalho Chehab cx->card = cx18_get_card(CX18_CARD_HVR_1600_ESMT);
645b285192aSMauro Carvalho Chehab CX18_INFO("Autodetected Hauppauge card\n");
646b285192aSMauro Carvalho Chehab }
647b285192aSMauro Carvalho Chehab }
648af28c996SMarkus Elfring if (!cx->card) {
649b285192aSMauro Carvalho Chehab for (i = 0; (cx->card = cx18_get_card(i)); i++) {
650af28c996SMarkus Elfring if (!cx->card->pci_list)
651b285192aSMauro Carvalho Chehab continue;
652b285192aSMauro Carvalho Chehab for (j = 0; cx->card->pci_list[j].device; j++) {
653b285192aSMauro Carvalho Chehab if (cx->pci_dev->device !=
654b285192aSMauro Carvalho Chehab cx->card->pci_list[j].device)
655b285192aSMauro Carvalho Chehab continue;
656b285192aSMauro Carvalho Chehab if (cx->pci_dev->subsystem_vendor !=
657b285192aSMauro Carvalho Chehab cx->card->pci_list[j].subsystem_vendor)
658b285192aSMauro Carvalho Chehab continue;
659b285192aSMauro Carvalho Chehab if (cx->pci_dev->subsystem_device !=
660b285192aSMauro Carvalho Chehab cx->card->pci_list[j].subsystem_device)
661b285192aSMauro Carvalho Chehab continue;
662b285192aSMauro Carvalho Chehab CX18_INFO("Autodetected %s card\n", cx->card->name);
663b285192aSMauro Carvalho Chehab goto done;
664b285192aSMauro Carvalho Chehab }
665b285192aSMauro Carvalho Chehab }
666b285192aSMauro Carvalho Chehab }
667b285192aSMauro Carvalho Chehab done:
668b285192aSMauro Carvalho Chehab
669af28c996SMarkus Elfring if (!cx->card) {
670b285192aSMauro Carvalho Chehab cx->card = cx18_get_card(CX18_CARD_HVR_1600_ESMT);
671b285192aSMauro Carvalho Chehab CX18_ERR("Unknown card: vendor/device: [%04x:%04x]\n",
672b285192aSMauro Carvalho Chehab cx->pci_dev->vendor, cx->pci_dev->device);
673b285192aSMauro Carvalho Chehab CX18_ERR(" subsystem vendor/device: [%04x:%04x]\n",
674b285192aSMauro Carvalho Chehab cx->pci_dev->subsystem_vendor,
675b285192aSMauro Carvalho Chehab cx->pci_dev->subsystem_device);
676b285192aSMauro Carvalho Chehab CX18_ERR("Defaulting to %s card\n", cx->card->name);
677b285192aSMauro Carvalho Chehab CX18_ERR("Please mail the vendor/device and subsystem vendor/device IDs and what kind of\n");
67855f240a2SHans Verkuil CX18_ERR("card you have to the linux-media mailinglist (www.linuxtv.org)\n");
679b285192aSMauro Carvalho Chehab CX18_ERR("Prefix your subject line with [UNKNOWN CX18 CARD].\n");
680b285192aSMauro Carvalho Chehab }
681b285192aSMauro Carvalho Chehab cx->v4l2_cap = cx->card->v4l2_capabilities;
682b285192aSMauro Carvalho Chehab cx->card_name = cx->card->name;
683b285192aSMauro Carvalho Chehab cx->card_i2c = cx->card->i2c;
684b285192aSMauro Carvalho Chehab }
685b285192aSMauro Carvalho Chehab
cx18_create_in_workq(struct cx18 * cx)6864c62e976SGreg Kroah-Hartman static int cx18_create_in_workq(struct cx18 *cx)
687b285192aSMauro Carvalho Chehab {
688b285192aSMauro Carvalho Chehab snprintf(cx->in_workq_name, sizeof(cx->in_workq_name), "%s-in",
689b285192aSMauro Carvalho Chehab cx->v4l2_dev.name);
690d8537548SKees Cook cx->in_work_queue = alloc_ordered_workqueue("%s", 0, cx->in_workq_name);
691af28c996SMarkus Elfring if (!cx->in_work_queue) {
692b285192aSMauro Carvalho Chehab CX18_ERR("Unable to create incoming mailbox handler thread\n");
693b285192aSMauro Carvalho Chehab return -ENOMEM;
694b285192aSMauro Carvalho Chehab }
695b285192aSMauro Carvalho Chehab return 0;
696b285192aSMauro Carvalho Chehab }
697b285192aSMauro Carvalho Chehab
cx18_init_in_work_orders(struct cx18 * cx)6984c62e976SGreg Kroah-Hartman static void cx18_init_in_work_orders(struct cx18 *cx)
699b285192aSMauro Carvalho Chehab {
700b285192aSMauro Carvalho Chehab int i;
701b285192aSMauro Carvalho Chehab for (i = 0; i < CX18_MAX_IN_WORK_ORDERS; i++) {
702b285192aSMauro Carvalho Chehab cx->in_work_order[i].cx = cx;
703b285192aSMauro Carvalho Chehab cx->in_work_order[i].str = cx->epu_debug_str;
704b285192aSMauro Carvalho Chehab INIT_WORK(&cx->in_work_order[i].work, cx18_in_work_handler);
705b285192aSMauro Carvalho Chehab }
706b285192aSMauro Carvalho Chehab }
707b285192aSMauro Carvalho Chehab
708b285192aSMauro Carvalho Chehab /* Precondition: the cx18 structure has been memset to 0. Only
709b285192aSMauro Carvalho Chehab the dev and instance fields have been filled in.
710b285192aSMauro Carvalho Chehab No assumptions on the card type may be made here (see cx18_init_struct2
711b285192aSMauro Carvalho Chehab for that).
712b285192aSMauro Carvalho Chehab */
cx18_init_struct1(struct cx18 * cx)7134c62e976SGreg Kroah-Hartman static int cx18_init_struct1(struct cx18 *cx)
714b285192aSMauro Carvalho Chehab {
715b285192aSMauro Carvalho Chehab int ret;
716b285192aSMauro Carvalho Chehab
717b285192aSMauro Carvalho Chehab cx->base_addr = pci_resource_start(cx->pci_dev, 0);
718b285192aSMauro Carvalho Chehab
719b285192aSMauro Carvalho Chehab mutex_init(&cx->serialize_lock);
720b285192aSMauro Carvalho Chehab mutex_init(&cx->gpio_lock);
721b285192aSMauro Carvalho Chehab mutex_init(&cx->epu2apu_mb_lock);
722b285192aSMauro Carvalho Chehab mutex_init(&cx->epu2cpu_mb_lock);
723b285192aSMauro Carvalho Chehab
724b285192aSMauro Carvalho Chehab ret = cx18_create_in_workq(cx);
725b285192aSMauro Carvalho Chehab if (ret)
726b285192aSMauro Carvalho Chehab return ret;
727b285192aSMauro Carvalho Chehab
728b285192aSMauro Carvalho Chehab cx18_init_in_work_orders(cx);
729b285192aSMauro Carvalho Chehab
730b285192aSMauro Carvalho Chehab /* start counting open_id at 1 */
731b285192aSMauro Carvalho Chehab cx->open_id = 1;
732b285192aSMauro Carvalho Chehab
733b285192aSMauro Carvalho Chehab /* Initial settings */
734b285192aSMauro Carvalho Chehab cx->cxhdl.port = CX2341X_PORT_MEMORY;
735b285192aSMauro Carvalho Chehab cx->cxhdl.capabilities = CX2341X_CAP_HAS_TS | CX2341X_CAP_HAS_SLICED_VBI;
736b285192aSMauro Carvalho Chehab cx->cxhdl.ops = &cx18_cxhdl_ops;
737b285192aSMauro Carvalho Chehab cx->cxhdl.func = cx18_api_func;
738b285192aSMauro Carvalho Chehab cx->cxhdl.priv = &cx->streams[CX18_ENC_STREAM_TYPE_MPG];
739b285192aSMauro Carvalho Chehab ret = cx2341x_handler_init(&cx->cxhdl, 50);
740b285192aSMauro Carvalho Chehab if (ret)
741b285192aSMauro Carvalho Chehab return ret;
742b285192aSMauro Carvalho Chehab cx->v4l2_dev.ctrl_handler = &cx->cxhdl.hdl;
743b285192aSMauro Carvalho Chehab
744b285192aSMauro Carvalho Chehab cx->temporal_strength = cx->cxhdl.video_temporal_filter->cur.val;
745b285192aSMauro Carvalho Chehab cx->spatial_strength = cx->cxhdl.video_spatial_filter->cur.val;
746b285192aSMauro Carvalho Chehab cx->filter_mode = cx->cxhdl.video_spatial_filter_mode->cur.val |
747b285192aSMauro Carvalho Chehab (cx->cxhdl.video_temporal_filter_mode->cur.val << 1) |
748b285192aSMauro Carvalho Chehab (cx->cxhdl.video_median_filter_type->cur.val << 2);
749b285192aSMauro Carvalho Chehab
750b285192aSMauro Carvalho Chehab init_waitqueue_head(&cx->cap_w);
751b285192aSMauro Carvalho Chehab init_waitqueue_head(&cx->mb_apu_waitq);
752b285192aSMauro Carvalho Chehab init_waitqueue_head(&cx->mb_cpu_waitq);
753b285192aSMauro Carvalho Chehab init_waitqueue_head(&cx->dma_waitq);
754b285192aSMauro Carvalho Chehab
755b285192aSMauro Carvalho Chehab /* VBI */
756b285192aSMauro Carvalho Chehab cx->vbi.in.type = V4L2_BUF_TYPE_VBI_CAPTURE;
757b285192aSMauro Carvalho Chehab cx->vbi.sliced_in = &cx->vbi.in.fmt.sliced;
758b285192aSMauro Carvalho Chehab
759b285192aSMauro Carvalho Chehab /* IVTV style VBI insertion into MPEG streams */
760b285192aSMauro Carvalho Chehab INIT_LIST_HEAD(&cx->vbi.sliced_mpeg_buf.list);
761b285192aSMauro Carvalho Chehab INIT_LIST_HEAD(&cx->vbi.sliced_mpeg_mdl.list);
762b285192aSMauro Carvalho Chehab INIT_LIST_HEAD(&cx->vbi.sliced_mpeg_mdl.buf_list);
763b285192aSMauro Carvalho Chehab list_add(&cx->vbi.sliced_mpeg_buf.list,
764b285192aSMauro Carvalho Chehab &cx->vbi.sliced_mpeg_mdl.buf_list);
765b285192aSMauro Carvalho Chehab return 0;
766b285192aSMauro Carvalho Chehab }
767b285192aSMauro Carvalho Chehab
768b285192aSMauro Carvalho Chehab /* Second initialization part. Here the card type has been
769b285192aSMauro Carvalho Chehab autodetected. */
cx18_init_struct2(struct cx18 * cx)7704c62e976SGreg Kroah-Hartman static void cx18_init_struct2(struct cx18 *cx)
771b285192aSMauro Carvalho Chehab {
772b285192aSMauro Carvalho Chehab int i;
773b285192aSMauro Carvalho Chehab
774*274cb009SHans Verkuil for (i = 0; i < CX18_CARD_MAX_VIDEO_INPUTS; i++)
775b285192aSMauro Carvalho Chehab if (cx->card->video_inputs[i].video_type == 0)
776b285192aSMauro Carvalho Chehab break;
777b285192aSMauro Carvalho Chehab cx->nof_inputs = i;
778*274cb009SHans Verkuil for (i = 0; i < CX18_CARD_MAX_AUDIO_INPUTS; i++)
779b285192aSMauro Carvalho Chehab if (cx->card->audio_inputs[i].audio_type == 0)
780b285192aSMauro Carvalho Chehab break;
781b285192aSMauro Carvalho Chehab cx->nof_audio_inputs = i;
782b285192aSMauro Carvalho Chehab
783b285192aSMauro Carvalho Chehab /* Find tuner input */
784b285192aSMauro Carvalho Chehab for (i = 0; i < cx->nof_inputs; i++) {
785b285192aSMauro Carvalho Chehab if (cx->card->video_inputs[i].video_type ==
786b285192aSMauro Carvalho Chehab CX18_CARD_INPUT_VID_TUNER)
787b285192aSMauro Carvalho Chehab break;
788b285192aSMauro Carvalho Chehab }
789b285192aSMauro Carvalho Chehab if (i == cx->nof_inputs)
790b285192aSMauro Carvalho Chehab i = 0;
791b285192aSMauro Carvalho Chehab cx->active_input = i;
792b285192aSMauro Carvalho Chehab cx->audio_input = cx->card->video_inputs[i].audio_index;
793b285192aSMauro Carvalho Chehab }
794b285192aSMauro Carvalho Chehab
cx18_setup_pci(struct cx18 * cx,struct pci_dev * pci_dev,const struct pci_device_id * pci_id)795b285192aSMauro Carvalho Chehab static int cx18_setup_pci(struct cx18 *cx, struct pci_dev *pci_dev,
796b285192aSMauro Carvalho Chehab const struct pci_device_id *pci_id)
797b285192aSMauro Carvalho Chehab {
798b285192aSMauro Carvalho Chehab u16 cmd;
799b285192aSMauro Carvalho Chehab unsigned char pci_latency;
800b285192aSMauro Carvalho Chehab
801b285192aSMauro Carvalho Chehab CX18_DEBUG_INFO("Enabling pci device\n");
802b285192aSMauro Carvalho Chehab
803b285192aSMauro Carvalho Chehab if (pci_enable_device(pci_dev)) {
804b285192aSMauro Carvalho Chehab CX18_ERR("Can't enable device %d!\n", cx->instance);
805b285192aSMauro Carvalho Chehab return -EIO;
806b285192aSMauro Carvalho Chehab }
807887069f4SChristophe JAILLET if (dma_set_mask(&pci_dev->dev, DMA_BIT_MASK(32))) {
808b285192aSMauro Carvalho Chehab CX18_ERR("No suitable DMA available, card %d\n", cx->instance);
809b285192aSMauro Carvalho Chehab return -EIO;
810b285192aSMauro Carvalho Chehab }
811b285192aSMauro Carvalho Chehab if (!request_mem_region(cx->base_addr, CX18_MEM_SIZE, "cx18 encoder")) {
812b285192aSMauro Carvalho Chehab CX18_ERR("Cannot request encoder memory region, card %d\n",
813b285192aSMauro Carvalho Chehab cx->instance);
814b285192aSMauro Carvalho Chehab return -EIO;
815b285192aSMauro Carvalho Chehab }
816b285192aSMauro Carvalho Chehab
817b285192aSMauro Carvalho Chehab /* Enable bus mastering and memory mapped IO for the CX23418 */
818b285192aSMauro Carvalho Chehab pci_read_config_word(pci_dev, PCI_COMMAND, &cmd);
819b285192aSMauro Carvalho Chehab cmd |= PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER;
820b285192aSMauro Carvalho Chehab pci_write_config_word(pci_dev, PCI_COMMAND, cmd);
821b285192aSMauro Carvalho Chehab
822b285192aSMauro Carvalho Chehab cx->card_rev = pci_dev->revision;
823b285192aSMauro Carvalho Chehab pci_read_config_byte(pci_dev, PCI_LATENCY_TIMER, &pci_latency);
824b285192aSMauro Carvalho Chehab
825b285192aSMauro Carvalho Chehab if (pci_latency < 64 && cx18_pci_latency) {
8266beb1388SMauro Carvalho Chehab CX18_INFO("Unreasonably low latency timer, setting to 64 (was %d)\n",
8276beb1388SMauro Carvalho Chehab pci_latency);
828b285192aSMauro Carvalho Chehab pci_write_config_byte(pci_dev, PCI_LATENCY_TIMER, 64);
829b285192aSMauro Carvalho Chehab pci_read_config_byte(pci_dev, PCI_LATENCY_TIMER, &pci_latency);
830b285192aSMauro Carvalho Chehab }
831b285192aSMauro Carvalho Chehab
8326beb1388SMauro Carvalho Chehab CX18_DEBUG_INFO("cx%d (rev %d) at %02x:%02x.%x, irq: %d, latency: %d, memory: 0x%llx\n",
833b285192aSMauro Carvalho Chehab cx->pci_dev->device, cx->card_rev, pci_dev->bus->number,
834b285192aSMauro Carvalho Chehab PCI_SLOT(pci_dev->devfn), PCI_FUNC(pci_dev->devfn),
835b285192aSMauro Carvalho Chehab cx->pci_dev->irq, pci_latency, (u64)cx->base_addr);
836b285192aSMauro Carvalho Chehab
837b285192aSMauro Carvalho Chehab return 0;
838b285192aSMauro Carvalho Chehab }
839b285192aSMauro Carvalho Chehab
cx18_init_subdevs(struct cx18 * cx)840b285192aSMauro Carvalho Chehab static void cx18_init_subdevs(struct cx18 *cx)
841b285192aSMauro Carvalho Chehab {
842b285192aSMauro Carvalho Chehab u32 hw = cx->card->hw_all;
843b285192aSMauro Carvalho Chehab u32 device;
844b285192aSMauro Carvalho Chehab int i;
845b285192aSMauro Carvalho Chehab
846b285192aSMauro Carvalho Chehab for (i = 0, device = 1; i < 32; i++, device <<= 1) {
847b285192aSMauro Carvalho Chehab
848b285192aSMauro Carvalho Chehab if (!(device & hw))
849b285192aSMauro Carvalho Chehab continue;
850b285192aSMauro Carvalho Chehab
851b285192aSMauro Carvalho Chehab switch (device) {
852b285192aSMauro Carvalho Chehab case CX18_HW_DVB:
853b285192aSMauro Carvalho Chehab case CX18_HW_TVEEPROM:
854b285192aSMauro Carvalho Chehab /* These subordinate devices do not use probing */
855b285192aSMauro Carvalho Chehab cx->hw_flags |= device;
856b285192aSMauro Carvalho Chehab break;
857b285192aSMauro Carvalho Chehab case CX18_HW_418_AV:
858b285192aSMauro Carvalho Chehab /* The A/V decoder gets probed earlier to set PLLs */
859b285192aSMauro Carvalho Chehab /* Just note that the card uses it (i.e. has analog) */
860b285192aSMauro Carvalho Chehab cx->hw_flags |= device;
861b285192aSMauro Carvalho Chehab break;
862b285192aSMauro Carvalho Chehab case CX18_HW_GPIO_RESET_CTRL:
863b285192aSMauro Carvalho Chehab /*
864b285192aSMauro Carvalho Chehab * The Reset Controller gets probed and added to
865b285192aSMauro Carvalho Chehab * hw_flags earlier for i2c adapter/bus initialization
866b285192aSMauro Carvalho Chehab */
867b285192aSMauro Carvalho Chehab break;
868b285192aSMauro Carvalho Chehab case CX18_HW_GPIO_MUX:
869b285192aSMauro Carvalho Chehab if (cx18_gpio_register(cx, device) == 0)
870b285192aSMauro Carvalho Chehab cx->hw_flags |= device;
871b285192aSMauro Carvalho Chehab break;
872b285192aSMauro Carvalho Chehab default:
873b285192aSMauro Carvalho Chehab if (cx18_i2c_register(cx, i) == 0)
874b285192aSMauro Carvalho Chehab cx->hw_flags |= device;
875b285192aSMauro Carvalho Chehab break;
876b285192aSMauro Carvalho Chehab }
877b285192aSMauro Carvalho Chehab }
878b285192aSMauro Carvalho Chehab
879b285192aSMauro Carvalho Chehab if (cx->hw_flags & CX18_HW_418_AV)
880b285192aSMauro Carvalho Chehab cx->sd_av = cx18_find_hw(cx, CX18_HW_418_AV);
881b285192aSMauro Carvalho Chehab
882b285192aSMauro Carvalho Chehab if (cx->card->hw_muxer != 0)
883b285192aSMauro Carvalho Chehab cx->sd_extmux = cx18_find_hw(cx, cx->card->hw_muxer);
884b285192aSMauro Carvalho Chehab }
885b285192aSMauro Carvalho Chehab
cx18_probe(struct pci_dev * pci_dev,const struct pci_device_id * pci_id)8864c62e976SGreg Kroah-Hartman static int cx18_probe(struct pci_dev *pci_dev,
887b285192aSMauro Carvalho Chehab const struct pci_device_id *pci_id)
888b285192aSMauro Carvalho Chehab {
889b285192aSMauro Carvalho Chehab int retval = 0;
890b285192aSMauro Carvalho Chehab int i;
891b285192aSMauro Carvalho Chehab u32 devtype;
892b285192aSMauro Carvalho Chehab struct cx18 *cx;
893b285192aSMauro Carvalho Chehab
894b285192aSMauro Carvalho Chehab /* FIXME - module parameter arrays constrain max instances */
895b285192aSMauro Carvalho Chehab i = atomic_inc_return(&cx18_instance) - 1;
896b285192aSMauro Carvalho Chehab if (i >= CX18_MAX_CARDS) {
8976beb1388SMauro Carvalho Chehab printk(KERN_ERR "cx18: cannot manage card %d, driver has a limit of 0 - %d\n",
8986beb1388SMauro Carvalho Chehab i, CX18_MAX_CARDS - 1);
899b285192aSMauro Carvalho Chehab return -ENOMEM;
900b285192aSMauro Carvalho Chehab }
901b285192aSMauro Carvalho Chehab
902ad89e2e3SJulia Lawall cx = kzalloc(sizeof(*cx), GFP_KERNEL);
903c38e8657SMarkus Elfring if (!cx)
904b285192aSMauro Carvalho Chehab return -ENOMEM;
905c38e8657SMarkus Elfring
906b285192aSMauro Carvalho Chehab cx->pci_dev = pci_dev;
907b285192aSMauro Carvalho Chehab cx->instance = i;
908b285192aSMauro Carvalho Chehab
909b285192aSMauro Carvalho Chehab retval = v4l2_device_register(&pci_dev->dev, &cx->v4l2_dev);
910b285192aSMauro Carvalho Chehab if (retval) {
9116beb1388SMauro Carvalho Chehab printk(KERN_ERR "cx18: v4l2_device_register of card %d failed\n",
9126beb1388SMauro Carvalho Chehab cx->instance);
913b285192aSMauro Carvalho Chehab kfree(cx);
914b285192aSMauro Carvalho Chehab return retval;
915b285192aSMauro Carvalho Chehab }
916b285192aSMauro Carvalho Chehab snprintf(cx->v4l2_dev.name, sizeof(cx->v4l2_dev.name), "cx18-%d",
917b285192aSMauro Carvalho Chehab cx->instance);
918b285192aSMauro Carvalho Chehab CX18_INFO("Initializing card %d\n", cx->instance);
919b285192aSMauro Carvalho Chehab
920b285192aSMauro Carvalho Chehab cx18_process_options(cx);
921b285192aSMauro Carvalho Chehab if (cx->options.cardtype == -1) {
922b285192aSMauro Carvalho Chehab retval = -ENODEV;
923b285192aSMauro Carvalho Chehab goto err;
924b285192aSMauro Carvalho Chehab }
925b285192aSMauro Carvalho Chehab
926b285192aSMauro Carvalho Chehab retval = cx18_init_struct1(cx);
927b285192aSMauro Carvalho Chehab if (retval)
928b285192aSMauro Carvalho Chehab goto err;
929b285192aSMauro Carvalho Chehab
930b285192aSMauro Carvalho Chehab CX18_DEBUG_INFO("base addr: 0x%llx\n", (u64)cx->base_addr);
931b285192aSMauro Carvalho Chehab
932b285192aSMauro Carvalho Chehab /* PCI Device Setup */
933b285192aSMauro Carvalho Chehab retval = cx18_setup_pci(cx, pci_dev, pci_id);
934b285192aSMauro Carvalho Chehab if (retval != 0)
935b285192aSMauro Carvalho Chehab goto free_workqueues;
936b285192aSMauro Carvalho Chehab
937b285192aSMauro Carvalho Chehab /* map io memory */
938b285192aSMauro Carvalho Chehab CX18_DEBUG_INFO("attempting ioremap at 0x%llx len 0x%08x\n",
939b285192aSMauro Carvalho Chehab (u64)cx->base_addr + CX18_MEM_OFFSET, CX18_MEM_SIZE);
9404bdc0d67SChristoph Hellwig cx->enc_mem = ioremap(cx->base_addr + CX18_MEM_OFFSET,
941b285192aSMauro Carvalho Chehab CX18_MEM_SIZE);
942b285192aSMauro Carvalho Chehab if (!cx->enc_mem) {
9436beb1388SMauro Carvalho Chehab CX18_ERR("ioremap failed. Can't get a window into CX23418 memory and register space\n");
9446beb1388SMauro Carvalho Chehab CX18_ERR("Each capture card with a CX23418 needs 64 MB of vmalloc address space for the window\n");
945b285192aSMauro Carvalho Chehab CX18_ERR("Check the output of 'grep Vmalloc /proc/meminfo'\n");
9466beb1388SMauro Carvalho Chehab CX18_ERR("Use the vmalloc= kernel command line option to set VmallocTotal to a larger value\n");
947b285192aSMauro Carvalho Chehab retval = -ENOMEM;
948b285192aSMauro Carvalho Chehab goto free_mem;
949b285192aSMauro Carvalho Chehab }
950b285192aSMauro Carvalho Chehab cx->reg_mem = cx->enc_mem + CX18_REG_OFFSET;
951b285192aSMauro Carvalho Chehab devtype = cx18_read_reg(cx, 0xC72028);
952b285192aSMauro Carvalho Chehab switch (devtype & 0xff000000) {
953b285192aSMauro Carvalho Chehab case 0xff000000:
954b285192aSMauro Carvalho Chehab CX18_INFO("cx23418 revision %08x (A)\n", devtype);
955b285192aSMauro Carvalho Chehab break;
956b285192aSMauro Carvalho Chehab case 0x01000000:
957b285192aSMauro Carvalho Chehab CX18_INFO("cx23418 revision %08x (B)\n", devtype);
958b285192aSMauro Carvalho Chehab break;
959b285192aSMauro Carvalho Chehab default:
960b285192aSMauro Carvalho Chehab CX18_INFO("cx23418 revision %08x (Unknown)\n", devtype);
961b285192aSMauro Carvalho Chehab break;
962b285192aSMauro Carvalho Chehab }
963b285192aSMauro Carvalho Chehab
964b285192aSMauro Carvalho Chehab cx18_init_power(cx, 1);
965b285192aSMauro Carvalho Chehab cx18_init_memory(cx);
966b285192aSMauro Carvalho Chehab
967b285192aSMauro Carvalho Chehab cx->scb = (struct cx18_scb __iomem *)(cx->enc_mem + SCB_OFFSET);
968b285192aSMauro Carvalho Chehab cx18_init_scb(cx);
969b285192aSMauro Carvalho Chehab
970b285192aSMauro Carvalho Chehab cx18_gpio_init(cx);
971b285192aSMauro Carvalho Chehab
972b285192aSMauro Carvalho Chehab /* Initialize integrated A/V decoder early to set PLLs, just in case */
973b285192aSMauro Carvalho Chehab retval = cx18_av_probe(cx);
974b285192aSMauro Carvalho Chehab if (retval) {
975b285192aSMauro Carvalho Chehab CX18_ERR("Could not register A/V decoder subdevice\n");
976b285192aSMauro Carvalho Chehab goto free_map;
977b285192aSMauro Carvalho Chehab }
978b285192aSMauro Carvalho Chehab
979b285192aSMauro Carvalho Chehab /* Initialize GPIO Reset Controller to do chip resets during i2c init */
980b285192aSMauro Carvalho Chehab if (cx->card->hw_all & CX18_HW_GPIO_RESET_CTRL) {
981b285192aSMauro Carvalho Chehab if (cx18_gpio_register(cx, CX18_HW_GPIO_RESET_CTRL) != 0)
9826beb1388SMauro Carvalho Chehab CX18_WARN("Could not register GPIO reset controllersubdevice; proceeding anyway.\n");
983b285192aSMauro Carvalho Chehab else
984b285192aSMauro Carvalho Chehab cx->hw_flags |= CX18_HW_GPIO_RESET_CTRL;
985b285192aSMauro Carvalho Chehab }
986b285192aSMauro Carvalho Chehab
987b285192aSMauro Carvalho Chehab /* active i2c */
988b285192aSMauro Carvalho Chehab CX18_DEBUG_INFO("activating i2c...\n");
989b285192aSMauro Carvalho Chehab retval = init_cx18_i2c(cx);
990b285192aSMauro Carvalho Chehab if (retval) {
991b285192aSMauro Carvalho Chehab CX18_ERR("Could not initialize i2c\n");
992b285192aSMauro Carvalho Chehab goto free_map;
993b285192aSMauro Carvalho Chehab }
994b285192aSMauro Carvalho Chehab
995b285192aSMauro Carvalho Chehab if (cx->card->hw_all & CX18_HW_TVEEPROM) {
996b285192aSMauro Carvalho Chehab /* Based on the model number the cardtype may be changed.
997b285192aSMauro Carvalho Chehab The PCI IDs are not always reliable. */
998b285192aSMauro Carvalho Chehab const struct cx18_card *orig_card = cx->card;
999b285192aSMauro Carvalho Chehab cx18_process_eeprom(cx);
1000b285192aSMauro Carvalho Chehab
1001b285192aSMauro Carvalho Chehab if (cx->card != orig_card) {
1002b285192aSMauro Carvalho Chehab /* Changed the cardtype; re-reset the I2C chips */
1003b285192aSMauro Carvalho Chehab cx18_gpio_init(cx);
1004b285192aSMauro Carvalho Chehab cx18_call_hw(cx, CX18_HW_GPIO_RESET_CTRL,
1005b285192aSMauro Carvalho Chehab core, reset, (u32) CX18_GPIO_RESET_I2C);
1006b285192aSMauro Carvalho Chehab }
1007b285192aSMauro Carvalho Chehab }
1008b285192aSMauro Carvalho Chehab if (cx->card->comment)
1009b285192aSMauro Carvalho Chehab CX18_INFO("%s", cx->card->comment);
1010b285192aSMauro Carvalho Chehab if (cx->card->v4l2_capabilities == 0) {
1011b285192aSMauro Carvalho Chehab retval = -ENODEV;
1012b285192aSMauro Carvalho Chehab goto free_i2c;
1013b285192aSMauro Carvalho Chehab }
1014b285192aSMauro Carvalho Chehab cx18_init_memory(cx);
1015b285192aSMauro Carvalho Chehab cx18_init_scb(cx);
1016b285192aSMauro Carvalho Chehab
1017b285192aSMauro Carvalho Chehab /* Register IRQ */
1018b285192aSMauro Carvalho Chehab retval = request_irq(cx->pci_dev->irq, cx18_irq_handler,
10199a373d17SMichael Opdenacker IRQF_SHARED, cx->v4l2_dev.name, (void *)cx);
1020b285192aSMauro Carvalho Chehab if (retval) {
1021b285192aSMauro Carvalho Chehab CX18_ERR("Failed to register irq %d\n", retval);
1022b285192aSMauro Carvalho Chehab goto free_i2c;
1023b285192aSMauro Carvalho Chehab }
1024b285192aSMauro Carvalho Chehab
1025b285192aSMauro Carvalho Chehab if (cx->std == 0)
1026b285192aSMauro Carvalho Chehab cx->std = V4L2_STD_NTSC_M;
1027b285192aSMauro Carvalho Chehab
1028b285192aSMauro Carvalho Chehab if (cx->options.tuner == -1) {
1029b285192aSMauro Carvalho Chehab for (i = 0; i < CX18_CARD_MAX_TUNERS; i++) {
1030b285192aSMauro Carvalho Chehab if ((cx->std & cx->card->tuners[i].std) == 0)
1031b285192aSMauro Carvalho Chehab continue;
1032b285192aSMauro Carvalho Chehab cx->options.tuner = cx->card->tuners[i].tuner;
1033b285192aSMauro Carvalho Chehab break;
1034b285192aSMauro Carvalho Chehab }
1035b285192aSMauro Carvalho Chehab }
1036b285192aSMauro Carvalho Chehab /* if no tuner was found, then pick the first tuner in the card list */
1037b285192aSMauro Carvalho Chehab if (cx->options.tuner == -1 && cx->card->tuners[0].std) {
1038b285192aSMauro Carvalho Chehab cx->std = cx->card->tuners[0].std;
1039b285192aSMauro Carvalho Chehab if (cx->std & V4L2_STD_PAL)
1040b285192aSMauro Carvalho Chehab cx->std = V4L2_STD_PAL_BG | V4L2_STD_PAL_H;
1041b285192aSMauro Carvalho Chehab else if (cx->std & V4L2_STD_NTSC)
1042b285192aSMauro Carvalho Chehab cx->std = V4L2_STD_NTSC_M;
1043b285192aSMauro Carvalho Chehab else if (cx->std & V4L2_STD_SECAM)
1044b285192aSMauro Carvalho Chehab cx->std = V4L2_STD_SECAM_L;
1045b285192aSMauro Carvalho Chehab cx->options.tuner = cx->card->tuners[0].tuner;
1046b285192aSMauro Carvalho Chehab }
1047b285192aSMauro Carvalho Chehab if (cx->options.radio == -1)
1048b285192aSMauro Carvalho Chehab cx->options.radio = (cx->card->radio_input.audio_type != 0);
1049b285192aSMauro Carvalho Chehab
1050b285192aSMauro Carvalho Chehab /* The card is now fully identified, continue with card-specific
1051b285192aSMauro Carvalho Chehab initialization. */
1052b285192aSMauro Carvalho Chehab cx18_init_struct2(cx);
1053b285192aSMauro Carvalho Chehab
1054b285192aSMauro Carvalho Chehab cx18_init_subdevs(cx);
1055b285192aSMauro Carvalho Chehab
1056b285192aSMauro Carvalho Chehab if (cx->std & V4L2_STD_525_60)
1057b285192aSMauro Carvalho Chehab cx->is_60hz = 1;
1058b285192aSMauro Carvalho Chehab else
1059b285192aSMauro Carvalho Chehab cx->is_50hz = 1;
1060b285192aSMauro Carvalho Chehab
1061b285192aSMauro Carvalho Chehab cx2341x_handler_set_50hz(&cx->cxhdl, !cx->is_60hz);
1062b285192aSMauro Carvalho Chehab
1063b285192aSMauro Carvalho Chehab if (cx->options.radio > 0)
1064b285192aSMauro Carvalho Chehab cx->v4l2_cap |= V4L2_CAP_RADIO;
1065b285192aSMauro Carvalho Chehab
1066b285192aSMauro Carvalho Chehab if (cx->options.tuner > -1) {
1067b285192aSMauro Carvalho Chehab struct tuner_setup setup;
1068b285192aSMauro Carvalho Chehab
1069b285192aSMauro Carvalho Chehab setup.addr = ADDR_UNSET;
1070b285192aSMauro Carvalho Chehab setup.type = cx->options.tuner;
1071b285192aSMauro Carvalho Chehab setup.mode_mask = T_ANALOG_TV; /* matches TV tuners */
10726a03dc92SHans Verkuil setup.config = NULL;
1073b285192aSMauro Carvalho Chehab if (cx->options.radio > 0)
1074b285192aSMauro Carvalho Chehab setup.mode_mask |= T_RADIO;
1075b285192aSMauro Carvalho Chehab setup.tuner_callback = (setup.type == TUNER_XC2028) ?
1076b285192aSMauro Carvalho Chehab cx18_reset_tuner_gpio : NULL;
1077b285192aSMauro Carvalho Chehab cx18_call_all(cx, tuner, s_type_addr, &setup);
1078b285192aSMauro Carvalho Chehab if (setup.type == TUNER_XC2028) {
1079b285192aSMauro Carvalho Chehab static struct xc2028_ctrl ctrl = {
1080b285192aSMauro Carvalho Chehab .fname = XC2028_DEFAULT_FIRMWARE,
1081b285192aSMauro Carvalho Chehab .max_len = 64,
1082b285192aSMauro Carvalho Chehab };
1083b285192aSMauro Carvalho Chehab struct v4l2_priv_tun_config cfg = {
1084b285192aSMauro Carvalho Chehab .tuner = cx->options.tuner,
1085b285192aSMauro Carvalho Chehab .priv = &ctrl,
1086b285192aSMauro Carvalho Chehab };
1087b285192aSMauro Carvalho Chehab cx18_call_all(cx, tuner, s_config, &cfg);
1088b285192aSMauro Carvalho Chehab }
1089b285192aSMauro Carvalho Chehab }
1090b285192aSMauro Carvalho Chehab
1091b285192aSMauro Carvalho Chehab /* The tuner is fixed to the standard. The other inputs (e.g. S-Video)
1092b285192aSMauro Carvalho Chehab are not. */
1093b285192aSMauro Carvalho Chehab cx->tuner_std = cx->std;
1094b285192aSMauro Carvalho Chehab if (cx->std == V4L2_STD_ALL)
1095b285192aSMauro Carvalho Chehab cx->std = V4L2_STD_NTSC_M;
1096b285192aSMauro Carvalho Chehab
1097b285192aSMauro Carvalho Chehab retval = cx18_streams_setup(cx);
1098b285192aSMauro Carvalho Chehab if (retval) {
1099b285192aSMauro Carvalho Chehab CX18_ERR("Error %d setting up streams\n", retval);
1100b285192aSMauro Carvalho Chehab goto free_irq;
1101b285192aSMauro Carvalho Chehab }
1102b285192aSMauro Carvalho Chehab retval = cx18_streams_register(cx);
1103b285192aSMauro Carvalho Chehab if (retval) {
1104b285192aSMauro Carvalho Chehab CX18_ERR("Error %d registering devices\n", retval);
1105b285192aSMauro Carvalho Chehab goto free_streams;
1106b285192aSMauro Carvalho Chehab }
1107b285192aSMauro Carvalho Chehab
1108b285192aSMauro Carvalho Chehab CX18_INFO("Initialized card: %s\n", cx->card_name);
1109b285192aSMauro Carvalho Chehab
1110b285192aSMauro Carvalho Chehab /* Load cx18 submodules (cx18-alsa) */
1111b285192aSMauro Carvalho Chehab request_modules(cx);
1112b285192aSMauro Carvalho Chehab return 0;
1113b285192aSMauro Carvalho Chehab
1114b285192aSMauro Carvalho Chehab free_streams:
1115b285192aSMauro Carvalho Chehab cx18_streams_cleanup(cx, 1);
1116b285192aSMauro Carvalho Chehab free_irq:
1117b285192aSMauro Carvalho Chehab free_irq(cx->pci_dev->irq, (void *)cx);
1118b285192aSMauro Carvalho Chehab free_i2c:
1119b285192aSMauro Carvalho Chehab exit_cx18_i2c(cx);
1120b285192aSMauro Carvalho Chehab free_map:
1121b285192aSMauro Carvalho Chehab cx18_iounmap(cx);
1122b285192aSMauro Carvalho Chehab free_mem:
1123b285192aSMauro Carvalho Chehab release_mem_region(cx->base_addr, CX18_MEM_SIZE);
1124b285192aSMauro Carvalho Chehab free_workqueues:
1125b285192aSMauro Carvalho Chehab destroy_workqueue(cx->in_work_queue);
1126b285192aSMauro Carvalho Chehab err:
1127b285192aSMauro Carvalho Chehab CX18_ERR("Error %d on initialization\n", retval);
1128b285192aSMauro Carvalho Chehab
1129b285192aSMauro Carvalho Chehab v4l2_device_unregister(&cx->v4l2_dev);
1130b285192aSMauro Carvalho Chehab kfree(cx);
1131b285192aSMauro Carvalho Chehab return retval;
1132b285192aSMauro Carvalho Chehab }
1133b285192aSMauro Carvalho Chehab
cx18_init_on_first_open(struct cx18 * cx)1134b285192aSMauro Carvalho Chehab int cx18_init_on_first_open(struct cx18 *cx)
1135b285192aSMauro Carvalho Chehab {
1136b285192aSMauro Carvalho Chehab int video_input;
1137b285192aSMauro Carvalho Chehab int fw_retry_count = 3;
1138b285192aSMauro Carvalho Chehab struct v4l2_frequency vf;
1139b285192aSMauro Carvalho Chehab struct cx18_open_id fh;
1140b285192aSMauro Carvalho Chehab v4l2_std_id std;
1141b285192aSMauro Carvalho Chehab
1142b285192aSMauro Carvalho Chehab fh.cx = cx;
1143b285192aSMauro Carvalho Chehab
1144b285192aSMauro Carvalho Chehab if (test_bit(CX18_F_I_FAILED, &cx->i_flags))
1145b285192aSMauro Carvalho Chehab return -ENXIO;
1146b285192aSMauro Carvalho Chehab
1147b285192aSMauro Carvalho Chehab if (test_and_set_bit(CX18_F_I_INITED, &cx->i_flags))
1148b285192aSMauro Carvalho Chehab return 0;
1149b285192aSMauro Carvalho Chehab
1150b285192aSMauro Carvalho Chehab while (--fw_retry_count > 0) {
1151b285192aSMauro Carvalho Chehab /* load firmware */
1152b285192aSMauro Carvalho Chehab if (cx18_firmware_init(cx) == 0)
1153b285192aSMauro Carvalho Chehab break;
1154b285192aSMauro Carvalho Chehab if (fw_retry_count > 1)
1155b285192aSMauro Carvalho Chehab CX18_WARN("Retry loading firmware\n");
1156b285192aSMauro Carvalho Chehab }
1157b285192aSMauro Carvalho Chehab
1158b285192aSMauro Carvalho Chehab if (fw_retry_count == 0) {
1159b285192aSMauro Carvalho Chehab set_bit(CX18_F_I_FAILED, &cx->i_flags);
1160b285192aSMauro Carvalho Chehab return -ENXIO;
1161b285192aSMauro Carvalho Chehab }
1162b285192aSMauro Carvalho Chehab set_bit(CX18_F_I_LOADED_FW, &cx->i_flags);
1163b285192aSMauro Carvalho Chehab
1164b285192aSMauro Carvalho Chehab /*
1165b285192aSMauro Carvalho Chehab * Init the firmware twice to work around a silicon bug
1166b285192aSMauro Carvalho Chehab * with the digital TS.
1167b285192aSMauro Carvalho Chehab *
1168b285192aSMauro Carvalho Chehab * The second firmware load requires us to normalize the APU state,
1169b285192aSMauro Carvalho Chehab * or the audio for the first analog capture will be badly incorrect.
1170b285192aSMauro Carvalho Chehab *
1171b285192aSMauro Carvalho Chehab * I can't seem to call APU_RESETAI and have it succeed without the
1172b285192aSMauro Carvalho Chehab * APU capturing audio, so we start and stop it here to do the reset
1173b285192aSMauro Carvalho Chehab */
1174b285192aSMauro Carvalho Chehab
1175b285192aSMauro Carvalho Chehab /* MPEG Encoding, 224 kbps, MPEG Layer II, 48 ksps */
1176b285192aSMauro Carvalho Chehab cx18_vapi(cx, CX18_APU_START, 2, CX18_APU_ENCODING_METHOD_MPEG|0xb9, 0);
1177b285192aSMauro Carvalho Chehab cx18_vapi(cx, CX18_APU_RESETAI, 0);
1178b285192aSMauro Carvalho Chehab cx18_vapi(cx, CX18_APU_STOP, 1, CX18_APU_ENCODING_METHOD_MPEG);
1179b285192aSMauro Carvalho Chehab
1180b285192aSMauro Carvalho Chehab fw_retry_count = 3;
1181b285192aSMauro Carvalho Chehab while (--fw_retry_count > 0) {
1182b285192aSMauro Carvalho Chehab /* load firmware */
1183b285192aSMauro Carvalho Chehab if (cx18_firmware_init(cx) == 0)
1184b285192aSMauro Carvalho Chehab break;
1185b285192aSMauro Carvalho Chehab if (fw_retry_count > 1)
1186b285192aSMauro Carvalho Chehab CX18_WARN("Retry loading firmware\n");
1187b285192aSMauro Carvalho Chehab }
1188b285192aSMauro Carvalho Chehab
1189b285192aSMauro Carvalho Chehab if (fw_retry_count == 0) {
1190b285192aSMauro Carvalho Chehab set_bit(CX18_F_I_FAILED, &cx->i_flags);
1191b285192aSMauro Carvalho Chehab return -ENXIO;
1192b285192aSMauro Carvalho Chehab }
1193b285192aSMauro Carvalho Chehab
1194b285192aSMauro Carvalho Chehab /*
1195b285192aSMauro Carvalho Chehab * The second firmware load requires us to normalize the APU state,
1196b285192aSMauro Carvalho Chehab * or the audio for the first analog capture will be badly incorrect.
1197b285192aSMauro Carvalho Chehab *
1198b285192aSMauro Carvalho Chehab * I can't seem to call APU_RESETAI and have it succeed without the
1199b285192aSMauro Carvalho Chehab * APU capturing audio, so we start and stop it here to do the reset
1200b285192aSMauro Carvalho Chehab */
1201b285192aSMauro Carvalho Chehab
1202b285192aSMauro Carvalho Chehab /* MPEG Encoding, 224 kbps, MPEG Layer II, 48 ksps */
1203b285192aSMauro Carvalho Chehab cx18_vapi(cx, CX18_APU_START, 2, CX18_APU_ENCODING_METHOD_MPEG|0xb9, 0);
1204b285192aSMauro Carvalho Chehab cx18_vapi(cx, CX18_APU_RESETAI, 0);
1205b285192aSMauro Carvalho Chehab cx18_vapi(cx, CX18_APU_STOP, 1, CX18_APU_ENCODING_METHOD_MPEG);
1206b285192aSMauro Carvalho Chehab
1207b285192aSMauro Carvalho Chehab /* Init the A/V decoder, if it hasn't been already */
1208b285192aSMauro Carvalho Chehab v4l2_subdev_call(cx->sd_av, core, load_fw);
1209b285192aSMauro Carvalho Chehab
1210b285192aSMauro Carvalho Chehab vf.tuner = 0;
1211b285192aSMauro Carvalho Chehab vf.type = V4L2_TUNER_ANALOG_TV;
1212b285192aSMauro Carvalho Chehab vf.frequency = 6400; /* the tuner 'baseline' frequency */
1213b285192aSMauro Carvalho Chehab
1214b285192aSMauro Carvalho Chehab /* Set initial frequency. For PAL/SECAM broadcasts no
1215b285192aSMauro Carvalho Chehab 'default' channel exists AFAIK. */
1216b285192aSMauro Carvalho Chehab if (cx->std == V4L2_STD_NTSC_M_JP)
1217b285192aSMauro Carvalho Chehab vf.frequency = 1460; /* ch. 1 91250*16/1000 */
1218b285192aSMauro Carvalho Chehab else if (cx->std & V4L2_STD_NTSC_M)
1219b285192aSMauro Carvalho Chehab vf.frequency = 1076; /* ch. 4 67250*16/1000 */
1220b285192aSMauro Carvalho Chehab
1221b285192aSMauro Carvalho Chehab video_input = cx->active_input;
1222b285192aSMauro Carvalho Chehab cx->active_input++; /* Force update of input */
1223b285192aSMauro Carvalho Chehab cx18_s_input(NULL, &fh, video_input);
1224b285192aSMauro Carvalho Chehab
1225b285192aSMauro Carvalho Chehab /* Let the VIDIOC_S_STD ioctl do all the work, keeps the code
1226b285192aSMauro Carvalho Chehab in one place. */
1227b285192aSMauro Carvalho Chehab cx->std++; /* Force full standard initialization */
1228b285192aSMauro Carvalho Chehab std = (cx->tuner_std == V4L2_STD_ALL) ? V4L2_STD_NTSC_M : cx->tuner_std;
1229314527acSHans Verkuil cx18_s_std(NULL, &fh, std);
1230b285192aSMauro Carvalho Chehab cx18_s_frequency(NULL, &fh, &vf);
1231b285192aSMauro Carvalho Chehab return 0;
1232b285192aSMauro Carvalho Chehab }
1233b285192aSMauro Carvalho Chehab
cx18_cancel_in_work_orders(struct cx18 * cx)1234b285192aSMauro Carvalho Chehab static void cx18_cancel_in_work_orders(struct cx18 *cx)
1235b285192aSMauro Carvalho Chehab {
1236b285192aSMauro Carvalho Chehab int i;
1237b285192aSMauro Carvalho Chehab for (i = 0; i < CX18_MAX_IN_WORK_ORDERS; i++)
1238b285192aSMauro Carvalho Chehab cancel_work_sync(&cx->in_work_order[i].work);
1239b285192aSMauro Carvalho Chehab }
1240b285192aSMauro Carvalho Chehab
cx18_cancel_out_work_orders(struct cx18 * cx)1241b285192aSMauro Carvalho Chehab static void cx18_cancel_out_work_orders(struct cx18 *cx)
1242b285192aSMauro Carvalho Chehab {
1243b285192aSMauro Carvalho Chehab int i;
1244b285192aSMauro Carvalho Chehab for (i = 0; i < CX18_MAX_STREAMS; i++)
1245eb1ca9a4SNathan Chancellor if (cx->streams[i].video_dev.v4l2_dev)
1246b285192aSMauro Carvalho Chehab cancel_work_sync(&cx->streams[i].out_work_order);
1247b285192aSMauro Carvalho Chehab }
1248b285192aSMauro Carvalho Chehab
cx18_remove(struct pci_dev * pci_dev)1249b285192aSMauro Carvalho Chehab static void cx18_remove(struct pci_dev *pci_dev)
1250b285192aSMauro Carvalho Chehab {
1251b285192aSMauro Carvalho Chehab struct v4l2_device *v4l2_dev = pci_get_drvdata(pci_dev);
1252b285192aSMauro Carvalho Chehab struct cx18 *cx = to_cx18(v4l2_dev);
1253b285192aSMauro Carvalho Chehab int i;
1254b285192aSMauro Carvalho Chehab
1255b285192aSMauro Carvalho Chehab CX18_DEBUG_INFO("Removing Card\n");
1256b285192aSMauro Carvalho Chehab
1257b285192aSMauro Carvalho Chehab flush_request_modules(cx);
1258b285192aSMauro Carvalho Chehab
1259b285192aSMauro Carvalho Chehab /* Stop all captures */
1260b285192aSMauro Carvalho Chehab CX18_DEBUG_INFO("Stopping all streams\n");
1261b285192aSMauro Carvalho Chehab if (atomic_read(&cx->tot_capturing) > 0)
1262b285192aSMauro Carvalho Chehab cx18_stop_all_captures(cx);
1263b285192aSMauro Carvalho Chehab
1264b285192aSMauro Carvalho Chehab /* Stop interrupts that cause incoming work to be queued */
1265b285192aSMauro Carvalho Chehab cx18_sw1_irq_disable(cx, IRQ_CPU_TO_EPU | IRQ_APU_TO_EPU);
1266b285192aSMauro Carvalho Chehab
1267b285192aSMauro Carvalho Chehab /* Incoming work can cause outgoing work, so clean up incoming first */
1268b285192aSMauro Carvalho Chehab cx18_cancel_in_work_orders(cx);
1269b285192aSMauro Carvalho Chehab cx18_cancel_out_work_orders(cx);
1270b285192aSMauro Carvalho Chehab
1271b285192aSMauro Carvalho Chehab /* Stop ack interrupts that may have been needed for work to finish */
1272b285192aSMauro Carvalho Chehab cx18_sw2_irq_disable(cx, IRQ_CPU_TO_EPU_ACK | IRQ_APU_TO_EPU_ACK);
1273b285192aSMauro Carvalho Chehab
1274b285192aSMauro Carvalho Chehab cx18_halt_firmware(cx);
1275b285192aSMauro Carvalho Chehab
1276b285192aSMauro Carvalho Chehab destroy_workqueue(cx->in_work_queue);
1277b285192aSMauro Carvalho Chehab
1278b285192aSMauro Carvalho Chehab cx18_streams_cleanup(cx, 1);
1279b285192aSMauro Carvalho Chehab
1280b285192aSMauro Carvalho Chehab exit_cx18_i2c(cx);
1281b285192aSMauro Carvalho Chehab
1282b285192aSMauro Carvalho Chehab free_irq(cx->pci_dev->irq, (void *)cx);
1283b285192aSMauro Carvalho Chehab
1284b285192aSMauro Carvalho Chehab cx18_iounmap(cx);
1285b285192aSMauro Carvalho Chehab
1286b285192aSMauro Carvalho Chehab release_mem_region(cx->base_addr, CX18_MEM_SIZE);
1287b285192aSMauro Carvalho Chehab
1288b285192aSMauro Carvalho Chehab pci_disable_device(cx->pci_dev);
1289b285192aSMauro Carvalho Chehab
1290af28c996SMarkus Elfring if (cx->vbi.sliced_mpeg_data[0])
1291b285192aSMauro Carvalho Chehab for (i = 0; i < CX18_VBI_FRAMES; i++)
1292b285192aSMauro Carvalho Chehab kfree(cx->vbi.sliced_mpeg_data[i]);
1293b285192aSMauro Carvalho Chehab
1294b285192aSMauro Carvalho Chehab v4l2_ctrl_handler_free(&cx->av_state.hdl);
1295b285192aSMauro Carvalho Chehab
1296b285192aSMauro Carvalho Chehab CX18_INFO("Removed %s\n", cx->card_name);
1297b285192aSMauro Carvalho Chehab
1298b285192aSMauro Carvalho Chehab v4l2_device_unregister(v4l2_dev);
1299b285192aSMauro Carvalho Chehab kfree(cx);
1300b285192aSMauro Carvalho Chehab }
1301b285192aSMauro Carvalho Chehab
1302b285192aSMauro Carvalho Chehab
1303b285192aSMauro Carvalho Chehab /* define a pci_driver for card detection */
1304b285192aSMauro Carvalho Chehab static struct pci_driver cx18_pci_driver = {
1305b285192aSMauro Carvalho Chehab .name = "cx18",
1306b285192aSMauro Carvalho Chehab .id_table = cx18_pci_tbl,
1307b285192aSMauro Carvalho Chehab .probe = cx18_probe,
1308b285192aSMauro Carvalho Chehab .remove = cx18_remove,
1309b285192aSMauro Carvalho Chehab };
1310b285192aSMauro Carvalho Chehab
module_start(void)1311b285192aSMauro Carvalho Chehab static int __init module_start(void)
1312b285192aSMauro Carvalho Chehab {
1313b285192aSMauro Carvalho Chehab printk(KERN_INFO "cx18: Start initialization, version %s\n",
1314b285192aSMauro Carvalho Chehab CX18_VERSION);
1315b285192aSMauro Carvalho Chehab
1316b285192aSMauro Carvalho Chehab /* Validate parameters */
1317b285192aSMauro Carvalho Chehab if (cx18_first_minor < 0 || cx18_first_minor >= CX18_MAX_CARDS) {
1318b285192aSMauro Carvalho Chehab printk(KERN_ERR "cx18: Exiting, cx18_first_minor must be between 0 and %d\n",
1319b285192aSMauro Carvalho Chehab CX18_MAX_CARDS - 1);
1320b285192aSMauro Carvalho Chehab return -1;
1321b285192aSMauro Carvalho Chehab }
1322b285192aSMauro Carvalho Chehab
1323b285192aSMauro Carvalho Chehab if (cx18_debug < 0 || cx18_debug > 511) {
1324b285192aSMauro Carvalho Chehab cx18_debug = 0;
1325b285192aSMauro Carvalho Chehab printk(KERN_INFO "cx18: Debug value must be >= 0 and <= 511!\n");
1326b285192aSMauro Carvalho Chehab }
1327b285192aSMauro Carvalho Chehab
1328b285192aSMauro Carvalho Chehab if (pci_register_driver(&cx18_pci_driver)) {
1329b285192aSMauro Carvalho Chehab printk(KERN_ERR "cx18: Error detecting PCI card\n");
1330b285192aSMauro Carvalho Chehab return -ENODEV;
1331b285192aSMauro Carvalho Chehab }
1332b285192aSMauro Carvalho Chehab printk(KERN_INFO "cx18: End initialization\n");
1333b285192aSMauro Carvalho Chehab return 0;
1334b285192aSMauro Carvalho Chehab }
1335b285192aSMauro Carvalho Chehab
module_cleanup(void)1336b285192aSMauro Carvalho Chehab static void __exit module_cleanup(void)
1337b285192aSMauro Carvalho Chehab {
1338b285192aSMauro Carvalho Chehab pci_unregister_driver(&cx18_pci_driver);
1339b285192aSMauro Carvalho Chehab }
1340b285192aSMauro Carvalho Chehab
1341b285192aSMauro Carvalho Chehab module_init(module_start);
1342b285192aSMauro Carvalho Chehab module_exit(module_cleanup);
1343b285192aSMauro Carvalho Chehab MODULE_FIRMWARE(XC2028_DEFAULT_FIRMWARE);
1344