1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21#define DEBUG_VARIABLE debug
22
23#include <media/saa7146_vv.h>
24#include <linux/video_decoder.h>
25
26#define I2C_SAA7111A 0x24
27
28
29#define SAA711X_CHIP_VERSION 0x00
30#define SAA711X_ANALOG_INPUT_CONTROL_1 0x02
31#define SAA711X_ANALOG_INPUT_CONTROL_2 0x03
32#define SAA711X_ANALOG_INPUT_CONTROL_3 0x04
33#define SAA711X_ANALOG_INPUT_CONTROL_4 0x05
34#define SAA711X_HORIZONTAL_SYNC_START 0x06
35#define SAA711X_HORIZONTAL_SYNC_STOP 0x07
36#define SAA711X_SYNC_CONTROL 0x08
37#define SAA711X_LUMINANCE_CONTROL 0x09
38#define SAA711X_LUMINANCE_BRIGHTNESS 0x0A
39#define SAA711X_LUMINANCE_CONTRAST 0x0B
40#define SAA711X_CHROMA_SATURATION 0x0C
41#define SAA711X_CHROMA_HUE_CONTROL 0x0D
42#define SAA711X_CHROMA_CONTROL 0x0E
43#define SAA711X_FORMAT_DELAY_CONTROL 0x10
44#define SAA711X_OUTPUT_CONTROL_1 0x11
45#define SAA711X_OUTPUT_CONTROL_2 0x12
46#define SAA711X_OUTPUT_CONTROL_3 0x13
47#define SAA711X_V_GATE_1_START 0x15
48#define SAA711X_V_GATE_1_STOP 0x16
49#define SAA711X_V_GATE_1_MSB 0x17
50#define SAA711X_TEXT_SLICER_STATUS 0x1A
51#define SAA711X_DECODED_BYTES_OF_TS_1 0x1B
52#define SAA711X_DECODED_BYTES_OF_TS_2 0x1C
53#define SAA711X_STATUS_BYTE 0x1F
54
55#define DPC_BOARD_CAN_DO_VBI(dev) (dev->revision != 0)
56
57static int debug = 0;
58module_param(debug, int, 0);
59MODULE_PARM_DESC(debug, "debug verbosity");
60
61static int dpc_num = 0;
62
63#define DPC_INPUTS 2
64static struct v4l2_input dpc_inputs[DPC_INPUTS] = {
65 { 0, "Port A", V4L2_INPUT_TYPE_CAMERA, 2, 0, V4L2_STD_PAL_BG|V4L2_STD_NTSC_M, 0 },
66 { 1, "Port B", V4L2_INPUT_TYPE_CAMERA, 2, 0, V4L2_STD_PAL_BG|V4L2_STD_NTSC_M, 0 },
67};
68
69#define DPC_AUDIOS 0
70
71static struct saa7146_extension_ioctls ioctls[] = {
72 { VIDIOC_G_INPUT, SAA7146_EXCLUSIVE },
73 { VIDIOC_S_INPUT, SAA7146_EXCLUSIVE },
74 { VIDIOC_ENUMINPUT, SAA7146_EXCLUSIVE },
75 { VIDIOC_S_STD, SAA7146_AFTER },
76 { 0, 0 }
77};
78
79struct dpc
80{
81 struct video_device *video_dev;
82 struct video_device *vbi_dev;
83
84 struct i2c_adapter i2c_adapter;
85 struct i2c_client *saa7111a;
86
87 int cur_input;
88};
89
90
91static int dpc_probe(struct saa7146_dev* dev)
92{
93 struct dpc* dpc = NULL;
94 struct i2c_client *client;
95
96 dpc = kzalloc(sizeof(struct dpc), GFP_KERNEL);
97 if( NULL == dpc ) {
98 printk("dpc_v4l2.o: dpc_probe: not enough kernel memory.\n");
99 return -ENOMEM;
100 }
101
102
103
104 saa7146_write(dev, MC1, (MASK_08 | MASK_24 | MASK_10 | MASK_26));
105
106 dpc->i2c_adapter = (struct i2c_adapter) {
107 .class = I2C_CLASS_TV_ANALOG,
108 .name = "dpc7146",
109 };
110 saa7146_i2c_adapter_prepare(dev, &dpc->i2c_adapter, SAA7146_I2C_BUS_BIT_RATE_480);
111 if(i2c_add_adapter(&dpc->i2c_adapter) < 0) {
112 DEB_S(("cannot register i2c-device. skipping.\n"));
113 kfree(dpc);
114 return -EFAULT;
115 }
116
117
118 list_for_each_entry(client, &dpc->i2c_adapter.clients, list)
119 if( I2C_SAA7111A == client->addr )
120 dpc->saa7111a = client;
121
122
123 if( 0 == dpc->saa7111a ) {
124 DEB_D(("dpc_v4l2.o: dpc_attach failed for this device.\n"));
125 i2c_del_adapter(&dpc->i2c_adapter);
126 kfree(dpc);
127 return -ENODEV;
128 }
129
130
131 DEB_D(("dpc_v4l2.o: dpc_probe succeeded for this device.\n"));
132
133
134 dev->ext_priv = dpc;
135
136 return 0;
137}
138
139
140
141
142
143static int dpc_init_done(struct saa7146_dev* dev)
144{
145 struct dpc* dpc = (struct dpc*)dev->ext_priv;
146
147 DEB_D(("dpc_v4l2.o: dpc_init_done called.\n"));
148
149
150 i2c_smbus_write_byte_data(dpc->saa7111a, 0x00, 0x11);
151
152 i2c_smbus_write_byte_data(dpc->saa7111a, 0x02, 0xc0);
153 i2c_smbus_write_byte_data(dpc->saa7111a, 0x03, 0x30);
154 i2c_smbus_write_byte_data(dpc->saa7111a, 0x04, 0x00);
155 i2c_smbus_write_byte_data(dpc->saa7111a, 0x05, 0x00);
156 i2c_smbus_write_byte_data(dpc->saa7111a, 0x06, 0xde);
157 i2c_smbus_write_byte_data(dpc->saa7111a, 0x07, 0xad);
158 i2c_smbus_write_byte_data(dpc->saa7111a, 0x08, 0xa8);
159 i2c_smbus_write_byte_data(dpc->saa7111a, 0x09, 0x00);
160 i2c_smbus_write_byte_data(dpc->saa7111a, 0x0a, 0x80);
161 i2c_smbus_write_byte_data(dpc->saa7111a, 0x0b, 0x47);
162 i2c_smbus_write_byte_data(dpc->saa7111a, 0x0c, 0x40);
163 i2c_smbus_write_byte_data(dpc->saa7111a, 0x0d, 0x00);
164 i2c_smbus_write_byte_data(dpc->saa7111a, 0x0e, 0x03);
165
166 i2c_smbus_write_byte_data(dpc->saa7111a, 0x10, 0xd0);
167 i2c_smbus_write_byte_data(dpc->saa7111a, 0x11, 0x1c);
168 i2c_smbus_write_byte_data(dpc->saa7111a, 0x12, 0xc1);
169 i2c_smbus_write_byte_data(dpc->saa7111a, 0x13, 0x30);
170
171 i2c_smbus_write_byte_data(dpc->saa7111a, 0x1f, 0x81);
172
173 return 0;
174}
175
176static struct saa7146_ext_vv vv_data;
177
178
179static int dpc_attach(struct saa7146_dev* dev, struct saa7146_pci_extension_data *info)
180{
181 struct dpc* dpc = (struct dpc*)dev->ext_priv;
182
183 DEB_D(("dpc_v4l2.o: dpc_attach called.\n"));
184
185
186
187
188 saa7146_vv_init(dev,&vv_data);
189 if( 0 != saa7146_register_device(&dpc->video_dev, dev, "dpc", VFL_TYPE_GRABBER)) {
190 ERR(("cannot register capture v4l2 device. skipping.\n"));
191 return -1;
192 }
193
194
195 if( 0 != DPC_BOARD_CAN_DO_VBI(dev)) {
196 if( 0 != saa7146_register_device(&dpc->vbi_dev, dev, "dpc", VFL_TYPE_VBI)) {
197 ERR(("cannot register vbi v4l2 device. skipping.\n"));
198 }
199 }
200
201 i2c_use_client(dpc->saa7111a);
202
203 printk("dpc: found 'dpc7146 demonstration board'-%d.\n",dpc_num);
204 dpc_num++;
205
206
207 dpc->cur_input = 0;
208 dpc_init_done(dev);
209
210 return 0;
211}
212
213static int dpc_detach(struct saa7146_dev* dev)
214{
215 struct dpc* dpc = (struct dpc*)dev->ext_priv;
216
217 DEB_EE(("dev:%p\n",dev));
218
219 i2c_release_client(dpc->saa7111a);
220
221 saa7146_unregister_device(&dpc->video_dev,dev);
222 if( 0 != DPC_BOARD_CAN_DO_VBI(dev)) {
223 saa7146_unregister_device(&dpc->vbi_dev,dev);
224 }
225 saa7146_vv_release(dev);
226
227 dpc_num--;
228
229 i2c_del_adapter(&dpc->i2c_adapter);
230 kfree(dpc);
231 return 0;
232}
233
234#ifdef axa
235int dpc_vbi_bypass(struct saa7146_dev* dev)
236{
237 struct dpc* dpc = (struct dpc*)dev->ext_priv;
238
239 int i = 1;
240
241
242 if ( 0 != dpc->saa7111a->driver->command(dpc->saa7111a,SAA711X_VBI_BYPASS, &i)) {
243 printk("dpc_v4l2.o: VBI_BYPASS: could not address saa7111a.\n");
244 return -1;
245 }
246
247 return 0;
248}
249#endif
250
251static int dpc_ioctl(struct saa7146_fh *fh, unsigned int cmd, void *arg)
252{
253 struct saa7146_dev *dev = fh->dev;
254 struct dpc* dpc = (struct dpc*)dev->ext_priv;
255
256
257
258 switch(cmd)
259 {
260 case VIDIOC_ENUMINPUT:
261 {
262 struct v4l2_input *i = arg;
263 DEB_EE(("VIDIOC_ENUMINPUT %d.\n",i->index));
264
265 if( i->index < 0 || i->index >= DPC_INPUTS) {
266 return -EINVAL;
267 }
268
269 memcpy(i, &dpc_inputs[i->index], sizeof(struct v4l2_input));
270
271 DEB_D(("dpc_v4l2.o: v4l2_ioctl: VIDIOC_ENUMINPUT %d.\n",i->index));
272 return 0;
273 }
274 case VIDIOC_G_INPUT:
275 {
276 int *input = (int *)arg;
277 *input = dpc->cur_input;
278
279 DEB_D(("dpc_v4l2.o: VIDIOC_G_INPUT: %d\n",*input));
280 return 0;
281 }
282 case VIDIOC_S_INPUT:
283 {
284 int input = *(int *)arg;
285
286 if (input < 0 || input >= DPC_INPUTS) {
287 return -EINVAL;
288 }
289
290 dpc->cur_input = input;
291
292
293
294 printk("dpc_v4l2.o: VIDIOC_S_INPUT: fixme switch input.\n");
295
296 return 0;
297 }
298 default:
299
300
301
302 return -ENOIOCTLCMD;
303 }
304 return 0;
305}
306
307static int std_callback(struct saa7146_dev* dev, struct saa7146_standard *std)
308{
309 return 0;
310}
311
312static struct saa7146_standard standard[] = {
313 {
314 .name = "PAL", .id = V4L2_STD_PAL,
315 .v_offset = 0x17, .v_field = 288,
316 .h_offset = 0x14, .h_pixels = 680,
317 .v_max_out = 576, .h_max_out = 768,
318 }, {
319 .name = "NTSC", .id = V4L2_STD_NTSC,
320 .v_offset = 0x16, .v_field = 240,
321 .h_offset = 0x06, .h_pixels = 708,
322 .v_max_out = 480, .h_max_out = 640,
323 }, {
324 .name = "SECAM", .id = V4L2_STD_SECAM,
325 .v_offset = 0x14, .v_field = 288,
326 .h_offset = 0x14, .h_pixels = 720,
327 .v_max_out = 576, .h_max_out = 768,
328 }
329};
330
331static struct saa7146_extension extension;
332
333static struct saa7146_pci_extension_data dpc = {
334 .ext_priv = "Multimedia eXtension Board",
335 .ext = &extension,
336};
337
338static struct pci_device_id pci_tbl[] = {
339 {
340 .vendor = PCI_VENDOR_ID_PHILIPS,
341 .device = PCI_DEVICE_ID_PHILIPS_SAA7146,
342 .subvendor = 0x0000,
343 .subdevice = 0x0000,
344 .driver_data = (unsigned long)&dpc,
345 }, {
346 .vendor = 0,
347 }
348};
349
350MODULE_DEVICE_TABLE(pci, pci_tbl);
351
352static struct saa7146_ext_vv vv_data = {
353 .inputs = DPC_INPUTS,
354 .capabilities = V4L2_CAP_VBI_CAPTURE,
355 .stds = &standard[0],
356 .num_stds = sizeof(standard)/sizeof(struct saa7146_standard),
357 .std_callback = &std_callback,
358 .ioctls = &ioctls[0],
359 .ioctl = dpc_ioctl,
360};
361
362static struct saa7146_extension extension = {
363 .name = "dpc7146 demonstration board",
364 .flags = SAA7146_USE_I2C_IRQ,
365
366 .pci_tbl = &pci_tbl[0],
367 .module = THIS_MODULE,
368
369 .probe = dpc_probe,
370 .attach = dpc_attach,
371 .detach = dpc_detach,
372
373 .irq_mask = 0,
374 .irq_func = NULL,
375};
376
377static int __init dpc_init_module(void)
378{
379 if( 0 != saa7146_register_extension(&extension)) {
380 DEB_S(("failed to register extension.\n"));
381 return -ENODEV;
382 }
383
384 return 0;
385}
386
387static void __exit dpc_cleanup_module(void)
388{
389 saa7146_unregister_extension(&extension);
390}
391
392module_init(dpc_init_module);
393module_exit(dpc_cleanup_module);
394
395MODULE_DESCRIPTION("video4linux-2 driver for the 'dpc7146 demonstration board'");
396MODULE_AUTHOR("Michael Hunold <michael@mihu.de>");
397MODULE_LICENSE("GPL");
398