Rev 425 | Details | Compare with Previous | Last modification | View Log | RSS feed
Rev | Author | Line No. | Line |
---|---|---|---|
425 | giacomo | 1 | /* |
2 | cm7326.c - v4l2 driver for pc104+ framegrabber module |
||
3 | http://www.rtdusa.com/PC104/UM/video/cm7326.htm |
||
4 | |||
5 | Copyright (C) 2002 Miguel Freitas |
||
6 | Copyright (C) 2003 Michael Hunold <michael@mihu.de> |
||
7 | |||
8 | Visit http://www.mihu.de/linux/saa7146 |
||
9 | for further details about this card. |
||
10 | |||
11 | This program is free software; you can redistribute it and/or modify |
||
12 | it under the terms of the GNU General Public License as published by |
||
13 | the Free Software Foundation; either version 2 of the License, or |
||
14 | (at your option) any later version. |
||
15 | |||
16 | This program is distributed in the hope that it will be useful, |
||
17 | but WITHOUT ANY WARRANTY; without even the implied warranty of |
||
18 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||
19 | GNU General Public License for more details. |
||
20 | |||
21 | You should have received a copy of the GNU General Public License |
||
22 | along with this program; if not, write to the Free Software |
||
23 | Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. |
||
24 | */ |
||
25 | |||
773 | giacomo | 26 | #include <linuxcomp.h> |
27 | |||
425 | giacomo | 28 | #define DEBUG_VARIABLE debug |
29 | #include "drivers/saa7146_vv.h" |
||
30 | |||
31 | #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,51) |
||
32 | #define KBUILD_MODNAME cm7326 |
||
33 | #endif |
||
34 | |||
35 | /* module parameters */ |
||
773 | giacomo | 36 | static int debug = 9; |
425 | giacomo | 37 | MODULE_PARM(debug,"i"); |
38 | MODULE_PARM_DESC(debug, "debug verbosity"); |
||
39 | |||
40 | /* global variables */ |
||
41 | static int cm7326_num = 0; |
||
42 | |||
43 | /* we simply use the two video-interfaces (aka port a and port b) */ |
||
44 | #define CM7326_INPUTS 6 |
||
45 | static struct v4l2_input cm7326_inputs[CM7326_INPUTS] = |
||
46 | { |
||
47 | { 0, "VID1", V4L2_INPUT_TYPE_CAMERA, 2, 0, V4L2_STD_PAL_BG|V4L2_STD_NTSC_M, 0 }, |
||
48 | { 1, "VID2", V4L2_INPUT_TYPE_CAMERA, 2, 0, V4L2_STD_PAL_BG|V4L2_STD_NTSC_M, 0 }, |
||
49 | { 2, "VID3", V4L2_INPUT_TYPE_CAMERA, 2, 0, V4L2_STD_PAL_BG|V4L2_STD_NTSC_M, 0 }, |
||
50 | { 3, "VID4", V4L2_INPUT_TYPE_CAMERA, 2, 0, V4L2_STD_PAL_BG|V4L2_STD_NTSC_M, 0 }, |
||
51 | { 4, "VID5", V4L2_INPUT_TYPE_CAMERA, 2, 0, V4L2_STD_PAL_BG|V4L2_STD_NTSC_M, 0 }, |
||
52 | { 5, "VID6", V4L2_INPUT_TYPE_CAMERA, 2, 0, V4L2_STD_PAL_BG|V4L2_STD_NTSC_M, 0 }, |
||
53 | }; |
||
54 | |||
55 | #define CM7326_AUDIOS 0 |
||
56 | |||
57 | /* you can demand that your extension get's called for any v4l2-ioctl. here, |
||
58 | we want to be called exclusively when the ioctls VIDIOC_S_INPUT and |
||
59 | VIDIOC_ENUMINPUT get called by an user application */ |
||
60 | static struct saa7146_extension_ioctls ioctls[] = |
||
61 | { |
||
62 | { VIDIOC_ENUMINPUT, SAA7146_EXCLUSIVE }, |
||
63 | { VIDIOC_G_INPUT, SAA7146_EXCLUSIVE }, |
||
64 | { VIDIOC_S_INPUT, SAA7146_EXCLUSIVE }, |
||
65 | { VIDIOC_S_STD, SAA7146_AFTER }, |
||
66 | { 0, 0 } |
||
67 | }; |
||
68 | |||
69 | struct cm7326 |
||
70 | { |
||
71 | struct video_device video_dev; |
||
72 | struct video_device vbi_dev; |
||
73 | |||
74 | struct i2c_adapter i2c_adapter; |
||
75 | |||
76 | int cur_input; /* current input */ |
||
77 | }; |
||
78 | |||
79 | static unsigned char saa7110_initseq[] = { |
||
80 | 0x4C, 0x3C, 0x0D, 0xEF, 0xBD, 0xF0, 0x00, 0x00, |
||
81 | 0xF8, 0xF8, 0x60, 0x60, 0x00, 0x06, 0x18, 0x90, |
||
82 | 0x00, 0x2C, 0x40, 0x46, 0x42, 0x1A, 0xFF, 0xDA, |
||
83 | 0xF0, 0x8B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
||
84 | 0xD9, 0x17, 0x40, 0x41, 0x80, 0x41, 0x80, 0x4F, |
||
85 | 0xFE, 0x01, 0xCF, 0x0F, 0x03, 0x01, 0x81, 0x03, |
||
86 | 0x40, 0x75, 0x01, 0x8C, 0x03 |
||
87 | }; |
||
88 | |||
89 | static int saa7110_init(struct cm7326 *cm7326) |
||
90 | { |
||
91 | union i2c_smbus_data data; |
||
92 | int ret = 0; |
||
93 | int i = 0; |
||
94 | |||
95 | for (i = 0; i < sizeof(saa7110_initseq); i++) { |
||
96 | data.byte = saa7110_initseq[i]; |
||
97 | if (0 != i2c_smbus_xfer(&cm7326->i2c_adapter, 0x4e, 0, I2C_SMBUS_WRITE, i, I2C_SMBUS_BYTE_DATA, &data)) { |
||
98 | DEB_D(("failed for address 0x%02x\n", i)); |
||
99 | return -EFAULT; |
||
100 | } |
||
101 | } |
||
102 | |||
103 | data.byte = 0x16; |
||
104 | ret += i2c_smbus_xfer(&cm7326->i2c_adapter, 0x4e, 0, I2C_SMBUS_WRITE, 0x21, I2C_SMBUS_BYTE_DATA, &data); |
||
105 | |||
106 | /* fixme: unclear why there are two writes to register 0x0d here ... */ |
||
107 | data.byte = 0x04; |
||
108 | ret += i2c_smbus_xfer(&cm7326->i2c_adapter, 0x4e, 0, I2C_SMBUS_WRITE, 0x0D, I2C_SMBUS_BYTE_DATA, &data); |
||
109 | data.byte = 0x06; |
||
110 | ret += i2c_smbus_xfer(&cm7326->i2c_adapter, 0x4e, 0, I2C_SMBUS_WRITE, 0x0D, I2C_SMBUS_BYTE_DATA, &data); |
||
111 | |||
112 | if (0 != ret) { |
||
113 | DEB_S(("writing to saa7110 failed.\n")); |
||
114 | return -EFAULT; |
||
115 | } |
||
116 | |||
117 | return 0; |
||
118 | } |
||
119 | |||
120 | static const unsigned char input_modes[9][8] = { |
||
121 | /* mode 0 */ { 0x00, 0xD9, 0x17, 0x40, 0x03, 0x44, 0x75, 0x16 }, |
||
122 | /* mode 1 */ { 0x00, 0xD8, 0x17, 0x40, 0x03, 0x44, 0x75, 0x16 }, |
||
123 | /* mode 2 */ { 0x00, 0xBA, 0x07, 0x91, 0x03, 0x60, 0xB5, 0x05 }, |
||
124 | /* mode 3 */ { 0x00, 0xB8, 0x07, 0x91, 0x03, 0x60, 0xB5, 0x05 }, |
||
125 | /* mode 4 */ { 0x00, 0x7C, 0x07, 0xD2, 0x83, 0x60, 0xB5, 0x03 }, |
||
126 | /* mode 5 */ { 0x00, 0x78, 0x07, 0xD2, 0x83, 0x60, 0xB5, 0x03 }, |
||
127 | /* mode 6 */ { 0x80, 0x59, 0x17, 0x42, 0xA3, 0x44, 0x75, 0x12 }, |
||
128 | /* mode 7 */ { 0x80, 0x9A, 0x17, 0xB1, 0x13, 0x60, 0xB5, 0x14 }, |
||
129 | /* mode 8 */ { 0x80, 0x3C, 0x27, 0xC1, 0x23, 0x44, 0x75, 0x21 } |
||
130 | }; |
||
131 | |||
132 | static int saa7110_selmux(struct cm7326 *cm7326, int chan) |
||
133 | { |
||
134 | const unsigned char* ptr = input_modes[chan]; |
||
135 | union i2c_smbus_data data; |
||
136 | int ret = 0; |
||
137 | |||
138 | data.byte = ptr[0]; /* Luminance control */ |
||
139 | ret += i2c_smbus_xfer(&cm7326->i2c_adapter, 0x4e, 0, I2C_SMBUS_WRITE, 0x06, I2C_SMBUS_BYTE_DATA, &data); |
||
140 | |||
141 | data.byte = ptr[1]; /* Analog Control #1 */ |
||
142 | ret += i2c_smbus_xfer(&cm7326->i2c_adapter, 0x4e, 0, I2C_SMBUS_WRITE, 0x20, I2C_SMBUS_BYTE_DATA, &data); |
||
143 | |||
144 | data.byte = ptr[2]; /* Analog Control #2 */ |
||
145 | ret += i2c_smbus_xfer(&cm7326->i2c_adapter, 0x4e, 0, I2C_SMBUS_WRITE, 0x21, I2C_SMBUS_BYTE_DATA, &data); |
||
146 | |||
147 | data.byte = ptr[3]; /* Mixer Control #1 */ |
||
148 | ret += i2c_smbus_xfer(&cm7326->i2c_adapter, 0x4e, 0, I2C_SMBUS_WRITE, 0x22, I2C_SMBUS_BYTE_DATA, &data); |
||
149 | |||
150 | data.byte = ptr[4]; /* Mixer Control #2 */ |
||
151 | ret += i2c_smbus_xfer(&cm7326->i2c_adapter, 0x4e, 0, I2C_SMBUS_WRITE, 0x2c, I2C_SMBUS_BYTE_DATA, &data); |
||
152 | |||
153 | data.byte = ptr[5]; /* ADCs gain control */ |
||
154 | ret += i2c_smbus_xfer(&cm7326->i2c_adapter, 0x4e, 0, I2C_SMBUS_WRITE, 0x30, I2C_SMBUS_BYTE_DATA, &data); |
||
155 | |||
156 | data.byte = ptr[6]; /* Mixer Control #3 */ |
||
157 | ret += i2c_smbus_xfer(&cm7326->i2c_adapter, 0x4e, 0, I2C_SMBUS_WRITE, 0x31, I2C_SMBUS_BYTE_DATA, &data); |
||
158 | |||
159 | /* fixme: unclear why there are two writes analog control #2 above and here */ |
||
160 | data.byte = ptr[7]; /* Analog Control #2 */ |
||
161 | ret += i2c_smbus_xfer(&cm7326->i2c_adapter, 0x4e, 0, I2C_SMBUS_WRITE, 0x21, I2C_SMBUS_BYTE_DATA, &data); |
||
162 | |||
163 | if (0 != ret) { |
||
164 | DEB_S(("writing to saa7110 failed.\n")); |
||
165 | return -EFAULT; |
||
166 | } |
||
167 | |||
168 | return 0; |
||
169 | } |
||
170 | |||
171 | static int cm7326_probe(struct saa7146_dev *dev) |
||
172 | { |
||
173 | struct cm7326 *cm7326 = NULL; |
||
174 | union i2c_smbus_data data; |
||
175 | int err = 0; |
||
176 | |||
177 | DEB_D(("cm7326_probe called.\n")); |
||
178 | |||
179 | cm7326 = (struct cm7326*)kmalloc(sizeof(struct cm7326), GFP_KERNEL); |
||
180 | if( NULL == cm7326 ) { |
||
181 | printk("cm7326: cm7326_probe: not enough kernel memory.\n"); |
||
182 | return -ENOMEM; |
||
183 | } |
||
184 | memset(cm7326, 0x0, sizeof(struct cm7326)); |
||
185 | |||
186 | saa7146_i2c_adapter_prepare(dev, &cm7326->i2c_adapter, SAA7146_I2C_BUS_BIT_RATE_480); |
||
187 | if(i2c_add_adapter(&cm7326->i2c_adapter) < 0) { |
||
188 | DEB_S(("cannot register i2c-device. skipping.\n")); |
||
189 | kfree(cm7326); |
||
190 | return -EFAULT; |
||
191 | } |
||
192 | |||
193 | /* have a look if a saa7110 is present */ |
||
194 | if (0 != (err = i2c_smbus_xfer(&cm7326->i2c_adapter, 0x4e, 0, I2C_SMBUS_READ, 0x00, I2C_SMBUS_BYTE_DATA, &data))) { |
||
195 | DEB_D(("cm7326_probe failed for this device.\n")); |
||
196 | i2c_del_adapter(&cm7326->i2c_adapter); |
||
197 | kfree(cm7326); |
||
198 | return -ENODEV; |
||
199 | } |
||
200 | |||
201 | DEB_D(("cm7326_probe succeeded for this device.\n")); |
||
202 | |||
203 | /* we store the pointer in our private data field */ |
||
204 | (struct cm7326*)dev->ext_priv = cm7326; |
||
205 | |||
206 | return 0; |
||
207 | } |
||
208 | |||
209 | /* bring hardware to a sane state. this has to be done, just in case someone |
||
210 | wants to capture from this device before it has been properly initialized. |
||
211 | the capture engine would badly fail, because no valid signal arrives on the |
||
212 | saa7146, thus leading to timeouts and stuff. */ |
||
213 | static int cm7326_init_done(struct saa7146_dev *dev) |
||
214 | { |
||
215 | struct cm7326* cm7326 = (struct cm7326*)dev->ext_priv; |
||
216 | int ret = 0; |
||
217 | |||
218 | DEB_D(("cm7326_init_done called.\n")); |
||
219 | |||
220 | /* initialize the helper ics to useful values */ |
||
221 | if (0 != (ret = saa7110_init(cm7326))) { |
||
222 | DEB_S(("initialization of saa7110 failed\n")); |
||
223 | return -EFAULT; |
||
224 | } |
||
225 | |||
226 | /* the rest for saa7146: you should definitely set some basic values |
||
227 | for the input-port handling of the saa7146. */ |
||
228 | |||
229 | /* some stuff is done via variables */ |
||
230 | saa7146_set_hps_source_and_sync(dev, SAA7146_HPS_SOURCE_PORT_A, SAA7146_HPS_SYNC_PORT_A); |
||
231 | |||
232 | /* some stuff is done via direct write to the registers */ |
||
233 | |||
234 | /* this is ugly, but because of the fact that this is completely |
||
235 | hardware dependend, it should be done directly... */ |
||
236 | saa7146_write(dev, DD1_STREAM_B, 0x00000000); |
||
237 | saa7146_write(dev, DD1_INIT, 0x02000200); |
||
238 | saa7146_write(dev, MC2, (MASK_09 | MASK_25 | MASK_10 | MASK_26)); |
||
239 | |||
240 | return 0; |
||
241 | } |
||
242 | |||
243 | static struct saa7146_ext_vv vv_data; |
||
244 | |||
245 | /* this function only gets called when the probing was successful */ |
||
246 | static int cm7326_attach(struct saa7146_dev *dev, struct saa7146_pci_extension_data *info) |
||
247 | { |
||
248 | struct cm7326* cm7326 = (struct cm7326*)dev->ext_priv; |
||
249 | |||
250 | DEB_D(("cm7326_attach called.\n")); |
||
251 | |||
252 | /* checking for i2c-devices can be omitted here, because we |
||
253 | already did this in "cm7326_vl42_probe" */ |
||
254 | |||
255 | saa7146_vv_init(dev,&vv_data); |
||
256 | if( 0 != saa7146_register_device(&cm7326->video_dev, dev, "cm7326", VFL_TYPE_GRABBER)) { |
||
257 | ERR(("cannot register capture v4l2 device. skipping.\n")); |
||
258 | return -1; |
||
259 | } |
||
260 | |||
261 | printk("cm7326: found 'cm7326'-%d.\n",cm7326_num); |
||
262 | cm7326_num++; |
||
263 | |||
264 | /* the rest */ |
||
265 | cm7326->cur_input = 0; |
||
266 | return cm7326_init_done(dev); |
||
267 | } |
||
268 | |||
269 | static int cm7326_detach(struct saa7146_dev *dev) |
||
270 | { |
||
271 | struct cm7326* cm7326 = (struct cm7326*)dev->ext_priv; |
||
272 | |||
273 | DEB_EE(("dev:%p\n",dev)); |
||
274 | |||
275 | saa7146_unregister_device(&cm7326->video_dev,dev); |
||
276 | saa7146_vv_release(dev); |
||
277 | |||
278 | cm7326_num--; |
||
279 | |||
280 | i2c_del_adapter(&cm7326->i2c_adapter); |
||
281 | kfree(cm7326); |
||
282 | return 0; |
||
283 | } |
||
284 | |||
285 | static int cm7326_ioctl(struct saa7146_fh *fh, unsigned int cmd, void *arg) |
||
286 | { |
||
287 | struct saa7146_dev *dev = fh->dev; |
||
288 | struct cm7326* card = (struct cm7326*)dev->ext_priv; |
||
289 | |||
290 | switch(cmd) |
||
291 | { |
||
292 | case VIDIOC_G_INPUT: |
||
293 | { |
||
294 | int* input = (int *)arg; |
||
295 | *input = card->cur_input; |
||
296 | |||
297 | DEB_D(("VIDIOC_G_INPUT %d.\n",*input)); |
||
298 | return 0; |
||
299 | } |
||
300 | case VIDIOC_S_INPUT: |
||
301 | { |
||
302 | int input = *(int *)arg; |
||
303 | int source = 0, sync = 0; |
||
304 | int i; |
||
305 | static int saa7110_inputs[6] = {5,4,3,2,1,0}; |
||
306 | |||
307 | if (input < 0 || input >= CM7326_INPUTS) { |
||
308 | DEB_D(("v4l2_ioctl: VIDIOC_S_INPUT: invalid input %d.\n",input)); |
||
309 | return -EINVAL; |
||
310 | } |
||
311 | |||
312 | DEB_D(("v4l2_ioctl: VIDIOC_S_INPUT %d.\n",input)); |
||
313 | |||
314 | source = SAA7146_HPS_SOURCE_PORT_A; |
||
315 | sync = SAA7146_HPS_SYNC_PORT_A; |
||
316 | card->cur_input = input; |
||
317 | |||
318 | /* switch video in saa7110 */ |
||
319 | saa7146_set_hps_source_and_sync(dev, source, sync); |
||
320 | i = saa7110_inputs[input]; |
||
321 | return saa7110_selmux(card, i); |
||
322 | } |
||
323 | case VIDIOC_ENUMINPUT: |
||
324 | { |
||
325 | struct v4l2_input *i = arg; |
||
326 | |||
327 | /* sanity check to satisfy xawtv */ |
||
328 | if( i->index < 0 || i->index >= CM7326_INPUTS) { |
||
329 | DEB_D(("v4l2_ioctl: VIDIOC_ENUMINPUT: invalid input %d.\n",i->index)); |
||
330 | return -EINVAL; |
||
331 | } |
||
332 | |||
333 | memcpy(i, &cm7326_inputs[i->index], sizeof(struct v4l2_input)); |
||
334 | |||
335 | DEB_D(("v4l2_ioctl: VIDIOC_ENUMINPUT %d.\n",i->index)); |
||
336 | return 0; |
||
337 | } |
||
338 | default: |
||
339 | DEB_D(("v4l2_ioctl does not handle this ioctl.\n")); |
||
340 | return -ENOIOCTLCMD; |
||
341 | } |
||
342 | return 0; |
||
343 | } |
||
344 | |||
345 | static int std_callback(struct saa7146_dev *dev, struct saa7146_standard *std) |
||
346 | { |
||
347 | struct cm7326* cm7326 = (struct cm7326*)dev->ext_priv; |
||
348 | union i2c_smbus_data data; |
||
349 | int ret = 0; |
||
350 | |||
351 | data.byte = 0x00; |
||
352 | ret += i2c_smbus_xfer(&cm7326->i2c_adapter, 0x4e, 0, I2C_SMBUS_WRITE, 0x06, I2C_SMBUS_BYTE_DATA, &data); |
||
353 | |||
354 | switch (std->id) { |
||
355 | case V4L2_STD_NTSC: |
||
356 | { |
||
357 | data.byte = 0x06; |
||
358 | ret += i2c_smbus_xfer(&cm7326->i2c_adapter, 0x4e, 0, I2C_SMBUS_WRITE, 0x0D, I2C_SMBUS_BYTE_DATA, &data); |
||
359 | data.byte = 0x2C; |
||
360 | ret += i2c_smbus_xfer(&cm7326->i2c_adapter, 0x4e, 0, I2C_SMBUS_WRITE, 0x11, I2C_SMBUS_BYTE_DATA, &data); |
||
361 | data.byte = 0x81; |
||
362 | ret += i2c_smbus_xfer(&cm7326->i2c_adapter, 0x4e, 0, I2C_SMBUS_WRITE, 0x30, I2C_SMBUS_BYTE_DATA, &data); |
||
363 | data.byte = 0xDF; |
||
364 | ret += i2c_smbus_xfer(&cm7326->i2c_adapter, 0x4e, 0, I2C_SMBUS_WRITE, 0x2A, I2C_SMBUS_BYTE_DATA, &data); |
||
365 | break; |
||
366 | } |
||
367 | case V4L2_STD_PAL: |
||
368 | { |
||
369 | data.byte = 0x06; |
||
370 | ret += i2c_smbus_xfer(&cm7326->i2c_adapter, 0x4e, 0, I2C_SMBUS_WRITE, 0x0D, I2C_SMBUS_BYTE_DATA, &data); |
||
371 | data.byte = 0x59; |
||
372 | ret += i2c_smbus_xfer(&cm7326->i2c_adapter, 0x4e, 0, I2C_SMBUS_WRITE, 0x11, I2C_SMBUS_BYTE_DATA, &data); |
||
373 | data.byte = 0x9A; |
||
374 | ret += i2c_smbus_xfer(&cm7326->i2c_adapter, 0x4e, 0, I2C_SMBUS_WRITE, 0x2E, I2C_SMBUS_BYTE_DATA, &data); |
||
375 | break; |
||
376 | } |
||
377 | case V4L2_STD_SECAM: |
||
378 | { |
||
379 | data.byte = 0x07; |
||
380 | ret += i2c_smbus_xfer(&cm7326->i2c_adapter, 0x4e, 0, I2C_SMBUS_WRITE, 0x0D, I2C_SMBUS_BYTE_DATA, &data); |
||
381 | data.byte = 0x59; |
||
382 | ret += i2c_smbus_xfer(&cm7326->i2c_adapter, 0x4e, 0, I2C_SMBUS_WRITE, 0x11, I2C_SMBUS_BYTE_DATA, &data); |
||
383 | data.byte = 0x9A; |
||
384 | ret += i2c_smbus_xfer(&cm7326->i2c_adapter, 0x4e, 0, I2C_SMBUS_WRITE, 0x2E, I2C_SMBUS_BYTE_DATA, &data); |
||
385 | break; |
||
386 | } |
||
387 | default: |
||
388 | { |
||
389 | DEB_S(("invalid standard.\n")); |
||
390 | return -EFAULT; |
||
391 | } |
||
392 | } |
||
393 | |||
394 | if (0 != ret) { |
||
395 | DEB_S(("writing to saa7110 failed.\n")); |
||
396 | return -EFAULT; |
||
397 | } |
||
398 | |||
399 | return 0; |
||
400 | } |
||
401 | |||
402 | static struct saa7146_standard standard[] = { |
||
403 | { |
||
404 | .name = "PAL", .id = V4L2_STD_PAL, |
||
405 | .v_offset = 0x17, .v_field = 288, .v_calc = 576, |
||
406 | .h_offset = 0x14, .h_pixels = 680, .h_calc = 680+1, |
||
407 | .v_max_out = 576, .h_max_out = 768, |
||
408 | }, { |
||
409 | .name = "NTSC", .id = V4L2_STD_NTSC, |
||
410 | .v_offset = 0x14, .v_field = 240, .v_calc = 480, |
||
411 | .h_offset = 0x00, .h_pixels = 640, .h_calc = 640+1, |
||
412 | .v_max_out = 480, .h_max_out = 640, |
||
413 | }, { |
||
414 | .name = "SECAM", .id = V4L2_STD_SECAM, |
||
415 | .v_offset = 0x14, .v_field = 288, .v_calc = 576, |
||
416 | .h_offset = 0x14, .h_pixels = 720, .h_calc = 720+1, |
||
417 | .v_max_out = 576, .h_max_out = 768, |
||
418 | } |
||
419 | }; |
||
420 | |||
421 | static struct saa7146_extension extension; |
||
422 | |||
423 | static struct saa7146_pci_extension_data cm7326 = { |
||
424 | .ext_priv = "cm7326", |
||
425 | .ext = &extension, |
||
426 | }; |
||
427 | |||
428 | static struct pci_device_id pci_tbl[] = { |
||
429 | { |
||
430 | .vendor = PCI_VENDOR_ID_PHILIPS, |
||
431 | .device = PCI_DEVICE_ID_PHILIPS_SAA7146, |
||
432 | .subvendor = 0x1435, |
||
433 | .subdevice = 0x3303, |
||
434 | .driver_data = (unsigned long)&cm7326, |
||
435 | }, { |
||
436 | .vendor = 0, |
||
437 | } |
||
438 | }; |
||
439 | |||
440 | static struct saa7146_ext_vv vv_data = { |
||
441 | .inputs = CM7326_INPUTS, |
||
442 | .capabilities = 0, |
||
443 | .stds = &standard[0], |
||
444 | .num_stds = sizeof(standard)/sizeof(struct saa7146_standard), |
||
445 | .std_callback = &std_callback, |
||
446 | .ioctls = &ioctls[0], |
||
447 | .ioctl = cm7326_ioctl, |
||
448 | }; |
||
449 | |||
450 | static struct saa7146_extension extension = { |
||
451 | .name = "cm7326", |
||
452 | .flags = SAA7146_USE_I2C_IRQ, |
||
453 | |||
454 | .pci_tbl = &pci_tbl[0], |
||
455 | .module = THIS_MODULE, |
||
456 | |||
457 | .probe = cm7326_probe, |
||
458 | .attach = cm7326_attach, |
||
459 | .detach = cm7326_detach, |
||
460 | |||
461 | .irq_mask = 0, |
||
462 | .irq_func = NULL, |
||
463 | }; |
||
464 | |||
465 | |||
466 | int __init cm7326_init_module(void) |
||
467 | { |
||
468 | int ret = 0; |
||
469 | |||
470 | ret = saa7146_register_extension(&extension); |
||
471 | if (0 != ret) { |
||
472 | DEB_S(("failed to register extension.\n")); |
||
473 | } |
||
474 | |||
475 | return ret; |
||
476 | } |
||
477 | |||
478 | void __exit cm7326_cleanup_module(void) |
||
479 | { |
||
480 | saa7146_unregister_extension(&extension); |
||
481 | } |
||
482 | |||
483 | module_init(cm7326_init_module); |
||
484 | module_exit(cm7326_cleanup_module); |
||
485 | |||
486 | MODULE_AUTHOR("Miguel Freitas, Michael Hunold"); |
||
487 | MODULE_DESCRIPTION("CM7326 frame grabber v4l2-driver"); |
||
488 | MODULE_LICENSE("GPL"); |
||
489 |