diff options
author | Jiri Kosina <jkosina@suse.cz> | 2010-10-30 16:16:56 -0400 |
---|---|---|
committer | Jiri Kosina <jkosina@suse.cz> | 2010-10-30 16:16:56 -0400 |
commit | f1e095f1d206b81b44160f41278ce5c78641e9b7 (patch) | |
tree | bd293d46d2d3e4cdf435a22ddb2877c6ba1b8acc /drivers/media/video/saa7164 | |
parent | b0438a1b71955c425c304a2a483765ef24841766 (diff) | |
parent | 1792f17b7210280a3d7ff29da9614ba779cfcedb (diff) |
Merge branch 'master' into for-next
Diffstat (limited to 'drivers/media/video/saa7164')
-rw-r--r-- | drivers/media/video/saa7164/Makefile | 2 | ||||
-rw-r--r-- | drivers/media/video/saa7164/saa7164-api.c | 973 | ||||
-rw-r--r-- | drivers/media/video/saa7164/saa7164-buffer.c | 194 | ||||
-rw-r--r-- | drivers/media/video/saa7164/saa7164-bus.c | 131 | ||||
-rw-r--r-- | drivers/media/video/saa7164/saa7164-cards.c | 33 | ||||
-rw-r--r-- | drivers/media/video/saa7164/saa7164-cmd.c | 35 | ||||
-rw-r--r-- | drivers/media/video/saa7164/saa7164-core.c | 890 | ||||
-rw-r--r-- | drivers/media/video/saa7164/saa7164-dvb.c | 109 | ||||
-rw-r--r-- | drivers/media/video/saa7164/saa7164-encoder.c | 1503 | ||||
-rw-r--r-- | drivers/media/video/saa7164/saa7164-fw.c | 11 | ||||
-rw-r--r-- | drivers/media/video/saa7164/saa7164-i2c.c | 2 | ||||
-rw-r--r-- | drivers/media/video/saa7164/saa7164-reg.h | 59 | ||||
-rw-r--r-- | drivers/media/video/saa7164/saa7164-types.h | 255 | ||||
-rw-r--r-- | drivers/media/video/saa7164/saa7164-vbi.c | 1375 | ||||
-rw-r--r-- | drivers/media/video/saa7164/saa7164.h | 295 |
15 files changed, 5522 insertions, 345 deletions
diff --git a/drivers/media/video/saa7164/Makefile b/drivers/media/video/saa7164/Makefile index 4b329fd42add..6303a8e60eac 100644 --- a/drivers/media/video/saa7164/Makefile +++ b/drivers/media/video/saa7164/Makefile | |||
@@ -1,6 +1,6 @@ | |||
1 | saa7164-objs := saa7164-cards.o saa7164-core.o saa7164-i2c.o saa7164-dvb.o \ | 1 | saa7164-objs := saa7164-cards.o saa7164-core.o saa7164-i2c.o saa7164-dvb.o \ |
2 | saa7164-fw.o saa7164-bus.o saa7164-cmd.o saa7164-api.o \ | 2 | saa7164-fw.o saa7164-bus.o saa7164-cmd.o saa7164-api.o \ |
3 | saa7164-buffer.o | 3 | saa7164-buffer.o saa7164-encoder.o saa7164-vbi.o |
4 | 4 | ||
5 | obj-$(CONFIG_VIDEO_SAA7164) += saa7164.o | 5 | obj-$(CONFIG_VIDEO_SAA7164) += saa7164.o |
6 | 6 | ||
diff --git a/drivers/media/video/saa7164/saa7164-api.c b/drivers/media/video/saa7164/saa7164-api.c index 3f1262b00cc0..ad3bc4154176 100644 --- a/drivers/media/video/saa7164/saa7164-api.c +++ b/drivers/media/video/saa7164/saa7164-api.c | |||
@@ -1,7 +1,7 @@ | |||
1 | /* | 1 | /* |
2 | * Driver for the NXP SAA7164 PCIe bridge | 2 | * Driver for the NXP SAA7164 PCIe bridge |
3 | * | 3 | * |
4 | * Copyright (c) 2009 Steven Toth <stoth@kernellabs.com> | 4 | * Copyright (c) 2010 Steven Toth <stoth@kernellabs.com> |
5 | * | 5 | * |
6 | * This program is free software; you can redistribute it and/or modify | 6 | * This program is free software; you can redistribute it and/or modify |
7 | * it under the terms of the GNU General Public License as published by | 7 | * it under the terms of the GNU General Public License as published by |
@@ -24,14 +24,750 @@ | |||
24 | 24 | ||
25 | #include "saa7164.h" | 25 | #include "saa7164.h" |
26 | 26 | ||
27 | int saa7164_api_transition_port(struct saa7164_tsport *port, u8 mode) | 27 | int saa7164_api_get_load_info(struct saa7164_dev *dev, struct tmFwInfoStruct *i) |
28 | { | 28 | { |
29 | int ret; | 29 | int ret; |
30 | 30 | ||
31 | if (!(saa_debug & DBGLVL_CPU)) | ||
32 | return 0; | ||
33 | |||
34 | dprintk(DBGLVL_API, "%s()\n", __func__); | ||
35 | |||
36 | i->deviceinst = 0; | ||
37 | i->devicespec = 0; | ||
38 | i->mode = 0; | ||
39 | i->status = 0; | ||
40 | |||
41 | ret = saa7164_cmd_send(dev, 0, GET_CUR, | ||
42 | GET_FW_STATUS_CONTROL, sizeof(struct tmFwInfoStruct), i); | ||
43 | if (ret != SAA_OK) { | ||
44 | printk(KERN_ERR "%s() error, ret = 0x%x\n", __func__, ret); | ||
45 | } | ||
46 | |||
47 | printk(KERN_INFO "saa7164[%d]-CPU: %d percent", dev->nr, i->CPULoad); | ||
48 | |||
49 | return ret; | ||
50 | } | ||
51 | |||
52 | int saa7164_api_collect_debug(struct saa7164_dev *dev) | ||
53 | { | ||
54 | struct tmComResDebugGetData d; | ||
55 | u8 more = 255; | ||
56 | int ret; | ||
57 | |||
58 | dprintk(DBGLVL_API, "%s()\n", __func__); | ||
59 | |||
60 | while (more--) { | ||
61 | |||
62 | memset(&d, 0, sizeof(d)); | ||
63 | |||
64 | ret = saa7164_cmd_send(dev, 0, GET_CUR, | ||
65 | GET_DEBUG_DATA_CONTROL, sizeof(d), &d); | ||
66 | if (ret != SAA_OK) { | ||
67 | printk(KERN_ERR "%s() error, ret = 0x%x\n", __func__, ret); | ||
68 | } | ||
69 | |||
70 | if (d.dwResult != SAA_OK) | ||
71 | break; | ||
72 | |||
73 | printk(KERN_INFO "saa7164[%d]-FWMSG: %s", dev->nr, d.ucDebugData); | ||
74 | } | ||
75 | |||
76 | return 0; | ||
77 | } | ||
78 | |||
79 | int saa7164_api_set_debug(struct saa7164_dev *dev, u8 level) | ||
80 | { | ||
81 | struct tmComResDebugSetLevel lvl; | ||
82 | int ret; | ||
83 | |||
84 | dprintk(DBGLVL_API, "%s(level=%d)\n", __func__, level); | ||
85 | |||
86 | /* Retrieve current state */ | ||
87 | ret = saa7164_cmd_send(dev, 0, GET_CUR, | ||
88 | SET_DEBUG_LEVEL_CONTROL, sizeof(lvl), &lvl); | ||
89 | if (ret != SAA_OK) { | ||
90 | printk(KERN_ERR "%s() error, ret = 0x%x\n", __func__, ret); | ||
91 | } | ||
92 | dprintk(DBGLVL_API, "%s() Was %d\n", __func__, lvl.dwDebugLevel); | ||
93 | |||
94 | lvl.dwDebugLevel = level; | ||
95 | |||
96 | /* set new state */ | ||
97 | ret = saa7164_cmd_send(dev, 0, SET_CUR, | ||
98 | SET_DEBUG_LEVEL_CONTROL, sizeof(lvl), &lvl); | ||
99 | if (ret != SAA_OK) { | ||
100 | printk(KERN_ERR "%s() error, ret = 0x%x\n", __func__, ret); | ||
101 | } | ||
102 | |||
103 | return ret; | ||
104 | } | ||
105 | |||
106 | int saa7164_api_set_vbi_format(struct saa7164_port *port) | ||
107 | { | ||
108 | struct saa7164_dev *dev = port->dev; | ||
109 | struct tmComResProbeCommit fmt, rsp; | ||
110 | int ret; | ||
111 | |||
112 | dprintk(DBGLVL_API, "%s(nr=%d, unitid=0x%x)\n", __func__, | ||
113 | port->nr, port->hwcfg.unitid); | ||
114 | |||
115 | fmt.bmHint = 0; | ||
116 | fmt.bFormatIndex = 1; | ||
117 | fmt.bFrameIndex = 1; | ||
118 | |||
119 | /* Probe, see if it can support this format */ | ||
120 | ret = saa7164_cmd_send(port->dev, port->hwcfg.unitid, | ||
121 | SET_CUR, SAA_PROBE_CONTROL, sizeof(fmt), &fmt); | ||
122 | if (ret != SAA_OK) | ||
123 | printk(KERN_ERR "%s() set error, ret = 0x%x\n", __func__, ret); | ||
124 | |||
125 | /* See of the format change was successful */ | ||
126 | ret = saa7164_cmd_send(port->dev, port->hwcfg.unitid, | ||
127 | GET_CUR, SAA_PROBE_CONTROL, sizeof(rsp), &rsp); | ||
128 | if (ret != SAA_OK) { | ||
129 | printk(KERN_ERR "%s() get error, ret = 0x%x\n", __func__, ret); | ||
130 | } else { | ||
131 | /* Compare requested vs received, should be same */ | ||
132 | if (memcmp(&fmt, &rsp, sizeof(rsp)) == 0) { | ||
133 | dprintk(DBGLVL_API, "SET/PROBE Verified\n"); | ||
134 | |||
135 | /* Ask the device to select the negotiated format */ | ||
136 | ret = saa7164_cmd_send(port->dev, port->hwcfg.unitid, | ||
137 | SET_CUR, SAA_COMMIT_CONTROL, sizeof(fmt), &fmt); | ||
138 | if (ret != SAA_OK) | ||
139 | printk(KERN_ERR "%s() commit error, ret = 0x%x\n", | ||
140 | __func__, ret); | ||
141 | |||
142 | ret = saa7164_cmd_send(port->dev, port->hwcfg.unitid, | ||
143 | GET_CUR, SAA_COMMIT_CONTROL, sizeof(rsp), &rsp); | ||
144 | if (ret != SAA_OK) | ||
145 | printk(KERN_ERR "%s() GET commit error, ret = 0x%x\n", | ||
146 | __func__, ret); | ||
147 | |||
148 | if (memcmp(&fmt, &rsp, sizeof(rsp)) != 0) { | ||
149 | printk(KERN_ERR "%s() memcmp error, ret = 0x%x\n", | ||
150 | __func__, ret); | ||
151 | } else | ||
152 | dprintk(DBGLVL_API, "SET/COMMIT Verified\n"); | ||
153 | |||
154 | dprintk(DBGLVL_API, "rsp.bmHint = 0x%x\n", rsp.bmHint); | ||
155 | dprintk(DBGLVL_API, "rsp.bFormatIndex = 0x%x\n", rsp.bFormatIndex); | ||
156 | dprintk(DBGLVL_API, "rsp.bFrameIndex = 0x%x\n", rsp.bFrameIndex); | ||
157 | } else | ||
158 | printk(KERN_ERR "%s() compare failed\n", __func__); | ||
159 | } | ||
160 | |||
161 | if (ret == SAA_OK) | ||
162 | dprintk(DBGLVL_API, "%s(nr=%d) Success\n", __func__, port->nr); | ||
163 | |||
164 | return ret; | ||
165 | } | ||
166 | |||
167 | int saa7164_api_set_gop_size(struct saa7164_port *port) | ||
168 | { | ||
169 | struct saa7164_dev *dev = port->dev; | ||
170 | struct tmComResEncVideoGopStructure gs; | ||
171 | int ret; | ||
172 | |||
173 | dprintk(DBGLVL_ENC, "%s()\n", __func__); | ||
174 | |||
175 | gs.ucRefFrameDist = port->encoder_params.refdist; | ||
176 | gs.ucGOPSize = port->encoder_params.gop_size; | ||
177 | ret = saa7164_cmd_send(port->dev, port->hwcfg.sourceid, SET_CUR, | ||
178 | EU_VIDEO_GOP_STRUCTURE_CONTROL, | ||
179 | sizeof(gs), &gs); | ||
180 | if (ret != SAA_OK) | ||
181 | printk(KERN_ERR "%s() error, ret = 0x%x\n", __func__, ret); | ||
182 | |||
183 | return ret; | ||
184 | } | ||
185 | |||
186 | int saa7164_api_set_encoder(struct saa7164_port *port) | ||
187 | { | ||
188 | struct saa7164_dev *dev = port->dev; | ||
189 | struct tmComResEncVideoBitRate vb; | ||
190 | struct tmComResEncAudioBitRate ab; | ||
191 | int ret; | ||
192 | |||
193 | dprintk(DBGLVL_ENC, "%s() unitid=0x%x\n", __func__, | ||
194 | port->hwcfg.sourceid); | ||
195 | |||
196 | if (port->encoder_params.stream_type == V4L2_MPEG_STREAM_TYPE_MPEG2_PS) | ||
197 | port->encoder_profile = EU_PROFILE_PS_DVD; | ||
198 | else | ||
199 | port->encoder_profile = EU_PROFILE_TS_HQ; | ||
200 | |||
201 | ret = saa7164_cmd_send(port->dev, port->hwcfg.sourceid, SET_CUR, | ||
202 | EU_PROFILE_CONTROL, sizeof(u8), &port->encoder_profile); | ||
203 | if (ret != SAA_OK) | ||
204 | printk(KERN_ERR "%s() error, ret = 0x%x\n", __func__, ret); | ||
205 | |||
206 | /* Resolution */ | ||
207 | ret = saa7164_cmd_send(port->dev, port->hwcfg.sourceid, SET_CUR, | ||
208 | EU_PROFILE_CONTROL, sizeof(u8), &port->encoder_profile); | ||
209 | if (ret != SAA_OK) | ||
210 | printk(KERN_ERR "%s() error, ret = 0x%x\n", __func__, ret); | ||
211 | |||
212 | /* Establish video bitrates */ | ||
213 | if (port->encoder_params.bitrate_mode == V4L2_MPEG_VIDEO_BITRATE_MODE_CBR) | ||
214 | vb.ucVideoBitRateMode = EU_VIDEO_BIT_RATE_MODE_CONSTANT; | ||
215 | else | ||
216 | vb.ucVideoBitRateMode = EU_VIDEO_BIT_RATE_MODE_VARIABLE_PEAK; | ||
217 | vb.dwVideoBitRate = port->encoder_params.bitrate; | ||
218 | vb.dwVideoBitRatePeak = port->encoder_params.bitrate_peak; | ||
219 | ret = saa7164_cmd_send(port->dev, port->hwcfg.sourceid, SET_CUR, | ||
220 | EU_VIDEO_BIT_RATE_CONTROL, sizeof(struct tmComResEncVideoBitRate), &vb); | ||
221 | if (ret != SAA_OK) | ||
222 | printk(KERN_ERR "%s() error, ret = 0x%x\n", __func__, ret); | ||
223 | |||
224 | /* Establish audio bitrates */ | ||
225 | ab.ucAudioBitRateMode = 0; | ||
226 | ab.dwAudioBitRate = 384000; | ||
227 | ab.dwAudioBitRatePeak = ab.dwAudioBitRate; | ||
228 | ret = saa7164_cmd_send(port->dev, port->hwcfg.sourceid, SET_CUR, | ||
229 | EU_AUDIO_BIT_RATE_CONTROL, sizeof(struct tmComResEncAudioBitRate), &ab); | ||
230 | if (ret != SAA_OK) | ||
231 | printk(KERN_ERR "%s() error, ret = 0x%x\n", __func__, ret); | ||
232 | |||
233 | saa7164_api_set_aspect_ratio(port); | ||
234 | saa7164_api_set_gop_size(port); | ||
235 | |||
236 | return ret; | ||
237 | } | ||
238 | |||
239 | int saa7164_api_get_encoder(struct saa7164_port *port) | ||
240 | { | ||
241 | struct saa7164_dev *dev = port->dev; | ||
242 | struct tmComResEncVideoBitRate v; | ||
243 | struct tmComResEncAudioBitRate a; | ||
244 | struct tmComResEncVideoInputAspectRatio ar; | ||
245 | int ret; | ||
246 | |||
247 | dprintk(DBGLVL_ENC, "%s() unitid=0x%x\n", __func__, port->hwcfg.sourceid); | ||
248 | |||
249 | port->encoder_profile = 0; | ||
250 | port->video_format = 0; | ||
251 | port->video_resolution = 0; | ||
252 | port->audio_format = 0; | ||
253 | |||
254 | ret = saa7164_cmd_send(port->dev, port->hwcfg.sourceid, GET_CUR, | ||
255 | EU_PROFILE_CONTROL, sizeof(u8), &port->encoder_profile); | ||
256 | if (ret != SAA_OK) | ||
257 | printk(KERN_ERR "%s() error, ret = 0x%x\n", __func__, ret); | ||
258 | |||
259 | ret = saa7164_cmd_send(port->dev, port->hwcfg.sourceid, GET_CUR, | ||
260 | EU_VIDEO_RESOLUTION_CONTROL, sizeof(u8), &port->video_resolution); | ||
261 | if (ret != SAA_OK) | ||
262 | printk(KERN_ERR "%s() error, ret = 0x%x\n", __func__, ret); | ||
263 | |||
264 | ret = saa7164_cmd_send(port->dev, port->hwcfg.sourceid, GET_CUR, | ||
265 | EU_VIDEO_FORMAT_CONTROL, sizeof(u8), &port->video_format); | ||
266 | if (ret != SAA_OK) | ||
267 | printk(KERN_ERR "%s() error, ret = 0x%x\n", __func__, ret); | ||
268 | |||
269 | ret = saa7164_cmd_send(port->dev, port->hwcfg.sourceid, GET_CUR, | ||
270 | EU_VIDEO_BIT_RATE_CONTROL, sizeof(v), &v); | ||
271 | if (ret != SAA_OK) | ||
272 | printk(KERN_ERR "%s() error, ret = 0x%x\n", __func__, ret); | ||
273 | |||
274 | ret = saa7164_cmd_send(port->dev, port->hwcfg.sourceid, GET_CUR, | ||
275 | EU_AUDIO_FORMAT_CONTROL, sizeof(u8), &port->audio_format); | ||
276 | if (ret != SAA_OK) | ||
277 | printk(KERN_ERR "%s() error, ret = 0x%x\n", __func__, ret); | ||
278 | |||
279 | ret = saa7164_cmd_send(port->dev, port->hwcfg.sourceid, GET_CUR, | ||
280 | EU_AUDIO_BIT_RATE_CONTROL, sizeof(a), &a); | ||
281 | if (ret != SAA_OK) | ||
282 | printk(KERN_ERR "%s() error, ret = 0x%x\n", __func__, ret); | ||
283 | |||
284 | /* Aspect Ratio */ | ||
285 | ar.width = 0; | ||
286 | ar.height = 0; | ||
287 | ret = saa7164_cmd_send(port->dev, port->hwcfg.sourceid, GET_CUR, | ||
288 | EU_VIDEO_INPUT_ASPECT_CONTROL, | ||
289 | sizeof(struct tmComResEncVideoInputAspectRatio), &ar); | ||
290 | if (ret != SAA_OK) | ||
291 | printk(KERN_ERR "%s() error, ret = 0x%x\n", __func__, ret); | ||
292 | |||
293 | dprintk(DBGLVL_ENC, "encoder_profile = %d\n", port->encoder_profile); | ||
294 | dprintk(DBGLVL_ENC, "video_format = %d\n", port->video_format); | ||
295 | dprintk(DBGLVL_ENC, "audio_format = %d\n", port->audio_format); | ||
296 | dprintk(DBGLVL_ENC, "video_resolution= %d\n", port->video_resolution); | ||
297 | dprintk(DBGLVL_ENC, "v.ucVideoBitRateMode = %d\n", v.ucVideoBitRateMode); | ||
298 | dprintk(DBGLVL_ENC, "v.dwVideoBitRate = %d\n", v.dwVideoBitRate); | ||
299 | dprintk(DBGLVL_ENC, "v.dwVideoBitRatePeak = %d\n", v.dwVideoBitRatePeak); | ||
300 | dprintk(DBGLVL_ENC, "a.ucVideoBitRateMode = %d\n", a.ucAudioBitRateMode); | ||
301 | dprintk(DBGLVL_ENC, "a.dwVideoBitRate = %d\n", a.dwAudioBitRate); | ||
302 | dprintk(DBGLVL_ENC, "a.dwVideoBitRatePeak = %d\n", a.dwAudioBitRatePeak); | ||
303 | dprintk(DBGLVL_ENC, "aspect.width / height = %d:%d\n", ar.width, ar.height); | ||
304 | |||
305 | return ret; | ||
306 | } | ||
307 | |||
308 | int saa7164_api_set_aspect_ratio(struct saa7164_port *port) | ||
309 | { | ||
310 | struct saa7164_dev *dev = port->dev; | ||
311 | struct tmComResEncVideoInputAspectRatio ar; | ||
312 | int ret; | ||
313 | |||
314 | dprintk(DBGLVL_ENC, "%s(%d)\n", __func__, | ||
315 | port->encoder_params.ctl_aspect); | ||
316 | |||
317 | switch (port->encoder_params.ctl_aspect) { | ||
318 | case V4L2_MPEG_VIDEO_ASPECT_1x1: | ||
319 | ar.width = 1; | ||
320 | ar.height = 1; | ||
321 | break; | ||
322 | case V4L2_MPEG_VIDEO_ASPECT_4x3: | ||
323 | ar.width = 4; | ||
324 | ar.height = 3; | ||
325 | break; | ||
326 | case V4L2_MPEG_VIDEO_ASPECT_16x9: | ||
327 | ar.width = 16; | ||
328 | ar.height = 9; | ||
329 | break; | ||
330 | case V4L2_MPEG_VIDEO_ASPECT_221x100: | ||
331 | ar.width = 221; | ||
332 | ar.height = 100; | ||
333 | break; | ||
334 | default: | ||
335 | BUG(); | ||
336 | } | ||
337 | |||
338 | dprintk(DBGLVL_ENC, "%s(%d) now %d:%d\n", __func__, | ||
339 | port->encoder_params.ctl_aspect, | ||
340 | ar.width, ar.height); | ||
341 | |||
342 | /* Aspect Ratio */ | ||
343 | ret = saa7164_cmd_send(port->dev, port->hwcfg.sourceid, SET_CUR, | ||
344 | EU_VIDEO_INPUT_ASPECT_CONTROL, | ||
345 | sizeof(struct tmComResEncVideoInputAspectRatio), &ar); | ||
346 | if (ret != SAA_OK) | ||
347 | printk(KERN_ERR "%s() error, ret = 0x%x\n", __func__, ret); | ||
348 | |||
349 | return ret; | ||
350 | } | ||
351 | |||
352 | int saa7164_api_set_usercontrol(struct saa7164_port *port, u8 ctl) | ||
353 | { | ||
354 | struct saa7164_dev *dev = port->dev; | ||
355 | int ret; | ||
356 | u16 val; | ||
357 | |||
358 | if (ctl == PU_BRIGHTNESS_CONTROL) | ||
359 | val = port->ctl_brightness; | ||
360 | else | ||
361 | if (ctl == PU_CONTRAST_CONTROL) | ||
362 | val = port->ctl_contrast; | ||
363 | else | ||
364 | if (ctl == PU_HUE_CONTROL) | ||
365 | val = port->ctl_hue; | ||
366 | else | ||
367 | if (ctl == PU_SATURATION_CONTROL) | ||
368 | val = port->ctl_saturation; | ||
369 | else | ||
370 | if (ctl == PU_SHARPNESS_CONTROL) | ||
371 | val = port->ctl_sharpness; | ||
372 | else | ||
373 | return -EINVAL; | ||
374 | |||
375 | dprintk(DBGLVL_ENC, "%s() unitid=0x%x ctl=%d, val=%d\n", | ||
376 | __func__, port->encunit.vsourceid, ctl, val); | ||
377 | |||
378 | ret = saa7164_cmd_send(port->dev, port->encunit.vsourceid, SET_CUR, | ||
379 | ctl, sizeof(u16), &val); | ||
380 | if (ret != SAA_OK) | ||
381 | printk(KERN_ERR "%s() error, ret = 0x%x\n", __func__, ret); | ||
382 | |||
383 | return ret; | ||
384 | } | ||
385 | |||
386 | int saa7164_api_get_usercontrol(struct saa7164_port *port, u8 ctl) | ||
387 | { | ||
388 | struct saa7164_dev *dev = port->dev; | ||
389 | int ret; | ||
390 | u16 val; | ||
391 | |||
392 | ret = saa7164_cmd_send(port->dev, port->encunit.vsourceid, GET_CUR, | ||
393 | ctl, sizeof(u16), &val); | ||
394 | if (ret != SAA_OK) { | ||
395 | printk(KERN_ERR "%s() error, ret = 0x%x\n", __func__, ret); | ||
396 | return ret; | ||
397 | } | ||
398 | |||
399 | dprintk(DBGLVL_ENC, "%s() ctl=%d, val=%d\n", | ||
400 | __func__, ctl, val); | ||
401 | |||
402 | if (ctl == PU_BRIGHTNESS_CONTROL) | ||
403 | port->ctl_brightness = val; | ||
404 | else | ||
405 | if (ctl == PU_CONTRAST_CONTROL) | ||
406 | port->ctl_contrast = val; | ||
407 | else | ||
408 | if (ctl == PU_HUE_CONTROL) | ||
409 | port->ctl_hue = val; | ||
410 | else | ||
411 | if (ctl == PU_SATURATION_CONTROL) | ||
412 | port->ctl_saturation = val; | ||
413 | else | ||
414 | if (ctl == PU_SHARPNESS_CONTROL) | ||
415 | port->ctl_sharpness = val; | ||
416 | |||
417 | return ret; | ||
418 | } | ||
419 | |||
420 | int saa7164_api_set_videomux(struct saa7164_port *port) | ||
421 | { | ||
422 | struct saa7164_dev *dev = port->dev; | ||
423 | u8 inputs[] = { 1, 2, 2, 2, 5, 5, 5 }; | ||
424 | int ret; | ||
425 | |||
426 | dprintk(DBGLVL_ENC, "%s() v_mux=%d a_mux=%d\n", | ||
427 | __func__, port->mux_input, inputs[port->mux_input - 1]); | ||
428 | |||
429 | /* Audio Mute */ | ||
430 | ret = saa7164_api_audio_mute(port, 1); | ||
431 | if (ret != SAA_OK) | ||
432 | printk(KERN_ERR "%s() error, ret = 0x%x\n", __func__, ret); | ||
433 | |||
434 | /* Video Mux */ | ||
435 | ret = saa7164_cmd_send(port->dev, port->vidproc.sourceid, SET_CUR, | ||
436 | SU_INPUT_SELECT_CONTROL, sizeof(u8), &port->mux_input); | ||
437 | if (ret != SAA_OK) | ||
438 | printk(KERN_ERR "%s() error, ret = 0x%x\n", __func__, ret); | ||
439 | |||
440 | /* Audio Mux */ | ||
441 | ret = saa7164_cmd_send(port->dev, port->audfeat.sourceid, SET_CUR, | ||
442 | SU_INPUT_SELECT_CONTROL, sizeof(u8), &inputs[port->mux_input - 1]); | ||
443 | if (ret != SAA_OK) | ||
444 | printk(KERN_ERR "%s() error, ret = 0x%x\n", __func__, ret); | ||
445 | |||
446 | /* Audio UnMute */ | ||
447 | ret = saa7164_api_audio_mute(port, 0); | ||
448 | if (ret != SAA_OK) | ||
449 | printk(KERN_ERR "%s() error, ret = 0x%x\n", __func__, ret); | ||
450 | |||
451 | return ret; | ||
452 | } | ||
453 | |||
454 | int saa7164_api_audio_mute(struct saa7164_port *port, int mute) | ||
455 | { | ||
456 | struct saa7164_dev *dev = port->dev; | ||
457 | u8 v = mute; | ||
458 | int ret; | ||
459 | |||
460 | dprintk(DBGLVL_API, "%s(%d)\n", __func__, mute); | ||
461 | |||
462 | ret = saa7164_cmd_send(port->dev, port->audfeat.unitid, SET_CUR, | ||
463 | MUTE_CONTROL, sizeof(u8), &v); | ||
464 | if (ret != SAA_OK) | ||
465 | printk(KERN_ERR "%s() error, ret = 0x%x\n", __func__, ret); | ||
466 | |||
467 | return ret; | ||
468 | } | ||
469 | |||
470 | /* 0 = silence, 0xff = full */ | ||
471 | int saa7164_api_set_audio_volume(struct saa7164_port *port, s8 level) | ||
472 | { | ||
473 | struct saa7164_dev *dev = port->dev; | ||
474 | s16 v, min, max; | ||
475 | int ret; | ||
476 | |||
477 | dprintk(DBGLVL_API, "%s(%d)\n", __func__, level); | ||
478 | |||
479 | /* Obtain the min/max ranges */ | ||
480 | ret = saa7164_cmd_send(port->dev, port->audfeat.unitid, GET_MIN, | ||
481 | VOLUME_CONTROL, sizeof(u16), &min); | ||
482 | if (ret != SAA_OK) | ||
483 | printk(KERN_ERR "%s() error, ret = 0x%x\n", __func__, ret); | ||
484 | |||
485 | ret = saa7164_cmd_send(port->dev, port->audfeat.unitid, GET_MAX, | ||
486 | VOLUME_CONTROL, sizeof(u16), &max); | ||
487 | if (ret != SAA_OK) | ||
488 | printk(KERN_ERR "%s() error, ret = 0x%x\n", __func__, ret); | ||
489 | |||
490 | ret = saa7164_cmd_send(port->dev, port->audfeat.unitid, GET_CUR, | ||
491 | (0x01 << 8) | VOLUME_CONTROL, sizeof(u16), &v); | ||
492 | if (ret != SAA_OK) | ||
493 | printk(KERN_ERR "%s() error, ret = 0x%x\n", __func__, ret); | ||
494 | |||
495 | dprintk(DBGLVL_API, "%s(%d) min=%d max=%d cur=%d\n", __func__, level, min, max, v); | ||
496 | |||
497 | v = level; | ||
498 | if (v < min) | ||
499 | v = min; | ||
500 | if (v > max) | ||
501 | v = max; | ||
502 | |||
503 | /* Left */ | ||
504 | ret = saa7164_cmd_send(port->dev, port->audfeat.unitid, SET_CUR, | ||
505 | (0x01 << 8) | VOLUME_CONTROL, sizeof(s16), &v); | ||
506 | if (ret != SAA_OK) | ||
507 | printk(KERN_ERR "%s() error, ret = 0x%x\n", __func__, ret); | ||
508 | |||
509 | /* Right */ | ||
510 | ret = saa7164_cmd_send(port->dev, port->audfeat.unitid, SET_CUR, | ||
511 | (0x02 << 8) | VOLUME_CONTROL, sizeof(s16), &v); | ||
512 | if (ret != SAA_OK) | ||
513 | printk(KERN_ERR "%s() error, ret = 0x%x\n", __func__, ret); | ||
514 | |||
515 | ret = saa7164_cmd_send(port->dev, port->audfeat.unitid, GET_CUR, | ||
516 | (0x01 << 8) | VOLUME_CONTROL, sizeof(u16), &v); | ||
517 | if (ret != SAA_OK) | ||
518 | printk(KERN_ERR "%s() error, ret = 0x%x\n", __func__, ret); | ||
519 | |||
520 | dprintk(DBGLVL_API, "%s(%d) min=%d max=%d cur=%d\n", __func__, level, min, max, v); | ||
521 | |||
522 | return ret; | ||
523 | } | ||
524 | |||
525 | int saa7164_api_set_audio_std(struct saa7164_port *port) | ||
526 | { | ||
527 | struct saa7164_dev *dev = port->dev; | ||
528 | struct tmComResAudioDefaults lvl; | ||
529 | struct tmComResTunerStandard tvaudio; | ||
530 | int ret; | ||
531 | |||
532 | dprintk(DBGLVL_API, "%s()\n", __func__); | ||
533 | |||
534 | /* Establish default levels */ | ||
535 | lvl.ucDecoderLevel = TMHW_LEV_ADJ_DECLEV_DEFAULT; | ||
536 | lvl.ucDecoderFM_Level = TMHW_LEV_ADJ_DECLEV_DEFAULT; | ||
537 | lvl.ucMonoLevel = TMHW_LEV_ADJ_MONOLEV_DEFAULT; | ||
538 | lvl.ucNICAM_Level = TMHW_LEV_ADJ_NICLEV_DEFAULT; | ||
539 | lvl.ucSAP_Level = TMHW_LEV_ADJ_SAPLEV_DEFAULT; | ||
540 | lvl.ucADC_Level = TMHW_LEV_ADJ_ADCLEV_DEFAULT; | ||
541 | ret = saa7164_cmd_send(port->dev, port->audfeat.unitid, SET_CUR, | ||
542 | AUDIO_DEFAULT_CONTROL, sizeof(struct tmComResAudioDefaults), &lvl); | ||
543 | if (ret != SAA_OK) | ||
544 | printk(KERN_ERR "%s() error, ret = 0x%x\n", __func__, ret); | ||
545 | |||
546 | /* Manually select the appropriate TV audio standard */ | ||
547 | if (port->encodernorm.id & V4L2_STD_NTSC) { | ||
548 | tvaudio.std = TU_STANDARD_NTSC_M; | ||
549 | tvaudio.country = 1; | ||
550 | } else { | ||
551 | tvaudio.std = TU_STANDARD_PAL_I; | ||
552 | tvaudio.country = 44; | ||
553 | } | ||
554 | |||
555 | ret = saa7164_cmd_send(port->dev, port->tunerunit.unitid, SET_CUR, | ||
556 | TU_STANDARD_CONTROL, sizeof(tvaudio), &tvaudio); | ||
557 | if (ret != SAA_OK) | ||
558 | printk(KERN_ERR "%s() TU_STANDARD_CONTROL error, ret = 0x%x\n", __func__, ret); | ||
559 | return ret; | ||
560 | } | ||
561 | |||
562 | int saa7164_api_set_audio_detection(struct saa7164_port *port, int autodetect) | ||
563 | { | ||
564 | struct saa7164_dev *dev = port->dev; | ||
565 | struct tmComResTunerStandardAuto p; | ||
566 | int ret; | ||
567 | |||
568 | dprintk(DBGLVL_API, "%s(%d)\n", __func__, autodetect); | ||
569 | |||
570 | /* Disable TV Audio autodetect if not already set (buggy) */ | ||
571 | if (autodetect) | ||
572 | p.mode = TU_STANDARD_AUTO; | ||
573 | else | ||
574 | p.mode = TU_STANDARD_MANUAL; | ||
575 | ret = saa7164_cmd_send(port->dev, port->tunerunit.unitid, SET_CUR, | ||
576 | TU_STANDARD_AUTO_CONTROL, sizeof(p), &p); | ||
577 | if (ret != SAA_OK) | ||
578 | printk(KERN_ERR "%s() TU_STANDARD_AUTO_CONTROL error, ret = 0x%x\n", __func__, ret); | ||
579 | |||
580 | return ret; | ||
581 | } | ||
582 | |||
583 | int saa7164_api_get_videomux(struct saa7164_port *port) | ||
584 | { | ||
585 | struct saa7164_dev *dev = port->dev; | ||
586 | int ret; | ||
587 | |||
588 | ret = saa7164_cmd_send(port->dev, port->vidproc.sourceid, GET_CUR, | ||
589 | SU_INPUT_SELECT_CONTROL, sizeof(u8), &port->mux_input); | ||
590 | if (ret != SAA_OK) | ||
591 | printk(KERN_ERR "%s() error, ret = 0x%x\n", __func__, ret); | ||
592 | |||
593 | dprintk(DBGLVL_ENC, "%s() v_mux=%d\n", | ||
594 | __func__, port->mux_input); | ||
595 | |||
596 | return ret; | ||
597 | } | ||
598 | |||
599 | int saa7164_api_set_dif(struct saa7164_port *port, u8 reg, u8 val) | ||
600 | { | ||
601 | struct saa7164_dev *dev = port->dev; | ||
602 | |||
603 | u16 len = 0; | ||
604 | u8 buf[256]; | ||
605 | int ret; | ||
606 | u8 mas; | ||
607 | |||
608 | dprintk(DBGLVL_API, "%s(nr=%d type=%d val=%x)\n", __func__, | ||
609 | port->nr, port->type, val); | ||
610 | |||
611 | if (port->nr == 0) | ||
612 | mas = 0xd0; | ||
613 | else | ||
614 | mas = 0xe0; | ||
615 | |||
616 | memset(buf, 0, sizeof(buf)); | ||
617 | |||
618 | buf[0x00] = 0x04; | ||
619 | buf[0x01] = 0x00; | ||
620 | buf[0x02] = 0x00; | ||
621 | buf[0x03] = 0x00; | ||
622 | |||
623 | buf[0x04] = 0x04; | ||
624 | buf[0x05] = 0x00; | ||
625 | buf[0x06] = 0x00; | ||
626 | buf[0x07] = 0x00; | ||
627 | |||
628 | buf[0x08] = reg; | ||
629 | buf[0x09] = 0x26; | ||
630 | buf[0x0a] = mas; | ||
631 | buf[0x0b] = 0xb0; | ||
632 | |||
633 | buf[0x0c] = val; | ||
634 | buf[0x0d] = 0x00; | ||
635 | buf[0x0e] = 0x00; | ||
636 | buf[0x0f] = 0x00; | ||
637 | |||
638 | ret = saa7164_cmd_send(dev, port->ifunit.unitid, GET_LEN, | ||
639 | EXU_REGISTER_ACCESS_CONTROL, sizeof(len), &len); | ||
640 | if (ret != SAA_OK) { | ||
641 | printk(KERN_ERR "%s() error, ret(1) = 0x%x\n", __func__, ret); | ||
642 | return -EIO; | ||
643 | } | ||
644 | |||
645 | ret = saa7164_cmd_send(dev, port->ifunit.unitid, SET_CUR, | ||
646 | EXU_REGISTER_ACCESS_CONTROL, len, &buf); | ||
647 | if (ret != SAA_OK) | ||
648 | printk(KERN_ERR "%s() error, ret(2) = 0x%x\n", __func__, ret); | ||
649 | |||
650 | //saa7164_dumphex16(dev, buf, 16); | ||
651 | |||
652 | return ret == SAA_OK ? 0 : -EIO; | ||
653 | } | ||
654 | |||
655 | /* Disable the IF block AGC controls */ | ||
656 | int saa7164_api_configure_dif(struct saa7164_port *port, u32 std) | ||
657 | { | ||
658 | struct saa7164_dev *dev = port->dev; | ||
659 | int ret = 0; | ||
660 | u8 agc_disable; | ||
661 | |||
662 | dprintk(DBGLVL_API, "%s(nr=%d, 0x%x)\n", __func__, port->nr, std); | ||
663 | |||
664 | if (std & V4L2_STD_NTSC) { | ||
665 | dprintk(DBGLVL_API, " NTSC\n"); | ||
666 | saa7164_api_set_dif(port, 0x00, 0x01); /* Video Standard */ | ||
667 | agc_disable = 0; | ||
668 | } else if (std & V4L2_STD_PAL_I) { | ||
669 | dprintk(DBGLVL_API, " PAL-I\n"); | ||
670 | saa7164_api_set_dif(port, 0x00, 0x08); /* Video Standard */ | ||
671 | agc_disable = 0; | ||
672 | } else if (std & V4L2_STD_PAL_M) { | ||
673 | dprintk(DBGLVL_API, " PAL-M\n"); | ||
674 | saa7164_api_set_dif(port, 0x00, 0x01); /* Video Standard */ | ||
675 | agc_disable = 0; | ||
676 | } else if (std & V4L2_STD_PAL_N) { | ||
677 | dprintk(DBGLVL_API, " PAL-N\n"); | ||
678 | saa7164_api_set_dif(port, 0x00, 0x01); /* Video Standard */ | ||
679 | agc_disable = 0; | ||
680 | } else if (std & V4L2_STD_PAL_Nc) { | ||
681 | dprintk(DBGLVL_API, " PAL-Nc\n"); | ||
682 | saa7164_api_set_dif(port, 0x00, 0x01); /* Video Standard */ | ||
683 | agc_disable = 0; | ||
684 | } else if (std & V4L2_STD_PAL_B) { | ||
685 | dprintk(DBGLVL_API, " PAL-B\n"); | ||
686 | saa7164_api_set_dif(port, 0x00, 0x02); /* Video Standard */ | ||
687 | agc_disable = 0; | ||
688 | } else if (std & V4L2_STD_PAL_DK) { | ||
689 | dprintk(DBGLVL_API, " PAL-DK\n"); | ||
690 | saa7164_api_set_dif(port, 0x00, 0x10); /* Video Standard */ | ||
691 | agc_disable = 0; | ||
692 | } else if (std & V4L2_STD_SECAM_L) { | ||
693 | dprintk(DBGLVL_API, " SECAM-L\n"); | ||
694 | saa7164_api_set_dif(port, 0x00, 0x20); /* Video Standard */ | ||
695 | agc_disable = 0; | ||
696 | } else { | ||
697 | /* Unknown standard, assume DTV */ | ||
698 | dprintk(DBGLVL_API, " Unknown (assuming DTV)\n"); | ||
699 | saa7164_api_set_dif(port, 0x00, 0x80); /* Undefined Video Standard */ | ||
700 | agc_disable = 1; | ||
701 | } | ||
702 | |||
703 | saa7164_api_set_dif(port, 0x48, 0xa0); /* AGC Functions 1 */ | ||
704 | saa7164_api_set_dif(port, 0xc0, agc_disable); /* AGC Output Disable */ | ||
705 | saa7164_api_set_dif(port, 0x7c, 0x04); /* CVBS EQ */ | ||
706 | saa7164_api_set_dif(port, 0x04, 0x01); /* Active */ | ||
707 | msleep(100); | ||
708 | saa7164_api_set_dif(port, 0x04, 0x00); /* Active (again) */ | ||
709 | msleep(100); | ||
710 | |||
711 | return ret; | ||
712 | } | ||
713 | |||
714 | /* Ensure the dif is in the correct state for the operating mode | ||
715 | * (analog / dtv). We only configure the diff through the analog encoder | ||
716 | * so when we're in digital mode we need to find the appropriate encoder | ||
717 | * and use it to configure the DIF. | ||
718 | */ | ||
719 | int saa7164_api_initialize_dif(struct saa7164_port *port) | ||
720 | { | ||
721 | struct saa7164_dev *dev = port->dev; | ||
722 | struct saa7164_port *p = 0; | ||
723 | int ret = -EINVAL; | ||
724 | u32 std = 0; | ||
725 | |||
726 | dprintk(DBGLVL_API, "%s(nr=%d type=%d)\n", __func__, | ||
727 | port->nr, port->type); | ||
728 | |||
729 | if (port->type == SAA7164_MPEG_ENCODER) { | ||
730 | /* Pick any analog standard to init the diff. | ||
731 | * we'll come back during encoder_init' | ||
732 | * and set the correct standard if requried. | ||
733 | */ | ||
734 | std = V4L2_STD_NTSC; | ||
735 | } else | ||
736 | if (port->type == SAA7164_MPEG_DVB) { | ||
737 | if (port->nr == SAA7164_PORT_TS1) | ||
738 | p = &dev->ports[SAA7164_PORT_ENC1]; | ||
739 | else | ||
740 | p = &dev->ports[SAA7164_PORT_ENC2]; | ||
741 | } else | ||
742 | if (port->type == SAA7164_MPEG_VBI) { | ||
743 | std = V4L2_STD_NTSC; | ||
744 | if (port->nr == SAA7164_PORT_VBI1) | ||
745 | p = &dev->ports[SAA7164_PORT_ENC1]; | ||
746 | else | ||
747 | p = &dev->ports[SAA7164_PORT_ENC2]; | ||
748 | } else | ||
749 | BUG(); | ||
750 | |||
751 | if (p) | ||
752 | ret = saa7164_api_configure_dif(p, std); | ||
753 | |||
754 | return ret; | ||
755 | } | ||
756 | |||
757 | int saa7164_api_transition_port(struct saa7164_port *port, u8 mode) | ||
758 | { | ||
759 | struct saa7164_dev *dev = port->dev; | ||
760 | |||
761 | int ret; | ||
762 | |||
763 | dprintk(DBGLVL_API, "%s(nr=%d unitid=0x%x,%d)\n", | ||
764 | __func__, port->nr, port->hwcfg.unitid, mode); | ||
765 | |||
31 | ret = saa7164_cmd_send(port->dev, port->hwcfg.unitid, SET_CUR, | 766 | ret = saa7164_cmd_send(port->dev, port->hwcfg.unitid, SET_CUR, |
32 | SAA_STATE_CONTROL, sizeof(mode), &mode); | 767 | SAA_STATE_CONTROL, sizeof(mode), &mode); |
33 | if (ret != SAA_OK) | 768 | if (ret != SAA_OK) |
34 | printk(KERN_ERR "%s() error, ret = 0x%x\n", __func__, ret); | 769 | printk(KERN_ERR "%s(portnr %d unitid 0x%x) error, ret = 0x%x\n", |
770 | __func__, port->nr, port->hwcfg.unitid, ret); | ||
35 | 771 | ||
36 | return ret; | 772 | return ret; |
37 | } | 773 | } |
@@ -61,10 +797,45 @@ int saa7164_api_read_eeprom(struct saa7164_dev *dev, u8 *buf, int buflen) | |||
61 | ®[0], 128, buf); | 797 | ®[0], 128, buf); |
62 | } | 798 | } |
63 | 799 | ||
800 | int saa7164_api_configure_port_vbi(struct saa7164_dev *dev, | ||
801 | struct saa7164_port *port) | ||
802 | { | ||
803 | struct tmComResVBIFormatDescrHeader *fmt = &port->vbi_fmt_ntsc; | ||
804 | |||
805 | dprintk(DBGLVL_API, " bFormatIndex = 0x%x\n", fmt->bFormatIndex); | ||
806 | dprintk(DBGLVL_API, " VideoStandard = 0x%x\n", fmt->VideoStandard); | ||
807 | dprintk(DBGLVL_API, " StartLine = %d\n", fmt->StartLine); | ||
808 | dprintk(DBGLVL_API, " EndLine = %d\n", fmt->EndLine); | ||
809 | dprintk(DBGLVL_API, " FieldRate = %d\n", fmt->FieldRate); | ||
810 | dprintk(DBGLVL_API, " bNumLines = %d\n", fmt->bNumLines); | ||
811 | |||
812 | /* Cache the hardware configuration in the port */ | ||
813 | |||
814 | port->bufcounter = port->hwcfg.BARLocation; | ||
815 | port->pitch = port->hwcfg.BARLocation + (2 * sizeof(u32)); | ||
816 | port->bufsize = port->hwcfg.BARLocation + (3 * sizeof(u32)); | ||
817 | port->bufoffset = port->hwcfg.BARLocation + (4 * sizeof(u32)); | ||
818 | port->bufptr32l = port->hwcfg.BARLocation + | ||
819 | (4 * sizeof(u32)) + | ||
820 | (sizeof(u32) * port->hwcfg.buffercount) + sizeof(u32); | ||
821 | port->bufptr32h = port->hwcfg.BARLocation + | ||
822 | (4 * sizeof(u32)) + | ||
823 | (sizeof(u32) * port->hwcfg.buffercount); | ||
824 | port->bufptr64 = port->hwcfg.BARLocation + | ||
825 | (4 * sizeof(u32)) + | ||
826 | (sizeof(u32) * port->hwcfg.buffercount); | ||
827 | dprintk(DBGLVL_API, " = port->hwcfg.BARLocation = 0x%x\n", | ||
828 | port->hwcfg.BARLocation); | ||
829 | |||
830 | dprintk(DBGLVL_API, " = VS_FORMAT_VBI (becomes dev->en[%d])\n", | ||
831 | port->nr); | ||
832 | |||
833 | return 0; | ||
834 | } | ||
64 | 835 | ||
65 | int saa7164_api_configure_port_mpeg2ts(struct saa7164_dev *dev, | 836 | int saa7164_api_configure_port_mpeg2ts(struct saa7164_dev *dev, |
66 | struct saa7164_tsport *port, | 837 | struct saa7164_port *port, |
67 | tmComResTSFormatDescrHeader_t *tsfmt) | 838 | struct tmComResTSFormatDescrHeader *tsfmt) |
68 | { | 839 | { |
69 | dprintk(DBGLVL_API, " bFormatIndex = 0x%x\n", tsfmt->bFormatIndex); | 840 | dprintk(DBGLVL_API, " bFormatIndex = 0x%x\n", tsfmt->bFormatIndex); |
70 | dprintk(DBGLVL_API, " bDataOffset = 0x%x\n", tsfmt->bDataOffset); | 841 | dprintk(DBGLVL_API, " bDataOffset = 0x%x\n", tsfmt->bDataOffset); |
@@ -96,27 +867,68 @@ int saa7164_api_configure_port_mpeg2ts(struct saa7164_dev *dev, | |||
96 | return 0; | 867 | return 0; |
97 | } | 868 | } |
98 | 869 | ||
870 | int saa7164_api_configure_port_mpeg2ps(struct saa7164_dev *dev, | ||
871 | struct saa7164_port *port, | ||
872 | struct tmComResPSFormatDescrHeader *fmt) | ||
873 | { | ||
874 | dprintk(DBGLVL_API, " bFormatIndex = 0x%x\n", fmt->bFormatIndex); | ||
875 | dprintk(DBGLVL_API, " wPacketLength= 0x%x\n", fmt->wPacketLength); | ||
876 | dprintk(DBGLVL_API, " wPackLength= 0x%x\n", fmt->wPackLength); | ||
877 | dprintk(DBGLVL_API, " bPackDataType= 0x%x\n", fmt->bPackDataType); | ||
878 | |||
879 | /* Cache the hardware configuration in the port */ | ||
880 | /* TODO: CHECK THIS in the port config */ | ||
881 | port->bufcounter = port->hwcfg.BARLocation; | ||
882 | port->pitch = port->hwcfg.BARLocation + (2 * sizeof(u32)); | ||
883 | port->bufsize = port->hwcfg.BARLocation + (3 * sizeof(u32)); | ||
884 | port->bufoffset = port->hwcfg.BARLocation + (4 * sizeof(u32)); | ||
885 | port->bufptr32l = port->hwcfg.BARLocation + | ||
886 | (4 * sizeof(u32)) + | ||
887 | (sizeof(u32) * port->hwcfg.buffercount) + sizeof(u32); | ||
888 | port->bufptr32h = port->hwcfg.BARLocation + | ||
889 | (4 * sizeof(u32)) + | ||
890 | (sizeof(u32) * port->hwcfg.buffercount); | ||
891 | port->bufptr64 = port->hwcfg.BARLocation + | ||
892 | (4 * sizeof(u32)) + | ||
893 | (sizeof(u32) * port->hwcfg.buffercount); | ||
894 | dprintk(DBGLVL_API, " = port->hwcfg.BARLocation = 0x%x\n", | ||
895 | port->hwcfg.BARLocation); | ||
896 | |||
897 | dprintk(DBGLVL_API, " = VS_FORMAT_MPEGPS (becomes dev->enc[%d])\n", | ||
898 | port->nr); | ||
899 | |||
900 | return 0; | ||
901 | } | ||
902 | |||
99 | int saa7164_api_dump_subdevs(struct saa7164_dev *dev, u8 *buf, int len) | 903 | int saa7164_api_dump_subdevs(struct saa7164_dev *dev, u8 *buf, int len) |
100 | { | 904 | { |
101 | struct saa7164_tsport *port = 0; | 905 | struct saa7164_port *tsport = 0; |
906 | struct saa7164_port *encport = 0; | ||
907 | struct saa7164_port *vbiport = 0; | ||
102 | u32 idx, next_offset; | 908 | u32 idx, next_offset; |
103 | int i; | 909 | int i; |
104 | tmComResDescrHeader_t *hdr, *t; | 910 | struct tmComResDescrHeader *hdr, *t; |
105 | tmComResExtDevDescrHeader_t *exthdr; | 911 | struct tmComResExtDevDescrHeader *exthdr; |
106 | tmComResPathDescrHeader_t *pathhdr; | 912 | struct tmComResPathDescrHeader *pathhdr; |
107 | tmComResAntTermDescrHeader_t *anttermhdr; | 913 | struct tmComResAntTermDescrHeader *anttermhdr; |
108 | tmComResTunerDescrHeader_t *tunerunithdr; | 914 | struct tmComResTunerDescrHeader *tunerunithdr; |
109 | tmComResDMATermDescrHeader_t *vcoutputtermhdr; | 915 | struct tmComResDMATermDescrHeader *vcoutputtermhdr; |
110 | tmComResTSFormatDescrHeader_t *tsfmt; | 916 | struct tmComResTSFormatDescrHeader *tsfmt; |
917 | struct tmComResPSFormatDescrHeader *psfmt; | ||
918 | struct tmComResSelDescrHeader *psel; | ||
919 | struct tmComResProcDescrHeader *pdh; | ||
920 | struct tmComResAFeatureDescrHeader *afd; | ||
921 | struct tmComResEncoderDescrHeader *edh; | ||
922 | struct tmComResVBIFormatDescrHeader *vbifmt; | ||
111 | u32 currpath = 0; | 923 | u32 currpath = 0; |
112 | 924 | ||
113 | dprintk(DBGLVL_API, | 925 | dprintk(DBGLVL_API, |
114 | "%s(?,?,%d) sizeof(tmComResDescrHeader_t) = %d bytes\n", | 926 | "%s(?,?,%d) sizeof(struct tmComResDescrHeader) = %d bytes\n", |
115 | __func__, len, (u32)sizeof(tmComResDescrHeader_t)); | 927 | __func__, len, (u32)sizeof(struct tmComResDescrHeader)); |
116 | 928 | ||
117 | for (idx = 0; idx < (len - sizeof(tmComResDescrHeader_t)); ) { | 929 | for (idx = 0; idx < (len - sizeof(struct tmComResDescrHeader));) { |
118 | 930 | ||
119 | hdr = (tmComResDescrHeader_t *)(buf + idx); | 931 | hdr = (struct tmComResDescrHeader *)(buf + idx); |
120 | 932 | ||
121 | if (hdr->type != CS_INTERFACE) | 933 | if (hdr->type != CS_INTERFACE) |
122 | return SAA_ERR_NOT_SUPPORTED; | 934 | return SAA_ERR_NOT_SUPPORTED; |
@@ -128,7 +940,7 @@ int saa7164_api_dump_subdevs(struct saa7164_dev *dev, u8 *buf, int len) | |||
128 | break; | 940 | break; |
129 | case VC_TUNER_PATH: | 941 | case VC_TUNER_PATH: |
130 | dprintk(DBGLVL_API, " VC_TUNER_PATH\n"); | 942 | dprintk(DBGLVL_API, " VC_TUNER_PATH\n"); |
131 | pathhdr = (tmComResPathDescrHeader_t *)(buf + idx); | 943 | pathhdr = (struct tmComResPathDescrHeader *)(buf + idx); |
132 | dprintk(DBGLVL_API, " pathid = 0x%x\n", | 944 | dprintk(DBGLVL_API, " pathid = 0x%x\n", |
133 | pathhdr->pathid); | 945 | pathhdr->pathid); |
134 | currpath = pathhdr->pathid; | 946 | currpath = pathhdr->pathid; |
@@ -136,7 +948,7 @@ int saa7164_api_dump_subdevs(struct saa7164_dev *dev, u8 *buf, int len) | |||
136 | case VC_INPUT_TERMINAL: | 948 | case VC_INPUT_TERMINAL: |
137 | dprintk(DBGLVL_API, " VC_INPUT_TERMINAL\n"); | 949 | dprintk(DBGLVL_API, " VC_INPUT_TERMINAL\n"); |
138 | anttermhdr = | 950 | anttermhdr = |
139 | (tmComResAntTermDescrHeader_t *)(buf + idx); | 951 | (struct tmComResAntTermDescrHeader *)(buf + idx); |
140 | dprintk(DBGLVL_API, " terminalid = 0x%x\n", | 952 | dprintk(DBGLVL_API, " terminalid = 0x%x\n", |
141 | anttermhdr->terminalid); | 953 | anttermhdr->terminalid); |
142 | dprintk(DBGLVL_API, " terminaltype = 0x%x\n", | 954 | dprintk(DBGLVL_API, " terminaltype = 0x%x\n", |
@@ -179,7 +991,7 @@ int saa7164_api_dump_subdevs(struct saa7164_dev *dev, u8 *buf, int len) | |||
179 | case VC_OUTPUT_TERMINAL: | 991 | case VC_OUTPUT_TERMINAL: |
180 | dprintk(DBGLVL_API, " VC_OUTPUT_TERMINAL\n"); | 992 | dprintk(DBGLVL_API, " VC_OUTPUT_TERMINAL\n"); |
181 | vcoutputtermhdr = | 993 | vcoutputtermhdr = |
182 | (tmComResDMATermDescrHeader_t *)(buf + idx); | 994 | (struct tmComResDMATermDescrHeader *)(buf + idx); |
183 | dprintk(DBGLVL_API, " unitid = 0x%x\n", | 995 | dprintk(DBGLVL_API, " unitid = 0x%x\n", |
184 | vcoutputtermhdr->unitid); | 996 | vcoutputtermhdr->unitid); |
185 | dprintk(DBGLVL_API, " terminaltype = 0x%x\n", | 997 | dprintk(DBGLVL_API, " terminaltype = 0x%x\n", |
@@ -233,32 +1045,49 @@ int saa7164_api_dump_subdevs(struct saa7164_dev *dev, u8 *buf, int len) | |||
233 | dprintk(DBGLVL_API, " numformats = 0x%x\n", | 1045 | dprintk(DBGLVL_API, " numformats = 0x%x\n", |
234 | vcoutputtermhdr->numformats); | 1046 | vcoutputtermhdr->numformats); |
235 | 1047 | ||
236 | t = (tmComResDescrHeader_t *) | 1048 | t = (struct tmComResDescrHeader *) |
237 | ((tmComResDMATermDescrHeader_t *)(buf + idx)); | 1049 | ((struct tmComResDMATermDescrHeader *)(buf + idx)); |
238 | next_offset = idx + (vcoutputtermhdr->len); | 1050 | next_offset = idx + (vcoutputtermhdr->len); |
239 | for (i = 0; i < vcoutputtermhdr->numformats; i++) { | 1051 | for (i = 0; i < vcoutputtermhdr->numformats; i++) { |
240 | t = (tmComResDescrHeader_t *) | 1052 | t = (struct tmComResDescrHeader *) |
241 | (buf + next_offset); | 1053 | (buf + next_offset); |
242 | switch (t->subtype) { | 1054 | switch (t->subtype) { |
243 | case VS_FORMAT_MPEG2TS: | 1055 | case VS_FORMAT_MPEG2TS: |
244 | tsfmt = | 1056 | tsfmt = |
245 | (tmComResTSFormatDescrHeader_t *)t; | 1057 | (struct tmComResTSFormatDescrHeader *)t; |
246 | if (currpath == 1) | 1058 | if (currpath == 1) |
247 | port = &dev->ts1; | 1059 | tsport = &dev->ports[SAA7164_PORT_TS1]; |
248 | else | 1060 | else |
249 | port = &dev->ts2; | 1061 | tsport = &dev->ports[SAA7164_PORT_TS2]; |
250 | memcpy(&port->hwcfg, vcoutputtermhdr, | 1062 | memcpy(&tsport->hwcfg, vcoutputtermhdr, |
251 | sizeof(*vcoutputtermhdr)); | 1063 | sizeof(*vcoutputtermhdr)); |
252 | saa7164_api_configure_port_mpeg2ts(dev, | 1064 | saa7164_api_configure_port_mpeg2ts(dev, |
253 | port, tsfmt); | 1065 | tsport, tsfmt); |
254 | break; | 1066 | break; |
255 | case VS_FORMAT_MPEG2PS: | 1067 | case VS_FORMAT_MPEG2PS: |
256 | dprintk(DBGLVL_API, | 1068 | psfmt = |
257 | " = VS_FORMAT_MPEG2PS\n"); | 1069 | (struct tmComResPSFormatDescrHeader *)t; |
1070 | if (currpath == 1) | ||
1071 | encport = &dev->ports[SAA7164_PORT_ENC1]; | ||
1072 | else | ||
1073 | encport = &dev->ports[SAA7164_PORT_ENC2]; | ||
1074 | memcpy(&encport->hwcfg, vcoutputtermhdr, | ||
1075 | sizeof(*vcoutputtermhdr)); | ||
1076 | saa7164_api_configure_port_mpeg2ps(dev, | ||
1077 | encport, psfmt); | ||
258 | break; | 1078 | break; |
259 | case VS_FORMAT_VBI: | 1079 | case VS_FORMAT_VBI: |
260 | dprintk(DBGLVL_API, | 1080 | vbifmt = |
261 | " = VS_FORMAT_VBI\n"); | 1081 | (struct tmComResVBIFormatDescrHeader *)t; |
1082 | if (currpath == 1) | ||
1083 | vbiport = &dev->ports[SAA7164_PORT_VBI1]; | ||
1084 | else | ||
1085 | vbiport = &dev->ports[SAA7164_PORT_VBI2]; | ||
1086 | memcpy(&vbiport->hwcfg, vcoutputtermhdr, | ||
1087 | sizeof(*vcoutputtermhdr)); | ||
1088 | memcpy(&vbiport->vbi_fmt_ntsc, vbifmt, sizeof(*vbifmt)); | ||
1089 | saa7164_api_configure_port_vbi(dev, | ||
1090 | vbiport); | ||
262 | break; | 1091 | break; |
263 | case VS_FORMAT_RDS: | 1092 | case VS_FORMAT_RDS: |
264 | dprintk(DBGLVL_API, | 1093 | dprintk(DBGLVL_API, |
@@ -284,7 +1113,7 @@ int saa7164_api_dump_subdevs(struct saa7164_dev *dev, u8 *buf, int len) | |||
284 | case TUNER_UNIT: | 1113 | case TUNER_UNIT: |
285 | dprintk(DBGLVL_API, " TUNER_UNIT\n"); | 1114 | dprintk(DBGLVL_API, " TUNER_UNIT\n"); |
286 | tunerunithdr = | 1115 | tunerunithdr = |
287 | (tmComResTunerDescrHeader_t *)(buf + idx); | 1116 | (struct tmComResTunerDescrHeader *)(buf + idx); |
288 | dprintk(DBGLVL_API, " unitid = 0x%x\n", | 1117 | dprintk(DBGLVL_API, " unitid = 0x%x\n", |
289 | tunerunithdr->unitid); | 1118 | tunerunithdr->unitid); |
290 | dprintk(DBGLVL_API, " sourceid = 0x%x\n", | 1119 | dprintk(DBGLVL_API, " sourceid = 0x%x\n", |
@@ -297,22 +1126,84 @@ int saa7164_api_dump_subdevs(struct saa7164_dev *dev, u8 *buf, int len) | |||
297 | tunerunithdr->controlsize); | 1126 | tunerunithdr->controlsize); |
298 | dprintk(DBGLVL_API, " controls = 0x%x\n", | 1127 | dprintk(DBGLVL_API, " controls = 0x%x\n", |
299 | tunerunithdr->controls); | 1128 | tunerunithdr->controls); |
1129 | |||
1130 | if (tunerunithdr->unitid == tunerunithdr->iunit) { | ||
1131 | if (currpath == 1) | ||
1132 | encport = &dev->ports[SAA7164_PORT_ENC1]; | ||
1133 | else | ||
1134 | encport = &dev->ports[SAA7164_PORT_ENC2]; | ||
1135 | memcpy(&encport->tunerunit, tunerunithdr, | ||
1136 | sizeof(struct tmComResTunerDescrHeader)); | ||
1137 | dprintk(DBGLVL_API, " (becomes dev->enc[%d] tuner)\n", encport->nr); | ||
1138 | } | ||
300 | break; | 1139 | break; |
301 | case VC_SELECTOR_UNIT: | 1140 | case VC_SELECTOR_UNIT: |
1141 | psel = (struct tmComResSelDescrHeader *)(buf + idx); | ||
302 | dprintk(DBGLVL_API, " VC_SELECTOR_UNIT\n"); | 1142 | dprintk(DBGLVL_API, " VC_SELECTOR_UNIT\n"); |
1143 | dprintk(DBGLVL_API, " unitid = 0x%x\n", | ||
1144 | psel->unitid); | ||
1145 | dprintk(DBGLVL_API, " nrinpins = 0x%x\n", | ||
1146 | psel->nrinpins); | ||
1147 | dprintk(DBGLVL_API, " sourceid = 0x%x\n", | ||
1148 | psel->sourceid); | ||
303 | break; | 1149 | break; |
304 | case VC_PROCESSING_UNIT: | 1150 | case VC_PROCESSING_UNIT: |
1151 | pdh = (struct tmComResProcDescrHeader *)(buf + idx); | ||
305 | dprintk(DBGLVL_API, " VC_PROCESSING_UNIT\n"); | 1152 | dprintk(DBGLVL_API, " VC_PROCESSING_UNIT\n"); |
1153 | dprintk(DBGLVL_API, " unitid = 0x%x\n", | ||
1154 | pdh->unitid); | ||
1155 | dprintk(DBGLVL_API, " sourceid = 0x%x\n", | ||
1156 | pdh->sourceid); | ||
1157 | dprintk(DBGLVL_API, " controlsize = 0x%x\n", | ||
1158 | pdh->controlsize); | ||
1159 | if (pdh->controlsize == 0x04) { | ||
1160 | if (currpath == 1) | ||
1161 | encport = &dev->ports[SAA7164_PORT_ENC1]; | ||
1162 | else | ||
1163 | encport = &dev->ports[SAA7164_PORT_ENC2]; | ||
1164 | memcpy(&encport->vidproc, pdh, | ||
1165 | sizeof(struct tmComResProcDescrHeader)); | ||
1166 | dprintk(DBGLVL_API, " (becomes dev->enc[%d])\n", encport->nr); | ||
1167 | } | ||
306 | break; | 1168 | break; |
307 | case FEATURE_UNIT: | 1169 | case FEATURE_UNIT: |
1170 | afd = (struct tmComResAFeatureDescrHeader *)(buf + idx); | ||
308 | dprintk(DBGLVL_API, " FEATURE_UNIT\n"); | 1171 | dprintk(DBGLVL_API, " FEATURE_UNIT\n"); |
1172 | dprintk(DBGLVL_API, " unitid = 0x%x\n", | ||
1173 | afd->unitid); | ||
1174 | dprintk(DBGLVL_API, " sourceid = 0x%x\n", | ||
1175 | afd->sourceid); | ||
1176 | dprintk(DBGLVL_API, " controlsize = 0x%x\n", | ||
1177 | afd->controlsize); | ||
1178 | if (currpath == 1) | ||
1179 | encport = &dev->ports[SAA7164_PORT_ENC1]; | ||
1180 | else | ||
1181 | encport = &dev->ports[SAA7164_PORT_ENC2]; | ||
1182 | memcpy(&encport->audfeat, afd, | ||
1183 | sizeof(struct tmComResAFeatureDescrHeader)); | ||
1184 | dprintk(DBGLVL_API, " (becomes dev->enc[%d])\n", encport->nr); | ||
309 | break; | 1185 | break; |
310 | case ENCODER_UNIT: | 1186 | case ENCODER_UNIT: |
1187 | edh = (struct tmComResEncoderDescrHeader *)(buf + idx); | ||
311 | dprintk(DBGLVL_API, " ENCODER_UNIT\n"); | 1188 | dprintk(DBGLVL_API, " ENCODER_UNIT\n"); |
1189 | dprintk(DBGLVL_API, " subtype = 0x%x\n", edh->subtype); | ||
1190 | dprintk(DBGLVL_API, " unitid = 0x%x\n", edh->unitid); | ||
1191 | dprintk(DBGLVL_API, " vsourceid = 0x%x\n", edh->vsourceid); | ||
1192 | dprintk(DBGLVL_API, " asourceid = 0x%x\n", edh->asourceid); | ||
1193 | dprintk(DBGLVL_API, " iunit = 0x%x\n", edh->iunit); | ||
1194 | if (edh->iunit == edh->unitid) { | ||
1195 | if (currpath == 1) | ||
1196 | encport = &dev->ports[SAA7164_PORT_ENC1]; | ||
1197 | else | ||
1198 | encport = &dev->ports[SAA7164_PORT_ENC2]; | ||
1199 | memcpy(&encport->encunit, edh, | ||
1200 | sizeof(struct tmComResEncoderDescrHeader)); | ||
1201 | dprintk(DBGLVL_API, " (becomes dev->enc[%d])\n", encport->nr); | ||
1202 | } | ||
312 | break; | 1203 | break; |
313 | case EXTENSION_UNIT: | 1204 | case EXTENSION_UNIT: |
314 | dprintk(DBGLVL_API, " EXTENSION_UNIT\n"); | 1205 | dprintk(DBGLVL_API, " EXTENSION_UNIT\n"); |
315 | exthdr = (tmComResExtDevDescrHeader_t *)(buf + idx); | 1206 | exthdr = (struct tmComResExtDevDescrHeader *)(buf + idx); |
316 | dprintk(DBGLVL_API, " unitid = 0x%x\n", | 1207 | dprintk(DBGLVL_API, " unitid = 0x%x\n", |
317 | exthdr->unitid); | 1208 | exthdr->unitid); |
318 | dprintk(DBGLVL_API, " deviceid = 0x%x\n", | 1209 | dprintk(DBGLVL_API, " deviceid = 0x%x\n", |
@@ -364,6 +1255,15 @@ int saa7164_api_dump_subdevs(struct saa7164_dev *dev, u8 *buf, int len) | |||
364 | exthdr->numgpiogroups); | 1255 | exthdr->numgpiogroups); |
365 | dprintk(DBGLVL_API, " controlsize = 0x%x\n", | 1256 | dprintk(DBGLVL_API, " controlsize = 0x%x\n", |
366 | exthdr->controlsize); | 1257 | exthdr->controlsize); |
1258 | if (exthdr->devicetype & 0x80) { | ||
1259 | if (currpath == 1) | ||
1260 | encport = &dev->ports[SAA7164_PORT_ENC1]; | ||
1261 | else | ||
1262 | encport = &dev->ports[SAA7164_PORT_ENC2]; | ||
1263 | memcpy(&encport->ifunit, exthdr, | ||
1264 | sizeof(struct tmComResExtDevDescrHeader)); | ||
1265 | dprintk(DBGLVL_API, " (becomes dev->enc[%d])\n", encport->nr); | ||
1266 | } | ||
367 | break; | 1267 | break; |
368 | case PVC_INFRARED_UNIT: | 1268 | case PVC_INFRARED_UNIT: |
369 | dprintk(DBGLVL_API, " PVC_INFRARED_UNIT\n"); | 1269 | dprintk(DBGLVL_API, " PVC_INFRARED_UNIT\n"); |
@@ -560,12 +1460,11 @@ int saa7164_api_i2c_write(struct saa7164_i2c *bus, u8 addr, u32 datalen, | |||
560 | return ret == SAA_OK ? 0 : -EIO; | 1460 | return ret == SAA_OK ? 0 : -EIO; |
561 | } | 1461 | } |
562 | 1462 | ||
563 | |||
564 | int saa7164_api_modify_gpio(struct saa7164_dev *dev, u8 unitid, | 1463 | int saa7164_api_modify_gpio(struct saa7164_dev *dev, u8 unitid, |
565 | u8 pin, u8 state) | 1464 | u8 pin, u8 state) |
566 | { | 1465 | { |
567 | int ret; | 1466 | int ret; |
568 | tmComResGPIO_t t; | 1467 | struct tmComResGPIO t; |
569 | 1468 | ||
570 | dprintk(DBGLVL_API, "%s(0x%x, %d, %d)\n", | 1469 | dprintk(DBGLVL_API, "%s(0x%x, %d, %d)\n", |
571 | __func__, unitid, pin, state); | 1470 | __func__, unitid, pin, state); |
@@ -597,5 +1496,3 @@ int saa7164_api_clear_gpiobit(struct saa7164_dev *dev, u8 unitid, | |||
597 | return saa7164_api_modify_gpio(dev, unitid, pin, 0); | 1496 | return saa7164_api_modify_gpio(dev, unitid, pin, 0); |
598 | } | 1497 | } |
599 | 1498 | ||
600 | |||
601 | |||
diff --git a/drivers/media/video/saa7164/saa7164-buffer.c b/drivers/media/video/saa7164/saa7164-buffer.c index ddd25d32723d..7230912acc7d 100644 --- a/drivers/media/video/saa7164/saa7164-buffer.c +++ b/drivers/media/video/saa7164/saa7164-buffer.c | |||
@@ -1,7 +1,7 @@ | |||
1 | /* | 1 | /* |
2 | * Driver for the NXP SAA7164 PCIe bridge | 2 | * Driver for the NXP SAA7164 PCIe bridge |
3 | * | 3 | * |
4 | * Copyright (c) 2009 Steven Toth <stoth@kernellabs.com> | 4 | * Copyright (c) 2010 Steven Toth <stoth@kernellabs.com> |
5 | * | 5 | * |
6 | * This program is free software; you can redistribute it and/or modify | 6 | * This program is free software; you can redistribute it and/or modify |
7 | * it under the terms of the GNU General Public License as published by | 7 | * it under the terms of the GNU General Public License as published by |
@@ -66,12 +66,33 @@ | |||
66 | | etc | 66 | | etc |
67 | */ | 67 | */ |
68 | 68 | ||
69 | void saa7164_buffer_display(struct saa7164_buffer *buf) | ||
70 | { | ||
71 | struct saa7164_dev *dev = buf->port->dev; | ||
72 | int i; | ||
73 | |||
74 | dprintk(DBGLVL_BUF, "%s() buffer @ 0x%p nr=%d\n", | ||
75 | __func__, buf, buf->idx); | ||
76 | dprintk(DBGLVL_BUF, " pci_cpu @ 0x%p dma @ 0x%08llx len = 0x%x\n", | ||
77 | buf->cpu, (long long)buf->dma, buf->pci_size); | ||
78 | dprintk(DBGLVL_BUF, " pt_cpu @ 0x%p pt_dma @ 0x%08llx len = 0x%x\n", | ||
79 | buf->pt_cpu, (long long)buf->pt_dma, buf->pt_size); | ||
80 | |||
81 | /* Format the Page Table Entries to point into the data buffer */ | ||
82 | for (i = 0 ; i < SAA7164_PT_ENTRIES; i++) { | ||
83 | |||
84 | dprintk(DBGLVL_BUF, " pt[%02d] = 0x%p -> 0x%llx\n", | ||
85 | i, buf->pt_cpu, (u64)*(buf->pt_cpu)); | ||
86 | |||
87 | } | ||
88 | } | ||
69 | /* Allocate a new buffer structure and associated PCI space in bytes. | 89 | /* Allocate a new buffer structure and associated PCI space in bytes. |
70 | * len must be a multiple of sizeof(u64) | 90 | * len must be a multiple of sizeof(u64) |
71 | */ | 91 | */ |
72 | struct saa7164_buffer *saa7164_buffer_alloc(struct saa7164_tsport *port, | 92 | struct saa7164_buffer *saa7164_buffer_alloc(struct saa7164_port *port, |
73 | u32 len) | 93 | u32 len) |
74 | { | 94 | { |
95 | struct tmHWStreamParameters *params = &port->hw_streamingparams; | ||
75 | struct saa7164_buffer *buf = 0; | 96 | struct saa7164_buffer *buf = 0; |
76 | struct saa7164_dev *dev = port->dev; | 97 | struct saa7164_dev *dev = port->dev; |
77 | int i; | 98 | int i; |
@@ -87,8 +108,12 @@ struct saa7164_buffer *saa7164_buffer_alloc(struct saa7164_tsport *port, | |||
87 | goto ret; | 108 | goto ret; |
88 | } | 109 | } |
89 | 110 | ||
111 | buf->idx = -1; | ||
90 | buf->port = port; | 112 | buf->port = port; |
91 | buf->flags = SAA7164_BUFFER_FREE; | 113 | buf->flags = SAA7164_BUFFER_FREE; |
114 | buf->pos = 0; | ||
115 | buf->actual_size = params->pitch * params->numberoflines; | ||
116 | buf->crc = 0; | ||
92 | /* TODO: arg len is being ignored */ | 117 | /* TODO: arg len is being ignored */ |
93 | buf->pci_size = SAA7164_PT_ENTRIES * 0x1000; | 118 | buf->pci_size = SAA7164_PT_ENTRIES * 0x1000; |
94 | buf->pt_size = (SAA7164_PT_ENTRIES * sizeof(u64)) + 0x1000; | 119 | buf->pt_size = (SAA7164_PT_ENTRIES * sizeof(u64)) + 0x1000; |
@@ -105,19 +130,23 @@ struct saa7164_buffer *saa7164_buffer_alloc(struct saa7164_tsport *port, | |||
105 | goto fail2; | 130 | goto fail2; |
106 | 131 | ||
107 | /* init the buffers to a known pattern, easier during debugging */ | 132 | /* init the buffers to a known pattern, easier during debugging */ |
108 | memset(buf->cpu, 0xff, buf->pci_size); | 133 | memset_io(buf->cpu, 0xff, buf->pci_size); |
109 | memset(buf->pt_cpu, 0xff, buf->pt_size); | 134 | buf->crc = crc32(0, buf->cpu, buf->actual_size); |
135 | memset_io(buf->pt_cpu, 0xff, buf->pt_size); | ||
110 | 136 | ||
111 | dprintk(DBGLVL_BUF, "%s() allocated buffer @ 0x%p\n", __func__, buf); | 137 | dprintk(DBGLVL_BUF, "%s() allocated buffer @ 0x%p (%d pageptrs)\n", |
138 | __func__, buf, params->numpagetables); | ||
112 | dprintk(DBGLVL_BUF, " pci_cpu @ 0x%p dma @ 0x%08lx len = 0x%x\n", | 139 | dprintk(DBGLVL_BUF, " pci_cpu @ 0x%p dma @ 0x%08lx len = 0x%x\n", |
113 | buf->cpu, (long)buf->dma, buf->pci_size); | 140 | buf->cpu, (long)buf->dma, buf->pci_size); |
114 | dprintk(DBGLVL_BUF, " pt_cpu @ 0x%p pt_dma @ 0x%08lx len = 0x%x\n", | 141 | dprintk(DBGLVL_BUF, " pt_cpu @ 0x%p pt_dma @ 0x%08lx len = 0x%x\n", |
115 | buf->pt_cpu, (long)buf->pt_dma, buf->pt_size); | 142 | buf->pt_cpu, (long)buf->pt_dma, buf->pt_size); |
116 | 143 | ||
117 | /* Format the Page Table Entries to point into the data buffer */ | 144 | /* Format the Page Table Entries to point into the data buffer */ |
118 | for (i = 0 ; i < SAA7164_PT_ENTRIES; i++) { | 145 | for (i = 0 ; i < params->numpagetables; i++) { |
119 | 146 | ||
120 | *(buf->pt_cpu + i) = buf->dma + (i * 0x1000); /* TODO */ | 147 | *(buf->pt_cpu + i) = buf->dma + (i * 0x1000); /* TODO */ |
148 | dprintk(DBGLVL_BUF, " pt[%02d] = 0x%p -> 0x%llx\n", | ||
149 | i, buf->pt_cpu, (u64)*(buf->pt_cpu)); | ||
121 | 150 | ||
122 | } | 151 | } |
123 | 152 | ||
@@ -133,26 +162,163 @@ ret: | |||
133 | return buf; | 162 | return buf; |
134 | } | 163 | } |
135 | 164 | ||
136 | int saa7164_buffer_dealloc(struct saa7164_tsport *port, | 165 | int saa7164_buffer_dealloc(struct saa7164_buffer *buf) |
137 | struct saa7164_buffer *buf) | ||
138 | { | 166 | { |
139 | struct saa7164_dev *dev; | 167 | struct saa7164_dev *dev; |
140 | 168 | ||
141 | if (!buf || !port) | 169 | if (!buf || !buf->port) |
142 | return SAA_ERR_BAD_PARAMETER; | 170 | return SAA_ERR_BAD_PARAMETER; |
143 | dev = port->dev; | 171 | dev = buf->port->dev; |
144 | 172 | ||
145 | dprintk(DBGLVL_BUF, "%s() deallocating buffer @ 0x%p\n", __func__, buf); | 173 | dprintk(DBGLVL_BUF, "%s() deallocating buffer @ 0x%p\n", |
174 | __func__, buf); | ||
146 | 175 | ||
147 | if (buf->flags != SAA7164_BUFFER_FREE) | 176 | if (buf->flags != SAA7164_BUFFER_FREE) |
148 | log_warn(" freeing a non-free buffer\n"); | 177 | log_warn(" freeing a non-free buffer\n"); |
149 | 178 | ||
150 | pci_free_consistent(port->dev->pci, buf->pci_size, buf->cpu, buf->dma); | 179 | pci_free_consistent(dev->pci, buf->pci_size, buf->cpu, buf->dma); |
151 | pci_free_consistent(port->dev->pci, buf->pt_size, buf->pt_cpu, | 180 | pci_free_consistent(dev->pci, buf->pt_size, buf->pt_cpu, buf->pt_dma); |
152 | buf->pt_dma); | ||
153 | 181 | ||
154 | kfree(buf); | 182 | kfree(buf); |
155 | 183 | ||
156 | return SAA_OK; | 184 | return SAA_OK; |
157 | } | 185 | } |
158 | 186 | ||
187 | int saa7164_buffer_zero_offsets(struct saa7164_port *port, int i) | ||
188 | { | ||
189 | struct saa7164_dev *dev = port->dev; | ||
190 | |||
191 | if ((i < 0) || (i >= port->hwcfg.buffercount)) | ||
192 | return -EINVAL; | ||
193 | |||
194 | dprintk(DBGLVL_BUF, "%s(idx = %d)\n", __func__, i); | ||
195 | |||
196 | saa7164_writel(port->bufoffset + (sizeof(u32) * i), 0); | ||
197 | |||
198 | return 0; | ||
199 | } | ||
200 | |||
201 | /* Write a buffer into the hardware */ | ||
202 | int saa7164_buffer_activate(struct saa7164_buffer *buf, int i) | ||
203 | { | ||
204 | struct saa7164_port *port = buf->port; | ||
205 | struct saa7164_dev *dev = port->dev; | ||
206 | |||
207 | if ((i < 0) || (i >= port->hwcfg.buffercount)) | ||
208 | return -EINVAL; | ||
209 | |||
210 | dprintk(DBGLVL_BUF, "%s(idx = %d)\n", __func__, i); | ||
211 | |||
212 | buf->idx = i; /* Note of which buffer list index position we occupy */ | ||
213 | buf->flags = SAA7164_BUFFER_BUSY; | ||
214 | buf->pos = 0; | ||
215 | |||
216 | /* TODO: Review this in light of 32v64 assignments */ | ||
217 | saa7164_writel(port->bufoffset + (sizeof(u32) * i), 0); | ||
218 | saa7164_writel(port->bufptr32h + ((sizeof(u32) * 2) * i), buf->pt_dma); | ||
219 | saa7164_writel(port->bufptr32l + ((sizeof(u32) * 2) * i), 0); | ||
220 | |||
221 | dprintk(DBGLVL_BUF, " buf[%d] offset 0x%llx (0x%x) " | ||
222 | "buf 0x%llx/%llx (0x%x/%x) nr=%d\n", | ||
223 | buf->idx, | ||
224 | (u64)port->bufoffset + (i * sizeof(u32)), | ||
225 | saa7164_readl(port->bufoffset + (sizeof(u32) * i)), | ||
226 | (u64)port->bufptr32h + ((sizeof(u32) * 2) * i), | ||
227 | (u64)port->bufptr32l + ((sizeof(u32) * 2) * i), | ||
228 | saa7164_readl(port->bufptr32h + ((sizeof(u32) * i) * 2)), | ||
229 | saa7164_readl(port->bufptr32l + ((sizeof(u32) * i) * 2)), | ||
230 | buf->idx); | ||
231 | |||
232 | return 0; | ||
233 | } | ||
234 | |||
235 | int saa7164_buffer_cfg_port(struct saa7164_port *port) | ||
236 | { | ||
237 | struct tmHWStreamParameters *params = &port->hw_streamingparams; | ||
238 | struct saa7164_dev *dev = port->dev; | ||
239 | struct saa7164_buffer *buf; | ||
240 | struct list_head *c, *n; | ||
241 | int i = 0; | ||
242 | |||
243 | dprintk(DBGLVL_BUF, "%s(port=%d)\n", __func__, port->nr); | ||
244 | |||
245 | saa7164_writel(port->bufcounter, 0); | ||
246 | saa7164_writel(port->pitch, params->pitch); | ||
247 | saa7164_writel(port->bufsize, params->pitch * params->numberoflines); | ||
248 | |||
249 | dprintk(DBGLVL_BUF, " configured:\n"); | ||
250 | dprintk(DBGLVL_BUF, " lmmio 0x%p\n", dev->lmmio); | ||
251 | dprintk(DBGLVL_BUF, " bufcounter 0x%x = 0x%x\n", port->bufcounter, | ||
252 | saa7164_readl(port->bufcounter)); | ||
253 | |||
254 | dprintk(DBGLVL_BUF, " pitch 0x%x = %d\n", port->pitch, | ||
255 | saa7164_readl(port->pitch)); | ||
256 | |||
257 | dprintk(DBGLVL_BUF, " bufsize 0x%x = %d\n", port->bufsize, | ||
258 | saa7164_readl(port->bufsize)); | ||
259 | |||
260 | dprintk(DBGLVL_BUF, " buffercount = %d\n", port->hwcfg.buffercount); | ||
261 | dprintk(DBGLVL_BUF, " bufoffset = 0x%x\n", port->bufoffset); | ||
262 | dprintk(DBGLVL_BUF, " bufptr32h = 0x%x\n", port->bufptr32h); | ||
263 | dprintk(DBGLVL_BUF, " bufptr32l = 0x%x\n", port->bufptr32l); | ||
264 | |||
265 | /* Poke the buffers and offsets into PCI space */ | ||
266 | mutex_lock(&port->dmaqueue_lock); | ||
267 | list_for_each_safe(c, n, &port->dmaqueue.list) { | ||
268 | buf = list_entry(c, struct saa7164_buffer, list); | ||
269 | |||
270 | if (buf->flags != SAA7164_BUFFER_FREE) | ||
271 | BUG(); | ||
272 | |||
273 | /* Place the buffer in the h/w queue */ | ||
274 | saa7164_buffer_activate(buf, i); | ||
275 | |||
276 | /* Don't exceed the device maximum # bufs */ | ||
277 | if (i++ > port->hwcfg.buffercount) | ||
278 | BUG(); | ||
279 | |||
280 | } | ||
281 | mutex_unlock(&port->dmaqueue_lock); | ||
282 | |||
283 | return 0; | ||
284 | } | ||
285 | |||
286 | struct saa7164_user_buffer *saa7164_buffer_alloc_user(struct saa7164_dev *dev, u32 len) | ||
287 | { | ||
288 | struct saa7164_user_buffer *buf; | ||
289 | |||
290 | buf = kzalloc(sizeof(struct saa7164_user_buffer), GFP_KERNEL); | ||
291 | if (buf == 0) | ||
292 | return 0; | ||
293 | |||
294 | buf->data = kzalloc(len, GFP_KERNEL); | ||
295 | |||
296 | if (buf->data == 0) { | ||
297 | kfree(buf); | ||
298 | return 0; | ||
299 | } | ||
300 | |||
301 | buf->actual_size = len; | ||
302 | buf->pos = 0; | ||
303 | buf->crc = 0; | ||
304 | |||
305 | dprintk(DBGLVL_BUF, "%s() allocated user buffer @ 0x%p\n", | ||
306 | __func__, buf); | ||
307 | |||
308 | return buf; | ||
309 | } | ||
310 | |||
311 | void saa7164_buffer_dealloc_user(struct saa7164_user_buffer *buf) | ||
312 | { | ||
313 | if (!buf) | ||
314 | return; | ||
315 | |||
316 | if (buf->data) { | ||
317 | kfree(buf->data); | ||
318 | buf->data = 0; | ||
319 | } | ||
320 | |||
321 | if (buf) | ||
322 | kfree(buf); | ||
323 | } | ||
324 | |||
diff --git a/drivers/media/video/saa7164/saa7164-bus.c b/drivers/media/video/saa7164/saa7164-bus.c index 83a04640a25a..30d5283da41e 100644 --- a/drivers/media/video/saa7164/saa7164-bus.c +++ b/drivers/media/video/saa7164/saa7164-bus.c | |||
@@ -1,7 +1,7 @@ | |||
1 | /* | 1 | /* |
2 | * Driver for the NXP SAA7164 PCIe bridge | 2 | * Driver for the NXP SAA7164 PCIe bridge |
3 | * | 3 | * |
4 | * Copyright (c) 2009 Steven Toth <stoth@kernellabs.com> | 4 | * Copyright (c) 2010 Steven Toth <stoth@kernellabs.com> |
5 | * | 5 | * |
6 | * This program is free software; you can redistribute it and/or modify | 6 | * This program is free software; you can redistribute it and/or modify |
7 | * it under the terms of the GNU General Public License as published by | 7 | * it under the terms of the GNU General Public License as published by |
@@ -26,7 +26,7 @@ | |||
26 | */ | 26 | */ |
27 | int saa7164_bus_setup(struct saa7164_dev *dev) | 27 | int saa7164_bus_setup(struct saa7164_dev *dev) |
28 | { | 28 | { |
29 | tmComResBusInfo_t *b = &dev->bus; | 29 | struct tmComResBusInfo *b = &dev->bus; |
30 | 30 | ||
31 | mutex_init(&b->lock); | 31 | mutex_init(&b->lock); |
32 | 32 | ||
@@ -43,24 +43,18 @@ int saa7164_bus_setup(struct saa7164_dev *dev) | |||
43 | 43 | ||
44 | b->m_dwSizeGetRing = SAA_DEVICE_BUFFERBLOCKSIZE; | 44 | b->m_dwSizeGetRing = SAA_DEVICE_BUFFERBLOCKSIZE; |
45 | 45 | ||
46 | b->m_pdwSetWritePos = (u32 *)((u8 *)(dev->bmmio + | 46 | b->m_dwSetWritePos = ((u32)dev->intfdesc.BARLocation) + (2 * sizeof(u64)); |
47 | ((u32)dev->intfdesc.BARLocation) + (2 * sizeof(u64)))); | 47 | b->m_dwSetReadPos = b->m_dwSetWritePos + (1 * sizeof(u32)); |
48 | 48 | ||
49 | b->m_pdwSetReadPos = (u32 *)((u8 *)b->m_pdwSetWritePos + | 49 | b->m_dwGetWritePos = b->m_dwSetWritePos + (2 * sizeof(u32)); |
50 | 1 * sizeof(u32)); | 50 | b->m_dwGetReadPos = b->m_dwSetWritePos + (3 * sizeof(u32)); |
51 | |||
52 | b->m_pdwGetWritePos = (u32 *)((u8 *)b->m_pdwSetWritePos + | ||
53 | 2 * sizeof(u32)); | ||
54 | |||
55 | b->m_pdwGetReadPos = (u32 *)((u8 *)b->m_pdwSetWritePos + | ||
56 | 3 * sizeof(u32)); | ||
57 | 51 | ||
58 | return 0; | 52 | return 0; |
59 | } | 53 | } |
60 | 54 | ||
61 | void saa7164_bus_dump(struct saa7164_dev *dev) | 55 | void saa7164_bus_dump(struct saa7164_dev *dev) |
62 | { | 56 | { |
63 | tmComResBusInfo_t *b = &dev->bus; | 57 | struct tmComResBusInfo *b = &dev->bus; |
64 | 58 | ||
65 | dprintk(DBGLVL_BUS, "Dumping the bus structure:\n"); | 59 | dprintk(DBGLVL_BUS, "Dumping the bus structure:\n"); |
66 | dprintk(DBGLVL_BUS, " .type = %d\n", b->Type); | 60 | dprintk(DBGLVL_BUS, " .type = %d\n", b->Type); |
@@ -71,20 +65,47 @@ void saa7164_bus_dump(struct saa7164_dev *dev) | |||
71 | dprintk(DBGLVL_BUS, " .m_pdwGetRing = 0x%p\n", b->m_pdwGetRing); | 65 | dprintk(DBGLVL_BUS, " .m_pdwGetRing = 0x%p\n", b->m_pdwGetRing); |
72 | dprintk(DBGLVL_BUS, " .m_dwSizeGetRing = 0x%x\n", b->m_dwSizeGetRing); | 66 | dprintk(DBGLVL_BUS, " .m_dwSizeGetRing = 0x%x\n", b->m_dwSizeGetRing); |
73 | 67 | ||
74 | dprintk(DBGLVL_BUS, " .m_pdwSetWritePos = 0x%p (0x%08x)\n", | 68 | dprintk(DBGLVL_BUS, " .m_dwSetReadPos = 0x%x (0x%08x)\n", |
75 | b->m_pdwSetWritePos, *b->m_pdwSetWritePos); | 69 | b->m_dwSetReadPos, saa7164_readl(b->m_dwSetReadPos)); |
70 | |||
71 | dprintk(DBGLVL_BUS, " .m_dwSetWritePos = 0x%x (0x%08x)\n", | ||
72 | b->m_dwSetWritePos, saa7164_readl(b->m_dwSetWritePos)); | ||
73 | |||
74 | dprintk(DBGLVL_BUS, " .m_dwGetReadPos = 0x%x (0x%08x)\n", | ||
75 | b->m_dwGetReadPos, saa7164_readl(b->m_dwGetReadPos)); | ||
76 | |||
77 | dprintk(DBGLVL_BUS, " .m_dwGetWritePos = 0x%x (0x%08x)\n", | ||
78 | b->m_dwGetWritePos, saa7164_readl(b->m_dwGetWritePos)); | ||
79 | |||
80 | } | ||
81 | |||
82 | /* Intensionally throw a BUG() if the state of the message bus looks corrupt */ | ||
83 | void saa7164_bus_verify(struct saa7164_dev *dev) | ||
84 | { | ||
85 | struct tmComResBusInfo *b = &dev->bus; | ||
86 | int bug = 0; | ||
76 | 87 | ||
77 | dprintk(DBGLVL_BUS, " .m_pdwSetReadPos = 0x%p (0x%08x)\n", | 88 | if (saa7164_readl(b->m_dwSetReadPos) > b->m_dwSizeSetRing) |
78 | b->m_pdwSetReadPos, *b->m_pdwSetReadPos); | 89 | bug++; |
79 | 90 | ||
80 | dprintk(DBGLVL_BUS, " .m_pdwGetWritePos = 0x%p (0x%08x)\n", | 91 | if (saa7164_readl(b->m_dwSetWritePos) > b->m_dwSizeSetRing) |
81 | b->m_pdwGetWritePos, *b->m_pdwGetWritePos); | 92 | bug++; |
82 | 93 | ||
83 | dprintk(DBGLVL_BUS, " .m_pdwGetReadPos = 0x%p (0x%08x)\n", | 94 | if (saa7164_readl(b->m_dwGetReadPos) > b->m_dwSizeGetRing) |
84 | b->m_pdwGetReadPos, *b->m_pdwGetReadPos); | 95 | bug++; |
96 | |||
97 | if (saa7164_readl(b->m_dwGetWritePos) > b->m_dwSizeGetRing) | ||
98 | bug++; | ||
99 | |||
100 | if (bug) { | ||
101 | saa_debug = 0xffff; /* Ensure we get the bus dump */ | ||
102 | saa7164_bus_dump(dev); | ||
103 | saa_debug = 1024; /* Ensure we get the bus dump */ | ||
104 | BUG(); | ||
105 | } | ||
85 | } | 106 | } |
86 | 107 | ||
87 | void saa7164_bus_dumpmsg(struct saa7164_dev *dev, tmComResInfo_t* m, void *buf) | 108 | void saa7164_bus_dumpmsg(struct saa7164_dev *dev, struct tmComResInfo* m, void *buf) |
88 | { | 109 | { |
89 | dprintk(DBGLVL_BUS, "Dumping msg structure:\n"); | 110 | dprintk(DBGLVL_BUS, "Dumping msg structure:\n"); |
90 | dprintk(DBGLVL_BUS, " .id = %d\n", m->id); | 111 | dprintk(DBGLVL_BUS, " .id = %d\n", m->id); |
@@ -100,7 +121,7 @@ void saa7164_bus_dumpmsg(struct saa7164_dev *dev, tmComResInfo_t* m, void *buf) | |||
100 | /* | 121 | /* |
101 | * Places a command or a response on the bus. The implementation does not | 122 | * Places a command or a response on the bus. The implementation does not |
102 | * know if it is a command or a response it just places the data on the | 123 | * know if it is a command or a response it just places the data on the |
103 | * bus depending on the bus information given in the tmComResBusInfo_t | 124 | * bus depending on the bus information given in the struct tmComResBusInfo |
104 | * structure. If the command or response does not fit into the bus ring | 125 | * structure. If the command or response does not fit into the bus ring |
105 | * buffer it will be refused. | 126 | * buffer it will be refused. |
106 | * | 127 | * |
@@ -108,10 +129,10 @@ void saa7164_bus_dumpmsg(struct saa7164_dev *dev, tmComResInfo_t* m, void *buf) | |||
108 | * SAA_OK The function executed successfully. | 129 | * SAA_OK The function executed successfully. |
109 | * < 0 One or more members are not initialized. | 130 | * < 0 One or more members are not initialized. |
110 | */ | 131 | */ |
111 | int saa7164_bus_set(struct saa7164_dev *dev, tmComResInfo_t* msg, void *buf) | 132 | int saa7164_bus_set(struct saa7164_dev *dev, struct tmComResInfo* msg, void *buf) |
112 | { | 133 | { |
113 | tmComResBusInfo_t *bus = &dev->bus; | 134 | struct tmComResBusInfo *bus = &dev->bus; |
114 | u32 bytes_to_write, read_distance, timeout, curr_srp, curr_swp; | 135 | u32 bytes_to_write, free_write_space, timeout, curr_srp, curr_swp; |
115 | u32 new_swp, space_rem; | 136 | u32 new_swp, space_rem; |
116 | int ret = SAA_ERR_BAD_PARAMETER; | 137 | int ret = SAA_ERR_BAD_PARAMETER; |
117 | 138 | ||
@@ -122,6 +143,8 @@ int saa7164_bus_set(struct saa7164_dev *dev, tmComResInfo_t* msg, void *buf) | |||
122 | 143 | ||
123 | dprintk(DBGLVL_BUS, "%s()\n", __func__); | 144 | dprintk(DBGLVL_BUS, "%s()\n", __func__); |
124 | 145 | ||
146 | saa7164_bus_verify(dev); | ||
147 | |||
125 | msg->size = cpu_to_le16(msg->size); | 148 | msg->size = cpu_to_le16(msg->size); |
126 | msg->command = cpu_to_le16(msg->command); | 149 | msg->command = cpu_to_le16(msg->command); |
127 | msg->controlselector = cpu_to_le16(msg->controlselector); | 150 | msg->controlselector = cpu_to_le16(msg->controlselector); |
@@ -141,30 +164,30 @@ int saa7164_bus_set(struct saa7164_dev *dev, tmComResInfo_t* msg, void *buf) | |||
141 | mutex_lock(&bus->lock); | 164 | mutex_lock(&bus->lock); |
142 | 165 | ||
143 | bytes_to_write = sizeof(*msg) + msg->size; | 166 | bytes_to_write = sizeof(*msg) + msg->size; |
144 | read_distance = 0; | 167 | free_write_space = 0; |
145 | timeout = SAA_BUS_TIMEOUT; | 168 | timeout = SAA_BUS_TIMEOUT; |
146 | curr_srp = le32_to_cpu(*bus->m_pdwSetReadPos); | 169 | curr_srp = le32_to_cpu(saa7164_readl(bus->m_dwSetReadPos)); |
147 | curr_swp = le32_to_cpu(*bus->m_pdwSetWritePos); | 170 | curr_swp = le32_to_cpu(saa7164_readl(bus->m_dwSetWritePos)); |
148 | 171 | ||
149 | /* Deal with ring wrapping issues */ | 172 | /* Deal with ring wrapping issues */ |
150 | if (curr_srp > curr_swp) | 173 | if (curr_srp > curr_swp) |
151 | /* The ring has not wrapped yet */ | ||
152 | read_distance = curr_srp - curr_swp; | ||
153 | else | ||
154 | /* Deal with the wrapped ring */ | 174 | /* Deal with the wrapped ring */ |
155 | read_distance = (curr_srp + bus->m_dwSizeSetRing) - curr_swp; | 175 | free_write_space = curr_srp - curr_swp; |
176 | else | ||
177 | /* The ring has not wrapped yet */ | ||
178 | free_write_space = (curr_srp + bus->m_dwSizeSetRing) - curr_swp; | ||
156 | 179 | ||
157 | dprintk(DBGLVL_BUS, "%s() bytes_to_write = %d\n", __func__, | 180 | dprintk(DBGLVL_BUS, "%s() bytes_to_write = %d\n", __func__, |
158 | bytes_to_write); | 181 | bytes_to_write); |
159 | 182 | ||
160 | dprintk(DBGLVL_BUS, "%s() read_distance = %d\n", __func__, | 183 | dprintk(DBGLVL_BUS, "%s() free_write_space = %d\n", __func__, |
161 | read_distance); | 184 | free_write_space); |
162 | 185 | ||
163 | dprintk(DBGLVL_BUS, "%s() curr_srp = %x\n", __func__, curr_srp); | 186 | dprintk(DBGLVL_BUS, "%s() curr_srp = %x\n", __func__, curr_srp); |
164 | dprintk(DBGLVL_BUS, "%s() curr_swp = %x\n", __func__, curr_swp); | 187 | dprintk(DBGLVL_BUS, "%s() curr_swp = %x\n", __func__, curr_swp); |
165 | 188 | ||
166 | /* Process the msg and write the content onto the bus */ | 189 | /* Process the msg and write the content onto the bus */ |
167 | while (bytes_to_write >= read_distance) { | 190 | while (bytes_to_write >= free_write_space) { |
168 | 191 | ||
169 | if (timeout-- == 0) { | 192 | if (timeout-- == 0) { |
170 | printk(KERN_ERR "%s() bus timeout\n", __func__); | 193 | printk(KERN_ERR "%s() bus timeout\n", __func__); |
@@ -177,15 +200,15 @@ int saa7164_bus_set(struct saa7164_dev *dev, tmComResInfo_t* msg, void *buf) | |||
177 | mdelay(1); | 200 | mdelay(1); |
178 | 201 | ||
179 | /* Check the space usage again */ | 202 | /* Check the space usage again */ |
180 | curr_srp = le32_to_cpu(*bus->m_pdwSetReadPos); | 203 | curr_srp = le32_to_cpu(saa7164_readl(bus->m_dwSetReadPos)); |
181 | 204 | ||
182 | /* Deal with ring wrapping issues */ | 205 | /* Deal with ring wrapping issues */ |
183 | if (curr_srp > curr_swp) | 206 | if (curr_srp > curr_swp) |
184 | /* Read didn't wrap around the buffer */ | ||
185 | read_distance = curr_srp - curr_swp; | ||
186 | else | ||
187 | /* Deal with the wrapped ring */ | 207 | /* Deal with the wrapped ring */ |
188 | read_distance = (curr_srp + bus->m_dwSizeSetRing) - | 208 | free_write_space = curr_srp - curr_swp; |
209 | else | ||
210 | /* Read didn't wrap around the buffer */ | ||
211 | free_write_space = (curr_srp + bus->m_dwSizeSetRing) - | ||
189 | curr_swp; | 212 | curr_swp; |
190 | 213 | ||
191 | } | 214 | } |
@@ -257,37 +280,37 @@ int saa7164_bus_set(struct saa7164_dev *dev, tmComResInfo_t* msg, void *buf) | |||
257 | 280 | ||
258 | dprintk(DBGLVL_BUS, "%s() new_swp = %x\n", __func__, new_swp); | 281 | dprintk(DBGLVL_BUS, "%s() new_swp = %x\n", __func__, new_swp); |
259 | 282 | ||
260 | /* TODO: Convert all of the direct PCI writes into | ||
261 | * saa7164_writel/b calls for consistency. | ||
262 | */ | ||
263 | |||
264 | /* Update the bus write position */ | 283 | /* Update the bus write position */ |
265 | *bus->m_pdwSetWritePos = cpu_to_le32(new_swp); | 284 | saa7164_writel(bus->m_dwSetWritePos, cpu_to_le32(new_swp)); |
266 | ret = SAA_OK; | 285 | ret = SAA_OK; |
267 | 286 | ||
268 | out: | 287 | out: |
288 | saa7164_bus_dump(dev); | ||
269 | mutex_unlock(&bus->lock); | 289 | mutex_unlock(&bus->lock); |
290 | saa7164_bus_verify(dev); | ||
270 | return ret; | 291 | return ret; |
271 | } | 292 | } |
272 | 293 | ||
273 | /* | 294 | /* |
274 | * Receive a command or a response from the bus. The implementation does not | 295 | * Receive a command or a response from the bus. The implementation does not |
275 | * know if it is a command or a response it simply dequeues the data, | 296 | * know if it is a command or a response it simply dequeues the data, |
276 | * depending on the bus information given in the tmComResBusInfo_t structure. | 297 | * depending on the bus information given in the struct tmComResBusInfo structure. |
277 | * | 298 | * |
278 | * Return Value: | 299 | * Return Value: |
279 | * 0 The function executed successfully. | 300 | * 0 The function executed successfully. |
280 | * < 0 One or more members are not initialized. | 301 | * < 0 One or more members are not initialized. |
281 | */ | 302 | */ |
282 | int saa7164_bus_get(struct saa7164_dev *dev, tmComResInfo_t* msg, void *buf, | 303 | int saa7164_bus_get(struct saa7164_dev *dev, struct tmComResInfo* msg, void *buf, |
283 | int peekonly) | 304 | int peekonly) |
284 | { | 305 | { |
285 | tmComResBusInfo_t *bus = &dev->bus; | 306 | struct tmComResBusInfo *bus = &dev->bus; |
286 | u32 bytes_to_read, write_distance, curr_grp, curr_gwp, | 307 | u32 bytes_to_read, write_distance, curr_grp, curr_gwp, |
287 | new_grp, buf_size, space_rem; | 308 | new_grp, buf_size, space_rem; |
288 | tmComResInfo_t msg_tmp; | 309 | struct tmComResInfo msg_tmp; |
289 | int ret = SAA_ERR_BAD_PARAMETER; | 310 | int ret = SAA_ERR_BAD_PARAMETER; |
290 | 311 | ||
312 | saa7164_bus_verify(dev); | ||
313 | |||
291 | if (msg == 0) | 314 | if (msg == 0) |
292 | return ret; | 315 | return ret; |
293 | 316 | ||
@@ -309,11 +332,10 @@ int saa7164_bus_get(struct saa7164_dev *dev, tmComResInfo_t* msg, void *buf, | |||
309 | /* Peek the bus to see if a msg exists, if it's not what we're expecting | 332 | /* Peek the bus to see if a msg exists, if it's not what we're expecting |
310 | * then return cleanly else read the message from the bus. | 333 | * then return cleanly else read the message from the bus. |
311 | */ | 334 | */ |
312 | curr_gwp = le32_to_cpu(*bus->m_pdwGetWritePos); | 335 | curr_gwp = le32_to_cpu(saa7164_readl(bus->m_dwGetWritePos)); |
313 | curr_grp = le32_to_cpu(*bus->m_pdwGetReadPos); | 336 | curr_grp = le32_to_cpu(saa7164_readl(bus->m_dwGetReadPos)); |
314 | 337 | ||
315 | if (curr_gwp == curr_grp) { | 338 | if (curr_gwp == curr_grp) { |
316 | dprintk(DBGLVL_BUS, "%s() No message on the bus\n", __func__); | ||
317 | ret = SAA_ERR_EMPTY; | 339 | ret = SAA_ERR_EMPTY; |
318 | goto out; | 340 | goto out; |
319 | } | 341 | } |
@@ -434,7 +456,7 @@ int saa7164_bus_get(struct saa7164_dev *dev, tmComResInfo_t* msg, void *buf, | |||
434 | } | 456 | } |
435 | 457 | ||
436 | /* Update the read positions, adjusting the ring */ | 458 | /* Update the read positions, adjusting the ring */ |
437 | *bus->m_pdwGetReadPos = cpu_to_le32(new_grp); | 459 | saa7164_writel(bus->m_dwGetReadPos, cpu_to_le32(new_grp)); |
438 | 460 | ||
439 | peekout: | 461 | peekout: |
440 | msg->size = le16_to_cpu(msg->size); | 462 | msg->size = le16_to_cpu(msg->size); |
@@ -443,6 +465,7 @@ peekout: | |||
443 | ret = SAA_OK; | 465 | ret = SAA_OK; |
444 | out: | 466 | out: |
445 | mutex_unlock(&bus->lock); | 467 | mutex_unlock(&bus->lock); |
468 | saa7164_bus_verify(dev); | ||
446 | return ret; | 469 | return ret; |
447 | } | 470 | } |
448 | 471 | ||
diff --git a/drivers/media/video/saa7164/saa7164-cards.c b/drivers/media/video/saa7164/saa7164-cards.c index a3c299405f46..4cb634e952a6 100644 --- a/drivers/media/video/saa7164/saa7164-cards.c +++ b/drivers/media/video/saa7164/saa7164-cards.c | |||
@@ -1,7 +1,7 @@ | |||
1 | /* | 1 | /* |
2 | * Driver for the NXP SAA7164 PCIe bridge | 2 | * Driver for the NXP SAA7164 PCIe bridge |
3 | * | 3 | * |
4 | * Copyright (c) 2009 Steven Toth <stoth@kernellabs.com> | 4 | * Copyright (c) 2010 Steven Toth <stoth@kernellabs.com> |
5 | * | 5 | * |
6 | * This program is free software; you can redistribute it and/or modify | 6 | * This program is free software; you can redistribute it and/or modify |
7 | * it under the terms of the GNU General Public License as published by | 7 | * it under the terms of the GNU General Public License as published by |
@@ -55,6 +55,10 @@ struct saa7164_board saa7164_boards[] = { | |||
55 | .name = "Hauppauge WinTV-HVR2200", | 55 | .name = "Hauppauge WinTV-HVR2200", |
56 | .porta = SAA7164_MPEG_DVB, | 56 | .porta = SAA7164_MPEG_DVB, |
57 | .portb = SAA7164_MPEG_DVB, | 57 | .portb = SAA7164_MPEG_DVB, |
58 | .portc = SAA7164_MPEG_ENCODER, | ||
59 | .portd = SAA7164_MPEG_ENCODER, | ||
60 | .porte = SAA7164_MPEG_VBI, | ||
61 | .portf = SAA7164_MPEG_VBI, | ||
58 | .chiprev = SAA7164_CHIP_REV3, | 62 | .chiprev = SAA7164_CHIP_REV3, |
59 | .unit = {{ | 63 | .unit = {{ |
60 | .id = 0x1d, | 64 | .id = 0x1d, |
@@ -97,6 +101,10 @@ struct saa7164_board saa7164_boards[] = { | |||
97 | .name = "Hauppauge WinTV-HVR2200", | 101 | .name = "Hauppauge WinTV-HVR2200", |
98 | .porta = SAA7164_MPEG_DVB, | 102 | .porta = SAA7164_MPEG_DVB, |
99 | .portb = SAA7164_MPEG_DVB, | 103 | .portb = SAA7164_MPEG_DVB, |
104 | .portc = SAA7164_MPEG_ENCODER, | ||
105 | .portd = SAA7164_MPEG_ENCODER, | ||
106 | .porte = SAA7164_MPEG_VBI, | ||
107 | .portf = SAA7164_MPEG_VBI, | ||
100 | .chiprev = SAA7164_CHIP_REV2, | 108 | .chiprev = SAA7164_CHIP_REV2, |
101 | .unit = {{ | 109 | .unit = {{ |
102 | .id = 0x06, | 110 | .id = 0x06, |
@@ -139,6 +147,10 @@ struct saa7164_board saa7164_boards[] = { | |||
139 | .name = "Hauppauge WinTV-HVR2200", | 147 | .name = "Hauppauge WinTV-HVR2200", |
140 | .porta = SAA7164_MPEG_DVB, | 148 | .porta = SAA7164_MPEG_DVB, |
141 | .portb = SAA7164_MPEG_DVB, | 149 | .portb = SAA7164_MPEG_DVB, |
150 | .portc = SAA7164_MPEG_ENCODER, | ||
151 | .portd = SAA7164_MPEG_ENCODER, | ||
152 | .porte = SAA7164_MPEG_VBI, | ||
153 | .portf = SAA7164_MPEG_VBI, | ||
142 | .chiprev = SAA7164_CHIP_REV2, | 154 | .chiprev = SAA7164_CHIP_REV2, |
143 | .unit = {{ | 155 | .unit = {{ |
144 | .id = 0x1d, | 156 | .id = 0x1d, |
@@ -195,6 +207,12 @@ struct saa7164_board saa7164_boards[] = { | |||
195 | .name = "Hauppauge WinTV-HVR2250", | 207 | .name = "Hauppauge WinTV-HVR2250", |
196 | .porta = SAA7164_MPEG_DVB, | 208 | .porta = SAA7164_MPEG_DVB, |
197 | .portb = SAA7164_MPEG_DVB, | 209 | .portb = SAA7164_MPEG_DVB, |
210 | .portc = SAA7164_MPEG_ENCODER, | ||
211 | .portd = SAA7164_MPEG_ENCODER, | ||
212 | .portc = SAA7164_MPEG_ENCODER, | ||
213 | .portd = SAA7164_MPEG_ENCODER, | ||
214 | .porte = SAA7164_MPEG_VBI, | ||
215 | .portf = SAA7164_MPEG_VBI, | ||
198 | .chiprev = SAA7164_CHIP_REV3, | 216 | .chiprev = SAA7164_CHIP_REV3, |
199 | .unit = {{ | 217 | .unit = {{ |
200 | .id = 0x22, | 218 | .id = 0x22, |
@@ -251,6 +269,12 @@ struct saa7164_board saa7164_boards[] = { | |||
251 | .name = "Hauppauge WinTV-HVR2250", | 269 | .name = "Hauppauge WinTV-HVR2250", |
252 | .porta = SAA7164_MPEG_DVB, | 270 | .porta = SAA7164_MPEG_DVB, |
253 | .portb = SAA7164_MPEG_DVB, | 271 | .portb = SAA7164_MPEG_DVB, |
272 | .portc = SAA7164_MPEG_ENCODER, | ||
273 | .portd = SAA7164_MPEG_ENCODER, | ||
274 | .porte = SAA7164_MPEG_VBI, | ||
275 | .portf = SAA7164_MPEG_VBI, | ||
276 | .porte = SAA7164_MPEG_VBI, | ||
277 | .portf = SAA7164_MPEG_VBI, | ||
254 | .chiprev = SAA7164_CHIP_REV3, | 278 | .chiprev = SAA7164_CHIP_REV3, |
255 | .unit = {{ | 279 | .unit = {{ |
256 | .id = 0x28, | 280 | .id = 0x28, |
@@ -307,6 +331,10 @@ struct saa7164_board saa7164_boards[] = { | |||
307 | .name = "Hauppauge WinTV-HVR2250", | 331 | .name = "Hauppauge WinTV-HVR2250", |
308 | .porta = SAA7164_MPEG_DVB, | 332 | .porta = SAA7164_MPEG_DVB, |
309 | .portb = SAA7164_MPEG_DVB, | 333 | .portb = SAA7164_MPEG_DVB, |
334 | .portc = SAA7164_MPEG_ENCODER, | ||
335 | .portd = SAA7164_MPEG_ENCODER, | ||
336 | .porte = SAA7164_MPEG_VBI, | ||
337 | .portf = SAA7164_MPEG_VBI, | ||
310 | .chiprev = SAA7164_CHIP_REV3, | 338 | .chiprev = SAA7164_CHIP_REV3, |
311 | .unit = {{ | 339 | .unit = {{ |
312 | .id = 0x26, | 340 | .id = 0x26, |
@@ -437,8 +465,6 @@ void saa7164_card_list(struct saa7164_dev *dev) | |||
437 | 465 | ||
438 | void saa7164_gpio_setup(struct saa7164_dev *dev) | 466 | void saa7164_gpio_setup(struct saa7164_dev *dev) |
439 | { | 467 | { |
440 | |||
441 | |||
442 | switch (dev->board) { | 468 | switch (dev->board) { |
443 | case SAA7164_BOARD_HAUPPAUGE_HVR2200: | 469 | case SAA7164_BOARD_HAUPPAUGE_HVR2200: |
444 | case SAA7164_BOARD_HAUPPAUGE_HVR2200_2: | 470 | case SAA7164_BOARD_HAUPPAUGE_HVR2200_2: |
@@ -462,7 +488,6 @@ void saa7164_gpio_setup(struct saa7164_dev *dev) | |||
462 | saa7164_api_set_gpiobit(dev, PCIEBRIDGE_UNITID, 3); | 488 | saa7164_api_set_gpiobit(dev, PCIEBRIDGE_UNITID, 3); |
463 | break; | 489 | break; |
464 | } | 490 | } |
465 | |||
466 | } | 491 | } |
467 | 492 | ||
468 | static void hauppauge_eeprom(struct saa7164_dev *dev, u8 *eeprom_data) | 493 | static void hauppauge_eeprom(struct saa7164_dev *dev, u8 *eeprom_data) |
diff --git a/drivers/media/video/saa7164/saa7164-cmd.c b/drivers/media/video/saa7164/saa7164-cmd.c index 9c1d3ac43869..301a9e302f45 100644 --- a/drivers/media/video/saa7164/saa7164-cmd.c +++ b/drivers/media/video/saa7164/saa7164-cmd.c | |||
@@ -1,7 +1,7 @@ | |||
1 | /* | 1 | /* |
2 | * Driver for the NXP SAA7164 PCIe bridge | 2 | * Driver for the NXP SAA7164 PCIe bridge |
3 | * | 3 | * |
4 | * Copyright (c) 2009 Steven Toth <stoth@kernellabs.com> | 4 | * Copyright (c) 2010 Steven Toth <stoth@kernellabs.com> |
5 | * | 5 | * |
6 | * This program is free software; you can redistribute it and/or modify | 6 | * This program is free software; you can redistribute it and/or modify |
7 | * it under the terms of the GNU General Public License as published by | 7 | * it under the terms of the GNU General Public License as published by |
@@ -82,16 +82,17 @@ u32 saa7164_cmd_timeout_get(struct saa7164_dev *dev, u8 seqno) | |||
82 | * -bus/c running buffer. */ | 82 | * -bus/c running buffer. */ |
83 | int saa7164_irq_dequeue(struct saa7164_dev *dev) | 83 | int saa7164_irq_dequeue(struct saa7164_dev *dev) |
84 | { | 84 | { |
85 | int ret = SAA_OK; | 85 | int ret = SAA_OK, i = 0; |
86 | u32 timeout; | 86 | u32 timeout; |
87 | wait_queue_head_t *q = 0; | 87 | wait_queue_head_t *q = 0; |
88 | u8 tmp[512]; | ||
88 | dprintk(DBGLVL_CMD, "%s()\n", __func__); | 89 | dprintk(DBGLVL_CMD, "%s()\n", __func__); |
89 | 90 | ||
90 | /* While any outstand message on the bus exists... */ | 91 | /* While any outstand message on the bus exists... */ |
91 | do { | 92 | do { |
92 | 93 | ||
93 | /* Peek the msg bus */ | 94 | /* Peek the msg bus */ |
94 | tmComResInfo_t tRsp = { 0, 0, 0, 0, 0, 0 }; | 95 | struct tmComResInfo tRsp = { 0, 0, 0, 0, 0, 0 }; |
95 | ret = saa7164_bus_get(dev, &tRsp, NULL, 1); | 96 | ret = saa7164_bus_get(dev, &tRsp, NULL, 1); |
96 | if (ret != SAA_OK) | 97 | if (ret != SAA_OK) |
97 | break; | 98 | break; |
@@ -109,8 +110,22 @@ int saa7164_irq_dequeue(struct saa7164_dev *dev) | |||
109 | printk(KERN_ERR | 110 | printk(KERN_ERR |
110 | "%s() found timed out command on the bus\n", | 111 | "%s() found timed out command on the bus\n", |
111 | __func__); | 112 | __func__); |
113 | |||
114 | /* Clean the bus */ | ||
115 | ret = saa7164_bus_get(dev, &tRsp, &tmp, 0); | ||
116 | printk(KERN_ERR "%s() ret = %x\n", __func__, ret); | ||
117 | if (ret == SAA_ERR_EMPTY) | ||
118 | /* Someone else already fetched the response */ | ||
119 | return SAA_OK; | ||
120 | |||
121 | if (ret != SAA_OK) | ||
122 | return ret; | ||
112 | } | 123 | } |
113 | } while (0); | 124 | |
125 | /* It's unlikely to have more than 4 or 5 pending messages, ensure we exit | ||
126 | * at some point regardles. | ||
127 | */ | ||
128 | } while (i++ < 32); | ||
114 | 129 | ||
115 | return ret; | 130 | return ret; |
116 | } | 131 | } |
@@ -128,7 +143,7 @@ int saa7164_cmd_dequeue(struct saa7164_dev *dev) | |||
128 | 143 | ||
129 | while (loop) { | 144 | while (loop) { |
130 | 145 | ||
131 | tmComResInfo_t tRsp = { 0, 0, 0, 0, 0, 0 }; | 146 | struct tmComResInfo tRsp = { 0, 0, 0, 0, 0, 0 }; |
132 | ret = saa7164_bus_get(dev, &tRsp, NULL, 1); | 147 | ret = saa7164_bus_get(dev, &tRsp, NULL, 1); |
133 | if (ret == SAA_ERR_EMPTY) | 148 | if (ret == SAA_ERR_EMPTY) |
134 | return SAA_OK; | 149 | return SAA_OK; |
@@ -171,9 +186,9 @@ int saa7164_cmd_dequeue(struct saa7164_dev *dev) | |||
171 | return SAA_OK; | 186 | return SAA_OK; |
172 | } | 187 | } |
173 | 188 | ||
174 | int saa7164_cmd_set(struct saa7164_dev *dev, tmComResInfo_t* msg, void *buf) | 189 | int saa7164_cmd_set(struct saa7164_dev *dev, struct tmComResInfo* msg, void *buf) |
175 | { | 190 | { |
176 | tmComResBusInfo_t *bus = &dev->bus; | 191 | struct tmComResBusInfo *bus = &dev->bus; |
177 | u8 cmd_sent; | 192 | u8 cmd_sent; |
178 | u16 size, idx; | 193 | u16 size, idx; |
179 | u32 cmds; | 194 | u32 cmds; |
@@ -324,11 +339,11 @@ void saa7164_cmd_signal(struct saa7164_dev *dev, u8 seqno) | |||
324 | mutex_unlock(&dev->lock); | 339 | mutex_unlock(&dev->lock); |
325 | } | 340 | } |
326 | 341 | ||
327 | int saa7164_cmd_send(struct saa7164_dev *dev, u8 id, tmComResCmd_t command, | 342 | int saa7164_cmd_send(struct saa7164_dev *dev, u8 id, enum tmComResCmd command, |
328 | u16 controlselector, u16 size, void *buf) | 343 | u16 controlselector, u16 size, void *buf) |
329 | { | 344 | { |
330 | tmComResInfo_t command_t, *pcommand_t; | 345 | struct tmComResInfo command_t, *pcommand_t; |
331 | tmComResInfo_t response_t, *presponse_t; | 346 | struct tmComResInfo response_t, *presponse_t; |
332 | u8 errdata[256]; | 347 | u8 errdata[256]; |
333 | u16 resp_dsize; | 348 | u16 resp_dsize; |
334 | u16 data_recd; | 349 | u16 data_recd; |
diff --git a/drivers/media/video/saa7164/saa7164-core.c b/drivers/media/video/saa7164/saa7164-core.c index e6aa0fbd1e91..e1bac5051460 100644 --- a/drivers/media/video/saa7164/saa7164-core.c +++ b/drivers/media/video/saa7164/saa7164-core.c | |||
@@ -1,7 +1,7 @@ | |||
1 | /* | 1 | /* |
2 | * Driver for the NXP SAA7164 PCIe bridge | 2 | * Driver for the NXP SAA7164 PCIe bridge |
3 | * | 3 | * |
4 | * Copyright (c) 2009 Steven Toth <stoth@kernellabs.com> | 4 | * Copyright (c) 2010 Steven Toth <stoth@kernellabs.com> |
5 | * | 5 | * |
6 | * This program is free software; you can redistribute it and/or modify | 6 | * This program is free software; you can redistribute it and/or modify |
7 | * it under the terms of the GNU General Public License as published by | 7 | * it under the terms of the GNU General Public License as published by |
@@ -30,6 +30,9 @@ | |||
30 | #include <linux/delay.h> | 30 | #include <linux/delay.h> |
31 | #include <asm/div64.h> | 31 | #include <asm/div64.h> |
32 | 32 | ||
33 | #ifdef CONFIG_PROC_FS | ||
34 | #include <linux/proc_fs.h> | ||
35 | #endif | ||
33 | #include "saa7164.h" | 36 | #include "saa7164.h" |
34 | 37 | ||
35 | MODULE_DESCRIPTION("Driver for NXP SAA7164 based TV cards"); | 38 | MODULE_DESCRIPTION("Driver for NXP SAA7164 based TV cards"); |
@@ -49,14 +52,38 @@ unsigned int saa_debug; | |||
49 | module_param_named(debug, saa_debug, int, 0644); | 52 | module_param_named(debug, saa_debug, int, 0644); |
50 | MODULE_PARM_DESC(debug, "enable debug messages"); | 53 | MODULE_PARM_DESC(debug, "enable debug messages"); |
51 | 54 | ||
55 | unsigned int fw_debug; | ||
56 | module_param(fw_debug, int, 0644); | ||
57 | MODULE_PARM_DESC(fw_debug, "Firware debug level def:2"); | ||
58 | |||
59 | unsigned int encoder_buffers = SAA7164_MAX_ENCODER_BUFFERS; | ||
60 | module_param(encoder_buffers, int, 0644); | ||
61 | MODULE_PARM_DESC(encoder_buffers, "Total buffers in read queue 16-512 def:64"); | ||
62 | |||
63 | unsigned int vbi_buffers = SAA7164_MAX_VBI_BUFFERS; | ||
64 | module_param(vbi_buffers, int, 0644); | ||
65 | MODULE_PARM_DESC(vbi_buffers, "Total buffers in read queue 16-512 def:64"); | ||
66 | |||
52 | unsigned int waitsecs = 10; | 67 | unsigned int waitsecs = 10; |
53 | module_param(waitsecs, int, 0644); | 68 | module_param(waitsecs, int, 0644); |
54 | MODULE_PARM_DESC(debug, "timeout on firmware messages"); | 69 | MODULE_PARM_DESC(waitsecs, "timeout on firmware messages"); |
55 | 70 | ||
56 | static unsigned int card[] = {[0 ... (SAA7164_MAXBOARDS - 1)] = UNSET }; | 71 | static unsigned int card[] = {[0 ... (SAA7164_MAXBOARDS - 1)] = UNSET }; |
57 | module_param_array(card, int, NULL, 0444); | 72 | module_param_array(card, int, NULL, 0444); |
58 | MODULE_PARM_DESC(card, "card type"); | 73 | MODULE_PARM_DESC(card, "card type"); |
59 | 74 | ||
75 | unsigned int print_histogram = 64; | ||
76 | module_param(print_histogram, int, 0644); | ||
77 | MODULE_PARM_DESC(print_histogram, "print histogram values once"); | ||
78 | |||
79 | unsigned int crc_checking = 1; | ||
80 | module_param(crc_checking, int, 0644); | ||
81 | MODULE_PARM_DESC(crc_checking, "enable crc sanity checking on buffers"); | ||
82 | |||
83 | unsigned int guard_checking = 1; | ||
84 | module_param(guard_checking, int, 0644); | ||
85 | MODULE_PARM_DESC(guard_checking, "enable dma sanity checking for buffer overruns"); | ||
86 | |||
60 | static unsigned int saa7164_devcount; | 87 | static unsigned int saa7164_devcount; |
61 | 88 | ||
62 | static DEFINE_MUTEX(devlist); | 89 | static DEFINE_MUTEX(devlist); |
@@ -64,6 +91,444 @@ LIST_HEAD(saa7164_devlist); | |||
64 | 91 | ||
65 | #define INT_SIZE 16 | 92 | #define INT_SIZE 16 |
66 | 93 | ||
94 | void saa7164_dumphex16FF(struct saa7164_dev *dev, u8 *buf, int len) | ||
95 | { | ||
96 | int i; | ||
97 | u8 tmp[16]; | ||
98 | memset(&tmp[0], 0xff, sizeof(tmp)); | ||
99 | |||
100 | printk(KERN_INFO "--------------------> " | ||
101 | "00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f\n"); | ||
102 | |||
103 | for (i = 0; i < len; i += 16) { | ||
104 | if (memcmp(&tmp, buf + i, sizeof(tmp)) != 0) { | ||
105 | printk(KERN_INFO " [0x%08x] " | ||
106 | "%02x %02x %02x %02x %02x %02x %02x %02x " | ||
107 | "%02x %02x %02x %02x %02x %02x %02x %02x\n", i, | ||
108 | *(buf+i+0), *(buf+i+1), *(buf+i+2), *(buf+i+3), | ||
109 | *(buf+i+4), *(buf+i+5), *(buf+i+6), *(buf+i+7), | ||
110 | *(buf+i+8), *(buf+i+9), *(buf+i+10), *(buf+i+11), | ||
111 | *(buf+i+12), *(buf+i+13), *(buf+i+14), *(buf+i+15)); | ||
112 | } | ||
113 | } | ||
114 | } | ||
115 | |||
116 | static void saa7164_pack_verifier(struct saa7164_buffer *buf) | ||
117 | { | ||
118 | u8 *p = (u8 *)buf->cpu; | ||
119 | int i; | ||
120 | |||
121 | for (i = 0; i < buf->actual_size; i += 2048) { | ||
122 | |||
123 | if ((*(p + i + 0) != 0x00) || (*(p + i + 1) != 0x00) || | ||
124 | (*(p + i + 2) != 0x01) || (*(p + i + 3) != 0xBA)) { | ||
125 | printk(KERN_ERR "No pack at 0x%x\n", i); | ||
126 | // saa7164_dumphex16FF(buf->port->dev, (p + i), 32); | ||
127 | } | ||
128 | } | ||
129 | } | ||
130 | |||
131 | #define FIXED_VIDEO_PID 0xf1 | ||
132 | #define FIXED_AUDIO_PID 0xf2 | ||
133 | |||
134 | static void saa7164_ts_verifier(struct saa7164_buffer *buf) | ||
135 | { | ||
136 | struct saa7164_port *port = buf->port; | ||
137 | u32 i; | ||
138 | u8 cc, a; | ||
139 | u16 pid; | ||
140 | u8 __iomem *bufcpu = (u8 *)buf->cpu; | ||
141 | |||
142 | port->sync_errors = 0; | ||
143 | port->v_cc_errors = 0; | ||
144 | port->a_cc_errors = 0; | ||
145 | |||
146 | for (i = 0; i < buf->actual_size; i += 188) { | ||
147 | if (*(bufcpu + i) != 0x47) | ||
148 | port->sync_errors++; | ||
149 | |||
150 | /* TODO: Query pid lower 8 bits, ignoring upper bits intensionally */ | ||
151 | pid = ((*(bufcpu + i + 1) & 0x1f) << 8) | *(bufcpu + i + 2); | ||
152 | cc = *(bufcpu + i + 3) & 0x0f; | ||
153 | |||
154 | if (pid == FIXED_VIDEO_PID) { | ||
155 | a = ((port->last_v_cc + 1) & 0x0f); | ||
156 | if (a != cc) { | ||
157 | printk(KERN_ERR "video cc last = %x current = %x i = %d\n", | ||
158 | port->last_v_cc, cc, i); | ||
159 | port->v_cc_errors++; | ||
160 | } | ||
161 | |||
162 | port->last_v_cc = cc; | ||
163 | } else | ||
164 | if (pid == FIXED_AUDIO_PID) { | ||
165 | a = ((port->last_a_cc + 1) & 0x0f); | ||
166 | if (a != cc) { | ||
167 | printk(KERN_ERR "audio cc last = %x current = %x i = %d\n", | ||
168 | port->last_a_cc, cc, i); | ||
169 | port->a_cc_errors++; | ||
170 | } | ||
171 | |||
172 | port->last_a_cc = cc; | ||
173 | } | ||
174 | |||
175 | } | ||
176 | |||
177 | /* Only report errors if we've been through this function atleast | ||
178 | * once already and the cached cc values are primed. First time through | ||
179 | * always generates errors. | ||
180 | */ | ||
181 | if (port->v_cc_errors && (port->done_first_interrupt > 1)) | ||
182 | printk(KERN_ERR "video pid cc, %d errors\n", port->v_cc_errors); | ||
183 | |||
184 | if (port->a_cc_errors && (port->done_first_interrupt > 1)) | ||
185 | printk(KERN_ERR "audio pid cc, %d errors\n", port->a_cc_errors); | ||
186 | |||
187 | if (port->sync_errors && (port->done_first_interrupt > 1)) | ||
188 | printk(KERN_ERR "sync_errors = %d\n", port->sync_errors); | ||
189 | |||
190 | if (port->done_first_interrupt == 1) | ||
191 | port->done_first_interrupt++; | ||
192 | } | ||
193 | |||
194 | static void saa7164_histogram_reset(struct saa7164_histogram *hg, char *name) | ||
195 | { | ||
196 | int i; | ||
197 | |||
198 | memset(hg, 0, sizeof(struct saa7164_histogram)); | ||
199 | strcpy(hg->name, name); | ||
200 | |||
201 | /* First 30ms x 1ms */ | ||
202 | for (i = 0; i < 30; i++) { | ||
203 | hg->counter1[0 + i].val = i; | ||
204 | } | ||
205 | |||
206 | /* 30 - 200ms x 10ms */ | ||
207 | for (i = 0; i < 18; i++) { | ||
208 | hg->counter1[30 + i].val = 30 + (i * 10); | ||
209 | } | ||
210 | |||
211 | /* 200 - 2000ms x 100ms */ | ||
212 | for (i = 0; i < 15; i++) { | ||
213 | hg->counter1[48 + i].val = 200 + (i * 200); | ||
214 | } | ||
215 | |||
216 | /* Catch all massive value (2secs) */ | ||
217 | hg->counter1[55].val = 2000; | ||
218 | |||
219 | /* Catch all massive value (4secs) */ | ||
220 | hg->counter1[56].val = 4000; | ||
221 | |||
222 | /* Catch all massive value (8secs) */ | ||
223 | hg->counter1[57].val = 8000; | ||
224 | |||
225 | /* Catch all massive value (15secs) */ | ||
226 | hg->counter1[58].val = 15000; | ||
227 | |||
228 | /* Catch all massive value (30secs) */ | ||
229 | hg->counter1[59].val = 30000; | ||
230 | |||
231 | /* Catch all massive value (60secs) */ | ||
232 | hg->counter1[60].val = 60000; | ||
233 | |||
234 | /* Catch all massive value (5mins) */ | ||
235 | hg->counter1[61].val = 300000; | ||
236 | |||
237 | /* Catch all massive value (15mins) */ | ||
238 | hg->counter1[62].val = 900000; | ||
239 | |||
240 | /* Catch all massive values (1hr) */ | ||
241 | hg->counter1[63].val = 3600000; | ||
242 | } | ||
243 | |||
244 | void saa7164_histogram_update(struct saa7164_histogram *hg, u32 val) | ||
245 | { | ||
246 | int i; | ||
247 | for (i = 0; i < 64; i++) { | ||
248 | if (val <= hg->counter1[i].val) { | ||
249 | hg->counter1[i].count++; | ||
250 | hg->counter1[i].update_time = jiffies; | ||
251 | break; | ||
252 | } | ||
253 | } | ||
254 | } | ||
255 | |||
256 | static void saa7164_histogram_print(struct saa7164_port *port, | ||
257 | struct saa7164_histogram *hg) | ||
258 | { | ||
259 | u32 entries = 0; | ||
260 | int i; | ||
261 | |||
262 | printk(KERN_ERR "Histogram named %s (ms, count, last_update_jiffy)\n", hg->name); | ||
263 | for (i = 0; i < 64; i++) { | ||
264 | if (hg->counter1[i].count == 0) | ||
265 | continue; | ||
266 | |||
267 | printk(KERN_ERR " %4d %12d %Ld\n", | ||
268 | hg->counter1[i].val, | ||
269 | hg->counter1[i].count, | ||
270 | hg->counter1[i].update_time); | ||
271 | |||
272 | entries++; | ||
273 | } | ||
274 | printk(KERN_ERR "Total: %d\n", entries); | ||
275 | } | ||
276 | |||
277 | static void saa7164_work_enchandler_helper(struct saa7164_port *port, int bufnr) | ||
278 | { | ||
279 | struct saa7164_dev *dev = port->dev; | ||
280 | struct saa7164_buffer *buf = 0; | ||
281 | struct saa7164_user_buffer *ubuf = 0; | ||
282 | struct list_head *c, *n; | ||
283 | int i = 0; | ||
284 | u8 __iomem *p; | ||
285 | |||
286 | mutex_lock(&port->dmaqueue_lock); | ||
287 | list_for_each_safe(c, n, &port->dmaqueue.list) { | ||
288 | |||
289 | buf = list_entry(c, struct saa7164_buffer, list); | ||
290 | if (i++ > port->hwcfg.buffercount) { | ||
291 | printk(KERN_ERR "%s() illegal i count %d\n", | ||
292 | __func__, i); | ||
293 | break; | ||
294 | } | ||
295 | |||
296 | if (buf->idx == bufnr) { | ||
297 | |||
298 | /* Found the buffer, deal with it */ | ||
299 | dprintk(DBGLVL_IRQ, "%s() bufnr: %d\n", __func__, bufnr); | ||
300 | |||
301 | if (crc_checking) { | ||
302 | /* Throw a new checksum on the dma buffer */ | ||
303 | buf->crc = crc32(0, buf->cpu, buf->actual_size); | ||
304 | } | ||
305 | |||
306 | if (guard_checking) { | ||
307 | p = (u8 *)buf->cpu; | ||
308 | if ((*(p + buf->actual_size + 0) != 0xff) || | ||
309 | (*(p + buf->actual_size + 1) != 0xff) || | ||
310 | (*(p + buf->actual_size + 2) != 0xff) || | ||
311 | (*(p + buf->actual_size + 3) != 0xff) || | ||
312 | (*(p + buf->actual_size + 0x10) != 0xff) || | ||
313 | (*(p + buf->actual_size + 0x11) != 0xff) || | ||
314 | (*(p + buf->actual_size + 0x12) != 0xff) || | ||
315 | (*(p + buf->actual_size + 0x13) != 0xff)) { | ||
316 | printk(KERN_ERR "%s() buf %p guard buffer breach\n", | ||
317 | __func__, buf); | ||
318 | // saa7164_dumphex16FF(dev, (p + buf->actual_size) - 32 , 64); | ||
319 | } | ||
320 | } | ||
321 | |||
322 | if ((port->nr != SAA7164_PORT_VBI1) && (port->nr != SAA7164_PORT_VBI2)) { | ||
323 | /* Validate the incoming buffer content */ | ||
324 | if (port->encoder_params.stream_type == V4L2_MPEG_STREAM_TYPE_MPEG2_TS) | ||
325 | saa7164_ts_verifier(buf); | ||
326 | else if (port->encoder_params.stream_type == V4L2_MPEG_STREAM_TYPE_MPEG2_PS) | ||
327 | saa7164_pack_verifier(buf); | ||
328 | } | ||
329 | |||
330 | /* find a free user buffer and clone to it */ | ||
331 | if (!list_empty(&port->list_buf_free.list)) { | ||
332 | |||
333 | /* Pull the first buffer from the used list */ | ||
334 | ubuf = list_first_entry(&port->list_buf_free.list, | ||
335 | struct saa7164_user_buffer, list); | ||
336 | |||
337 | if (buf->actual_size <= ubuf->actual_size) { | ||
338 | |||
339 | memcpy_fromio(ubuf->data, buf->cpu, | ||
340 | ubuf->actual_size); | ||
341 | |||
342 | if (crc_checking) { | ||
343 | /* Throw a new checksum on the read buffer */ | ||
344 | ubuf->crc = crc32(0, ubuf->data, ubuf->actual_size); | ||
345 | } | ||
346 | |||
347 | /* Requeue the buffer on the free list */ | ||
348 | ubuf->pos = 0; | ||
349 | |||
350 | list_move_tail(&ubuf->list, | ||
351 | &port->list_buf_used.list); | ||
352 | |||
353 | /* Flag any userland waiters */ | ||
354 | wake_up_interruptible(&port->wait_read); | ||
355 | |||
356 | } else { | ||
357 | printk(KERN_ERR "buf %p bufsize fails match\n", buf); | ||
358 | } | ||
359 | |||
360 | } else | ||
361 | printk(KERN_ERR "encirq no free buffers, increase param encoder_buffers\n"); | ||
362 | |||
363 | /* Ensure offset into buffer remains 0, fill buffer | ||
364 | * with known bad data. We check for this data at a later point | ||
365 | * in time. */ | ||
366 | saa7164_buffer_zero_offsets(port, bufnr); | ||
367 | memset_io(buf->cpu, 0xff, buf->pci_size); | ||
368 | if (crc_checking) { | ||
369 | /* Throw yet aanother new checksum on the dma buffer */ | ||
370 | buf->crc = crc32(0, buf->cpu, buf->actual_size); | ||
371 | } | ||
372 | |||
373 | break; | ||
374 | } | ||
375 | } | ||
376 | mutex_unlock(&port->dmaqueue_lock); | ||
377 | } | ||
378 | |||
379 | static void saa7164_work_enchandler(struct work_struct *w) | ||
380 | { | ||
381 | struct saa7164_port *port = | ||
382 | container_of(w, struct saa7164_port, workenc); | ||
383 | struct saa7164_dev *dev = port->dev; | ||
384 | |||
385 | u32 wp, mcb, rp, cnt = 0; | ||
386 | |||
387 | port->last_svc_msecs_diff = port->last_svc_msecs; | ||
388 | port->last_svc_msecs = jiffies_to_msecs(jiffies); | ||
389 | |||
390 | port->last_svc_msecs_diff = port->last_svc_msecs - | ||
391 | port->last_svc_msecs_diff; | ||
392 | |||
393 | saa7164_histogram_update(&port->svc_interval, | ||
394 | port->last_svc_msecs_diff); | ||
395 | |||
396 | port->last_irq_svc_msecs_diff = port->last_svc_msecs - | ||
397 | port->last_irq_msecs; | ||
398 | |||
399 | saa7164_histogram_update(&port->irq_svc_interval, | ||
400 | port->last_irq_svc_msecs_diff); | ||
401 | |||
402 | dprintk(DBGLVL_IRQ, | ||
403 | "%s() %Ldms elapsed irq->deferred %Ldms wp: %d rp: %d\n", | ||
404 | __func__, | ||
405 | port->last_svc_msecs_diff, | ||
406 | port->last_irq_svc_msecs_diff, | ||
407 | port->last_svc_wp, | ||
408 | port->last_svc_rp | ||
409 | ); | ||
410 | |||
411 | /* Current write position */ | ||
412 | wp = saa7164_readl(port->bufcounter); | ||
413 | if (wp > (port->hwcfg.buffercount - 1)) { | ||
414 | printk(KERN_ERR "%s() illegal buf count %d\n", __func__, wp); | ||
415 | return; | ||
416 | } | ||
417 | |||
418 | /* Most current complete buffer */ | ||
419 | if (wp == 0) | ||
420 | mcb = (port->hwcfg.buffercount - 1); | ||
421 | else | ||
422 | mcb = wp - 1; | ||
423 | |||
424 | while (1) { | ||
425 | if (port->done_first_interrupt == 0) { | ||
426 | port->done_first_interrupt++; | ||
427 | rp = mcb; | ||
428 | } else | ||
429 | rp = (port->last_svc_rp + 1) % 8; | ||
430 | |||
431 | if ((rp < 0) || (rp > (port->hwcfg.buffercount - 1))) { | ||
432 | printk(KERN_ERR "%s() illegal rp count %d\n", __func__, rp); | ||
433 | break; | ||
434 | } | ||
435 | |||
436 | saa7164_work_enchandler_helper(port, rp); | ||
437 | port->last_svc_rp = rp; | ||
438 | cnt++; | ||
439 | |||
440 | if (rp == mcb) | ||
441 | break; | ||
442 | } | ||
443 | |||
444 | /* TODO: Convert this into a /proc/saa7164 style readable file */ | ||
445 | if (print_histogram == port->nr) { | ||
446 | saa7164_histogram_print(port, &port->irq_interval); | ||
447 | saa7164_histogram_print(port, &port->svc_interval); | ||
448 | saa7164_histogram_print(port, &port->irq_svc_interval); | ||
449 | saa7164_histogram_print(port, &port->read_interval); | ||
450 | saa7164_histogram_print(port, &port->poll_interval); | ||
451 | /* TODO: fix this to preserve any previous state */ | ||
452 | print_histogram = 64 + port->nr; | ||
453 | } | ||
454 | } | ||
455 | |||
456 | static void saa7164_work_vbihandler(struct work_struct *w) | ||
457 | { | ||
458 | struct saa7164_port *port = | ||
459 | container_of(w, struct saa7164_port, workenc); | ||
460 | struct saa7164_dev *dev = port->dev; | ||
461 | |||
462 | u32 wp, mcb, rp, cnt = 0; | ||
463 | |||
464 | port->last_svc_msecs_diff = port->last_svc_msecs; | ||
465 | port->last_svc_msecs = jiffies_to_msecs(jiffies); | ||
466 | port->last_svc_msecs_diff = port->last_svc_msecs - | ||
467 | port->last_svc_msecs_diff; | ||
468 | |||
469 | saa7164_histogram_update(&port->svc_interval, | ||
470 | port->last_svc_msecs_diff); | ||
471 | |||
472 | port->last_irq_svc_msecs_diff = port->last_svc_msecs - | ||
473 | port->last_irq_msecs; | ||
474 | |||
475 | saa7164_histogram_update(&port->irq_svc_interval, | ||
476 | port->last_irq_svc_msecs_diff); | ||
477 | |||
478 | dprintk(DBGLVL_IRQ, | ||
479 | "%s() %Ldms elapsed irq->deferred %Ldms wp: %d rp: %d\n", | ||
480 | __func__, | ||
481 | port->last_svc_msecs_diff, | ||
482 | port->last_irq_svc_msecs_diff, | ||
483 | port->last_svc_wp, | ||
484 | port->last_svc_rp | ||
485 | ); | ||
486 | |||
487 | /* Current write position */ | ||
488 | wp = saa7164_readl(port->bufcounter); | ||
489 | if (wp > (port->hwcfg.buffercount - 1)) { | ||
490 | printk(KERN_ERR "%s() illegal buf count %d\n", __func__, wp); | ||
491 | return; | ||
492 | } | ||
493 | |||
494 | /* Most current complete buffer */ | ||
495 | if (wp == 0) | ||
496 | mcb = (port->hwcfg.buffercount - 1); | ||
497 | else | ||
498 | mcb = wp - 1; | ||
499 | |||
500 | while (1) { | ||
501 | if (port->done_first_interrupt == 0) { | ||
502 | port->done_first_interrupt++; | ||
503 | rp = mcb; | ||
504 | } else | ||
505 | rp = (port->last_svc_rp + 1) % 8; | ||
506 | |||
507 | if ((rp < 0) || (rp > (port->hwcfg.buffercount - 1))) { | ||
508 | printk(KERN_ERR "%s() illegal rp count %d\n", __func__, rp); | ||
509 | break; | ||
510 | } | ||
511 | |||
512 | saa7164_work_enchandler_helper(port, rp); | ||
513 | port->last_svc_rp = rp; | ||
514 | cnt++; | ||
515 | |||
516 | if (rp == mcb) | ||
517 | break; | ||
518 | } | ||
519 | |||
520 | /* TODO: Convert this into a /proc/saa7164 style readable file */ | ||
521 | if (print_histogram == port->nr) { | ||
522 | saa7164_histogram_print(port, &port->irq_interval); | ||
523 | saa7164_histogram_print(port, &port->svc_interval); | ||
524 | saa7164_histogram_print(port, &port->irq_svc_interval); | ||
525 | saa7164_histogram_print(port, &port->read_interval); | ||
526 | saa7164_histogram_print(port, &port->poll_interval); | ||
527 | /* TODO: fix this to preserve any previous state */ | ||
528 | print_histogram = 64 + port->nr; | ||
529 | } | ||
530 | } | ||
531 | |||
67 | static void saa7164_work_cmdhandler(struct work_struct *w) | 532 | static void saa7164_work_cmdhandler(struct work_struct *w) |
68 | { | 533 | { |
69 | struct saa7164_dev *dev = container_of(w, struct saa7164_dev, workcmd); | 534 | struct saa7164_dev *dev = container_of(w, struct saa7164_dev, workcmd); |
@@ -74,7 +539,7 @@ static void saa7164_work_cmdhandler(struct work_struct *w) | |||
74 | 539 | ||
75 | static void saa7164_buffer_deliver(struct saa7164_buffer *buf) | 540 | static void saa7164_buffer_deliver(struct saa7164_buffer *buf) |
76 | { | 541 | { |
77 | struct saa7164_tsport *port = buf->port; | 542 | struct saa7164_port *port = buf->port; |
78 | 543 | ||
79 | /* Feed the transport payload into the kernel demux */ | 544 | /* Feed the transport payload into the kernel demux */ |
80 | dvb_dmx_swfilter_packets(&port->dvb.demux, (u8 *)buf->cpu, | 545 | dvb_dmx_swfilter_packets(&port->dvb.demux, (u8 *)buf->cpu, |
@@ -82,7 +547,56 @@ static void saa7164_buffer_deliver(struct saa7164_buffer *buf) | |||
82 | 547 | ||
83 | } | 548 | } |
84 | 549 | ||
85 | static irqreturn_t saa7164_irq_ts(struct saa7164_tsport *port) | 550 | static irqreturn_t saa7164_irq_vbi(struct saa7164_port *port) |
551 | { | ||
552 | struct saa7164_dev *dev = port->dev; | ||
553 | |||
554 | /* Store old time */ | ||
555 | port->last_irq_msecs_diff = port->last_irq_msecs; | ||
556 | |||
557 | /* Collect new stats */ | ||
558 | port->last_irq_msecs = jiffies_to_msecs(jiffies); | ||
559 | |||
560 | /* Calculate stats */ | ||
561 | port->last_irq_msecs_diff = port->last_irq_msecs - | ||
562 | port->last_irq_msecs_diff; | ||
563 | |||
564 | saa7164_histogram_update(&port->irq_interval, | ||
565 | port->last_irq_msecs_diff); | ||
566 | |||
567 | dprintk(DBGLVL_IRQ, "%s() %Ldms elapsed\n", __func__, | ||
568 | port->last_irq_msecs_diff); | ||
569 | |||
570 | /* Tis calls the vbi irq handler */ | ||
571 | schedule_work(&port->workenc); | ||
572 | return 0; | ||
573 | } | ||
574 | |||
575 | static irqreturn_t saa7164_irq_encoder(struct saa7164_port *port) | ||
576 | { | ||
577 | struct saa7164_dev *dev = port->dev; | ||
578 | |||
579 | /* Store old time */ | ||
580 | port->last_irq_msecs_diff = port->last_irq_msecs; | ||
581 | |||
582 | /* Collect new stats */ | ||
583 | port->last_irq_msecs = jiffies_to_msecs(jiffies); | ||
584 | |||
585 | /* Calculate stats */ | ||
586 | port->last_irq_msecs_diff = port->last_irq_msecs - | ||
587 | port->last_irq_msecs_diff; | ||
588 | |||
589 | saa7164_histogram_update(&port->irq_interval, | ||
590 | port->last_irq_msecs_diff); | ||
591 | |||
592 | dprintk(DBGLVL_IRQ, "%s() %Ldms elapsed\n", __func__, | ||
593 | port->last_irq_msecs_diff); | ||
594 | |||
595 | schedule_work(&port->workenc); | ||
596 | return 0; | ||
597 | } | ||
598 | |||
599 | static irqreturn_t saa7164_irq_ts(struct saa7164_port *port) | ||
86 | { | 600 | { |
87 | struct saa7164_dev *dev = port->dev; | 601 | struct saa7164_dev *dev = port->dev; |
88 | struct saa7164_buffer *buf; | 602 | struct saa7164_buffer *buf; |
@@ -96,7 +610,7 @@ static irqreturn_t saa7164_irq_ts(struct saa7164_tsport *port) | |||
96 | 610 | ||
97 | /* Find the previous buffer to the current write point */ | 611 | /* Find the previous buffer to the current write point */ |
98 | if (wp == 0) | 612 | if (wp == 0) |
99 | rp = 7; | 613 | rp = (port->hwcfg.buffercount - 1); |
100 | else | 614 | else |
101 | rp = wp - 1; | 615 | rp = wp - 1; |
102 | 616 | ||
@@ -107,7 +621,7 @@ static irqreturn_t saa7164_irq_ts(struct saa7164_tsport *port) | |||
107 | if (i++ > port->hwcfg.buffercount) | 621 | if (i++ > port->hwcfg.buffercount) |
108 | BUG(); | 622 | BUG(); |
109 | 623 | ||
110 | if (buf->nr == rp) { | 624 | if (buf->idx == rp) { |
111 | /* Found the buffer, deal with it */ | 625 | /* Found the buffer, deal with it */ |
112 | dprintk(DBGLVL_IRQ, "%s() wp: %d processing: %d\n", | 626 | dprintk(DBGLVL_IRQ, "%s() wp: %d processing: %d\n", |
113 | __func__, wp, rp); | 627 | __func__, wp, rp); |
@@ -123,6 +637,13 @@ static irqreturn_t saa7164_irq_ts(struct saa7164_tsport *port) | |||
123 | static irqreturn_t saa7164_irq(int irq, void *dev_id) | 637 | static irqreturn_t saa7164_irq(int irq, void *dev_id) |
124 | { | 638 | { |
125 | struct saa7164_dev *dev = dev_id; | 639 | struct saa7164_dev *dev = dev_id; |
640 | struct saa7164_port *porta = &dev->ports[SAA7164_PORT_TS1]; | ||
641 | struct saa7164_port *portb = &dev->ports[SAA7164_PORT_TS2]; | ||
642 | struct saa7164_port *portc = &dev->ports[SAA7164_PORT_ENC1]; | ||
643 | struct saa7164_port *portd = &dev->ports[SAA7164_PORT_ENC2]; | ||
644 | struct saa7164_port *porte = &dev->ports[SAA7164_PORT_VBI1]; | ||
645 | struct saa7164_port *portf = &dev->ports[SAA7164_PORT_VBI2]; | ||
646 | |||
126 | u32 intid, intstat[INT_SIZE/4]; | 647 | u32 intid, intstat[INT_SIZE/4]; |
127 | int i, handled = 0, bit; | 648 | int i, handled = 0, bit; |
128 | 649 | ||
@@ -168,17 +689,35 @@ static irqreturn_t saa7164_irq(int irq, void *dev_id) | |||
168 | if (intid == dev->intfdesc.bInterruptId) { | 689 | if (intid == dev->intfdesc.bInterruptId) { |
169 | /* A response to an cmd/api call */ | 690 | /* A response to an cmd/api call */ |
170 | schedule_work(&dev->workcmd); | 691 | schedule_work(&dev->workcmd); |
171 | } else if (intid == | 692 | } else if (intid == porta->hwcfg.interruptid) { |
172 | dev->ts1.hwcfg.interruptid) { | ||
173 | 693 | ||
174 | /* Transport path 1 */ | 694 | /* Transport path 1 */ |
175 | saa7164_irq_ts(&dev->ts1); | 695 | saa7164_irq_ts(porta); |
176 | 696 | ||
177 | } else if (intid == | 697 | } else if (intid == portb->hwcfg.interruptid) { |
178 | dev->ts2.hwcfg.interruptid) { | ||
179 | 698 | ||
180 | /* Transport path 2 */ | 699 | /* Transport path 2 */ |
181 | saa7164_irq_ts(&dev->ts2); | 700 | saa7164_irq_ts(portb); |
701 | |||
702 | } else if (intid == portc->hwcfg.interruptid) { | ||
703 | |||
704 | /* Encoder path 1 */ | ||
705 | saa7164_irq_encoder(portc); | ||
706 | |||
707 | } else if (intid == portd->hwcfg.interruptid) { | ||
708 | |||
709 | /* Encoder path 2 */ | ||
710 | saa7164_irq_encoder(portd); | ||
711 | |||
712 | } else if (intid == porte->hwcfg.interruptid) { | ||
713 | |||
714 | /* VBI path 1 */ | ||
715 | saa7164_irq_vbi(porte); | ||
716 | |||
717 | } else if (intid == portf->hwcfg.interruptid) { | ||
718 | |||
719 | /* VBI path 2 */ | ||
720 | saa7164_irq_vbi(portf); | ||
182 | 721 | ||
183 | } else { | 722 | } else { |
184 | /* Find the function */ | 723 | /* Find the function */ |
@@ -286,8 +825,8 @@ void saa7164_dumpregs(struct saa7164_dev *dev, u32 addr) | |||
286 | 825 | ||
287 | static void saa7164_dump_hwdesc(struct saa7164_dev *dev) | 826 | static void saa7164_dump_hwdesc(struct saa7164_dev *dev) |
288 | { | 827 | { |
289 | dprintk(1, "@0x%p hwdesc sizeof(tmComResHWDescr_t) = %d bytes\n", | 828 | dprintk(1, "@0x%p hwdesc sizeof(struct tmComResHWDescr) = %d bytes\n", |
290 | &dev->hwdesc, (u32)sizeof(tmComResHWDescr_t)); | 829 | &dev->hwdesc, (u32)sizeof(struct tmComResHWDescr)); |
291 | 830 | ||
292 | dprintk(1, " .bLength = 0x%x\n", dev->hwdesc.bLength); | 831 | dprintk(1, " .bLength = 0x%x\n", dev->hwdesc.bLength); |
293 | dprintk(1, " .bDescriptorType = 0x%x\n", dev->hwdesc.bDescriptorType); | 832 | dprintk(1, " .bDescriptorType = 0x%x\n", dev->hwdesc.bDescriptorType); |
@@ -317,8 +856,8 @@ static void saa7164_dump_hwdesc(struct saa7164_dev *dev) | |||
317 | static void saa7164_dump_intfdesc(struct saa7164_dev *dev) | 856 | static void saa7164_dump_intfdesc(struct saa7164_dev *dev) |
318 | { | 857 | { |
319 | dprintk(1, "@0x%p intfdesc " | 858 | dprintk(1, "@0x%p intfdesc " |
320 | "sizeof(tmComResInterfaceDescr_t) = %d bytes\n", | 859 | "sizeof(struct tmComResInterfaceDescr) = %d bytes\n", |
321 | &dev->intfdesc, (u32)sizeof(tmComResInterfaceDescr_t)); | 860 | &dev->intfdesc, (u32)sizeof(struct tmComResInterfaceDescr)); |
322 | 861 | ||
323 | dprintk(1, " .bLength = 0x%x\n", dev->intfdesc.bLength); | 862 | dprintk(1, " .bLength = 0x%x\n", dev->intfdesc.bLength); |
324 | dprintk(1, " .bDescriptorType = 0x%x\n", dev->intfdesc.bDescriptorType); | 863 | dprintk(1, " .bDescriptorType = 0x%x\n", dev->intfdesc.bDescriptorType); |
@@ -338,8 +877,8 @@ static void saa7164_dump_intfdesc(struct saa7164_dev *dev) | |||
338 | 877 | ||
339 | static void saa7164_dump_busdesc(struct saa7164_dev *dev) | 878 | static void saa7164_dump_busdesc(struct saa7164_dev *dev) |
340 | { | 879 | { |
341 | dprintk(1, "@0x%p busdesc sizeof(tmComResBusDescr_t) = %d bytes\n", | 880 | dprintk(1, "@0x%p busdesc sizeof(struct tmComResBusDescr) = %d bytes\n", |
342 | &dev->busdesc, (u32)sizeof(tmComResBusDescr_t)); | 881 | &dev->busdesc, (u32)sizeof(struct tmComResBusDescr)); |
343 | 882 | ||
344 | dprintk(1, " .CommandRing = 0x%016Lx\n", dev->busdesc.CommandRing); | 883 | dprintk(1, " .CommandRing = 0x%016Lx\n", dev->busdesc.CommandRing); |
345 | dprintk(1, " .ResponseRing = 0x%016Lx\n", dev->busdesc.ResponseRing); | 884 | dprintk(1, " .ResponseRing = 0x%016Lx\n", dev->busdesc.ResponseRing); |
@@ -356,23 +895,23 @@ static void saa7164_dump_busdesc(struct saa7164_dev *dev) | |||
356 | */ | 895 | */ |
357 | static void saa7164_get_descriptors(struct saa7164_dev *dev) | 896 | static void saa7164_get_descriptors(struct saa7164_dev *dev) |
358 | { | 897 | { |
359 | memcpy(&dev->hwdesc, dev->bmmio, sizeof(tmComResHWDescr_t)); | 898 | memcpy_fromio(&dev->hwdesc, dev->bmmio, sizeof(struct tmComResHWDescr)); |
360 | memcpy(&dev->intfdesc, dev->bmmio + sizeof(tmComResHWDescr_t), | 899 | memcpy_fromio(&dev->intfdesc, dev->bmmio + sizeof(struct tmComResHWDescr), |
361 | sizeof(tmComResInterfaceDescr_t)); | 900 | sizeof(struct tmComResInterfaceDescr)); |
362 | memcpy(&dev->busdesc, dev->bmmio + dev->intfdesc.BARLocation, | 901 | memcpy_fromio(&dev->busdesc, dev->bmmio + dev->intfdesc.BARLocation, |
363 | sizeof(tmComResBusDescr_t)); | 902 | sizeof(struct tmComResBusDescr)); |
364 | 903 | ||
365 | if (dev->hwdesc.bLength != sizeof(tmComResHWDescr_t)) { | 904 | if (dev->hwdesc.bLength != sizeof(struct tmComResHWDescr)) { |
366 | printk(KERN_ERR "Structure tmComResHWDescr_t is mangled\n"); | 905 | printk(KERN_ERR "Structure struct tmComResHWDescr is mangled\n"); |
367 | printk(KERN_ERR "Need %x got %d\n", dev->hwdesc.bLength, | 906 | printk(KERN_ERR "Need %x got %d\n", dev->hwdesc.bLength, |
368 | (u32)sizeof(tmComResHWDescr_t)); | 907 | (u32)sizeof(struct tmComResHWDescr)); |
369 | } else | 908 | } else |
370 | saa7164_dump_hwdesc(dev); | 909 | saa7164_dump_hwdesc(dev); |
371 | 910 | ||
372 | if (dev->intfdesc.bLength != sizeof(tmComResInterfaceDescr_t)) { | 911 | if (dev->intfdesc.bLength != sizeof(struct tmComResInterfaceDescr)) { |
373 | printk(KERN_ERR "struct tmComResInterfaceDescr_t is mangled\n"); | 912 | printk(KERN_ERR "struct struct tmComResInterfaceDescr is mangled\n"); |
374 | printk(KERN_ERR "Need %x got %d\n", dev->intfdesc.bLength, | 913 | printk(KERN_ERR "Need %x got %d\n", dev->intfdesc.bLength, |
375 | (u32)sizeof(tmComResInterfaceDescr_t)); | 914 | (u32)sizeof(struct tmComResInterfaceDescr)); |
376 | } else | 915 | } else |
377 | saa7164_dump_intfdesc(dev); | 916 | saa7164_dump_intfdesc(dev); |
378 | 917 | ||
@@ -402,6 +941,58 @@ static int get_resources(struct saa7164_dev *dev) | |||
402 | return -EBUSY; | 941 | return -EBUSY; |
403 | } | 942 | } |
404 | 943 | ||
944 | static int saa7164_port_init(struct saa7164_dev *dev, int portnr) | ||
945 | { | ||
946 | struct saa7164_port *port = 0; | ||
947 | |||
948 | if ((portnr < 0) || (portnr >= SAA7164_MAX_PORTS)) | ||
949 | BUG(); | ||
950 | |||
951 | port = &dev->ports[portnr]; | ||
952 | |||
953 | port->dev = dev; | ||
954 | port->nr = portnr; | ||
955 | |||
956 | if ((portnr == SAA7164_PORT_TS1) || (portnr == SAA7164_PORT_TS2)) | ||
957 | port->type = SAA7164_MPEG_DVB; | ||
958 | else | ||
959 | if ((portnr == SAA7164_PORT_ENC1) || (portnr == SAA7164_PORT_ENC2)) { | ||
960 | port->type = SAA7164_MPEG_ENCODER; | ||
961 | |||
962 | /* We need a deferred interrupt handler for cmd handling */ | ||
963 | INIT_WORK(&port->workenc, saa7164_work_enchandler); | ||
964 | } | ||
965 | else | ||
966 | if ((portnr == SAA7164_PORT_VBI1) || (portnr == SAA7164_PORT_VBI2)) { | ||
967 | port->type = SAA7164_MPEG_VBI; | ||
968 | |||
969 | /* We need a deferred interrupt handler for cmd handling */ | ||
970 | INIT_WORK(&port->workenc, saa7164_work_vbihandler); | ||
971 | } else | ||
972 | BUG(); | ||
973 | |||
974 | /* Init all the critical resources */ | ||
975 | mutex_init(&port->dvb.lock); | ||
976 | INIT_LIST_HEAD(&port->dmaqueue.list); | ||
977 | mutex_init(&port->dmaqueue_lock); | ||
978 | |||
979 | INIT_LIST_HEAD(&port->list_buf_used.list); | ||
980 | INIT_LIST_HEAD(&port->list_buf_free.list); | ||
981 | init_waitqueue_head(&port->wait_read); | ||
982 | |||
983 | |||
984 | saa7164_histogram_reset(&port->irq_interval, "irq intervals"); | ||
985 | saa7164_histogram_reset(&port->svc_interval, "deferred intervals"); | ||
986 | saa7164_histogram_reset(&port->irq_svc_interval, | ||
987 | "irq to deferred intervals"); | ||
988 | saa7164_histogram_reset(&port->read_interval, | ||
989 | "encoder/vbi read() intervals"); | ||
990 | saa7164_histogram_reset(&port->poll_interval, | ||
991 | "encoder/vbi poll() intervals"); | ||
992 | |||
993 | return 0; | ||
994 | } | ||
995 | |||
405 | static int saa7164_dev_setup(struct saa7164_dev *dev) | 996 | static int saa7164_dev_setup(struct saa7164_dev *dev) |
406 | { | 997 | { |
407 | int i; | 998 | int i; |
@@ -443,23 +1034,13 @@ static int saa7164_dev_setup(struct saa7164_dev *dev) | |||
443 | dev->i2c_bus[2].dev = dev; | 1034 | dev->i2c_bus[2].dev = dev; |
444 | dev->i2c_bus[2].nr = 2; | 1035 | dev->i2c_bus[2].nr = 2; |
445 | 1036 | ||
446 | /* Transport port A Defaults / setup */ | 1037 | /* Transport + Encoder ports 1, 2, 3, 4 - Defaults / setup */ |
447 | dev->ts1.dev = dev; | 1038 | saa7164_port_init(dev, SAA7164_PORT_TS1); |
448 | dev->ts1.nr = 0; | 1039 | saa7164_port_init(dev, SAA7164_PORT_TS2); |
449 | mutex_init(&dev->ts1.dvb.lock); | 1040 | saa7164_port_init(dev, SAA7164_PORT_ENC1); |
450 | INIT_LIST_HEAD(&dev->ts1.dmaqueue.list); | 1041 | saa7164_port_init(dev, SAA7164_PORT_ENC2); |
451 | INIT_LIST_HEAD(&dev->ts1.dummy_dmaqueue.list); | 1042 | saa7164_port_init(dev, SAA7164_PORT_VBI1); |
452 | mutex_init(&dev->ts1.dmaqueue_lock); | 1043 | saa7164_port_init(dev, SAA7164_PORT_VBI2); |
453 | mutex_init(&dev->ts1.dummy_dmaqueue_lock); | ||
454 | |||
455 | /* Transport port B Defaults / setup */ | ||
456 | dev->ts2.dev = dev; | ||
457 | dev->ts2.nr = 1; | ||
458 | mutex_init(&dev->ts2.dvb.lock); | ||
459 | INIT_LIST_HEAD(&dev->ts2.dmaqueue.list); | ||
460 | INIT_LIST_HEAD(&dev->ts2.dummy_dmaqueue.list); | ||
461 | mutex_init(&dev->ts2.dmaqueue_lock); | ||
462 | mutex_init(&dev->ts2.dummy_dmaqueue_lock); | ||
463 | 1044 | ||
464 | if (get_resources(dev) < 0) { | 1045 | if (get_resources(dev) < 0) { |
465 | printk(KERN_ERR "CORE %s No more PCIe resources for " | 1046 | printk(KERN_ERR "CORE %s No more PCIe resources for " |
@@ -516,6 +1097,132 @@ static void saa7164_dev_unregister(struct saa7164_dev *dev) | |||
516 | return; | 1097 | return; |
517 | } | 1098 | } |
518 | 1099 | ||
1100 | #ifdef CONFIG_PROC_FS | ||
1101 | static int saa7164_proc_show(struct seq_file *m, void *v) | ||
1102 | { | ||
1103 | struct saa7164_dev *dev; | ||
1104 | struct tmComResBusInfo *b; | ||
1105 | struct list_head *list; | ||
1106 | int i, c; | ||
1107 | |||
1108 | if (saa7164_devcount == 0) | ||
1109 | return 0; | ||
1110 | |||
1111 | list_for_each(list, &saa7164_devlist) { | ||
1112 | dev = list_entry(list, struct saa7164_dev, devlist); | ||
1113 | seq_printf(m, "%s = %p\n", dev->name, dev); | ||
1114 | |||
1115 | /* Lock the bus from any other access */ | ||
1116 | b = &dev->bus; | ||
1117 | mutex_lock(&b->lock); | ||
1118 | |||
1119 | seq_printf(m, " .m_pdwSetWritePos = 0x%x (0x%08x)\n", | ||
1120 | b->m_dwSetReadPos, saa7164_readl(b->m_dwSetReadPos)); | ||
1121 | |||
1122 | seq_printf(m, " .m_pdwSetReadPos = 0x%x (0x%08x)\n", | ||
1123 | b->m_dwSetWritePos, saa7164_readl(b->m_dwSetWritePos)); | ||
1124 | |||
1125 | seq_printf(m, " .m_pdwGetWritePos = 0x%x (0x%08x)\n", | ||
1126 | b->m_dwGetReadPos, saa7164_readl(b->m_dwGetReadPos)); | ||
1127 | |||
1128 | seq_printf(m, " .m_pdwGetReadPos = 0x%x (0x%08x)\n", | ||
1129 | b->m_dwGetWritePos, saa7164_readl(b->m_dwGetWritePos)); | ||
1130 | c = 0; | ||
1131 | seq_printf(m, "\n Set Ring:\n"); | ||
1132 | seq_printf(m, "\n addr 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f\n"); | ||
1133 | for (i = 0; i < b->m_dwSizeSetRing; i++) { | ||
1134 | if (c == 0) | ||
1135 | seq_printf(m, " %04x:", i); | ||
1136 | |||
1137 | seq_printf(m, " %02x", *(b->m_pdwSetRing + i)); | ||
1138 | |||
1139 | if (++c == 16) { | ||
1140 | seq_printf(m, "\n"); | ||
1141 | c = 0; | ||
1142 | } | ||
1143 | } | ||
1144 | |||
1145 | c = 0; | ||
1146 | seq_printf(m, "\n Get Ring:\n"); | ||
1147 | seq_printf(m, "\n addr 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f\n"); | ||
1148 | for (i = 0; i < b->m_dwSizeGetRing; i++) { | ||
1149 | if (c == 0) | ||
1150 | seq_printf(m, " %04x:", i); | ||
1151 | |||
1152 | seq_printf(m, " %02x", *(b->m_pdwGetRing + i)); | ||
1153 | |||
1154 | if (++c == 16) { | ||
1155 | seq_printf(m, "\n"); | ||
1156 | c = 0; | ||
1157 | } | ||
1158 | } | ||
1159 | |||
1160 | mutex_unlock(&b->lock); | ||
1161 | |||
1162 | } | ||
1163 | |||
1164 | return 0; | ||
1165 | } | ||
1166 | |||
1167 | static int saa7164_proc_open(struct inode *inode, struct file *filp) | ||
1168 | { | ||
1169 | return single_open(filp, saa7164_proc_show, NULL); | ||
1170 | } | ||
1171 | |||
1172 | static struct file_operations saa7164_proc_fops = { | ||
1173 | .open = saa7164_proc_open, | ||
1174 | .read = seq_read, | ||
1175 | .llseek = seq_lseek, | ||
1176 | .release = single_release, | ||
1177 | }; | ||
1178 | |||
1179 | static int saa7164_proc_create(void) | ||
1180 | { | ||
1181 | struct proc_dir_entry *pe; | ||
1182 | |||
1183 | pe = proc_create("saa7164", S_IRUGO, NULL, &saa7164_proc_fops); | ||
1184 | if (!pe) | ||
1185 | return -ENOMEM; | ||
1186 | |||
1187 | return 0; | ||
1188 | } | ||
1189 | #endif | ||
1190 | |||
1191 | static int saa7164_thread_function(void *data) | ||
1192 | { | ||
1193 | struct saa7164_dev *dev = data; | ||
1194 | struct tmFwInfoStruct fwinfo; | ||
1195 | u64 last_poll_time = 0; | ||
1196 | |||
1197 | dprintk(DBGLVL_THR, "thread started\n"); | ||
1198 | |||
1199 | set_freezable(); | ||
1200 | |||
1201 | while (1) { | ||
1202 | msleep_interruptible(100); | ||
1203 | if (kthread_should_stop()) | ||
1204 | break; | ||
1205 | try_to_freeze(); | ||
1206 | |||
1207 | dprintk(DBGLVL_THR, "thread running\n"); | ||
1208 | |||
1209 | /* Dump the firmware debug message to console */ | ||
1210 | /* Polling this costs us 1-2% of the arm CPU */ | ||
1211 | /* convert this into a respnde to interrupt 0x7a */ | ||
1212 | saa7164_api_collect_debug(dev); | ||
1213 | |||
1214 | /* Monitor CPU load every 1 second */ | ||
1215 | if ((last_poll_time + 1000 /* ms */) < jiffies_to_msecs(jiffies)) { | ||
1216 | saa7164_api_get_load_info(dev, &fwinfo); | ||
1217 | last_poll_time = jiffies_to_msecs(jiffies); | ||
1218 | } | ||
1219 | |||
1220 | } | ||
1221 | |||
1222 | dprintk(DBGLVL_THR, "thread exiting\n"); | ||
1223 | return 0; | ||
1224 | } | ||
1225 | |||
519 | static int __devinit saa7164_initdev(struct pci_dev *pci_dev, | 1226 | static int __devinit saa7164_initdev(struct pci_dev *pci_dev, |
520 | const struct pci_device_id *pci_id) | 1227 | const struct pci_device_id *pci_id) |
521 | { | 1228 | { |
@@ -622,7 +1329,6 @@ static int __devinit saa7164_initdev(struct pci_dev *pci_dev, | |||
622 | saa7164_gpio_setup(dev); | 1329 | saa7164_gpio_setup(dev); |
623 | saa7164_card_setup(dev); | 1330 | saa7164_card_setup(dev); |
624 | 1331 | ||
625 | |||
626 | /* Parse the dynamic device configuration, find various | 1332 | /* Parse the dynamic device configuration, find various |
627 | * media endpoints (MPEG, WMV, PS, TS) and cache their | 1333 | * media endpoints (MPEG, WMV, PS, TS) and cache their |
628 | * configuration details into the driver, so we can | 1334 | * configuration details into the driver, so we can |
@@ -633,7 +1339,7 @@ static int __devinit saa7164_initdev(struct pci_dev *pci_dev, | |||
633 | 1339 | ||
634 | /* Begin to create the video sub-systems and register funcs */ | 1340 | /* Begin to create the video sub-systems and register funcs */ |
635 | if (saa7164_boards[dev->board].porta == SAA7164_MPEG_DVB) { | 1341 | if (saa7164_boards[dev->board].porta == SAA7164_MPEG_DVB) { |
636 | if (saa7164_dvb_register(&dev->ts1) < 0) { | 1342 | if (saa7164_dvb_register(&dev->ports[SAA7164_PORT_TS1]) < 0) { |
637 | printk(KERN_ERR "%s() Failed to register " | 1343 | printk(KERN_ERR "%s() Failed to register " |
638 | "dvb adapters on porta\n", | 1344 | "dvb adapters on porta\n", |
639 | __func__); | 1345 | __func__); |
@@ -641,13 +1347,50 @@ static int __devinit saa7164_initdev(struct pci_dev *pci_dev, | |||
641 | } | 1347 | } |
642 | 1348 | ||
643 | if (saa7164_boards[dev->board].portb == SAA7164_MPEG_DVB) { | 1349 | if (saa7164_boards[dev->board].portb == SAA7164_MPEG_DVB) { |
644 | if (saa7164_dvb_register(&dev->ts2) < 0) { | 1350 | if (saa7164_dvb_register(&dev->ports[SAA7164_PORT_TS2]) < 0) { |
645 | printk(KERN_ERR"%s() Failed to register " | 1351 | printk(KERN_ERR"%s() Failed to register " |
646 | "dvb adapters on portb\n", | 1352 | "dvb adapters on portb\n", |
647 | __func__); | 1353 | __func__); |
648 | } | 1354 | } |
649 | } | 1355 | } |
650 | 1356 | ||
1357 | if (saa7164_boards[dev->board].portc == SAA7164_MPEG_ENCODER) { | ||
1358 | if (saa7164_encoder_register(&dev->ports[SAA7164_PORT_ENC1]) < 0) { | ||
1359 | printk(KERN_ERR"%s() Failed to register " | ||
1360 | "mpeg encoder\n", __func__); | ||
1361 | } | ||
1362 | } | ||
1363 | |||
1364 | if (saa7164_boards[dev->board].portd == SAA7164_MPEG_ENCODER) { | ||
1365 | if (saa7164_encoder_register(&dev->ports[SAA7164_PORT_ENC2]) < 0) { | ||
1366 | printk(KERN_ERR"%s() Failed to register " | ||
1367 | "mpeg encoder\n", __func__); | ||
1368 | } | ||
1369 | } | ||
1370 | |||
1371 | if (saa7164_boards[dev->board].porte == SAA7164_MPEG_VBI) { | ||
1372 | if (saa7164_vbi_register(&dev->ports[SAA7164_PORT_VBI1]) < 0) { | ||
1373 | printk(KERN_ERR"%s() Failed to register " | ||
1374 | "vbi device\n", __func__); | ||
1375 | } | ||
1376 | } | ||
1377 | |||
1378 | if (saa7164_boards[dev->board].portf == SAA7164_MPEG_VBI) { | ||
1379 | if (saa7164_vbi_register(&dev->ports[SAA7164_PORT_VBI2]) < 0) { | ||
1380 | printk(KERN_ERR"%s() Failed to register " | ||
1381 | "vbi device\n", __func__); | ||
1382 | } | ||
1383 | } | ||
1384 | saa7164_api_set_debug(dev, fw_debug); | ||
1385 | |||
1386 | if (fw_debug) { | ||
1387 | dev->kthread = kthread_run(saa7164_thread_function, dev, | ||
1388 | "saa7164 debug"); | ||
1389 | if (!dev->kthread) | ||
1390 | printk(KERN_ERR "%s() Failed to create " | ||
1391 | "debug kernel thread\n", __func__); | ||
1392 | } | ||
1393 | |||
651 | } /* != BOARD_UNKNOWN */ | 1394 | } /* != BOARD_UNKNOWN */ |
652 | else | 1395 | else |
653 | printk(KERN_ERR "%s() Unsupported board detected, " | 1396 | printk(KERN_ERR "%s() Unsupported board detected, " |
@@ -675,13 +1418,49 @@ static void __devexit saa7164_finidev(struct pci_dev *pci_dev) | |||
675 | { | 1418 | { |
676 | struct saa7164_dev *dev = pci_get_drvdata(pci_dev); | 1419 | struct saa7164_dev *dev = pci_get_drvdata(pci_dev); |
677 | 1420 | ||
1421 | if (dev->board != SAA7164_BOARD_UNKNOWN) { | ||
1422 | if (fw_debug && dev->kthread) { | ||
1423 | kthread_stop(dev->kthread); | ||
1424 | dev->kthread = NULL; | ||
1425 | } | ||
1426 | if (dev->firmwareloaded) | ||
1427 | saa7164_api_set_debug(dev, 0x00); | ||
1428 | } | ||
1429 | |||
1430 | saa7164_histogram_print(&dev->ports[SAA7164_PORT_ENC1], | ||
1431 | &dev->ports[SAA7164_PORT_ENC1].irq_interval); | ||
1432 | saa7164_histogram_print(&dev->ports[SAA7164_PORT_ENC1], | ||
1433 | &dev->ports[SAA7164_PORT_ENC1].svc_interval); | ||
1434 | saa7164_histogram_print(&dev->ports[SAA7164_PORT_ENC1], | ||
1435 | &dev->ports[SAA7164_PORT_ENC1].irq_svc_interval); | ||
1436 | saa7164_histogram_print(&dev->ports[SAA7164_PORT_ENC1], | ||
1437 | &dev->ports[SAA7164_PORT_ENC1].read_interval); | ||
1438 | saa7164_histogram_print(&dev->ports[SAA7164_PORT_ENC1], | ||
1439 | &dev->ports[SAA7164_PORT_ENC1].poll_interval); | ||
1440 | saa7164_histogram_print(&dev->ports[SAA7164_PORT_VBI1], | ||
1441 | &dev->ports[SAA7164_PORT_VBI1].read_interval); | ||
1442 | saa7164_histogram_print(&dev->ports[SAA7164_PORT_VBI2], | ||
1443 | &dev->ports[SAA7164_PORT_VBI2].poll_interval); | ||
1444 | |||
678 | saa7164_shutdown(dev); | 1445 | saa7164_shutdown(dev); |
679 | 1446 | ||
680 | if (saa7164_boards[dev->board].porta == SAA7164_MPEG_DVB) | 1447 | if (saa7164_boards[dev->board].porta == SAA7164_MPEG_DVB) |
681 | saa7164_dvb_unregister(&dev->ts1); | 1448 | saa7164_dvb_unregister(&dev->ports[SAA7164_PORT_TS1]); |
682 | 1449 | ||
683 | if (saa7164_boards[dev->board].portb == SAA7164_MPEG_DVB) | 1450 | if (saa7164_boards[dev->board].portb == SAA7164_MPEG_DVB) |
684 | saa7164_dvb_unregister(&dev->ts2); | 1451 | saa7164_dvb_unregister(&dev->ports[SAA7164_PORT_TS2]); |
1452 | |||
1453 | if (saa7164_boards[dev->board].portc == SAA7164_MPEG_ENCODER) | ||
1454 | saa7164_encoder_unregister(&dev->ports[SAA7164_PORT_ENC1]); | ||
1455 | |||
1456 | if (saa7164_boards[dev->board].portd == SAA7164_MPEG_ENCODER) | ||
1457 | saa7164_encoder_unregister(&dev->ports[SAA7164_PORT_ENC2]); | ||
1458 | |||
1459 | if (saa7164_boards[dev->board].porte == SAA7164_MPEG_VBI) | ||
1460 | saa7164_vbi_unregister(&dev->ports[SAA7164_PORT_VBI1]); | ||
1461 | |||
1462 | if (saa7164_boards[dev->board].portf == SAA7164_MPEG_VBI) | ||
1463 | saa7164_vbi_unregister(&dev->ports[SAA7164_PORT_VBI2]); | ||
685 | 1464 | ||
686 | saa7164_i2c_unregister(&dev->i2c_bus[0]); | 1465 | saa7164_i2c_unregister(&dev->i2c_bus[0]); |
687 | saa7164_i2c_unregister(&dev->i2c_bus[1]); | 1466 | saa7164_i2c_unregister(&dev->i2c_bus[1]); |
@@ -727,11 +1506,18 @@ static struct pci_driver saa7164_pci_driver = { | |||
727 | static int __init saa7164_init(void) | 1506 | static int __init saa7164_init(void) |
728 | { | 1507 | { |
729 | printk(KERN_INFO "saa7164 driver loaded\n"); | 1508 | printk(KERN_INFO "saa7164 driver loaded\n"); |
1509 | |||
1510 | #ifdef CONFIG_PROC_FS | ||
1511 | saa7164_proc_create(); | ||
1512 | #endif | ||
730 | return pci_register_driver(&saa7164_pci_driver); | 1513 | return pci_register_driver(&saa7164_pci_driver); |
731 | } | 1514 | } |
732 | 1515 | ||
733 | static void __exit saa7164_fini(void) | 1516 | static void __exit saa7164_fini(void) |
734 | { | 1517 | { |
1518 | #ifdef CONFIG_PROC_FS | ||
1519 | remove_proc_entry("saa7164", NULL); | ||
1520 | #endif | ||
735 | pci_unregister_driver(&saa7164_pci_driver); | 1521 | pci_unregister_driver(&saa7164_pci_driver); |
736 | } | 1522 | } |
737 | 1523 | ||
diff --git a/drivers/media/video/saa7164/saa7164-dvb.c b/drivers/media/video/saa7164/saa7164-dvb.c index cf099c59b38e..b305a01b3bde 100644 --- a/drivers/media/video/saa7164/saa7164-dvb.c +++ b/drivers/media/video/saa7164/saa7164-dvb.c | |||
@@ -1,7 +1,7 @@ | |||
1 | /* | 1 | /* |
2 | * Driver for the NXP SAA7164 PCIe bridge | 2 | * Driver for the NXP SAA7164 PCIe bridge |
3 | * | 3 | * |
4 | * Copyright (c) 2009 Steven Toth <stoth@kernellabs.com> | 4 | * Copyright (c) 2010 Steven Toth <stoth@kernellabs.com> |
5 | * | 5 | * |
6 | * This program is free software; you can redistribute it and/or modify | 6 | * This program is free software; you can redistribute it and/or modify |
7 | * it under the terms of the GNU General Public License as published by | 7 | * it under the terms of the GNU General Public License as published by |
@@ -82,7 +82,7 @@ static struct s5h1411_config hauppauge_s5h1411_config = { | |||
82 | .mpeg_timing = S5H1411_MPEGTIMING_CONTINOUS_NONINVERTING_CLOCK, | 82 | .mpeg_timing = S5H1411_MPEGTIMING_CONTINOUS_NONINVERTING_CLOCK, |
83 | }; | 83 | }; |
84 | 84 | ||
85 | static int saa7164_dvb_stop_tsport(struct saa7164_tsport *port) | 85 | static int saa7164_dvb_stop_port(struct saa7164_port *port) |
86 | { | 86 | { |
87 | struct saa7164_dev *dev = port->dev; | 87 | struct saa7164_dev *dev = port->dev; |
88 | int ret; | 88 | int ret; |
@@ -100,7 +100,7 @@ static int saa7164_dvb_stop_tsport(struct saa7164_tsport *port) | |||
100 | return ret; | 100 | return ret; |
101 | } | 101 | } |
102 | 102 | ||
103 | static int saa7164_dvb_acquire_tsport(struct saa7164_tsport *port) | 103 | static int saa7164_dvb_acquire_port(struct saa7164_port *port) |
104 | { | 104 | { |
105 | struct saa7164_dev *dev = port->dev; | 105 | struct saa7164_dev *dev = port->dev; |
106 | int ret; | 106 | int ret; |
@@ -118,7 +118,7 @@ static int saa7164_dvb_acquire_tsport(struct saa7164_tsport *port) | |||
118 | return ret; | 118 | return ret; |
119 | } | 119 | } |
120 | 120 | ||
121 | static int saa7164_dvb_pause_tsport(struct saa7164_tsport *port) | 121 | static int saa7164_dvb_pause_port(struct saa7164_port *port) |
122 | { | 122 | { |
123 | struct saa7164_dev *dev = port->dev; | 123 | struct saa7164_dev *dev = port->dev; |
124 | int ret; | 124 | int ret; |
@@ -140,90 +140,38 @@ static int saa7164_dvb_pause_tsport(struct saa7164_tsport *port) | |||
140 | * the part through AVStream / KS Windows stages, forwards or backwards. | 140 | * the part through AVStream / KS Windows stages, forwards or backwards. |
141 | * States are: stopped, acquired (h/w), paused, started. | 141 | * States are: stopped, acquired (h/w), paused, started. |
142 | */ | 142 | */ |
143 | static int saa7164_dvb_stop_streaming(struct saa7164_tsport *port) | 143 | static int saa7164_dvb_stop_streaming(struct saa7164_port *port) |
144 | { | 144 | { |
145 | struct saa7164_dev *dev = port->dev; | 145 | struct saa7164_dev *dev = port->dev; |
146 | int ret; | ||
147 | |||
148 | dprintk(DBGLVL_DVB, "%s(port=%d)\n", __func__, port->nr); | ||
149 | |||
150 | ret = saa7164_dvb_pause_tsport(port); | ||
151 | ret = saa7164_dvb_acquire_tsport(port); | ||
152 | ret = saa7164_dvb_stop_tsport(port); | ||
153 | |||
154 | return ret; | ||
155 | } | ||
156 | |||
157 | static int saa7164_dvb_cfg_tsport(struct saa7164_tsport *port) | ||
158 | { | ||
159 | tmHWStreamParameters_t *params = &port->hw_streamingparams; | ||
160 | struct saa7164_dev *dev = port->dev; | ||
161 | struct saa7164_buffer *buf; | 146 | struct saa7164_buffer *buf; |
162 | struct list_head *c, *n; | 147 | struct list_head *p, *q; |
163 | int i = 0; | 148 | int ret; |
164 | 149 | ||
165 | dprintk(DBGLVL_DVB, "%s(port=%d)\n", __func__, port->nr); | 150 | dprintk(DBGLVL_DVB, "%s(port=%d)\n", __func__, port->nr); |
166 | 151 | ||
167 | saa7164_writel(port->pitch, params->pitch); | 152 | ret = saa7164_dvb_pause_port(port); |
168 | saa7164_writel(port->bufsize, params->pitch * params->numberoflines); | 153 | ret = saa7164_dvb_acquire_port(port); |
154 | ret = saa7164_dvb_stop_port(port); | ||
169 | 155 | ||
170 | dprintk(DBGLVL_DVB, " configured:\n"); | 156 | /* Mark the hardware buffers as free */ |
171 | dprintk(DBGLVL_DVB, " lmmio 0x%p\n", dev->lmmio); | ||
172 | dprintk(DBGLVL_DVB, " bufcounter 0x%x = 0x%x\n", port->bufcounter, | ||
173 | saa7164_readl(port->bufcounter)); | ||
174 | |||
175 | dprintk(DBGLVL_DVB, " pitch 0x%x = %d\n", port->pitch, | ||
176 | saa7164_readl(port->pitch)); | ||
177 | |||
178 | dprintk(DBGLVL_DVB, " bufsize 0x%x = %d\n", port->bufsize, | ||
179 | saa7164_readl(port->bufsize)); | ||
180 | |||
181 | dprintk(DBGLVL_DVB, " buffercount = %d\n", port->hwcfg.buffercount); | ||
182 | dprintk(DBGLVL_DVB, " bufoffset = 0x%x\n", port->bufoffset); | ||
183 | dprintk(DBGLVL_DVB, " bufptr32h = 0x%x\n", port->bufptr32h); | ||
184 | dprintk(DBGLVL_DVB, " bufptr32l = 0x%x\n", port->bufptr32l); | ||
185 | |||
186 | /* Poke the buffers and offsets into PCI space */ | ||
187 | mutex_lock(&port->dmaqueue_lock); | 157 | mutex_lock(&port->dmaqueue_lock); |
188 | list_for_each_safe(c, n, &port->dmaqueue.list) { | 158 | list_for_each_safe(p, q, &port->dmaqueue.list) { |
189 | buf = list_entry(c, struct saa7164_buffer, list); | 159 | buf = list_entry(p, struct saa7164_buffer, list); |
190 | 160 | buf->flags = SAA7164_BUFFER_FREE; | |
191 | /* TODO: Review this in light of 32v64 assignments */ | ||
192 | saa7164_writel(port->bufoffset + (sizeof(u32) * i), 0); | ||
193 | saa7164_writel(port->bufptr32h + ((sizeof(u32) * 2) * i), | ||
194 | buf->pt_dma); | ||
195 | saa7164_writel(port->bufptr32l + ((sizeof(u32) * 2) * i), 0); | ||
196 | |||
197 | dprintk(DBGLVL_DVB, | ||
198 | " buf[%d] offset 0x%llx (0x%x) " | ||
199 | "buf 0x%llx/%llx (0x%x/%x)\n", | ||
200 | i, | ||
201 | (u64)port->bufoffset + (i * sizeof(u32)), | ||
202 | saa7164_readl(port->bufoffset + (sizeof(u32) * i)), | ||
203 | (u64)port->bufptr32h + ((sizeof(u32) * 2) * i), | ||
204 | (u64)port->bufptr32l + ((sizeof(u32) * 2) * i), | ||
205 | saa7164_readl(port->bufptr32h + ((sizeof(u32) * i) | ||
206 | * 2)), | ||
207 | saa7164_readl(port->bufptr32l + ((sizeof(u32) * i) | ||
208 | * 2))); | ||
209 | |||
210 | if (i++ > port->hwcfg.buffercount) | ||
211 | BUG(); | ||
212 | |||
213 | } | 161 | } |
214 | mutex_unlock(&port->dmaqueue_lock); | 162 | mutex_unlock(&port->dmaqueue_lock); |
215 | 163 | ||
216 | return 0; | 164 | return ret; |
217 | } | 165 | } |
218 | 166 | ||
219 | static int saa7164_dvb_start_tsport(struct saa7164_tsport *port) | 167 | static int saa7164_dvb_start_port(struct saa7164_port *port) |
220 | { | 168 | { |
221 | struct saa7164_dev *dev = port->dev; | 169 | struct saa7164_dev *dev = port->dev; |
222 | int ret = 0, result; | 170 | int ret = 0, result; |
223 | 171 | ||
224 | dprintk(DBGLVL_DVB, "%s(port=%d)\n", __func__, port->nr); | 172 | dprintk(DBGLVL_DVB, "%s(port=%d)\n", __func__, port->nr); |
225 | 173 | ||
226 | saa7164_dvb_cfg_tsport(port); | 174 | saa7164_buffer_cfg_port(port); |
227 | 175 | ||
228 | /* Acquire the hardware */ | 176 | /* Acquire the hardware */ |
229 | result = saa7164_api_transition_port(port, SAA_DMASTATE_ACQUIRE); | 177 | result = saa7164_api_transition_port(port, SAA_DMASTATE_ACQUIRE); |
@@ -284,7 +232,7 @@ out: | |||
284 | static int saa7164_dvb_start_feed(struct dvb_demux_feed *feed) | 232 | static int saa7164_dvb_start_feed(struct dvb_demux_feed *feed) |
285 | { | 233 | { |
286 | struct dvb_demux *demux = feed->demux; | 234 | struct dvb_demux *demux = feed->demux; |
287 | struct saa7164_tsport *port = (struct saa7164_tsport *) demux->priv; | 235 | struct saa7164_port *port = (struct saa7164_port *) demux->priv; |
288 | struct saa7164_dvb *dvb = &port->dvb; | 236 | struct saa7164_dvb *dvb = &port->dvb; |
289 | struct saa7164_dev *dev = port->dev; | 237 | struct saa7164_dev *dev = port->dev; |
290 | int ret = 0; | 238 | int ret = 0; |
@@ -298,7 +246,7 @@ static int saa7164_dvb_start_feed(struct dvb_demux_feed *feed) | |||
298 | mutex_lock(&dvb->lock); | 246 | mutex_lock(&dvb->lock); |
299 | if (dvb->feeding++ == 0) { | 247 | if (dvb->feeding++ == 0) { |
300 | /* Start transport */ | 248 | /* Start transport */ |
301 | ret = saa7164_dvb_start_tsport(port); | 249 | ret = saa7164_dvb_start_port(port); |
302 | } | 250 | } |
303 | mutex_unlock(&dvb->lock); | 251 | mutex_unlock(&dvb->lock); |
304 | dprintk(DBGLVL_DVB, "%s(port=%d) now feeding = %d\n", | 252 | dprintk(DBGLVL_DVB, "%s(port=%d) now feeding = %d\n", |
@@ -311,7 +259,7 @@ static int saa7164_dvb_start_feed(struct dvb_demux_feed *feed) | |||
311 | static int saa7164_dvb_stop_feed(struct dvb_demux_feed *feed) | 259 | static int saa7164_dvb_stop_feed(struct dvb_demux_feed *feed) |
312 | { | 260 | { |
313 | struct dvb_demux *demux = feed->demux; | 261 | struct dvb_demux *demux = feed->demux; |
314 | struct saa7164_tsport *port = (struct saa7164_tsport *) demux->priv; | 262 | struct saa7164_port *port = (struct saa7164_port *) demux->priv; |
315 | struct saa7164_dvb *dvb = &port->dvb; | 263 | struct saa7164_dvb *dvb = &port->dvb; |
316 | struct saa7164_dev *dev = port->dev; | 264 | struct saa7164_dev *dev = port->dev; |
317 | int ret = 0; | 265 | int ret = 0; |
@@ -332,7 +280,7 @@ static int saa7164_dvb_stop_feed(struct dvb_demux_feed *feed) | |||
332 | return ret; | 280 | return ret; |
333 | } | 281 | } |
334 | 282 | ||
335 | static int dvb_register(struct saa7164_tsport *port) | 283 | static int dvb_register(struct saa7164_port *port) |
336 | { | 284 | { |
337 | struct saa7164_dvb *dvb = &port->dvb; | 285 | struct saa7164_dvb *dvb = &port->dvb; |
338 | struct saa7164_dev *dev = port->dev; | 286 | struct saa7164_dev *dev = port->dev; |
@@ -341,6 +289,9 @@ static int dvb_register(struct saa7164_tsport *port) | |||
341 | 289 | ||
342 | dprintk(DBGLVL_DVB, "%s(port=%d)\n", __func__, port->nr); | 290 | dprintk(DBGLVL_DVB, "%s(port=%d)\n", __func__, port->nr); |
343 | 291 | ||
292 | if (port->type != SAA7164_MPEG_DVB) | ||
293 | BUG(); | ||
294 | |||
344 | /* Sanity check that the PCI configuration space is active */ | 295 | /* Sanity check that the PCI configuration space is active */ |
345 | if (port->hwcfg.BARLocation == 0) { | 296 | if (port->hwcfg.BARLocation == 0) { |
346 | result = -ENOMEM; | 297 | result = -ENOMEM; |
@@ -378,7 +329,6 @@ static int dvb_register(struct saa7164_tsport *port) | |||
378 | DRIVER_NAME, result); | 329 | DRIVER_NAME, result); |
379 | goto fail_adapter; | 330 | goto fail_adapter; |
380 | } | 331 | } |
381 | buf->nr = i; | ||
382 | 332 | ||
383 | mutex_lock(&port->dmaqueue_lock); | 333 | mutex_lock(&port->dmaqueue_lock); |
384 | list_add_tail(&buf->list, &port->dmaqueue.list); | 334 | list_add_tail(&buf->list, &port->dmaqueue.list); |
@@ -473,7 +423,7 @@ fail_adapter: | |||
473 | return result; | 423 | return result; |
474 | } | 424 | } |
475 | 425 | ||
476 | int saa7164_dvb_unregister(struct saa7164_tsport *port) | 426 | int saa7164_dvb_unregister(struct saa7164_port *port) |
477 | { | 427 | { |
478 | struct saa7164_dvb *dvb = &port->dvb; | 428 | struct saa7164_dvb *dvb = &port->dvb; |
479 | struct saa7164_dev *dev = port->dev; | 429 | struct saa7164_dev *dev = port->dev; |
@@ -482,12 +432,15 @@ int saa7164_dvb_unregister(struct saa7164_tsport *port) | |||
482 | 432 | ||
483 | dprintk(DBGLVL_DVB, "%s()\n", __func__); | 433 | dprintk(DBGLVL_DVB, "%s()\n", __func__); |
484 | 434 | ||
435 | if (port->type != SAA7164_MPEG_DVB) | ||
436 | BUG(); | ||
437 | |||
485 | /* Remove any allocated buffers */ | 438 | /* Remove any allocated buffers */ |
486 | mutex_lock(&port->dmaqueue_lock); | 439 | mutex_lock(&port->dmaqueue_lock); |
487 | list_for_each_safe(c, n, &port->dmaqueue.list) { | 440 | list_for_each_safe(c, n, &port->dmaqueue.list) { |
488 | b = list_entry(c, struct saa7164_buffer, list); | 441 | b = list_entry(c, struct saa7164_buffer, list); |
489 | list_del(c); | 442 | list_del(c); |
490 | saa7164_buffer_dealloc(port, b); | 443 | saa7164_buffer_dealloc(b); |
491 | } | 444 | } |
492 | mutex_unlock(&port->dmaqueue_lock); | 445 | mutex_unlock(&port->dmaqueue_lock); |
493 | 446 | ||
@@ -508,7 +461,7 @@ int saa7164_dvb_unregister(struct saa7164_tsport *port) | |||
508 | /* All the DVB attach calls go here, this function get's modified | 461 | /* All the DVB attach calls go here, this function get's modified |
509 | * for each new card. | 462 | * for each new card. |
510 | */ | 463 | */ |
511 | int saa7164_dvb_register(struct saa7164_tsport *port) | 464 | int saa7164_dvb_register(struct saa7164_port *port) |
512 | { | 465 | { |
513 | struct saa7164_dev *dev = port->dev; | 466 | struct saa7164_dev *dev = port->dev; |
514 | struct saa7164_dvb *dvb = &port->dvb; | 467 | struct saa7164_dvb *dvb = &port->dvb; |
@@ -588,8 +541,6 @@ int saa7164_dvb_register(struct saa7164_tsport *port) | |||
588 | return -1; | 541 | return -1; |
589 | } | 542 | } |
590 | 543 | ||
591 | /* Put the analog decoder in standby to keep it quiet */ | ||
592 | |||
593 | /* register everything */ | 544 | /* register everything */ |
594 | ret = dvb_register(port); | 545 | ret = dvb_register(port); |
595 | if (ret < 0) { | 546 | if (ret < 0) { |
diff --git a/drivers/media/video/saa7164/saa7164-encoder.c b/drivers/media/video/saa7164/saa7164-encoder.c new file mode 100644 index 000000000000..cbb53d0ee979 --- /dev/null +++ b/drivers/media/video/saa7164/saa7164-encoder.c | |||
@@ -0,0 +1,1503 @@ | |||
1 | /* | ||
2 | * Driver for the NXP SAA7164 PCIe bridge | ||
3 | * | ||
4 | * Copyright (c) 2010 Steven Toth <stoth@kernellabs.com> | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify | ||
7 | * it under the terms of the GNU General Public License as published by | ||
8 | * the Free Software Foundation; either version 2 of the License, or | ||
9 | * (at your option) any later version. | ||
10 | * | ||
11 | * This program is distributed in the hope that it will be useful, | ||
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
14 | * | ||
15 | * GNU General Public License for more details. | ||
16 | * | ||
17 | * You should have received a copy of the GNU General Public License | ||
18 | * along with this program; if not, write to the Free Software | ||
19 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
20 | */ | ||
21 | |||
22 | #include "saa7164.h" | ||
23 | |||
24 | #define ENCODER_MAX_BITRATE 6500000 | ||
25 | #define ENCODER_MIN_BITRATE 1000000 | ||
26 | #define ENCODER_DEF_BITRATE 5000000 | ||
27 | |||
28 | static struct saa7164_tvnorm saa7164_tvnorms[] = { | ||
29 | { | ||
30 | .name = "NTSC-M", | ||
31 | .id = V4L2_STD_NTSC_M, | ||
32 | }, { | ||
33 | .name = "NTSC-JP", | ||
34 | .id = V4L2_STD_NTSC_M_JP, | ||
35 | } | ||
36 | }; | ||
37 | |||
38 | static const u32 saa7164_v4l2_ctrls[] = { | ||
39 | V4L2_CID_BRIGHTNESS, | ||
40 | V4L2_CID_CONTRAST, | ||
41 | V4L2_CID_SATURATION, | ||
42 | V4L2_CID_HUE, | ||
43 | V4L2_CID_AUDIO_VOLUME, | ||
44 | V4L2_CID_SHARPNESS, | ||
45 | V4L2_CID_MPEG_STREAM_TYPE, | ||
46 | V4L2_CID_MPEG_VIDEO_ASPECT, | ||
47 | V4L2_CID_MPEG_VIDEO_B_FRAMES, | ||
48 | V4L2_CID_MPEG_VIDEO_GOP_SIZE, | ||
49 | V4L2_CID_MPEG_AUDIO_MUTE, | ||
50 | V4L2_CID_MPEG_VIDEO_BITRATE_MODE, | ||
51 | V4L2_CID_MPEG_VIDEO_BITRATE, | ||
52 | V4L2_CID_MPEG_VIDEO_BITRATE_PEAK, | ||
53 | 0 | ||
54 | }; | ||
55 | |||
56 | /* Take the encoder configuration form the port struct and | ||
57 | * flush it to the hardware. | ||
58 | */ | ||
59 | static void saa7164_encoder_configure(struct saa7164_port *port) | ||
60 | { | ||
61 | struct saa7164_dev *dev = port->dev; | ||
62 | dprintk(DBGLVL_ENC, "%s()\n", __func__); | ||
63 | |||
64 | port->encoder_params.width = port->width; | ||
65 | port->encoder_params.height = port->height; | ||
66 | port->encoder_params.is_50hz = | ||
67 | (port->encodernorm.id & V4L2_STD_625_50) != 0; | ||
68 | |||
69 | /* Set up the DIF (enable it) for analog mode by default */ | ||
70 | saa7164_api_initialize_dif(port); | ||
71 | |||
72 | /* Configure the correct video standard */ | ||
73 | saa7164_api_configure_dif(port, port->encodernorm.id); | ||
74 | |||
75 | /* Ensure the audio decoder is correct configured */ | ||
76 | saa7164_api_set_audio_std(port); | ||
77 | } | ||
78 | |||
79 | static int saa7164_encoder_buffers_dealloc(struct saa7164_port *port) | ||
80 | { | ||
81 | struct list_head *c, *n, *p, *q, *l, *v; | ||
82 | struct saa7164_dev *dev = port->dev; | ||
83 | struct saa7164_buffer *buf; | ||
84 | struct saa7164_user_buffer *ubuf; | ||
85 | |||
86 | /* Remove any allocated buffers */ | ||
87 | mutex_lock(&port->dmaqueue_lock); | ||
88 | |||
89 | dprintk(DBGLVL_ENC, "%s(port=%d) dmaqueue\n", __func__, port->nr); | ||
90 | list_for_each_safe(c, n, &port->dmaqueue.list) { | ||
91 | buf = list_entry(c, struct saa7164_buffer, list); | ||
92 | list_del(c); | ||
93 | saa7164_buffer_dealloc(buf); | ||
94 | } | ||
95 | |||
96 | dprintk(DBGLVL_ENC, "%s(port=%d) used\n", __func__, port->nr); | ||
97 | list_for_each_safe(p, q, &port->list_buf_used.list) { | ||
98 | ubuf = list_entry(p, struct saa7164_user_buffer, list); | ||
99 | list_del(p); | ||
100 | saa7164_buffer_dealloc_user(ubuf); | ||
101 | } | ||
102 | |||
103 | dprintk(DBGLVL_ENC, "%s(port=%d) free\n", __func__, port->nr); | ||
104 | list_for_each_safe(l, v, &port->list_buf_free.list) { | ||
105 | ubuf = list_entry(l, struct saa7164_user_buffer, list); | ||
106 | list_del(l); | ||
107 | saa7164_buffer_dealloc_user(ubuf); | ||
108 | } | ||
109 | |||
110 | mutex_unlock(&port->dmaqueue_lock); | ||
111 | dprintk(DBGLVL_ENC, "%s(port=%d) done\n", __func__, port->nr); | ||
112 | |||
113 | return 0; | ||
114 | } | ||
115 | |||
116 | /* Dynamic buffer switch at encoder start time */ | ||
117 | static int saa7164_encoder_buffers_alloc(struct saa7164_port *port) | ||
118 | { | ||
119 | struct saa7164_dev *dev = port->dev; | ||
120 | struct saa7164_buffer *buf; | ||
121 | struct saa7164_user_buffer *ubuf; | ||
122 | struct tmHWStreamParameters *params = &port->hw_streamingparams; | ||
123 | int result = -ENODEV, i; | ||
124 | int len = 0; | ||
125 | |||
126 | dprintk(DBGLVL_ENC, "%s()\n", __func__); | ||
127 | |||
128 | if (port->encoder_params.stream_type == V4L2_MPEG_STREAM_TYPE_MPEG2_PS) { | ||
129 | dprintk(DBGLVL_ENC, "%s() type=V4L2_MPEG_STREAM_TYPE_MPEG2_PS\n", __func__); | ||
130 | params->samplesperline = 128; | ||
131 | params->numberoflines = 256; | ||
132 | params->pitch = 128; | ||
133 | params->numpagetables = 2 + | ||
134 | ((SAA7164_PS_NUMBER_OF_LINES * 128) / PAGE_SIZE); | ||
135 | } else | ||
136 | if (port->encoder_params.stream_type == V4L2_MPEG_STREAM_TYPE_MPEG2_TS) { | ||
137 | dprintk(DBGLVL_ENC, "%s() type=V4L2_MPEG_STREAM_TYPE_MPEG2_TS\n", __func__); | ||
138 | params->samplesperline = 188; | ||
139 | params->numberoflines = 312; | ||
140 | params->pitch = 188; | ||
141 | params->numpagetables = 2 + | ||
142 | ((SAA7164_TS_NUMBER_OF_LINES * 188) / PAGE_SIZE); | ||
143 | } else | ||
144 | BUG(); | ||
145 | |||
146 | /* Init and establish defaults */ | ||
147 | params->bitspersample = 8; | ||
148 | params->linethreshold = 0; | ||
149 | params->pagetablelistvirt = 0; | ||
150 | params->pagetablelistphys = 0; | ||
151 | params->numpagetableentries = port->hwcfg.buffercount; | ||
152 | |||
153 | /* Allocate the PCI resources, buffers (hard) */ | ||
154 | for (i = 0; i < port->hwcfg.buffercount; i++) { | ||
155 | buf = saa7164_buffer_alloc(port, | ||
156 | params->numberoflines * | ||
157 | params->pitch); | ||
158 | |||
159 | if (!buf) { | ||
160 | printk(KERN_ERR "%s() failed " | ||
161 | "(errno = %d), unable to allocate buffer\n", | ||
162 | __func__, result); | ||
163 | result = -ENOMEM; | ||
164 | goto failed; | ||
165 | } else { | ||
166 | |||
167 | mutex_lock(&port->dmaqueue_lock); | ||
168 | list_add_tail(&buf->list, &port->dmaqueue.list); | ||
169 | mutex_unlock(&port->dmaqueue_lock); | ||
170 | |||
171 | } | ||
172 | } | ||
173 | |||
174 | /* Allocate some kenrel kernel buffers for copying | ||
175 | * to userpsace. | ||
176 | */ | ||
177 | len = params->numberoflines * params->pitch; | ||
178 | |||
179 | if (encoder_buffers < 16) | ||
180 | encoder_buffers = 16; | ||
181 | if (encoder_buffers > 512) | ||
182 | encoder_buffers = 512; | ||
183 | |||
184 | for (i = 0; i < encoder_buffers; i++) { | ||
185 | |||
186 | ubuf = saa7164_buffer_alloc_user(dev, len); | ||
187 | if (ubuf) { | ||
188 | mutex_lock(&port->dmaqueue_lock); | ||
189 | list_add_tail(&ubuf->list, &port->list_buf_free.list); | ||
190 | mutex_unlock(&port->dmaqueue_lock); | ||
191 | } | ||
192 | |||
193 | } | ||
194 | |||
195 | result = 0; | ||
196 | |||
197 | failed: | ||
198 | return result; | ||
199 | } | ||
200 | |||
201 | static int saa7164_encoder_initialize(struct saa7164_port *port) | ||
202 | { | ||
203 | saa7164_encoder_configure(port); | ||
204 | return 0; | ||
205 | } | ||
206 | |||
207 | /* -- V4L2 --------------------------------------------------------- */ | ||
208 | static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id *id) | ||
209 | { | ||
210 | struct saa7164_encoder_fh *fh = file->private_data; | ||
211 | struct saa7164_port *port = fh->port; | ||
212 | struct saa7164_dev *dev = port->dev; | ||
213 | unsigned int i; | ||
214 | |||
215 | dprintk(DBGLVL_ENC, "%s(id=0x%x)\n", __func__, (u32)*id); | ||
216 | |||
217 | for (i = 0; i < ARRAY_SIZE(saa7164_tvnorms); i++) { | ||
218 | if (*id & saa7164_tvnorms[i].id) | ||
219 | break; | ||
220 | } | ||
221 | if (i == ARRAY_SIZE(saa7164_tvnorms)) | ||
222 | return -EINVAL; | ||
223 | |||
224 | port->encodernorm = saa7164_tvnorms[i]; | ||
225 | |||
226 | /* Update the audio decoder while is not running in | ||
227 | * auto detect mode. | ||
228 | */ | ||
229 | saa7164_api_set_audio_std(port); | ||
230 | |||
231 | dprintk(DBGLVL_ENC, "%s(id=0x%x) OK\n", __func__, (u32)*id); | ||
232 | |||
233 | return 0; | ||
234 | } | ||
235 | |||
236 | static int vidioc_enum_input(struct file *file, void *priv, | ||
237 | struct v4l2_input *i) | ||
238 | { | ||
239 | int n; | ||
240 | |||
241 | char *inputs[] = { "tuner", "composite", "svideo", "aux", | ||
242 | "composite 2", "svideo 2", "aux 2" }; | ||
243 | |||
244 | if (i->index >= 7) | ||
245 | return -EINVAL; | ||
246 | |||
247 | strcpy(i->name, inputs[i->index]); | ||
248 | |||
249 | if (i->index == 0) | ||
250 | i->type = V4L2_INPUT_TYPE_TUNER; | ||
251 | else | ||
252 | i->type = V4L2_INPUT_TYPE_CAMERA; | ||
253 | |||
254 | for (n = 0; n < ARRAY_SIZE(saa7164_tvnorms); n++) | ||
255 | i->std |= saa7164_tvnorms[n].id; | ||
256 | |||
257 | return 0; | ||
258 | } | ||
259 | |||
260 | static int vidioc_g_input(struct file *file, void *priv, unsigned int *i) | ||
261 | { | ||
262 | struct saa7164_encoder_fh *fh = file->private_data; | ||
263 | struct saa7164_port *port = fh->port; | ||
264 | struct saa7164_dev *dev = port->dev; | ||
265 | |||
266 | if (saa7164_api_get_videomux(port) != SAA_OK) | ||
267 | return -EIO; | ||
268 | |||
269 | *i = (port->mux_input - 1); | ||
270 | |||
271 | dprintk(DBGLVL_ENC, "%s() input=%d\n", __func__, *i); | ||
272 | |||
273 | return 0; | ||
274 | } | ||
275 | |||
276 | static int vidioc_s_input(struct file *file, void *priv, unsigned int i) | ||
277 | { | ||
278 | struct saa7164_encoder_fh *fh = file->private_data; | ||
279 | struct saa7164_port *port = fh->port; | ||
280 | struct saa7164_dev *dev = port->dev; | ||
281 | |||
282 | dprintk(DBGLVL_ENC, "%s() input=%d\n", __func__, i); | ||
283 | |||
284 | if (i >= 7) | ||
285 | return -EINVAL; | ||
286 | |||
287 | port->mux_input = i + 1; | ||
288 | |||
289 | if (saa7164_api_set_videomux(port) != SAA_OK) | ||
290 | return -EIO; | ||
291 | |||
292 | return 0; | ||
293 | } | ||
294 | |||
295 | static int vidioc_g_tuner(struct file *file, void *priv, | ||
296 | struct v4l2_tuner *t) | ||
297 | { | ||
298 | struct saa7164_encoder_fh *fh = file->private_data; | ||
299 | struct saa7164_port *port = fh->port; | ||
300 | struct saa7164_dev *dev = port->dev; | ||
301 | |||
302 | if (0 != t->index) | ||
303 | return -EINVAL; | ||
304 | |||
305 | strcpy(t->name, "tuner"); | ||
306 | t->type = V4L2_TUNER_ANALOG_TV; | ||
307 | t->capability = V4L2_TUNER_CAP_NORM | V4L2_TUNER_CAP_STEREO; | ||
308 | |||
309 | dprintk(DBGLVL_ENC, "VIDIOC_G_TUNER: tuner type %d\n", t->type); | ||
310 | |||
311 | return 0; | ||
312 | } | ||
313 | |||
314 | static int vidioc_s_tuner(struct file *file, void *priv, | ||
315 | struct v4l2_tuner *t) | ||
316 | { | ||
317 | /* Update the A/V core */ | ||
318 | return 0; | ||
319 | } | ||
320 | |||
321 | static int vidioc_g_frequency(struct file *file, void *priv, | ||
322 | struct v4l2_frequency *f) | ||
323 | { | ||
324 | struct saa7164_encoder_fh *fh = file->private_data; | ||
325 | struct saa7164_port *port = fh->port; | ||
326 | |||
327 | f->type = V4L2_TUNER_ANALOG_TV; | ||
328 | f->frequency = port->freq; | ||
329 | |||
330 | return 0; | ||
331 | } | ||
332 | |||
333 | static int vidioc_s_frequency(struct file *file, void *priv, | ||
334 | struct v4l2_frequency *f) | ||
335 | { | ||
336 | struct saa7164_encoder_fh *fh = file->private_data; | ||
337 | struct saa7164_port *port = fh->port; | ||
338 | struct saa7164_dev *dev = port->dev; | ||
339 | struct saa7164_port *tsport; | ||
340 | struct dvb_frontend *fe; | ||
341 | |||
342 | /* TODO: Pull this for the std */ | ||
343 | struct analog_parameters params = { | ||
344 | .mode = V4L2_TUNER_ANALOG_TV, | ||
345 | .audmode = V4L2_TUNER_MODE_STEREO, | ||
346 | .std = port->encodernorm.id, | ||
347 | .frequency = f->frequency | ||
348 | }; | ||
349 | |||
350 | /* Stop the encoder */ | ||
351 | dprintk(DBGLVL_ENC, "%s() frequency=%d tuner=%d\n", __func__, | ||
352 | f->frequency, f->tuner); | ||
353 | |||
354 | if (f->tuner != 0) | ||
355 | return -EINVAL; | ||
356 | |||
357 | if (f->type != V4L2_TUNER_ANALOG_TV) | ||
358 | return -EINVAL; | ||
359 | |||
360 | port->freq = f->frequency; | ||
361 | |||
362 | /* Update the hardware */ | ||
363 | if (port->nr == SAA7164_PORT_ENC1) | ||
364 | tsport = &dev->ports[SAA7164_PORT_TS1]; | ||
365 | else | ||
366 | if (port->nr == SAA7164_PORT_ENC2) | ||
367 | tsport = &dev->ports[SAA7164_PORT_TS2]; | ||
368 | else | ||
369 | BUG(); | ||
370 | |||
371 | fe = tsport->dvb.frontend; | ||
372 | |||
373 | if (fe && fe->ops.tuner_ops.set_analog_params) | ||
374 | fe->ops.tuner_ops.set_analog_params(fe, ¶ms); | ||
375 | else | ||
376 | printk(KERN_ERR "%s() No analog tuner, aborting\n", __func__); | ||
377 | |||
378 | saa7164_encoder_initialize(port); | ||
379 | |||
380 | return 0; | ||
381 | } | ||
382 | |||
383 | static int vidioc_g_ctrl(struct file *file, void *priv, | ||
384 | struct v4l2_control *ctl) | ||
385 | { | ||
386 | struct saa7164_encoder_fh *fh = file->private_data; | ||
387 | struct saa7164_port *port = fh->port; | ||
388 | struct saa7164_dev *dev = port->dev; | ||
389 | |||
390 | dprintk(DBGLVL_ENC, "%s(id=%d, value=%d)\n", __func__, | ||
391 | ctl->id, ctl->value); | ||
392 | |||
393 | switch (ctl->id) { | ||
394 | case V4L2_CID_BRIGHTNESS: | ||
395 | ctl->value = port->ctl_brightness; | ||
396 | break; | ||
397 | case V4L2_CID_CONTRAST: | ||
398 | ctl->value = port->ctl_contrast; | ||
399 | break; | ||
400 | case V4L2_CID_SATURATION: | ||
401 | ctl->value = port->ctl_saturation; | ||
402 | break; | ||
403 | case V4L2_CID_HUE: | ||
404 | ctl->value = port->ctl_hue; | ||
405 | break; | ||
406 | case V4L2_CID_SHARPNESS: | ||
407 | ctl->value = port->ctl_sharpness; | ||
408 | break; | ||
409 | case V4L2_CID_AUDIO_VOLUME: | ||
410 | ctl->value = port->ctl_volume; | ||
411 | break; | ||
412 | default: | ||
413 | return -EINVAL; | ||
414 | } | ||
415 | |||
416 | return 0; | ||
417 | } | ||
418 | |||
419 | static int vidioc_s_ctrl(struct file *file, void *priv, | ||
420 | struct v4l2_control *ctl) | ||
421 | { | ||
422 | struct saa7164_encoder_fh *fh = file->private_data; | ||
423 | struct saa7164_port *port = fh->port; | ||
424 | struct saa7164_dev *dev = port->dev; | ||
425 | int ret = 0; | ||
426 | |||
427 | dprintk(DBGLVL_ENC, "%s(id=%d, value=%d)\n", __func__, | ||
428 | ctl->id, ctl->value); | ||
429 | |||
430 | switch (ctl->id) { | ||
431 | case V4L2_CID_BRIGHTNESS: | ||
432 | if ((ctl->value >= 0) && (ctl->value <= 255)) { | ||
433 | port->ctl_brightness = ctl->value; | ||
434 | saa7164_api_set_usercontrol(port, | ||
435 | PU_BRIGHTNESS_CONTROL); | ||
436 | } else | ||
437 | ret = -EINVAL; | ||
438 | break; | ||
439 | case V4L2_CID_CONTRAST: | ||
440 | if ((ctl->value >= 0) && (ctl->value <= 255)) { | ||
441 | port->ctl_contrast = ctl->value; | ||
442 | saa7164_api_set_usercontrol(port, PU_CONTRAST_CONTROL); | ||
443 | } else | ||
444 | ret = -EINVAL; | ||
445 | break; | ||
446 | case V4L2_CID_SATURATION: | ||
447 | if ((ctl->value >= 0) && (ctl->value <= 255)) { | ||
448 | port->ctl_saturation = ctl->value; | ||
449 | saa7164_api_set_usercontrol(port, | ||
450 | PU_SATURATION_CONTROL); | ||
451 | } else | ||
452 | ret = -EINVAL; | ||
453 | break; | ||
454 | case V4L2_CID_HUE: | ||
455 | if ((ctl->value >= 0) && (ctl->value <= 255)) { | ||
456 | port->ctl_hue = ctl->value; | ||
457 | saa7164_api_set_usercontrol(port, PU_HUE_CONTROL); | ||
458 | } else | ||
459 | ret = -EINVAL; | ||
460 | break; | ||
461 | case V4L2_CID_SHARPNESS: | ||
462 | if ((ctl->value >= 0) && (ctl->value <= 255)) { | ||
463 | port->ctl_sharpness = ctl->value; | ||
464 | saa7164_api_set_usercontrol(port, PU_SHARPNESS_CONTROL); | ||
465 | } else | ||
466 | ret = -EINVAL; | ||
467 | break; | ||
468 | case V4L2_CID_AUDIO_VOLUME: | ||
469 | if ((ctl->value >= -83) && (ctl->value <= 24)) { | ||
470 | port->ctl_volume = ctl->value; | ||
471 | saa7164_api_set_audio_volume(port, port->ctl_volume); | ||
472 | } else | ||
473 | ret = -EINVAL; | ||
474 | break; | ||
475 | default: | ||
476 | ret = -EINVAL; | ||
477 | } | ||
478 | |||
479 | return ret; | ||
480 | } | ||
481 | |||
482 | static int saa7164_get_ctrl(struct saa7164_port *port, | ||
483 | struct v4l2_ext_control *ctrl) | ||
484 | { | ||
485 | struct saa7164_encoder_params *params = &port->encoder_params; | ||
486 | |||
487 | switch (ctrl->id) { | ||
488 | case V4L2_CID_MPEG_VIDEO_BITRATE: | ||
489 | ctrl->value = params->bitrate; | ||
490 | break; | ||
491 | case V4L2_CID_MPEG_STREAM_TYPE: | ||
492 | ctrl->value = params->stream_type; | ||
493 | break; | ||
494 | case V4L2_CID_MPEG_AUDIO_MUTE: | ||
495 | ctrl->value = params->ctl_mute; | ||
496 | break; | ||
497 | case V4L2_CID_MPEG_VIDEO_ASPECT: | ||
498 | ctrl->value = params->ctl_aspect; | ||
499 | break; | ||
500 | case V4L2_CID_MPEG_VIDEO_BITRATE_MODE: | ||
501 | ctrl->value = params->bitrate_mode; | ||
502 | break; | ||
503 | case V4L2_CID_MPEG_VIDEO_B_FRAMES: | ||
504 | ctrl->value = params->refdist; | ||
505 | break; | ||
506 | case V4L2_CID_MPEG_VIDEO_BITRATE_PEAK: | ||
507 | ctrl->value = params->bitrate_peak; | ||
508 | break; | ||
509 | case V4L2_CID_MPEG_VIDEO_GOP_SIZE: | ||
510 | ctrl->value = params->gop_size; | ||
511 | break; | ||
512 | default: | ||
513 | return -EINVAL; | ||
514 | } | ||
515 | return 0; | ||
516 | } | ||
517 | |||
518 | static int vidioc_g_ext_ctrls(struct file *file, void *priv, | ||
519 | struct v4l2_ext_controls *ctrls) | ||
520 | { | ||
521 | struct saa7164_encoder_fh *fh = file->private_data; | ||
522 | struct saa7164_port *port = fh->port; | ||
523 | int i, err = 0; | ||
524 | |||
525 | if (ctrls->ctrl_class == V4L2_CTRL_CLASS_MPEG) { | ||
526 | for (i = 0; i < ctrls->count; i++) { | ||
527 | struct v4l2_ext_control *ctrl = ctrls->controls + i; | ||
528 | |||
529 | err = saa7164_get_ctrl(port, ctrl); | ||
530 | if (err) { | ||
531 | ctrls->error_idx = i; | ||
532 | break; | ||
533 | } | ||
534 | } | ||
535 | return err; | ||
536 | |||
537 | } | ||
538 | |||
539 | return -EINVAL; | ||
540 | } | ||
541 | |||
542 | static int saa7164_try_ctrl(struct v4l2_ext_control *ctrl, int ac3) | ||
543 | { | ||
544 | int ret = -EINVAL; | ||
545 | |||
546 | switch (ctrl->id) { | ||
547 | case V4L2_CID_MPEG_VIDEO_BITRATE: | ||
548 | if ((ctrl->value >= ENCODER_MIN_BITRATE) && | ||
549 | (ctrl->value <= ENCODER_MAX_BITRATE)) | ||
550 | ret = 0; | ||
551 | break; | ||
552 | case V4L2_CID_MPEG_STREAM_TYPE: | ||
553 | if ((ctrl->value == V4L2_MPEG_STREAM_TYPE_MPEG2_PS) || | ||
554 | (ctrl->value == V4L2_MPEG_STREAM_TYPE_MPEG2_TS)) | ||
555 | ret = 0; | ||
556 | break; | ||
557 | case V4L2_CID_MPEG_AUDIO_MUTE: | ||
558 | if ((ctrl->value >= 0) && | ||
559 | (ctrl->value <= 1)) | ||
560 | ret = 0; | ||
561 | break; | ||
562 | case V4L2_CID_MPEG_VIDEO_ASPECT: | ||
563 | if ((ctrl->value >= V4L2_MPEG_VIDEO_ASPECT_1x1) && | ||
564 | (ctrl->value <= V4L2_MPEG_VIDEO_ASPECT_221x100)) | ||
565 | ret = 0; | ||
566 | break; | ||
567 | case V4L2_CID_MPEG_VIDEO_GOP_SIZE: | ||
568 | if ((ctrl->value >= 0) && | ||
569 | (ctrl->value <= 255)) | ||
570 | ret = 0; | ||
571 | break; | ||
572 | case V4L2_CID_MPEG_VIDEO_BITRATE_MODE: | ||
573 | if ((ctrl->value == V4L2_MPEG_VIDEO_BITRATE_MODE_VBR) || | ||
574 | (ctrl->value == V4L2_MPEG_VIDEO_BITRATE_MODE_CBR)) | ||
575 | ret = 0; | ||
576 | break; | ||
577 | case V4L2_CID_MPEG_VIDEO_B_FRAMES: | ||
578 | if ((ctrl->value >= 1) && | ||
579 | (ctrl->value <= 3)) | ||
580 | ret = 0; | ||
581 | break; | ||
582 | case V4L2_CID_MPEG_VIDEO_BITRATE_PEAK: | ||
583 | if ((ctrl->value >= ENCODER_MIN_BITRATE) && | ||
584 | (ctrl->value <= ENCODER_MAX_BITRATE)) | ||
585 | ret = 0; | ||
586 | break; | ||
587 | default: | ||
588 | ret = -EINVAL; | ||
589 | } | ||
590 | |||
591 | return ret; | ||
592 | } | ||
593 | |||
594 | static int vidioc_try_ext_ctrls(struct file *file, void *priv, | ||
595 | struct v4l2_ext_controls *ctrls) | ||
596 | { | ||
597 | int i, err = 0; | ||
598 | |||
599 | if (ctrls->ctrl_class == V4L2_CTRL_CLASS_MPEG) { | ||
600 | for (i = 0; i < ctrls->count; i++) { | ||
601 | struct v4l2_ext_control *ctrl = ctrls->controls + i; | ||
602 | |||
603 | err = saa7164_try_ctrl(ctrl, 0); | ||
604 | if (err) { | ||
605 | ctrls->error_idx = i; | ||
606 | break; | ||
607 | } | ||
608 | } | ||
609 | return err; | ||
610 | } | ||
611 | |||
612 | return -EINVAL; | ||
613 | } | ||
614 | |||
615 | static int saa7164_set_ctrl(struct saa7164_port *port, | ||
616 | struct v4l2_ext_control *ctrl) | ||
617 | { | ||
618 | struct saa7164_encoder_params *params = &port->encoder_params; | ||
619 | int ret = 0; | ||
620 | |||
621 | switch (ctrl->id) { | ||
622 | case V4L2_CID_MPEG_VIDEO_BITRATE: | ||
623 | params->bitrate = ctrl->value; | ||
624 | break; | ||
625 | case V4L2_CID_MPEG_STREAM_TYPE: | ||
626 | params->stream_type = ctrl->value; | ||
627 | break; | ||
628 | case V4L2_CID_MPEG_AUDIO_MUTE: | ||
629 | params->ctl_mute = ctrl->value; | ||
630 | ret = saa7164_api_audio_mute(port, params->ctl_mute); | ||
631 | if (ret != SAA_OK) { | ||
632 | printk(KERN_ERR "%s() error, ret = 0x%x\n", __func__, | ||
633 | ret); | ||
634 | ret = -EIO; | ||
635 | } | ||
636 | break; | ||
637 | case V4L2_CID_MPEG_VIDEO_ASPECT: | ||
638 | params->ctl_aspect = ctrl->value; | ||
639 | ret = saa7164_api_set_aspect_ratio(port); | ||
640 | if (ret != SAA_OK) { | ||
641 | printk(KERN_ERR "%s() error, ret = 0x%x\n", __func__, | ||
642 | ret); | ||
643 | ret = -EIO; | ||
644 | } | ||
645 | break; | ||
646 | case V4L2_CID_MPEG_VIDEO_BITRATE_MODE: | ||
647 | params->bitrate_mode = ctrl->value; | ||
648 | break; | ||
649 | case V4L2_CID_MPEG_VIDEO_B_FRAMES: | ||
650 | params->refdist = ctrl->value; | ||
651 | break; | ||
652 | case V4L2_CID_MPEG_VIDEO_BITRATE_PEAK: | ||
653 | params->bitrate_peak = ctrl->value; | ||
654 | break; | ||
655 | case V4L2_CID_MPEG_VIDEO_GOP_SIZE: | ||
656 | params->gop_size = ctrl->value; | ||
657 | break; | ||
658 | default: | ||
659 | return -EINVAL; | ||
660 | } | ||
661 | |||
662 | /* TODO: Update the hardware */ | ||
663 | |||
664 | return ret; | ||
665 | } | ||
666 | |||
667 | static int vidioc_s_ext_ctrls(struct file *file, void *priv, | ||
668 | struct v4l2_ext_controls *ctrls) | ||
669 | { | ||
670 | struct saa7164_encoder_fh *fh = file->private_data; | ||
671 | struct saa7164_port *port = fh->port; | ||
672 | int i, err = 0; | ||
673 | |||
674 | if (ctrls->ctrl_class == V4L2_CTRL_CLASS_MPEG) { | ||
675 | for (i = 0; i < ctrls->count; i++) { | ||
676 | struct v4l2_ext_control *ctrl = ctrls->controls + i; | ||
677 | |||
678 | err = saa7164_try_ctrl(ctrl, 0); | ||
679 | if (err) { | ||
680 | ctrls->error_idx = i; | ||
681 | break; | ||
682 | } | ||
683 | err = saa7164_set_ctrl(port, ctrl); | ||
684 | if (err) { | ||
685 | ctrls->error_idx = i; | ||
686 | break; | ||
687 | } | ||
688 | } | ||
689 | return err; | ||
690 | |||
691 | } | ||
692 | |||
693 | return -EINVAL; | ||
694 | } | ||
695 | |||
696 | static int vidioc_querycap(struct file *file, void *priv, | ||
697 | struct v4l2_capability *cap) | ||
698 | { | ||
699 | struct saa7164_encoder_fh *fh = file->private_data; | ||
700 | struct saa7164_port *port = fh->port; | ||
701 | struct saa7164_dev *dev = port->dev; | ||
702 | |||
703 | strcpy(cap->driver, dev->name); | ||
704 | strlcpy(cap->card, saa7164_boards[dev->board].name, | ||
705 | sizeof(cap->card)); | ||
706 | sprintf(cap->bus_info, "PCI:%s", pci_name(dev->pci)); | ||
707 | |||
708 | cap->capabilities = | ||
709 | V4L2_CAP_VIDEO_CAPTURE | | ||
710 | V4L2_CAP_READWRITE | | ||
711 | 0; | ||
712 | |||
713 | cap->capabilities |= V4L2_CAP_TUNER; | ||
714 | cap->version = 0; | ||
715 | |||
716 | return 0; | ||
717 | } | ||
718 | |||
719 | static int vidioc_enum_fmt_vid_cap(struct file *file, void *priv, | ||
720 | struct v4l2_fmtdesc *f) | ||
721 | { | ||
722 | if (f->index != 0) | ||
723 | return -EINVAL; | ||
724 | |||
725 | strlcpy(f->description, "MPEG", sizeof(f->description)); | ||
726 | f->pixelformat = V4L2_PIX_FMT_MPEG; | ||
727 | |||
728 | return 0; | ||
729 | } | ||
730 | |||
731 | static int vidioc_g_fmt_vid_cap(struct file *file, void *priv, | ||
732 | struct v4l2_format *f) | ||
733 | { | ||
734 | struct saa7164_encoder_fh *fh = file->private_data; | ||
735 | struct saa7164_port *port = fh->port; | ||
736 | struct saa7164_dev *dev = port->dev; | ||
737 | |||
738 | f->fmt.pix.pixelformat = V4L2_PIX_FMT_MPEG; | ||
739 | f->fmt.pix.bytesperline = 0; | ||
740 | f->fmt.pix.sizeimage = | ||
741 | port->ts_packet_size * port->ts_packet_count; | ||
742 | f->fmt.pix.colorspace = 0; | ||
743 | f->fmt.pix.width = port->width; | ||
744 | f->fmt.pix.height = port->height; | ||
745 | |||
746 | dprintk(DBGLVL_ENC, "VIDIOC_G_FMT: w: %d, h: %d\n", | ||
747 | port->width, port->height); | ||
748 | |||
749 | return 0; | ||
750 | } | ||
751 | |||
752 | static int vidioc_try_fmt_vid_cap(struct file *file, void *priv, | ||
753 | struct v4l2_format *f) | ||
754 | { | ||
755 | struct saa7164_encoder_fh *fh = file->private_data; | ||
756 | struct saa7164_port *port = fh->port; | ||
757 | struct saa7164_dev *dev = port->dev; | ||
758 | |||
759 | f->fmt.pix.pixelformat = V4L2_PIX_FMT_MPEG; | ||
760 | f->fmt.pix.bytesperline = 0; | ||
761 | f->fmt.pix.sizeimage = | ||
762 | port->ts_packet_size * port->ts_packet_count; | ||
763 | f->fmt.pix.colorspace = 0; | ||
764 | dprintk(DBGLVL_ENC, "VIDIOC_TRY_FMT: w: %d, h: %d\n", | ||
765 | port->width, port->height); | ||
766 | return 0; | ||
767 | } | ||
768 | |||
769 | static int vidioc_s_fmt_vid_cap(struct file *file, void *priv, | ||
770 | struct v4l2_format *f) | ||
771 | { | ||
772 | struct saa7164_encoder_fh *fh = file->private_data; | ||
773 | struct saa7164_port *port = fh->port; | ||
774 | struct saa7164_dev *dev = port->dev; | ||
775 | |||
776 | f->fmt.pix.pixelformat = V4L2_PIX_FMT_MPEG; | ||
777 | f->fmt.pix.bytesperline = 0; | ||
778 | f->fmt.pix.sizeimage = | ||
779 | port->ts_packet_size * port->ts_packet_count; | ||
780 | f->fmt.pix.colorspace = 0; | ||
781 | |||
782 | dprintk(DBGLVL_ENC, "VIDIOC_S_FMT: w: %d, h: %d, f: %d\n", | ||
783 | f->fmt.pix.width, f->fmt.pix.height, f->fmt.pix.field); | ||
784 | |||
785 | return 0; | ||
786 | } | ||
787 | |||
788 | static int vidioc_log_status(struct file *file, void *priv) | ||
789 | { | ||
790 | return 0; | ||
791 | } | ||
792 | |||
793 | static int fill_queryctrl(struct saa7164_encoder_params *params, | ||
794 | struct v4l2_queryctrl *c) | ||
795 | { | ||
796 | switch (c->id) { | ||
797 | case V4L2_CID_BRIGHTNESS: | ||
798 | return v4l2_ctrl_query_fill(c, 0x0, 0xff, 1, 127); | ||
799 | case V4L2_CID_CONTRAST: | ||
800 | return v4l2_ctrl_query_fill(c, 0x0, 0xff, 1, 66); | ||
801 | case V4L2_CID_SATURATION: | ||
802 | return v4l2_ctrl_query_fill(c, 0x0, 0xff, 1, 62); | ||
803 | case V4L2_CID_HUE: | ||
804 | return v4l2_ctrl_query_fill(c, 0x0, 0xff, 1, 128); | ||
805 | case V4L2_CID_SHARPNESS: | ||
806 | return v4l2_ctrl_query_fill(c, 0x0, 0x0f, 1, 8); | ||
807 | case V4L2_CID_MPEG_AUDIO_MUTE: | ||
808 | return v4l2_ctrl_query_fill(c, 0x0, 0x01, 1, 0); | ||
809 | case V4L2_CID_AUDIO_VOLUME: | ||
810 | return v4l2_ctrl_query_fill(c, -83, 24, 1, 20); | ||
811 | case V4L2_CID_MPEG_VIDEO_BITRATE: | ||
812 | return v4l2_ctrl_query_fill(c, | ||
813 | ENCODER_MIN_BITRATE, ENCODER_MAX_BITRATE, | ||
814 | 100000, ENCODER_DEF_BITRATE); | ||
815 | case V4L2_CID_MPEG_STREAM_TYPE: | ||
816 | return v4l2_ctrl_query_fill(c, | ||
817 | V4L2_MPEG_STREAM_TYPE_MPEG2_PS, | ||
818 | V4L2_MPEG_STREAM_TYPE_MPEG2_TS, | ||
819 | 1, V4L2_MPEG_STREAM_TYPE_MPEG2_PS); | ||
820 | case V4L2_CID_MPEG_VIDEO_ASPECT: | ||
821 | return v4l2_ctrl_query_fill(c, | ||
822 | V4L2_MPEG_VIDEO_ASPECT_1x1, | ||
823 | V4L2_MPEG_VIDEO_ASPECT_221x100, | ||
824 | 1, V4L2_MPEG_VIDEO_ASPECT_4x3); | ||
825 | case V4L2_CID_MPEG_VIDEO_GOP_SIZE: | ||
826 | return v4l2_ctrl_query_fill(c, 1, 255, 1, 15); | ||
827 | case V4L2_CID_MPEG_VIDEO_BITRATE_MODE: | ||
828 | return v4l2_ctrl_query_fill(c, | ||
829 | V4L2_MPEG_VIDEO_BITRATE_MODE_VBR, V4L2_MPEG_VIDEO_BITRATE_MODE_CBR, | ||
830 | 1, V4L2_MPEG_VIDEO_BITRATE_MODE_VBR); | ||
831 | case V4L2_CID_MPEG_VIDEO_B_FRAMES: | ||
832 | return v4l2_ctrl_query_fill(c, | ||
833 | 1, 3, 1, 1); | ||
834 | case V4L2_CID_MPEG_VIDEO_BITRATE_PEAK: | ||
835 | return v4l2_ctrl_query_fill(c, | ||
836 | ENCODER_MIN_BITRATE, ENCODER_MAX_BITRATE, | ||
837 | 100000, ENCODER_DEF_BITRATE); | ||
838 | default: | ||
839 | return -EINVAL; | ||
840 | } | ||
841 | } | ||
842 | |||
843 | static int vidioc_queryctrl(struct file *file, void *priv, | ||
844 | struct v4l2_queryctrl *c) | ||
845 | { | ||
846 | struct saa7164_encoder_fh *fh = priv; | ||
847 | struct saa7164_port *port = fh->port; | ||
848 | int i, next; | ||
849 | u32 id = c->id; | ||
850 | |||
851 | memset(c, 0, sizeof(*c)); | ||
852 | |||
853 | next = !!(id & V4L2_CTRL_FLAG_NEXT_CTRL); | ||
854 | c->id = id & ~V4L2_CTRL_FLAG_NEXT_CTRL; | ||
855 | |||
856 | for (i = 0; i < ARRAY_SIZE(saa7164_v4l2_ctrls); i++) { | ||
857 | if (next) { | ||
858 | if (c->id < saa7164_v4l2_ctrls[i]) | ||
859 | c->id = saa7164_v4l2_ctrls[i]; | ||
860 | else | ||
861 | continue; | ||
862 | } | ||
863 | |||
864 | if (c->id == saa7164_v4l2_ctrls[i]) | ||
865 | return fill_queryctrl(&port->encoder_params, c); | ||
866 | |||
867 | if (c->id < saa7164_v4l2_ctrls[i]) | ||
868 | break; | ||
869 | } | ||
870 | |||
871 | return -EINVAL; | ||
872 | } | ||
873 | |||
874 | static int saa7164_encoder_stop_port(struct saa7164_port *port) | ||
875 | { | ||
876 | struct saa7164_dev *dev = port->dev; | ||
877 | int ret; | ||
878 | |||
879 | ret = saa7164_api_transition_port(port, SAA_DMASTATE_STOP); | ||
880 | if ((ret != SAA_OK) && (ret != SAA_ERR_ALREADY_STOPPED)) { | ||
881 | printk(KERN_ERR "%s() stop transition failed, ret = 0x%x\n", | ||
882 | __func__, ret); | ||
883 | ret = -EIO; | ||
884 | } else { | ||
885 | dprintk(DBGLVL_ENC, "%s() Stopped\n", __func__); | ||
886 | ret = 0; | ||
887 | } | ||
888 | |||
889 | return ret; | ||
890 | } | ||
891 | |||
892 | static int saa7164_encoder_acquire_port(struct saa7164_port *port) | ||
893 | { | ||
894 | struct saa7164_dev *dev = port->dev; | ||
895 | int ret; | ||
896 | |||
897 | ret = saa7164_api_transition_port(port, SAA_DMASTATE_ACQUIRE); | ||
898 | if ((ret != SAA_OK) && (ret != SAA_ERR_ALREADY_STOPPED)) { | ||
899 | printk(KERN_ERR "%s() acquire transition failed, ret = 0x%x\n", | ||
900 | __func__, ret); | ||
901 | ret = -EIO; | ||
902 | } else { | ||
903 | dprintk(DBGLVL_ENC, "%s() Acquired\n", __func__); | ||
904 | ret = 0; | ||
905 | } | ||
906 | |||
907 | return ret; | ||
908 | } | ||
909 | |||
910 | static int saa7164_encoder_pause_port(struct saa7164_port *port) | ||
911 | { | ||
912 | struct saa7164_dev *dev = port->dev; | ||
913 | int ret; | ||
914 | |||
915 | ret = saa7164_api_transition_port(port, SAA_DMASTATE_PAUSE); | ||
916 | if ((ret != SAA_OK) && (ret != SAA_ERR_ALREADY_STOPPED)) { | ||
917 | printk(KERN_ERR "%s() pause transition failed, ret = 0x%x\n", | ||
918 | __func__, ret); | ||
919 | ret = -EIO; | ||
920 | } else { | ||
921 | dprintk(DBGLVL_ENC, "%s() Paused\n", __func__); | ||
922 | ret = 0; | ||
923 | } | ||
924 | |||
925 | return ret; | ||
926 | } | ||
927 | |||
928 | /* Firmware is very windows centric, meaning you have to transition | ||
929 | * the part through AVStream / KS Windows stages, forwards or backwards. | ||
930 | * States are: stopped, acquired (h/w), paused, started. | ||
931 | * We have to leave here will all of the soft buffers on the free list, | ||
932 | * else the cfg_post() func won't have soft buffers to correctly configure. | ||
933 | */ | ||
934 | static int saa7164_encoder_stop_streaming(struct saa7164_port *port) | ||
935 | { | ||
936 | struct saa7164_dev *dev = port->dev; | ||
937 | struct saa7164_buffer *buf; | ||
938 | struct saa7164_user_buffer *ubuf; | ||
939 | struct list_head *c, *n; | ||
940 | int ret; | ||
941 | |||
942 | dprintk(DBGLVL_ENC, "%s(port=%d)\n", __func__, port->nr); | ||
943 | |||
944 | ret = saa7164_encoder_pause_port(port); | ||
945 | ret = saa7164_encoder_acquire_port(port); | ||
946 | ret = saa7164_encoder_stop_port(port); | ||
947 | |||
948 | dprintk(DBGLVL_ENC, "%s(port=%d) Hardware stopped\n", __func__, | ||
949 | port->nr); | ||
950 | |||
951 | /* Reset the state of any allocated buffer resources */ | ||
952 | mutex_lock(&port->dmaqueue_lock); | ||
953 | |||
954 | /* Reset the hard and soft buffer state */ | ||
955 | list_for_each_safe(c, n, &port->dmaqueue.list) { | ||
956 | buf = list_entry(c, struct saa7164_buffer, list); | ||
957 | buf->flags = SAA7164_BUFFER_FREE; | ||
958 | buf->pos = 0; | ||
959 | } | ||
960 | |||
961 | list_for_each_safe(c, n, &port->list_buf_used.list) { | ||
962 | ubuf = list_entry(c, struct saa7164_user_buffer, list); | ||
963 | ubuf->pos = 0; | ||
964 | list_move_tail(&ubuf->list, &port->list_buf_free.list); | ||
965 | } | ||
966 | |||
967 | mutex_unlock(&port->dmaqueue_lock); | ||
968 | |||
969 | /* Free any allocated resources */ | ||
970 | saa7164_encoder_buffers_dealloc(port); | ||
971 | |||
972 | dprintk(DBGLVL_ENC, "%s(port=%d) Released\n", __func__, port->nr); | ||
973 | |||
974 | return ret; | ||
975 | } | ||
976 | |||
977 | static int saa7164_encoder_start_streaming(struct saa7164_port *port) | ||
978 | { | ||
979 | struct saa7164_dev *dev = port->dev; | ||
980 | int result, ret = 0; | ||
981 | |||
982 | dprintk(DBGLVL_ENC, "%s(port=%d)\n", __func__, port->nr); | ||
983 | |||
984 | port->done_first_interrupt = 0; | ||
985 | |||
986 | /* allocate all of the PCIe DMA buffer resources on the fly, | ||
987 | * allowing switching between TS and PS payloads without | ||
988 | * requiring a complete driver reload. | ||
989 | */ | ||
990 | saa7164_encoder_buffers_alloc(port); | ||
991 | |||
992 | /* Configure the encoder with any cache values */ | ||
993 | saa7164_api_set_encoder(port); | ||
994 | saa7164_api_get_encoder(port); | ||
995 | |||
996 | /* Place the empty buffers on the hardware */ | ||
997 | saa7164_buffer_cfg_port(port); | ||
998 | |||
999 | /* Acquire the hardware */ | ||
1000 | result = saa7164_api_transition_port(port, SAA_DMASTATE_ACQUIRE); | ||
1001 | if ((result != SAA_OK) && (result != SAA_ERR_ALREADY_STOPPED)) { | ||
1002 | printk(KERN_ERR "%s() acquire transition failed, res = 0x%x\n", | ||
1003 | __func__, result); | ||
1004 | |||
1005 | /* Stop the hardware, regardless */ | ||
1006 | result = saa7164_api_transition_port(port, SAA_DMASTATE_STOP); | ||
1007 | if ((result != SAA_OK) && (result != SAA_ERR_ALREADY_STOPPED)) { | ||
1008 | printk(KERN_ERR "%s() acquire/forced stop transition " | ||
1009 | "failed, res = 0x%x\n", __func__, result); | ||
1010 | } | ||
1011 | ret = -EIO; | ||
1012 | goto out; | ||
1013 | } else | ||
1014 | dprintk(DBGLVL_ENC, "%s() Acquired\n", __func__); | ||
1015 | |||
1016 | /* Pause the hardware */ | ||
1017 | result = saa7164_api_transition_port(port, SAA_DMASTATE_PAUSE); | ||
1018 | if ((result != SAA_OK) && (result != SAA_ERR_ALREADY_STOPPED)) { | ||
1019 | printk(KERN_ERR "%s() pause transition failed, res = 0x%x\n", | ||
1020 | __func__, result); | ||
1021 | |||
1022 | /* Stop the hardware, regardless */ | ||
1023 | result = saa7164_api_transition_port(port, SAA_DMASTATE_STOP); | ||
1024 | if ((result != SAA_OK) && (result != SAA_ERR_ALREADY_STOPPED)) { | ||
1025 | printk(KERN_ERR "%s() pause/forced stop transition " | ||
1026 | "failed, res = 0x%x\n", __func__, result); | ||
1027 | } | ||
1028 | |||
1029 | ret = -EIO; | ||
1030 | goto out; | ||
1031 | } else | ||
1032 | dprintk(DBGLVL_ENC, "%s() Paused\n", __func__); | ||
1033 | |||
1034 | /* Start the hardware */ | ||
1035 | result = saa7164_api_transition_port(port, SAA_DMASTATE_RUN); | ||
1036 | if ((result != SAA_OK) && (result != SAA_ERR_ALREADY_STOPPED)) { | ||
1037 | printk(KERN_ERR "%s() run transition failed, result = 0x%x\n", | ||
1038 | __func__, result); | ||
1039 | |||
1040 | /* Stop the hardware, regardless */ | ||
1041 | result = saa7164_api_transition_port(port, SAA_DMASTATE_STOP); | ||
1042 | if ((result != SAA_OK) && (result != SAA_ERR_ALREADY_STOPPED)) { | ||
1043 | printk(KERN_ERR "%s() run/forced stop transition " | ||
1044 | "failed, res = 0x%x\n", __func__, result); | ||
1045 | } | ||
1046 | |||
1047 | ret = -EIO; | ||
1048 | } else | ||
1049 | dprintk(DBGLVL_ENC, "%s() Running\n", __func__); | ||
1050 | |||
1051 | out: | ||
1052 | return ret; | ||
1053 | } | ||
1054 | |||
1055 | static int fops_open(struct file *file) | ||
1056 | { | ||
1057 | struct saa7164_dev *dev; | ||
1058 | struct saa7164_port *port; | ||
1059 | struct saa7164_encoder_fh *fh; | ||
1060 | |||
1061 | port = (struct saa7164_port *)video_get_drvdata(video_devdata(file)); | ||
1062 | if (!port) | ||
1063 | return -ENODEV; | ||
1064 | |||
1065 | dev = port->dev; | ||
1066 | |||
1067 | dprintk(DBGLVL_ENC, "%s()\n", __func__); | ||
1068 | |||
1069 | /* allocate + initialize per filehandle data */ | ||
1070 | fh = kzalloc(sizeof(*fh), GFP_KERNEL); | ||
1071 | if (NULL == fh) | ||
1072 | return -ENOMEM; | ||
1073 | |||
1074 | file->private_data = fh; | ||
1075 | fh->port = port; | ||
1076 | |||
1077 | return 0; | ||
1078 | } | ||
1079 | |||
1080 | static int fops_release(struct file *file) | ||
1081 | { | ||
1082 | struct saa7164_encoder_fh *fh = file->private_data; | ||
1083 | struct saa7164_port *port = fh->port; | ||
1084 | struct saa7164_dev *dev = port->dev; | ||
1085 | |||
1086 | dprintk(DBGLVL_ENC, "%s()\n", __func__); | ||
1087 | |||
1088 | /* Shut device down on last close */ | ||
1089 | if (atomic_cmpxchg(&fh->v4l_reading, 1, 0) == 1) { | ||
1090 | if (atomic_dec_return(&port->v4l_reader_count) == 0) { | ||
1091 | /* stop mpeg capture then cancel buffers */ | ||
1092 | saa7164_encoder_stop_streaming(port); | ||
1093 | } | ||
1094 | } | ||
1095 | |||
1096 | file->private_data = NULL; | ||
1097 | kfree(fh); | ||
1098 | |||
1099 | return 0; | ||
1100 | } | ||
1101 | |||
1102 | struct saa7164_user_buffer *saa7164_enc_next_buf(struct saa7164_port *port) | ||
1103 | { | ||
1104 | struct saa7164_user_buffer *ubuf = 0; | ||
1105 | struct saa7164_dev *dev = port->dev; | ||
1106 | u32 crc; | ||
1107 | |||
1108 | mutex_lock(&port->dmaqueue_lock); | ||
1109 | if (!list_empty(&port->list_buf_used.list)) { | ||
1110 | ubuf = list_first_entry(&port->list_buf_used.list, | ||
1111 | struct saa7164_user_buffer, list); | ||
1112 | |||
1113 | if (crc_checking) { | ||
1114 | crc = crc32(0, ubuf->data, ubuf->actual_size); | ||
1115 | if (crc != ubuf->crc) { | ||
1116 | printk(KERN_ERR "%s() ubuf %p crc became invalid, was 0x%x became 0x%x\n", __func__, | ||
1117 | ubuf, ubuf->crc, crc); | ||
1118 | } | ||
1119 | } | ||
1120 | |||
1121 | } | ||
1122 | mutex_unlock(&port->dmaqueue_lock); | ||
1123 | |||
1124 | dprintk(DBGLVL_ENC, "%s() returns %p\n", __func__, ubuf); | ||
1125 | |||
1126 | return ubuf; | ||
1127 | } | ||
1128 | |||
1129 | static ssize_t fops_read(struct file *file, char __user *buffer, | ||
1130 | size_t count, loff_t *pos) | ||
1131 | { | ||
1132 | struct saa7164_encoder_fh *fh = file->private_data; | ||
1133 | struct saa7164_port *port = fh->port; | ||
1134 | struct saa7164_user_buffer *ubuf = NULL; | ||
1135 | struct saa7164_dev *dev = port->dev; | ||
1136 | int ret = 0; | ||
1137 | int rem, cnt; | ||
1138 | u8 *p; | ||
1139 | |||
1140 | port->last_read_msecs_diff = port->last_read_msecs; | ||
1141 | port->last_read_msecs = jiffies_to_msecs(jiffies); | ||
1142 | port->last_read_msecs_diff = port->last_read_msecs - | ||
1143 | port->last_read_msecs_diff; | ||
1144 | |||
1145 | saa7164_histogram_update(&port->read_interval, | ||
1146 | port->last_read_msecs_diff); | ||
1147 | |||
1148 | if (*pos) { | ||
1149 | printk(KERN_ERR "%s() ESPIPE\n", __func__); | ||
1150 | return -ESPIPE; | ||
1151 | } | ||
1152 | |||
1153 | if (atomic_cmpxchg(&fh->v4l_reading, 0, 1) == 0) { | ||
1154 | if (atomic_inc_return(&port->v4l_reader_count) == 1) { | ||
1155 | |||
1156 | if (saa7164_encoder_initialize(port) < 0) { | ||
1157 | printk(KERN_ERR "%s() EINVAL\n", __func__); | ||
1158 | return -EINVAL; | ||
1159 | } | ||
1160 | |||
1161 | saa7164_encoder_start_streaming(port); | ||
1162 | msleep(200); | ||
1163 | } | ||
1164 | } | ||
1165 | |||
1166 | /* blocking wait for buffer */ | ||
1167 | if ((file->f_flags & O_NONBLOCK) == 0) { | ||
1168 | if (wait_event_interruptible(port->wait_read, | ||
1169 | saa7164_enc_next_buf(port))) { | ||
1170 | printk(KERN_ERR "%s() ERESTARTSYS\n", __func__); | ||
1171 | return -ERESTARTSYS; | ||
1172 | } | ||
1173 | } | ||
1174 | |||
1175 | /* Pull the first buffer from the used list */ | ||
1176 | ubuf = saa7164_enc_next_buf(port); | ||
1177 | |||
1178 | while ((count > 0) && ubuf) { | ||
1179 | |||
1180 | /* set remaining bytes to copy */ | ||
1181 | rem = ubuf->actual_size - ubuf->pos; | ||
1182 | cnt = rem > count ? count : rem; | ||
1183 | |||
1184 | p = ubuf->data + ubuf->pos; | ||
1185 | |||
1186 | dprintk(DBGLVL_ENC, | ||
1187 | "%s() count=%d cnt=%d rem=%d buf=%p buf->pos=%d\n", | ||
1188 | __func__, (int)count, cnt, rem, ubuf, ubuf->pos); | ||
1189 | |||
1190 | if (copy_to_user(buffer, p, cnt)) { | ||
1191 | printk(KERN_ERR "%s() copy_to_user failed\n", __func__); | ||
1192 | if (!ret) { | ||
1193 | printk(KERN_ERR "%s() EFAULT\n", __func__); | ||
1194 | ret = -EFAULT; | ||
1195 | } | ||
1196 | goto err; | ||
1197 | } | ||
1198 | |||
1199 | ubuf->pos += cnt; | ||
1200 | count -= cnt; | ||
1201 | buffer += cnt; | ||
1202 | ret += cnt; | ||
1203 | |||
1204 | if (ubuf->pos > ubuf->actual_size) { | ||
1205 | printk(KERN_ERR "read() pos > actual, huh?\n"); | ||
1206 | } | ||
1207 | |||
1208 | if (ubuf->pos == ubuf->actual_size) { | ||
1209 | |||
1210 | /* finished with current buffer, take next buffer */ | ||
1211 | |||
1212 | /* Requeue the buffer on the free list */ | ||
1213 | ubuf->pos = 0; | ||
1214 | |||
1215 | mutex_lock(&port->dmaqueue_lock); | ||
1216 | list_move_tail(&ubuf->list, &port->list_buf_free.list); | ||
1217 | mutex_unlock(&port->dmaqueue_lock); | ||
1218 | |||
1219 | /* Dequeue next */ | ||
1220 | if ((file->f_flags & O_NONBLOCK) == 0) { | ||
1221 | if (wait_event_interruptible(port->wait_read, | ||
1222 | saa7164_enc_next_buf(port))) { | ||
1223 | break; | ||
1224 | } | ||
1225 | } | ||
1226 | ubuf = saa7164_enc_next_buf(port); | ||
1227 | } | ||
1228 | } | ||
1229 | err: | ||
1230 | if (!ret && !ubuf) { | ||
1231 | ret = -EAGAIN; | ||
1232 | } | ||
1233 | |||
1234 | return ret; | ||
1235 | } | ||
1236 | |||
1237 | static unsigned int fops_poll(struct file *file, poll_table *wait) | ||
1238 | { | ||
1239 | struct saa7164_encoder_fh *fh = (struct saa7164_encoder_fh *)file->private_data; | ||
1240 | struct saa7164_port *port = fh->port; | ||
1241 | struct saa7164_user_buffer *ubuf; | ||
1242 | unsigned int mask = 0; | ||
1243 | |||
1244 | port->last_poll_msecs_diff = port->last_poll_msecs; | ||
1245 | port->last_poll_msecs = jiffies_to_msecs(jiffies); | ||
1246 | port->last_poll_msecs_diff = port->last_poll_msecs - | ||
1247 | port->last_poll_msecs_diff; | ||
1248 | |||
1249 | saa7164_histogram_update(&port->poll_interval, | ||
1250 | port->last_poll_msecs_diff); | ||
1251 | |||
1252 | if (!video_is_registered(port->v4l_device)) { | ||
1253 | return -EIO; | ||
1254 | } | ||
1255 | |||
1256 | if (atomic_cmpxchg(&fh->v4l_reading, 0, 1) == 0) { | ||
1257 | if (atomic_inc_return(&port->v4l_reader_count) == 1) { | ||
1258 | if (saa7164_encoder_initialize(port) < 0) | ||
1259 | return -EINVAL; | ||
1260 | saa7164_encoder_start_streaming(port); | ||
1261 | msleep(200); | ||
1262 | } | ||
1263 | } | ||
1264 | |||
1265 | /* blocking wait for buffer */ | ||
1266 | if ((file->f_flags & O_NONBLOCK) == 0) { | ||
1267 | if (wait_event_interruptible(port->wait_read, | ||
1268 | saa7164_enc_next_buf(port))) { | ||
1269 | return -ERESTARTSYS; | ||
1270 | } | ||
1271 | } | ||
1272 | |||
1273 | /* Pull the first buffer from the used list */ | ||
1274 | ubuf = list_first_entry(&port->list_buf_used.list, | ||
1275 | struct saa7164_user_buffer, list); | ||
1276 | |||
1277 | if (ubuf) | ||
1278 | mask |= POLLIN | POLLRDNORM; | ||
1279 | |||
1280 | return mask; | ||
1281 | } | ||
1282 | |||
1283 | static const struct v4l2_file_operations mpeg_fops = { | ||
1284 | .owner = THIS_MODULE, | ||
1285 | .open = fops_open, | ||
1286 | .release = fops_release, | ||
1287 | .read = fops_read, | ||
1288 | .poll = fops_poll, | ||
1289 | .unlocked_ioctl = video_ioctl2, | ||
1290 | }; | ||
1291 | |||
1292 | int saa7164_g_chip_ident(struct file *file, void *fh, | ||
1293 | struct v4l2_dbg_chip_ident *chip) | ||
1294 | { | ||
1295 | struct saa7164_port *port = ((struct saa7164_encoder_fh *)fh)->port; | ||
1296 | struct saa7164_dev *dev = port->dev; | ||
1297 | dprintk(DBGLVL_ENC, "%s()\n", __func__); | ||
1298 | |||
1299 | return 0; | ||
1300 | } | ||
1301 | |||
1302 | int saa7164_g_register(struct file *file, void *fh, | ||
1303 | struct v4l2_dbg_register *reg) | ||
1304 | { | ||
1305 | struct saa7164_port *port = ((struct saa7164_encoder_fh *)fh)->port; | ||
1306 | struct saa7164_dev *dev = port->dev; | ||
1307 | dprintk(DBGLVL_ENC, "%s()\n", __func__); | ||
1308 | |||
1309 | if (!capable(CAP_SYS_ADMIN)) | ||
1310 | return -EPERM; | ||
1311 | |||
1312 | return 0; | ||
1313 | } | ||
1314 | |||
1315 | int saa7164_s_register(struct file *file, void *fh, | ||
1316 | struct v4l2_dbg_register *reg) | ||
1317 | { | ||
1318 | struct saa7164_port *port = ((struct saa7164_encoder_fh *)fh)->port; | ||
1319 | struct saa7164_dev *dev = port->dev; | ||
1320 | dprintk(DBGLVL_ENC, "%s()\n", __func__); | ||
1321 | |||
1322 | if (!capable(CAP_SYS_ADMIN)) | ||
1323 | return -EPERM; | ||
1324 | |||
1325 | return 0; | ||
1326 | } | ||
1327 | |||
1328 | static const struct v4l2_ioctl_ops mpeg_ioctl_ops = { | ||
1329 | .vidioc_s_std = vidioc_s_std, | ||
1330 | .vidioc_enum_input = vidioc_enum_input, | ||
1331 | .vidioc_g_input = vidioc_g_input, | ||
1332 | .vidioc_s_input = vidioc_s_input, | ||
1333 | .vidioc_g_tuner = vidioc_g_tuner, | ||
1334 | .vidioc_s_tuner = vidioc_s_tuner, | ||
1335 | .vidioc_g_frequency = vidioc_g_frequency, | ||
1336 | .vidioc_s_frequency = vidioc_s_frequency, | ||
1337 | .vidioc_s_ctrl = vidioc_s_ctrl, | ||
1338 | .vidioc_g_ctrl = vidioc_g_ctrl, | ||
1339 | .vidioc_querycap = vidioc_querycap, | ||
1340 | .vidioc_enum_fmt_vid_cap = vidioc_enum_fmt_vid_cap, | ||
1341 | .vidioc_g_fmt_vid_cap = vidioc_g_fmt_vid_cap, | ||
1342 | .vidioc_try_fmt_vid_cap = vidioc_try_fmt_vid_cap, | ||
1343 | .vidioc_s_fmt_vid_cap = vidioc_s_fmt_vid_cap, | ||
1344 | .vidioc_g_ext_ctrls = vidioc_g_ext_ctrls, | ||
1345 | .vidioc_s_ext_ctrls = vidioc_s_ext_ctrls, | ||
1346 | .vidioc_try_ext_ctrls = vidioc_try_ext_ctrls, | ||
1347 | .vidioc_log_status = vidioc_log_status, | ||
1348 | .vidioc_queryctrl = vidioc_queryctrl, | ||
1349 | .vidioc_g_chip_ident = saa7164_g_chip_ident, | ||
1350 | #ifdef CONFIG_VIDEO_ADV_DEBUG | ||
1351 | .vidioc_g_register = saa7164_g_register, | ||
1352 | .vidioc_s_register = saa7164_s_register, | ||
1353 | #endif | ||
1354 | }; | ||
1355 | |||
1356 | static struct video_device saa7164_mpeg_template = { | ||
1357 | .name = "saa7164", | ||
1358 | .fops = &mpeg_fops, | ||
1359 | .ioctl_ops = &mpeg_ioctl_ops, | ||
1360 | .minor = -1, | ||
1361 | .tvnorms = SAA7164_NORMS, | ||
1362 | .current_norm = V4L2_STD_NTSC_M, | ||
1363 | }; | ||
1364 | |||
1365 | static struct video_device *saa7164_encoder_alloc( | ||
1366 | struct saa7164_port *port, | ||
1367 | struct pci_dev *pci, | ||
1368 | struct video_device *template, | ||
1369 | char *type) | ||
1370 | { | ||
1371 | struct video_device *vfd; | ||
1372 | struct saa7164_dev *dev = port->dev; | ||
1373 | |||
1374 | dprintk(DBGLVL_ENC, "%s()\n", __func__); | ||
1375 | |||
1376 | vfd = video_device_alloc(); | ||
1377 | if (NULL == vfd) | ||
1378 | return NULL; | ||
1379 | |||
1380 | *vfd = *template; | ||
1381 | snprintf(vfd->name, sizeof(vfd->name), "%s %s (%s)", dev->name, | ||
1382 | type, saa7164_boards[dev->board].name); | ||
1383 | |||
1384 | vfd->parent = &pci->dev; | ||
1385 | vfd->release = video_device_release; | ||
1386 | return vfd; | ||
1387 | } | ||
1388 | |||
1389 | int saa7164_encoder_register(struct saa7164_port *port) | ||
1390 | { | ||
1391 | struct saa7164_dev *dev = port->dev; | ||
1392 | int result = -ENODEV; | ||
1393 | |||
1394 | dprintk(DBGLVL_ENC, "%s()\n", __func__); | ||
1395 | |||
1396 | if (port->type != SAA7164_MPEG_ENCODER) | ||
1397 | BUG(); | ||
1398 | |||
1399 | /* Sanity check that the PCI configuration space is active */ | ||
1400 | if (port->hwcfg.BARLocation == 0) { | ||
1401 | printk(KERN_ERR "%s() failed " | ||
1402 | "(errno = %d), NO PCI configuration\n", | ||
1403 | __func__, result); | ||
1404 | result = -ENOMEM; | ||
1405 | goto failed; | ||
1406 | } | ||
1407 | |||
1408 | /* Establish encoder defaults here */ | ||
1409 | /* Set default TV standard */ | ||
1410 | port->encodernorm = saa7164_tvnorms[0]; | ||
1411 | port->width = 720; | ||
1412 | port->mux_input = 1; /* Composite */ | ||
1413 | port->video_format = EU_VIDEO_FORMAT_MPEG_2; | ||
1414 | port->audio_format = 0; | ||
1415 | port->video_resolution = 0; | ||
1416 | port->ctl_brightness = 127; | ||
1417 | port->ctl_contrast = 66; | ||
1418 | port->ctl_hue = 128; | ||
1419 | port->ctl_saturation = 62; | ||
1420 | port->ctl_sharpness = 8; | ||
1421 | port->encoder_params.bitrate = ENCODER_DEF_BITRATE; | ||
1422 | port->encoder_params.bitrate_peak = ENCODER_DEF_BITRATE; | ||
1423 | port->encoder_params.bitrate_mode = V4L2_MPEG_VIDEO_BITRATE_MODE_CBR; | ||
1424 | port->encoder_params.stream_type = V4L2_MPEG_STREAM_TYPE_MPEG2_PS; | ||
1425 | port->encoder_params.ctl_mute = 0; | ||
1426 | port->encoder_params.ctl_aspect = V4L2_MPEG_VIDEO_ASPECT_4x3; | ||
1427 | port->encoder_params.refdist = 1; | ||
1428 | port->encoder_params.gop_size = SAA7164_ENCODER_DEFAULT_GOP_SIZE; | ||
1429 | |||
1430 | if (port->encodernorm.id & V4L2_STD_525_60) | ||
1431 | port->height = 480; | ||
1432 | else | ||
1433 | port->height = 576; | ||
1434 | |||
1435 | /* Allocate and register the video device node */ | ||
1436 | port->v4l_device = saa7164_encoder_alloc(port, | ||
1437 | dev->pci, &saa7164_mpeg_template, "mpeg"); | ||
1438 | |||
1439 | if (port->v4l_device == NULL) { | ||
1440 | printk(KERN_INFO "%s: can't allocate mpeg device\n", | ||
1441 | dev->name); | ||
1442 | result = -ENOMEM; | ||
1443 | goto failed; | ||
1444 | } | ||
1445 | |||
1446 | video_set_drvdata(port->v4l_device, port); | ||
1447 | result = video_register_device(port->v4l_device, | ||
1448 | VFL_TYPE_GRABBER, -1); | ||
1449 | if (result < 0) { | ||
1450 | printk(KERN_INFO "%s: can't register mpeg device\n", | ||
1451 | dev->name); | ||
1452 | /* TODO: We're going to leak here if we don't dealloc | ||
1453 | The buffers above. The unreg function can't deal wit it. | ||
1454 | */ | ||
1455 | goto failed; | ||
1456 | } | ||
1457 | |||
1458 | printk(KERN_INFO "%s: registered device video%d [mpeg]\n", | ||
1459 | dev->name, port->v4l_device->num); | ||
1460 | |||
1461 | /* Configure the hardware defaults */ | ||
1462 | saa7164_api_set_videomux(port); | ||
1463 | saa7164_api_set_usercontrol(port, PU_BRIGHTNESS_CONTROL); | ||
1464 | saa7164_api_set_usercontrol(port, PU_CONTRAST_CONTROL); | ||
1465 | saa7164_api_set_usercontrol(port, PU_HUE_CONTROL); | ||
1466 | saa7164_api_set_usercontrol(port, PU_SATURATION_CONTROL); | ||
1467 | saa7164_api_set_usercontrol(port, PU_SHARPNESS_CONTROL); | ||
1468 | saa7164_api_audio_mute(port, 0); | ||
1469 | saa7164_api_set_audio_volume(port, 20); | ||
1470 | saa7164_api_set_aspect_ratio(port); | ||
1471 | |||
1472 | /* Disable audio standard detection, it's buggy */ | ||
1473 | saa7164_api_set_audio_detection(port, 0); | ||
1474 | |||
1475 | saa7164_api_set_encoder(port); | ||
1476 | saa7164_api_get_encoder(port); | ||
1477 | |||
1478 | result = 0; | ||
1479 | failed: | ||
1480 | return result; | ||
1481 | } | ||
1482 | |||
1483 | void saa7164_encoder_unregister(struct saa7164_port *port) | ||
1484 | { | ||
1485 | struct saa7164_dev *dev = port->dev; | ||
1486 | |||
1487 | dprintk(DBGLVL_ENC, "%s(port=%d)\n", __func__, port->nr); | ||
1488 | |||
1489 | if (port->type != SAA7164_MPEG_ENCODER) | ||
1490 | BUG(); | ||
1491 | |||
1492 | if (port->v4l_device) { | ||
1493 | if (port->v4l_device->minor != -1) | ||
1494 | video_unregister_device(port->v4l_device); | ||
1495 | else | ||
1496 | video_device_release(port->v4l_device); | ||
1497 | |||
1498 | port->v4l_device = NULL; | ||
1499 | } | ||
1500 | |||
1501 | dprintk(DBGLVL_ENC, "%s(port=%d) done\n", __func__, port->nr); | ||
1502 | } | ||
1503 | |||
diff --git a/drivers/media/video/saa7164/saa7164-fw.c b/drivers/media/video/saa7164/saa7164-fw.c index 270245d275ab..484533c32bb1 100644 --- a/drivers/media/video/saa7164/saa7164-fw.c +++ b/drivers/media/video/saa7164/saa7164-fw.c | |||
@@ -1,7 +1,7 @@ | |||
1 | /* | 1 | /* |
2 | * Driver for the NXP SAA7164 PCIe bridge | 2 | * Driver for the NXP SAA7164 PCIe bridge |
3 | * | 3 | * |
4 | * Copyright (c) 2009 Steven Toth <stoth@kernellabs.com> | 4 | * Copyright (c) 2010 Steven Toth <stoth@kernellabs.com> |
5 | * | 5 | * |
6 | * This program is free software; you can redistribute it and/or modify | 6 | * This program is free software; you can redistribute it and/or modify |
7 | * it under the terms of the GNU General Public License as published by | 7 | * it under the terms of the GNU General Public License as published by |
@@ -24,11 +24,11 @@ | |||
24 | 24 | ||
25 | #include "saa7164.h" | 25 | #include "saa7164.h" |
26 | 26 | ||
27 | #define SAA7164_REV2_FIRMWARE "v4l-saa7164-1.0.2.fw" | 27 | #define SAA7164_REV2_FIRMWARE "NXP7164-2010-03-10.1.fw" |
28 | #define SAA7164_REV2_FIRMWARE_SIZE 3978608 | 28 | #define SAA7164_REV2_FIRMWARE_SIZE 4019072 |
29 | 29 | ||
30 | #define SAA7164_REV3_FIRMWARE "v4l-saa7164-1.0.3.fw" | 30 | #define SAA7164_REV3_FIRMWARE "NXP7164-2010-03-10.1.fw" |
31 | #define SAA7164_REV3_FIRMWARE_SIZE 3978608 | 31 | #define SAA7164_REV3_FIRMWARE_SIZE 4019072 |
32 | 32 | ||
33 | struct fw_header { | 33 | struct fw_header { |
34 | u32 firmwaresize; | 34 | u32 firmwaresize; |
@@ -604,6 +604,7 @@ int saa7164_downloadfirmware(struct saa7164_dev *dev) | |||
604 | } | 604 | } |
605 | } | 605 | } |
606 | 606 | ||
607 | dev->firmwareloaded = 1; | ||
607 | ret = 0; | 608 | ret = 0; |
608 | 609 | ||
609 | out: | 610 | out: |
diff --git a/drivers/media/video/saa7164/saa7164-i2c.c b/drivers/media/video/saa7164/saa7164-i2c.c index e1ae9b01bf0f..b5167d33650a 100644 --- a/drivers/media/video/saa7164/saa7164-i2c.c +++ b/drivers/media/video/saa7164/saa7164-i2c.c | |||
@@ -1,7 +1,7 @@ | |||
1 | /* | 1 | /* |
2 | * Driver for the NXP SAA7164 PCIe bridge | 2 | * Driver for the NXP SAA7164 PCIe bridge |
3 | * | 3 | * |
4 | * Copyright (c) 2009 Steven Toth <stoth@kernellabs.com> | 4 | * Copyright (c) 2010 Steven Toth <stoth@kernellabs.com> |
5 | * | 5 | * |
6 | * This program is free software; you can redistribute it and/or modify | 6 | * This program is free software; you can redistribute it and/or modify |
7 | * it under the terms of the GNU General Public License as published by | 7 | * it under the terms of the GNU General Public License as published by |
diff --git a/drivers/media/video/saa7164/saa7164-reg.h b/drivers/media/video/saa7164/saa7164-reg.h index 06be4c13d5b1..2bbf81583d33 100644 --- a/drivers/media/video/saa7164/saa7164-reg.h +++ b/drivers/media/video/saa7164/saa7164-reg.h | |||
@@ -1,7 +1,7 @@ | |||
1 | /* | 1 | /* |
2 | * Driver for the NXP SAA7164 PCIe bridge | 2 | * Driver for the NXP SAA7164 PCIe bridge |
3 | * | 3 | * |
4 | * Copyright (c) 2009 Steven Toth <stoth@kernellabs.com> | 4 | * Copyright (c) 2010 Steven Toth <stoth@kernellabs.com> |
5 | * | 5 | * |
6 | * This program is free software; you can redistribute it and/or modify | 6 | * This program is free software; you can redistribute it and/or modify |
7 | * it under the terms of the GNU General Public License as published by | 7 | * it under the terms of the GNU General Public License as published by |
@@ -60,6 +60,7 @@ | |||
60 | #define GET_STRING_CONTROL 0x03 | 60 | #define GET_STRING_CONTROL 0x03 |
61 | #define GET_LANGUAGE_CONTROL 0x05 | 61 | #define GET_LANGUAGE_CONTROL 0x05 |
62 | #define SET_POWER_CONTROL 0x07 | 62 | #define SET_POWER_CONTROL 0x07 |
63 | #define GET_FW_STATUS_CONTROL 0x08 | ||
63 | #define GET_FW_VERSION_CONTROL 0x09 | 64 | #define GET_FW_VERSION_CONTROL 0x09 |
64 | #define SET_DEBUG_LEVEL_CONTROL 0x0B | 65 | #define SET_DEBUG_LEVEL_CONTROL 0x0B |
65 | #define GET_DEBUG_DATA_CONTROL 0x0C | 66 | #define GET_DEBUG_DATA_CONTROL 0x0C |
@@ -156,11 +157,63 @@ | |||
156 | #define EXU_INTERRUPT_CONTROL 0x03 | 157 | #define EXU_INTERRUPT_CONTROL 0x03 |
157 | 158 | ||
158 | /* State Transition and args */ | 159 | /* State Transition and args */ |
160 | #define SAA_PROBE_CONTROL 0x01 | ||
161 | #define SAA_COMMIT_CONTROL 0x02 | ||
159 | #define SAA_STATE_CONTROL 0x03 | 162 | #define SAA_STATE_CONTROL 0x03 |
160 | #define SAA_DMASTATE_STOP 0x00 | 163 | #define SAA_DMASTATE_STOP 0x00 |
161 | #define SAA_DMASTATE_ACQUIRE 0x01 | 164 | #define SAA_DMASTATE_ACQUIRE 0x01 |
162 | #define SAA_DMASTATE_PAUSE 0x02 | 165 | #define SAA_DMASTATE_PAUSE 0x02 |
163 | #define SAA_DMASTATE_RUN 0x03 | 166 | #define SAA_DMASTATE_RUN 0x03 |
164 | 167 | ||
165 | /* Hardware registers */ | 168 | /* A/V Mux Input Selector */ |
166 | 169 | #define SU_INPUT_SELECT_CONTROL 0x01 | |
170 | |||
171 | /* Encoder Profiles */ | ||
172 | #define EU_PROFILE_PS_DVD 0x06 | ||
173 | #define EU_PROFILE_TS_HQ 0x09 | ||
174 | #define EU_VIDEO_FORMAT_MPEG_2 0x02 | ||
175 | |||
176 | /* Tuner */ | ||
177 | #define TU_AUDIO_MODE_CONTROL 0x17 | ||
178 | |||
179 | /* Video Formats */ | ||
180 | #define TU_STANDARD_CONTROL 0x00 | ||
181 | #define TU_STANDARD_AUTO_CONTROL 0x01 | ||
182 | #define TU_STANDARD_NONE 0x00 | ||
183 | #define TU_STANDARD_NTSC_M 0x01 | ||
184 | #define TU_STANDARD_PAL_I 0x08 | ||
185 | #define TU_STANDARD_MANUAL 0x00 | ||
186 | #define TU_STANDARD_AUTO 0x01 | ||
187 | |||
188 | /* Video Controls */ | ||
189 | #define PU_BRIGHTNESS_CONTROL 0x02 | ||
190 | #define PU_CONTRAST_CONTROL 0x03 | ||
191 | #define PU_HUE_CONTROL 0x06 | ||
192 | #define PU_SATURATION_CONTROL 0x07 | ||
193 | #define PU_SHARPNESS_CONTROL 0x08 | ||
194 | |||
195 | /* Audio Controls */ | ||
196 | #define MUTE_CONTROL 0x01 | ||
197 | #define VOLUME_CONTROL 0x02 | ||
198 | #define AUDIO_DEFAULT_CONTROL 0x0D | ||
199 | |||
200 | /* Default Volume Levels */ | ||
201 | #define TMHW_LEV_ADJ_DECLEV_DEFAULT 0x00 | ||
202 | #define TMHW_LEV_ADJ_MONOLEV_DEFAULT 0x00 | ||
203 | #define TMHW_LEV_ADJ_NICLEV_DEFAULT 0x00 | ||
204 | #define TMHW_LEV_ADJ_SAPLEV_DEFAULT 0x00 | ||
205 | #define TMHW_LEV_ADJ_ADCLEV_DEFAULT 0x00 | ||
206 | |||
207 | /* Encoder Related Commands */ | ||
208 | #define EU_PROFILE_CONTROL 0x00 | ||
209 | #define EU_VIDEO_FORMAT_CONTROL 0x01 | ||
210 | #define EU_VIDEO_BIT_RATE_CONTROL 0x02 | ||
211 | #define EU_VIDEO_RESOLUTION_CONTROL 0x03 | ||
212 | #define EU_VIDEO_GOP_STRUCTURE_CONTROL 0x04 | ||
213 | #define EU_VIDEO_INPUT_ASPECT_CONTROL 0x0A | ||
214 | #define EU_AUDIO_FORMAT_CONTROL 0x0C | ||
215 | #define EU_AUDIO_BIT_RATE_CONTROL 0x0D | ||
216 | |||
217 | /* Firmware Debugging */ | ||
218 | #define SET_DEBUG_LEVEL_CONTROL 0x0B | ||
219 | #define GET_DEBUG_DATA_CONTROL 0x0C | ||
diff --git a/drivers/media/video/saa7164/saa7164-types.h b/drivers/media/video/saa7164/saa7164-types.h index 99093f23aae5..df1d2997fa6c 100644 --- a/drivers/media/video/saa7164/saa7164-types.h +++ b/drivers/media/video/saa7164/saa7164-types.h | |||
@@ -1,7 +1,7 @@ | |||
1 | /* | 1 | /* |
2 | * Driver for the NXP SAA7164 PCIe bridge | 2 | * Driver for the NXP SAA7164 PCIe bridge |
3 | * | 3 | * |
4 | * Copyright (c) 2009 Steven Toth <stoth@kernellabs.com> | 4 | * Copyright (c) 2010 Steven Toth <stoth@kernellabs.com> |
5 | * | 5 | * |
6 | * This program is free software; you can redistribute it and/or modify | 6 | * This program is free software; you can redistribute it and/or modify |
7 | * it under the terms of the GNU General Public License as published by | 7 | * it under the terms of the GNU General Public License as published by |
@@ -24,7 +24,7 @@ | |||
24 | /* Some structues are passed directly to/from the firmware and | 24 | /* Some structues are passed directly to/from the firmware and |
25 | * have strict alignment requirements. This is one of them. | 25 | * have strict alignment requirements. This is one of them. |
26 | */ | 26 | */ |
27 | typedef struct { | 27 | struct tmComResHWDescr { |
28 | u8 bLength; | 28 | u8 bLength; |
29 | u8 bDescriptorType; | 29 | u8 bDescriptorType; |
30 | u8 bDescriptorSubtype; | 30 | u8 bDescriptorSubtype; |
@@ -37,14 +37,14 @@ typedef struct { | |||
37 | u32 dwHostMemoryRegionSize; | 37 | u32 dwHostMemoryRegionSize; |
38 | u32 dwHostHibernatMemRegion; | 38 | u32 dwHostHibernatMemRegion; |
39 | u32 dwHostHibernatMemRegionSize; | 39 | u32 dwHostHibernatMemRegionSize; |
40 | } __attribute__((packed)) tmComResHWDescr_t; | 40 | } __attribute__((packed)); |
41 | 41 | ||
42 | /* This is DWORD aligned on windows but I can't find the right | 42 | /* This is DWORD aligned on windows but I can't find the right |
43 | * gcc syntax to match the binary data from the device. | 43 | * gcc syntax to match the binary data from the device. |
44 | * I've manually padded with Reserved[3] bytes to match the hardware, | 44 | * I've manually padded with Reserved[3] bytes to match the hardware, |
45 | * but this could break if GCC decies to pack in a different way. | 45 | * but this could break if GCC decies to pack in a different way. |
46 | */ | 46 | */ |
47 | typedef struct { | 47 | struct tmComResInterfaceDescr { |
48 | u8 bLength; | 48 | u8 bLength; |
49 | u8 bDescriptorType; | 49 | u8 bDescriptorType; |
50 | u8 bDescriptorSubtype; | 50 | u8 bDescriptorSubtype; |
@@ -56,52 +56,52 @@ typedef struct { | |||
56 | u8 bDebugInterruptId; | 56 | u8 bDebugInterruptId; |
57 | u8 BARLocation; | 57 | u8 BARLocation; |
58 | u8 Reserved[3]; | 58 | u8 Reserved[3]; |
59 | } tmComResInterfaceDescr_t; | 59 | }; |
60 | 60 | ||
61 | typedef struct { | 61 | struct tmComResBusDescr { |
62 | u64 CommandRing; | 62 | u64 CommandRing; |
63 | u64 ResponseRing; | 63 | u64 ResponseRing; |
64 | u32 CommandWrite; | 64 | u32 CommandWrite; |
65 | u32 CommandRead; | 65 | u32 CommandRead; |
66 | u32 ResponseWrite; | 66 | u32 ResponseWrite; |
67 | u32 ResponseRead; | 67 | u32 ResponseRead; |
68 | } tmComResBusDescr_t; | 68 | }; |
69 | 69 | ||
70 | typedef enum { | 70 | enum tmBusType { |
71 | NONE = 0, | 71 | NONE = 0, |
72 | TYPE_BUS_PCI = 1, | 72 | TYPE_BUS_PCI = 1, |
73 | TYPE_BUS_PCIe = 2, | 73 | TYPE_BUS_PCIe = 2, |
74 | TYPE_BUS_USB = 3, | 74 | TYPE_BUS_USB = 3, |
75 | TYPE_BUS_I2C = 4 | 75 | TYPE_BUS_I2C = 4 |
76 | } tmBusType_t; | 76 | }; |
77 | 77 | ||
78 | typedef struct { | 78 | struct tmComResBusInfo { |
79 | tmBusType_t Type; | 79 | enum tmBusType Type; |
80 | u16 m_wMaxReqSize; | 80 | u16 m_wMaxReqSize; |
81 | u8 *m_pdwSetRing; | 81 | u8 *m_pdwSetRing; |
82 | u32 m_dwSizeSetRing; | 82 | u32 m_dwSizeSetRing; |
83 | u8 *m_pdwGetRing; | 83 | u8 *m_pdwGetRing; |
84 | u32 m_dwSizeGetRing; | 84 | u32 m_dwSizeGetRing; |
85 | u32 *m_pdwSetWritePos; | 85 | u32 m_dwSetWritePos; |
86 | u32 *m_pdwSetReadPos; | 86 | u32 m_dwSetReadPos; |
87 | u32 *m_pdwGetWritePos; | 87 | u32 m_dwGetWritePos; |
88 | u32 *m_pdwGetReadPos; | 88 | u32 m_dwGetReadPos; |
89 | 89 | ||
90 | /* All access is protected */ | 90 | /* All access is protected */ |
91 | struct mutex lock; | 91 | struct mutex lock; |
92 | 92 | ||
93 | } tmComResBusInfo_t; | 93 | }; |
94 | 94 | ||
95 | typedef struct { | 95 | struct tmComResInfo { |
96 | u8 id; | 96 | u8 id; |
97 | u8 flags; | 97 | u8 flags; |
98 | u16 size; | 98 | u16 size; |
99 | u32 command; | 99 | u32 command; |
100 | u16 controlselector; | 100 | u16 controlselector; |
101 | u8 seqno; | 101 | u8 seqno; |
102 | } __attribute__((packed)) tmComResInfo_t; | 102 | } __attribute__((packed)); |
103 | 103 | ||
104 | typedef enum { | 104 | enum tmComResCmd { |
105 | SET_CUR = 0x01, | 105 | SET_CUR = 0x01, |
106 | GET_CUR = 0x81, | 106 | GET_CUR = 0x81, |
107 | GET_MIN = 0x82, | 107 | GET_MIN = 0x82, |
@@ -110,7 +110,7 @@ typedef enum { | |||
110 | GET_LEN = 0x85, | 110 | GET_LEN = 0x85, |
111 | GET_INFO = 0x86, | 111 | GET_INFO = 0x86, |
112 | GET_DEF = 0x87 | 112 | GET_DEF = 0x87 |
113 | } tmComResCmd_t; | 113 | }; |
114 | 114 | ||
115 | struct cmd { | 115 | struct cmd { |
116 | u8 seqno; | 116 | u8 seqno; |
@@ -121,20 +121,20 @@ struct cmd { | |||
121 | wait_queue_head_t wait; | 121 | wait_queue_head_t wait; |
122 | }; | 122 | }; |
123 | 123 | ||
124 | typedef struct { | 124 | struct tmDescriptor { |
125 | u32 pathid; | 125 | u32 pathid; |
126 | u32 size; | 126 | u32 size; |
127 | void *descriptor; | 127 | void *descriptor; |
128 | } tmDescriptor_t; | 128 | }; |
129 | 129 | ||
130 | typedef struct { | 130 | struct tmComResDescrHeader { |
131 | u8 len; | 131 | u8 len; |
132 | u8 type; | 132 | u8 type; |
133 | u8 subtype; | 133 | u8 subtype; |
134 | u8 unitid; | 134 | u8 unitid; |
135 | } __attribute__((packed)) tmComResDescrHeader_t; | 135 | } __attribute__((packed)); |
136 | 136 | ||
137 | typedef struct { | 137 | struct tmComResExtDevDescrHeader { |
138 | u8 len; | 138 | u8 len; |
139 | u8 type; | 139 | u8 type; |
140 | u8 subtype; | 140 | u8 subtype; |
@@ -144,22 +144,22 @@ typedef struct { | |||
144 | u32 numgpiopins; | 144 | u32 numgpiopins; |
145 | u8 numgpiogroups; | 145 | u8 numgpiogroups; |
146 | u8 controlsize; | 146 | u8 controlsize; |
147 | } __attribute__((packed)) tmComResExtDevDescrHeader_t; | 147 | } __attribute__((packed)); |
148 | 148 | ||
149 | typedef struct { | 149 | struct tmComResGPIO { |
150 | u32 pin; | 150 | u32 pin; |
151 | u8 state; | 151 | u8 state; |
152 | } __attribute__((packed)) tmComResGPIO_t; | 152 | } __attribute__((packed)); |
153 | 153 | ||
154 | typedef struct { | 154 | struct tmComResPathDescrHeader { |
155 | u8 len; | 155 | u8 len; |
156 | u8 type; | 156 | u8 type; |
157 | u8 subtype; | 157 | u8 subtype; |
158 | u8 pathid; | 158 | u8 pathid; |
159 | } __attribute__((packed)) tmComResPathDescrHeader_t; | 159 | } __attribute__((packed)); |
160 | 160 | ||
161 | /* terminaltype */ | 161 | /* terminaltype */ |
162 | typedef enum { | 162 | enum tmComResTermType { |
163 | ITT_ANTENNA = 0x0203, | 163 | ITT_ANTENNA = 0x0203, |
164 | LINE_CONNECTOR = 0x0603, | 164 | LINE_CONNECTOR = 0x0603, |
165 | SPDIF_CONNECTOR = 0x0605, | 165 | SPDIF_CONNECTOR = 0x0605, |
@@ -167,9 +167,9 @@ typedef enum { | |||
167 | SVIDEO_CONNECTOR = 0x0402, | 167 | SVIDEO_CONNECTOR = 0x0402, |
168 | COMPONENT_CONNECTOR = 0x0403, | 168 | COMPONENT_CONNECTOR = 0x0403, |
169 | STANDARD_DMA = 0xF101 | 169 | STANDARD_DMA = 0xF101 |
170 | } tmComResTermType_t; | 170 | }; |
171 | 171 | ||
172 | typedef struct { | 172 | struct tmComResAntTermDescrHeader { |
173 | u8 len; | 173 | u8 len; |
174 | u8 type; | 174 | u8 type; |
175 | u8 subtype; | 175 | u8 subtype; |
@@ -178,9 +178,9 @@ typedef struct { | |||
178 | u8 assocterminal; | 178 | u8 assocterminal; |
179 | u8 iterminal; | 179 | u8 iterminal; |
180 | u8 controlsize; | 180 | u8 controlsize; |
181 | } __attribute__((packed)) tmComResAntTermDescrHeader_t; | 181 | } __attribute__((packed)); |
182 | 182 | ||
183 | typedef struct { | 183 | struct tmComResTunerDescrHeader { |
184 | u8 len; | 184 | u8 len; |
185 | u8 type; | 185 | u8 type; |
186 | u8 subtype; | 186 | u8 subtype; |
@@ -190,9 +190,9 @@ typedef struct { | |||
190 | u32 tuningstandards; | 190 | u32 tuningstandards; |
191 | u8 controlsize; | 191 | u8 controlsize; |
192 | u32 controls; | 192 | u32 controls; |
193 | } __attribute__((packed)) tmComResTunerDescrHeader_t; | 193 | } __attribute__((packed)); |
194 | 194 | ||
195 | typedef enum { | 195 | enum tmBufferFlag { |
196 | /* the buffer does not contain any valid data */ | 196 | /* the buffer does not contain any valid data */ |
197 | TM_BUFFER_FLAG_EMPTY, | 197 | TM_BUFFER_FLAG_EMPTY, |
198 | 198 | ||
@@ -201,23 +201,23 @@ typedef enum { | |||
201 | 201 | ||
202 | /* the buffer is the dummy buffer - TODO??? */ | 202 | /* the buffer is the dummy buffer - TODO??? */ |
203 | TM_BUFFER_FLAG_DUMMY_BUFFER | 203 | TM_BUFFER_FLAG_DUMMY_BUFFER |
204 | } tmBufferFlag_t; | 204 | }; |
205 | 205 | ||
206 | typedef struct { | 206 | struct tmBuffer { |
207 | u64 *pagetablevirt; | 207 | u64 *pagetablevirt; |
208 | u64 pagetablephys; | 208 | u64 pagetablephys; |
209 | u16 offset; | 209 | u16 offset; |
210 | u8 *context; | 210 | u8 *context; |
211 | u64 timestamp; | 211 | u64 timestamp; |
212 | tmBufferFlag_t BufferFlag_t; | 212 | enum tmBufferFlag BufferFlag; |
213 | u32 lostbuffers; | 213 | u32 lostbuffers; |
214 | u32 validbuffers; | 214 | u32 validbuffers; |
215 | u64 *dummypagevirt; | 215 | u64 *dummypagevirt; |
216 | u64 dummypagephys; | 216 | u64 dummypagephys; |
217 | u64 *addressvirt; | 217 | u64 *addressvirt; |
218 | } tmBuffer_t; | 218 | }; |
219 | 219 | ||
220 | typedef struct { | 220 | struct tmHWStreamParameters { |
221 | u32 bitspersample; | 221 | u32 bitspersample; |
222 | u32 samplesperline; | 222 | u32 samplesperline; |
223 | u32 numberoflines; | 223 | u32 numberoflines; |
@@ -227,15 +227,15 @@ typedef struct { | |||
227 | u64 *pagetablelistphys; | 227 | u64 *pagetablelistphys; |
228 | u32 numpagetables; | 228 | u32 numpagetables; |
229 | u32 numpagetableentries; | 229 | u32 numpagetableentries; |
230 | } tmHWStreamParameters_t; | 230 | }; |
231 | 231 | ||
232 | typedef struct { | 232 | struct tmStreamParameters { |
233 | tmHWStreamParameters_t HWStreamParameters_t; | 233 | struct tmHWStreamParameters HWStreamParameters; |
234 | u64 qwDummyPageTablePhys; | 234 | u64 qwDummyPageTablePhys; |
235 | u64 *pDummyPageTableVirt; | 235 | u64 *pDummyPageTableVirt; |
236 | } tmStreamParameters_t; | 236 | }; |
237 | 237 | ||
238 | typedef struct { | 238 | struct tmComResDMATermDescrHeader { |
239 | u8 len; | 239 | u8 len; |
240 | u8 type; | 240 | u8 type; |
241 | u8 subtyle; | 241 | u8 subtyle; |
@@ -251,7 +251,7 @@ typedef struct { | |||
251 | u8 metadatasize; | 251 | u8 metadatasize; |
252 | u8 numformats; | 252 | u8 numformats; |
253 | u8 controlsize; | 253 | u8 controlsize; |
254 | } __attribute__((packed)) tmComResDMATermDescrHeader_t; | 254 | } __attribute__((packed)); |
255 | 255 | ||
256 | /* | 256 | /* |
257 | * | 257 | * |
@@ -274,7 +274,7 @@ typedef struct { | |||
274 | * Data is to be ignored by the application. | 274 | * Data is to be ignored by the application. |
275 | * | 275 | * |
276 | */ | 276 | */ |
277 | typedef struct { | 277 | struct tmComResTSFormatDescrHeader { |
278 | u8 len; | 278 | u8 len; |
279 | u8 type; | 279 | u8 type; |
280 | u8 subtype; | 280 | u8 subtype; |
@@ -283,5 +283,160 @@ typedef struct { | |||
283 | u8 bPacketLength; | 283 | u8 bPacketLength; |
284 | u8 bStrideLength; | 284 | u8 bStrideLength; |
285 | u8 guidStrideFormat[16]; | 285 | u8 guidStrideFormat[16]; |
286 | } __attribute__((packed)) tmComResTSFormatDescrHeader_t; | 286 | } __attribute__((packed)); |
287 | |||
288 | /* Encoder related structures */ | ||
289 | |||
290 | /* A/V Mux Selector */ | ||
291 | struct tmComResSelDescrHeader { | ||
292 | u8 len; | ||
293 | u8 type; | ||
294 | u8 subtype; | ||
295 | u8 unitid; | ||
296 | u8 nrinpins; | ||
297 | u8 sourceid; | ||
298 | } __attribute__((packed)); | ||
299 | |||
300 | /* A/V Audio processor definitions */ | ||
301 | struct tmComResProcDescrHeader { | ||
302 | u8 len; | ||
303 | u8 type; | ||
304 | u8 subtype; | ||
305 | u8 unitid; | ||
306 | u8 sourceid; | ||
307 | u16 wreserved; | ||
308 | u8 controlsize; | ||
309 | } __attribute__((packed)); | ||
310 | |||
311 | /* Video bitrate control message */ | ||
312 | #define EU_VIDEO_BIT_RATE_MODE_CONSTANT (0) | ||
313 | #define EU_VIDEO_BIT_RATE_MODE_VARIABLE_AVERAGE (1) | ||
314 | #define EU_VIDEO_BIT_RATE_MODE_VARIABLE_PEAK (2) | ||
315 | struct tmComResEncVideoBitRate { | ||
316 | u8 ucVideoBitRateMode; | ||
317 | u32 dwVideoBitRate; | ||
318 | u32 dwVideoBitRatePeak; | ||
319 | } __attribute__((packed)); | ||
320 | |||
321 | /* Video Encoder Aspect Ratio message */ | ||
322 | struct tmComResEncVideoInputAspectRatio { | ||
323 | u8 width; | ||
324 | u8 height; | ||
325 | } __attribute__((packed)); | ||
326 | |||
327 | /* Video Encoder GOP IBP message */ | ||
328 | /* 1. IPPPPPPPPPPPPPP */ | ||
329 | /* 2. IBPBPBPBPBPBPBP */ | ||
330 | /* 3. IBBPBBPBBPBBP */ | ||
331 | #define SAA7164_ENCODER_DEFAULT_GOP_DIST (1) | ||
332 | #define SAA7164_ENCODER_DEFAULT_GOP_SIZE (15) | ||
333 | struct tmComResEncVideoGopStructure { | ||
334 | u8 ucGOPSize; /* GOP Size 12, 15 */ | ||
335 | u8 ucRefFrameDist; /* Reference Frame Distance */ | ||
336 | } __attribute__((packed)); | ||
337 | |||
338 | /* Encoder processor definition */ | ||
339 | struct tmComResEncoderDescrHeader { | ||
340 | u8 len; | ||
341 | u8 type; | ||
342 | u8 subtype; | ||
343 | u8 unitid; | ||
344 | u8 vsourceid; | ||
345 | u8 asourceid; | ||
346 | u8 iunit; | ||
347 | u32 dwmControlCap; | ||
348 | u32 dwmProfileCap; | ||
349 | u32 dwmVidFormatCap; | ||
350 | u8 bmVidBitrateCap; | ||
351 | u16 wmVidResolutionsCap; | ||
352 | u16 wmVidFrmRateCap; | ||
353 | u32 dwmAudFormatCap; | ||
354 | u8 bmAudBitrateCap; | ||
355 | } __attribute__((packed)); | ||
356 | |||
357 | /* Audio processor definition */ | ||
358 | struct tmComResAFeatureDescrHeader { | ||
359 | u8 len; | ||
360 | u8 type; | ||
361 | u8 subtype; | ||
362 | u8 unitid; | ||
363 | u8 sourceid; | ||
364 | u8 controlsize; | ||
365 | } __attribute__((packed)); | ||
366 | |||
367 | /* Audio control messages */ | ||
368 | struct tmComResAudioDefaults { | ||
369 | u8 ucDecoderLevel; | ||
370 | u8 ucDecoderFM_Level; | ||
371 | u8 ucMonoLevel; | ||
372 | u8 ucNICAM_Level; | ||
373 | u8 ucSAP_Level; | ||
374 | u8 ucADC_Level; | ||
375 | } __attribute__((packed)); | ||
376 | |||
377 | /* Audio bitrate control message */ | ||
378 | struct tmComResEncAudioBitRate { | ||
379 | u8 ucAudioBitRateMode; | ||
380 | u32 dwAudioBitRate; | ||
381 | u32 dwAudioBitRatePeak; | ||
382 | } __attribute__((packed)); | ||
383 | |||
384 | /* Tuner / AV Decoder messages */ | ||
385 | struct tmComResTunerStandard { | ||
386 | u8 std; | ||
387 | u32 country; | ||
388 | } __attribute__((packed)); | ||
389 | |||
390 | struct tmComResTunerStandardAuto { | ||
391 | u8 mode; | ||
392 | } __attribute__((packed)); | ||
393 | |||
394 | /* EEPROM definition for PS stream types */ | ||
395 | struct tmComResPSFormatDescrHeader { | ||
396 | u8 len; | ||
397 | u8 type; | ||
398 | u8 subtype; | ||
399 | u8 bFormatIndex; | ||
400 | u16 wPacketLength; | ||
401 | u16 wPackLength; | ||
402 | u8 bPackDataType; | ||
403 | } __attribute__((packed)); | ||
404 | |||
405 | /* VBI control structure */ | ||
406 | struct tmComResVBIFormatDescrHeader { | ||
407 | u8 len; | ||
408 | u8 type; | ||
409 | u8 subtype; /* VS_FORMAT_VBI */ | ||
410 | u8 bFormatIndex; | ||
411 | u32 VideoStandard; /* See KS_AnalogVideoStandard, NTSC = 1 */ | ||
412 | u8 StartLine; /* NTSC Start = 10 */ | ||
413 | u8 EndLine; /* NTSC = 21 */ | ||
414 | u8 FieldRate; /* 60 for NTSC */ | ||
415 | u8 bNumLines; /* Unsed - scheduled for removal */ | ||
416 | } __attribute__((packed)); | ||
417 | |||
418 | struct tmComResProbeCommit { | ||
419 | u16 bmHint; | ||
420 | u8 bFormatIndex; | ||
421 | u8 bFrameIndex; | ||
422 | } __attribute__((packed)); | ||
423 | |||
424 | struct tmComResDebugSetLevel { | ||
425 | u32 dwDebugLevel; | ||
426 | } __attribute__((packed)); | ||
427 | |||
428 | struct tmComResDebugGetData { | ||
429 | u32 dwResult; | ||
430 | u8 ucDebugData[256]; | ||
431 | } __attribute__((packed)); | ||
287 | 432 | ||
433 | struct tmFwInfoStruct { | ||
434 | u32 status; | ||
435 | u32 mode; | ||
436 | u32 devicespec; | ||
437 | u32 deviceinst; | ||
438 | u32 CPULoad; | ||
439 | u32 RemainHeap; | ||
440 | u32 CPUClock; | ||
441 | u32 RAMSpeed; | ||
442 | } __attribute__((packed)); | ||
diff --git a/drivers/media/video/saa7164/saa7164-vbi.c b/drivers/media/video/saa7164/saa7164-vbi.c new file mode 100644 index 000000000000..323c7cdca37b --- /dev/null +++ b/drivers/media/video/saa7164/saa7164-vbi.c | |||
@@ -0,0 +1,1375 @@ | |||
1 | /* | ||
2 | * Driver for the NXP SAA7164 PCIe bridge | ||
3 | * | ||
4 | * Copyright (c) 2010 Steven Toth <stoth@kernellabs.com> | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify | ||
7 | * it under the terms of the GNU General Public License as published by | ||
8 | * the Free Software Foundation; either version 2 of the License, or | ||
9 | * (at your option) any later version. | ||
10 | * | ||
11 | * This program is distributed in the hope that it will be useful, | ||
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
14 | * | ||
15 | * GNU General Public License for more details. | ||
16 | * | ||
17 | * You should have received a copy of the GNU General Public License | ||
18 | * along with this program; if not, write to the Free Software | ||
19 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
20 | */ | ||
21 | |||
22 | #include "saa7164.h" | ||
23 | |||
24 | static struct saa7164_tvnorm saa7164_tvnorms[] = { | ||
25 | { | ||
26 | .name = "NTSC-M", | ||
27 | .id = V4L2_STD_NTSC_M, | ||
28 | }, { | ||
29 | .name = "NTSC-JP", | ||
30 | .id = V4L2_STD_NTSC_M_JP, | ||
31 | } | ||
32 | }; | ||
33 | |||
34 | static const u32 saa7164_v4l2_ctrls[] = { | ||
35 | 0 | ||
36 | }; | ||
37 | |||
38 | /* Take the encoder configuration from the port struct and | ||
39 | * flush it to the hardware. | ||
40 | */ | ||
41 | static void saa7164_vbi_configure(struct saa7164_port *port) | ||
42 | { | ||
43 | struct saa7164_dev *dev = port->dev; | ||
44 | dprintk(DBGLVL_VBI, "%s()\n", __func__); | ||
45 | |||
46 | port->vbi_params.width = port->width; | ||
47 | port->vbi_params.height = port->height; | ||
48 | port->vbi_params.is_50hz = | ||
49 | (port->encodernorm.id & V4L2_STD_625_50) != 0; | ||
50 | |||
51 | /* Set up the DIF (enable it) for analog mode by default */ | ||
52 | saa7164_api_initialize_dif(port); | ||
53 | |||
54 | // /* Configure the correct video standard */ | ||
55 | // saa7164_api_configure_dif(port, port->encodernorm.id); | ||
56 | |||
57 | // /* Ensure the audio decoder is correct configured */ | ||
58 | // saa7164_api_set_audio_std(port); | ||
59 | dprintk(DBGLVL_VBI, "%s() ends\n", __func__); | ||
60 | } | ||
61 | |||
62 | static int saa7164_vbi_buffers_dealloc(struct saa7164_port *port) | ||
63 | { | ||
64 | struct list_head *c, *n, *p, *q, *l, *v; | ||
65 | struct saa7164_dev *dev = port->dev; | ||
66 | struct saa7164_buffer *buf; | ||
67 | struct saa7164_user_buffer *ubuf; | ||
68 | |||
69 | /* Remove any allocated buffers */ | ||
70 | mutex_lock(&port->dmaqueue_lock); | ||
71 | |||
72 | dprintk(DBGLVL_VBI, "%s(port=%d) dmaqueue\n", __func__, port->nr); | ||
73 | list_for_each_safe(c, n, &port->dmaqueue.list) { | ||
74 | buf = list_entry(c, struct saa7164_buffer, list); | ||
75 | list_del(c); | ||
76 | saa7164_buffer_dealloc(buf); | ||
77 | } | ||
78 | |||
79 | dprintk(DBGLVL_VBI, "%s(port=%d) used\n", __func__, port->nr); | ||
80 | list_for_each_safe(p, q, &port->list_buf_used.list) { | ||
81 | ubuf = list_entry(p, struct saa7164_user_buffer, list); | ||
82 | list_del(p); | ||
83 | saa7164_buffer_dealloc_user(ubuf); | ||
84 | } | ||
85 | |||
86 | dprintk(DBGLVL_VBI, "%s(port=%d) free\n", __func__, port->nr); | ||
87 | list_for_each_safe(l, v, &port->list_buf_free.list) { | ||
88 | ubuf = list_entry(l, struct saa7164_user_buffer, list); | ||
89 | list_del(l); | ||
90 | saa7164_buffer_dealloc_user(ubuf); | ||
91 | } | ||
92 | |||
93 | mutex_unlock(&port->dmaqueue_lock); | ||
94 | dprintk(DBGLVL_VBI, "%s(port=%d) done\n", __func__, port->nr); | ||
95 | |||
96 | return 0; | ||
97 | } | ||
98 | |||
99 | /* Dynamic buffer switch at vbi start time */ | ||
100 | static int saa7164_vbi_buffers_alloc(struct saa7164_port *port) | ||
101 | { | ||
102 | struct saa7164_dev *dev = port->dev; | ||
103 | struct saa7164_buffer *buf; | ||
104 | struct saa7164_user_buffer *ubuf; | ||
105 | struct tmHWStreamParameters *params = &port->hw_streamingparams; | ||
106 | int result = -ENODEV, i; | ||
107 | int len = 0; | ||
108 | |||
109 | dprintk(DBGLVL_VBI, "%s()\n", __func__); | ||
110 | |||
111 | /* TODO: NTSC SPECIFIC */ | ||
112 | /* Init and establish defaults */ | ||
113 | params->samplesperline = 1440; | ||
114 | params->numberoflines = 12; | ||
115 | params->numberoflines = 18; | ||
116 | params->pitch = 1600; | ||
117 | params->pitch = 1440; | ||
118 | params->numpagetables = 2 + | ||
119 | ((params->numberoflines * params->pitch) / PAGE_SIZE); | ||
120 | params->bitspersample = 8; | ||
121 | params->linethreshold = 0; | ||
122 | params->pagetablelistvirt = 0; | ||
123 | params->pagetablelistphys = 0; | ||
124 | params->numpagetableentries = port->hwcfg.buffercount; | ||
125 | |||
126 | /* Allocate the PCI resources, buffers (hard) */ | ||
127 | for (i = 0; i < port->hwcfg.buffercount; i++) { | ||
128 | buf = saa7164_buffer_alloc(port, | ||
129 | params->numberoflines * | ||
130 | params->pitch); | ||
131 | |||
132 | if (!buf) { | ||
133 | printk(KERN_ERR "%s() failed " | ||
134 | "(errno = %d), unable to allocate buffer\n", | ||
135 | __func__, result); | ||
136 | result = -ENOMEM; | ||
137 | goto failed; | ||
138 | } else { | ||
139 | |||
140 | mutex_lock(&port->dmaqueue_lock); | ||
141 | list_add_tail(&buf->list, &port->dmaqueue.list); | ||
142 | mutex_unlock(&port->dmaqueue_lock); | ||
143 | |||
144 | } | ||
145 | } | ||
146 | |||
147 | /* Allocate some kenrel kernel buffers for copying | ||
148 | * to userpsace. | ||
149 | */ | ||
150 | len = params->numberoflines * params->pitch; | ||
151 | |||
152 | if (vbi_buffers < 16) | ||
153 | vbi_buffers = 16; | ||
154 | if (vbi_buffers > 512) | ||
155 | vbi_buffers = 512; | ||
156 | |||
157 | for (i = 0; i < vbi_buffers; i++) { | ||
158 | |||
159 | ubuf = saa7164_buffer_alloc_user(dev, len); | ||
160 | if (ubuf) { | ||
161 | mutex_lock(&port->dmaqueue_lock); | ||
162 | list_add_tail(&ubuf->list, &port->list_buf_free.list); | ||
163 | mutex_unlock(&port->dmaqueue_lock); | ||
164 | } | ||
165 | |||
166 | } | ||
167 | |||
168 | result = 0; | ||
169 | |||
170 | failed: | ||
171 | return result; | ||
172 | } | ||
173 | |||
174 | |||
175 | static int saa7164_vbi_initialize(struct saa7164_port *port) | ||
176 | { | ||
177 | saa7164_vbi_configure(port); | ||
178 | return 0; | ||
179 | } | ||
180 | |||
181 | /* -- V4L2 --------------------------------------------------------- */ | ||
182 | static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id *id) | ||
183 | { | ||
184 | struct saa7164_vbi_fh *fh = file->private_data; | ||
185 | struct saa7164_port *port = fh->port; | ||
186 | struct saa7164_dev *dev = port->dev; | ||
187 | unsigned int i; | ||
188 | |||
189 | dprintk(DBGLVL_VBI, "%s(id=0x%x)\n", __func__, (u32)*id); | ||
190 | |||
191 | for (i = 0; i < ARRAY_SIZE(saa7164_tvnorms); i++) { | ||
192 | if (*id & saa7164_tvnorms[i].id) | ||
193 | break; | ||
194 | } | ||
195 | if (i == ARRAY_SIZE(saa7164_tvnorms)) | ||
196 | return -EINVAL; | ||
197 | |||
198 | port->encodernorm = saa7164_tvnorms[i]; | ||
199 | |||
200 | /* Update the audio decoder while is not running in | ||
201 | * auto detect mode. | ||
202 | */ | ||
203 | saa7164_api_set_audio_std(port); | ||
204 | |||
205 | dprintk(DBGLVL_VBI, "%s(id=0x%x) OK\n", __func__, (u32)*id); | ||
206 | |||
207 | return 0; | ||
208 | } | ||
209 | |||
210 | static int vidioc_enum_input(struct file *file, void *priv, | ||
211 | struct v4l2_input *i) | ||
212 | { | ||
213 | int n; | ||
214 | |||
215 | char *inputs[] = { "tuner", "composite", "svideo", "aux", | ||
216 | "composite 2", "svideo 2", "aux 2" }; | ||
217 | |||
218 | if (i->index >= 7) | ||
219 | return -EINVAL; | ||
220 | |||
221 | strcpy(i->name, inputs[i->index]); | ||
222 | |||
223 | if (i->index == 0) | ||
224 | i->type = V4L2_INPUT_TYPE_TUNER; | ||
225 | else | ||
226 | i->type = V4L2_INPUT_TYPE_CAMERA; | ||
227 | |||
228 | for (n = 0; n < ARRAY_SIZE(saa7164_tvnorms); n++) | ||
229 | i->std |= saa7164_tvnorms[n].id; | ||
230 | |||
231 | return 0; | ||
232 | } | ||
233 | |||
234 | static int vidioc_g_input(struct file *file, void *priv, unsigned int *i) | ||
235 | { | ||
236 | struct saa7164_vbi_fh *fh = file->private_data; | ||
237 | struct saa7164_port *port = fh->port; | ||
238 | struct saa7164_dev *dev = port->dev; | ||
239 | |||
240 | if (saa7164_api_get_videomux(port) != SAA_OK) | ||
241 | return -EIO; | ||
242 | |||
243 | *i = (port->mux_input - 1); | ||
244 | |||
245 | dprintk(DBGLVL_VBI, "%s() input=%d\n", __func__, *i); | ||
246 | |||
247 | return 0; | ||
248 | } | ||
249 | |||
250 | static int vidioc_s_input(struct file *file, void *priv, unsigned int i) | ||
251 | { | ||
252 | struct saa7164_vbi_fh *fh = file->private_data; | ||
253 | struct saa7164_port *port = fh->port; | ||
254 | struct saa7164_dev *dev = port->dev; | ||
255 | |||
256 | dprintk(DBGLVL_VBI, "%s() input=%d\n", __func__, i); | ||
257 | |||
258 | if (i >= 7) | ||
259 | return -EINVAL; | ||
260 | |||
261 | port->mux_input = i + 1; | ||
262 | |||
263 | if (saa7164_api_set_videomux(port) != SAA_OK) | ||
264 | return -EIO; | ||
265 | |||
266 | return 0; | ||
267 | } | ||
268 | |||
269 | static int vidioc_g_tuner(struct file *file, void *priv, | ||
270 | struct v4l2_tuner *t) | ||
271 | { | ||
272 | struct saa7164_vbi_fh *fh = file->private_data; | ||
273 | struct saa7164_port *port = fh->port; | ||
274 | struct saa7164_dev *dev = port->dev; | ||
275 | |||
276 | if (0 != t->index) | ||
277 | return -EINVAL; | ||
278 | |||
279 | strcpy(t->name, "tuner"); | ||
280 | t->type = V4L2_TUNER_ANALOG_TV; | ||
281 | t->capability = V4L2_TUNER_CAP_NORM | V4L2_TUNER_CAP_STEREO; | ||
282 | |||
283 | dprintk(DBGLVL_VBI, "VIDIOC_G_TUNER: tuner type %d\n", t->type); | ||
284 | |||
285 | return 0; | ||
286 | } | ||
287 | |||
288 | static int vidioc_s_tuner(struct file *file, void *priv, | ||
289 | struct v4l2_tuner *t) | ||
290 | { | ||
291 | /* Update the A/V core */ | ||
292 | return 0; | ||
293 | } | ||
294 | |||
295 | static int vidioc_g_frequency(struct file *file, void *priv, | ||
296 | struct v4l2_frequency *f) | ||
297 | { | ||
298 | struct saa7164_vbi_fh *fh = file->private_data; | ||
299 | struct saa7164_port *port = fh->port; | ||
300 | |||
301 | f->type = V4L2_TUNER_ANALOG_TV; | ||
302 | f->frequency = port->freq; | ||
303 | |||
304 | return 0; | ||
305 | } | ||
306 | |||
307 | static int vidioc_s_frequency(struct file *file, void *priv, | ||
308 | struct v4l2_frequency *f) | ||
309 | { | ||
310 | struct saa7164_vbi_fh *fh = file->private_data; | ||
311 | struct saa7164_port *port = fh->port; | ||
312 | struct saa7164_dev *dev = port->dev; | ||
313 | struct saa7164_port *tsport; | ||
314 | struct dvb_frontend *fe; | ||
315 | |||
316 | /* TODO: Pull this for the std */ | ||
317 | struct analog_parameters params = { | ||
318 | .mode = V4L2_TUNER_ANALOG_TV, | ||
319 | .audmode = V4L2_TUNER_MODE_STEREO, | ||
320 | .std = port->encodernorm.id, | ||
321 | .frequency = f->frequency | ||
322 | }; | ||
323 | |||
324 | /* Stop the encoder */ | ||
325 | dprintk(DBGLVL_VBI, "%s() frequency=%d tuner=%d\n", __func__, | ||
326 | f->frequency, f->tuner); | ||
327 | |||
328 | if (f->tuner != 0) | ||
329 | return -EINVAL; | ||
330 | |||
331 | if (f->type != V4L2_TUNER_ANALOG_TV) | ||
332 | return -EINVAL; | ||
333 | |||
334 | port->freq = f->frequency; | ||
335 | |||
336 | /* Update the hardware */ | ||
337 | if (port->nr == SAA7164_PORT_VBI1) | ||
338 | tsport = &dev->ports[SAA7164_PORT_TS1]; | ||
339 | else | ||
340 | if (port->nr == SAA7164_PORT_VBI2) | ||
341 | tsport = &dev->ports[SAA7164_PORT_TS2]; | ||
342 | else | ||
343 | BUG(); | ||
344 | |||
345 | fe = tsport->dvb.frontend; | ||
346 | |||
347 | if (fe && fe->ops.tuner_ops.set_analog_params) | ||
348 | fe->ops.tuner_ops.set_analog_params(fe, ¶ms); | ||
349 | else | ||
350 | printk(KERN_ERR "%s() No analog tuner, aborting\n", __func__); | ||
351 | |||
352 | saa7164_vbi_initialize(port); | ||
353 | |||
354 | return 0; | ||
355 | } | ||
356 | |||
357 | static int vidioc_g_ctrl(struct file *file, void *priv, | ||
358 | struct v4l2_control *ctl) | ||
359 | { | ||
360 | struct saa7164_vbi_fh *fh = file->private_data; | ||
361 | struct saa7164_port *port = fh->port; | ||
362 | struct saa7164_dev *dev = port->dev; | ||
363 | |||
364 | dprintk(DBGLVL_VBI, "%s(id=%d, value=%d)\n", __func__, | ||
365 | ctl->id, ctl->value); | ||
366 | |||
367 | switch (ctl->id) { | ||
368 | case V4L2_CID_BRIGHTNESS: | ||
369 | ctl->value = port->ctl_brightness; | ||
370 | break; | ||
371 | case V4L2_CID_CONTRAST: | ||
372 | ctl->value = port->ctl_contrast; | ||
373 | break; | ||
374 | case V4L2_CID_SATURATION: | ||
375 | ctl->value = port->ctl_saturation; | ||
376 | break; | ||
377 | case V4L2_CID_HUE: | ||
378 | ctl->value = port->ctl_hue; | ||
379 | break; | ||
380 | case V4L2_CID_SHARPNESS: | ||
381 | ctl->value = port->ctl_sharpness; | ||
382 | break; | ||
383 | case V4L2_CID_AUDIO_VOLUME: | ||
384 | ctl->value = port->ctl_volume; | ||
385 | break; | ||
386 | default: | ||
387 | return -EINVAL; | ||
388 | } | ||
389 | |||
390 | return 0; | ||
391 | } | ||
392 | |||
393 | static int vidioc_s_ctrl(struct file *file, void *priv, | ||
394 | struct v4l2_control *ctl) | ||
395 | { | ||
396 | struct saa7164_vbi_fh *fh = file->private_data; | ||
397 | struct saa7164_port *port = fh->port; | ||
398 | struct saa7164_dev *dev = port->dev; | ||
399 | int ret = 0; | ||
400 | |||
401 | dprintk(DBGLVL_VBI, "%s(id=%d, value=%d)\n", __func__, | ||
402 | ctl->id, ctl->value); | ||
403 | |||
404 | switch (ctl->id) { | ||
405 | case V4L2_CID_BRIGHTNESS: | ||
406 | if ((ctl->value >= 0) && (ctl->value <= 255)) { | ||
407 | port->ctl_brightness = ctl->value; | ||
408 | saa7164_api_set_usercontrol(port, | ||
409 | PU_BRIGHTNESS_CONTROL); | ||
410 | } else | ||
411 | ret = -EINVAL; | ||
412 | break; | ||
413 | case V4L2_CID_CONTRAST: | ||
414 | if ((ctl->value >= 0) && (ctl->value <= 255)) { | ||
415 | port->ctl_contrast = ctl->value; | ||
416 | saa7164_api_set_usercontrol(port, PU_CONTRAST_CONTROL); | ||
417 | } else | ||
418 | ret = -EINVAL; | ||
419 | break; | ||
420 | case V4L2_CID_SATURATION: | ||
421 | if ((ctl->value >= 0) && (ctl->value <= 255)) { | ||
422 | port->ctl_saturation = ctl->value; | ||
423 | saa7164_api_set_usercontrol(port, | ||
424 | PU_SATURATION_CONTROL); | ||
425 | } else | ||
426 | ret = -EINVAL; | ||
427 | break; | ||
428 | case V4L2_CID_HUE: | ||
429 | if ((ctl->value >= 0) && (ctl->value <= 255)) { | ||
430 | port->ctl_hue = ctl->value; | ||
431 | saa7164_api_set_usercontrol(port, PU_HUE_CONTROL); | ||
432 | } else | ||
433 | ret = -EINVAL; | ||
434 | break; | ||
435 | case V4L2_CID_SHARPNESS: | ||
436 | if ((ctl->value >= 0) && (ctl->value <= 255)) { | ||
437 | port->ctl_sharpness = ctl->value; | ||
438 | saa7164_api_set_usercontrol(port, PU_SHARPNESS_CONTROL); | ||
439 | } else | ||
440 | ret = -EINVAL; | ||
441 | break; | ||
442 | case V4L2_CID_AUDIO_VOLUME: | ||
443 | if ((ctl->value >= -83) && (ctl->value <= 24)) { | ||
444 | port->ctl_volume = ctl->value; | ||
445 | saa7164_api_set_audio_volume(port, port->ctl_volume); | ||
446 | } else | ||
447 | ret = -EINVAL; | ||
448 | break; | ||
449 | default: | ||
450 | ret = -EINVAL; | ||
451 | } | ||
452 | |||
453 | return ret; | ||
454 | } | ||
455 | |||
456 | static int saa7164_get_ctrl(struct saa7164_port *port, | ||
457 | struct v4l2_ext_control *ctrl) | ||
458 | { | ||
459 | struct saa7164_vbi_params *params = &port->vbi_params; | ||
460 | |||
461 | switch (ctrl->id) { | ||
462 | case V4L2_CID_MPEG_STREAM_TYPE: | ||
463 | ctrl->value = params->stream_type; | ||
464 | break; | ||
465 | case V4L2_CID_MPEG_AUDIO_MUTE: | ||
466 | ctrl->value = params->ctl_mute; | ||
467 | break; | ||
468 | case V4L2_CID_MPEG_VIDEO_ASPECT: | ||
469 | ctrl->value = params->ctl_aspect; | ||
470 | break; | ||
471 | case V4L2_CID_MPEG_VIDEO_B_FRAMES: | ||
472 | ctrl->value = params->refdist; | ||
473 | break; | ||
474 | case V4L2_CID_MPEG_VIDEO_GOP_SIZE: | ||
475 | ctrl->value = params->gop_size; | ||
476 | break; | ||
477 | default: | ||
478 | return -EINVAL; | ||
479 | } | ||
480 | return 0; | ||
481 | } | ||
482 | |||
483 | static int vidioc_g_ext_ctrls(struct file *file, void *priv, | ||
484 | struct v4l2_ext_controls *ctrls) | ||
485 | { | ||
486 | struct saa7164_vbi_fh *fh = file->private_data; | ||
487 | struct saa7164_port *port = fh->port; | ||
488 | int i, err = 0; | ||
489 | |||
490 | if (ctrls->ctrl_class == V4L2_CTRL_CLASS_MPEG) { | ||
491 | for (i = 0; i < ctrls->count; i++) { | ||
492 | struct v4l2_ext_control *ctrl = ctrls->controls + i; | ||
493 | |||
494 | err = saa7164_get_ctrl(port, ctrl); | ||
495 | if (err) { | ||
496 | ctrls->error_idx = i; | ||
497 | break; | ||
498 | } | ||
499 | } | ||
500 | return err; | ||
501 | |||
502 | } | ||
503 | |||
504 | return -EINVAL; | ||
505 | } | ||
506 | |||
507 | static int saa7164_try_ctrl(struct v4l2_ext_control *ctrl, int ac3) | ||
508 | { | ||
509 | int ret = -EINVAL; | ||
510 | |||
511 | switch (ctrl->id) { | ||
512 | case V4L2_CID_MPEG_STREAM_TYPE: | ||
513 | if ((ctrl->value == V4L2_MPEG_STREAM_TYPE_MPEG2_PS) || | ||
514 | (ctrl->value == V4L2_MPEG_STREAM_TYPE_MPEG2_TS)) | ||
515 | ret = 0; | ||
516 | break; | ||
517 | case V4L2_CID_MPEG_AUDIO_MUTE: | ||
518 | if ((ctrl->value >= 0) && | ||
519 | (ctrl->value <= 1)) | ||
520 | ret = 0; | ||
521 | break; | ||
522 | case V4L2_CID_MPEG_VIDEO_ASPECT: | ||
523 | if ((ctrl->value >= V4L2_MPEG_VIDEO_ASPECT_1x1) && | ||
524 | (ctrl->value <= V4L2_MPEG_VIDEO_ASPECT_221x100)) | ||
525 | ret = 0; | ||
526 | break; | ||
527 | case V4L2_CID_MPEG_VIDEO_GOP_SIZE: | ||
528 | if ((ctrl->value >= 0) && | ||
529 | (ctrl->value <= 255)) | ||
530 | ret = 0; | ||
531 | break; | ||
532 | case V4L2_CID_MPEG_VIDEO_B_FRAMES: | ||
533 | if ((ctrl->value >= 1) && | ||
534 | (ctrl->value <= 3)) | ||
535 | ret = 0; | ||
536 | break; | ||
537 | default: | ||
538 | ret = -EINVAL; | ||
539 | } | ||
540 | |||
541 | return ret; | ||
542 | } | ||
543 | |||
544 | static int vidioc_try_ext_ctrls(struct file *file, void *priv, | ||
545 | struct v4l2_ext_controls *ctrls) | ||
546 | { | ||
547 | int i, err = 0; | ||
548 | |||
549 | if (ctrls->ctrl_class == V4L2_CTRL_CLASS_MPEG) { | ||
550 | for (i = 0; i < ctrls->count; i++) { | ||
551 | struct v4l2_ext_control *ctrl = ctrls->controls + i; | ||
552 | |||
553 | err = saa7164_try_ctrl(ctrl, 0); | ||
554 | if (err) { | ||
555 | ctrls->error_idx = i; | ||
556 | break; | ||
557 | } | ||
558 | } | ||
559 | return err; | ||
560 | } | ||
561 | |||
562 | return -EINVAL; | ||
563 | } | ||
564 | |||
565 | static int saa7164_set_ctrl(struct saa7164_port *port, | ||
566 | struct v4l2_ext_control *ctrl) | ||
567 | { | ||
568 | struct saa7164_vbi_params *params = &port->vbi_params; | ||
569 | int ret = 0; | ||
570 | |||
571 | switch (ctrl->id) { | ||
572 | case V4L2_CID_MPEG_STREAM_TYPE: | ||
573 | params->stream_type = ctrl->value; | ||
574 | break; | ||
575 | case V4L2_CID_MPEG_AUDIO_MUTE: | ||
576 | params->ctl_mute = ctrl->value; | ||
577 | ret = saa7164_api_audio_mute(port, params->ctl_mute); | ||
578 | if (ret != SAA_OK) { | ||
579 | printk(KERN_ERR "%s() error, ret = 0x%x\n", __func__, | ||
580 | ret); | ||
581 | ret = -EIO; | ||
582 | } | ||
583 | break; | ||
584 | case V4L2_CID_MPEG_VIDEO_ASPECT: | ||
585 | params->ctl_aspect = ctrl->value; | ||
586 | ret = saa7164_api_set_aspect_ratio(port); | ||
587 | if (ret != SAA_OK) { | ||
588 | printk(KERN_ERR "%s() error, ret = 0x%x\n", __func__, | ||
589 | ret); | ||
590 | ret = -EIO; | ||
591 | } | ||
592 | break; | ||
593 | case V4L2_CID_MPEG_VIDEO_B_FRAMES: | ||
594 | params->refdist = ctrl->value; | ||
595 | break; | ||
596 | case V4L2_CID_MPEG_VIDEO_GOP_SIZE: | ||
597 | params->gop_size = ctrl->value; | ||
598 | break; | ||
599 | default: | ||
600 | return -EINVAL; | ||
601 | } | ||
602 | |||
603 | /* TODO: Update the hardware */ | ||
604 | |||
605 | return ret; | ||
606 | } | ||
607 | |||
608 | static int vidioc_s_ext_ctrls(struct file *file, void *priv, | ||
609 | struct v4l2_ext_controls *ctrls) | ||
610 | { | ||
611 | struct saa7164_vbi_fh *fh = file->private_data; | ||
612 | struct saa7164_port *port = fh->port; | ||
613 | int i, err = 0; | ||
614 | |||
615 | if (ctrls->ctrl_class == V4L2_CTRL_CLASS_MPEG) { | ||
616 | for (i = 0; i < ctrls->count; i++) { | ||
617 | struct v4l2_ext_control *ctrl = ctrls->controls + i; | ||
618 | |||
619 | err = saa7164_try_ctrl(ctrl, 0); | ||
620 | if (err) { | ||
621 | ctrls->error_idx = i; | ||
622 | break; | ||
623 | } | ||
624 | err = saa7164_set_ctrl(port, ctrl); | ||
625 | if (err) { | ||
626 | ctrls->error_idx = i; | ||
627 | break; | ||
628 | } | ||
629 | } | ||
630 | return err; | ||
631 | |||
632 | } | ||
633 | |||
634 | return -EINVAL; | ||
635 | } | ||
636 | |||
637 | static int vidioc_querycap(struct file *file, void *priv, | ||
638 | struct v4l2_capability *cap) | ||
639 | { | ||
640 | struct saa7164_vbi_fh *fh = file->private_data; | ||
641 | struct saa7164_port *port = fh->port; | ||
642 | struct saa7164_dev *dev = port->dev; | ||
643 | |||
644 | strcpy(cap->driver, dev->name); | ||
645 | strlcpy(cap->card, saa7164_boards[dev->board].name, | ||
646 | sizeof(cap->card)); | ||
647 | sprintf(cap->bus_info, "PCI:%s", pci_name(dev->pci)); | ||
648 | |||
649 | cap->capabilities = | ||
650 | V4L2_CAP_VBI_CAPTURE | | ||
651 | V4L2_CAP_READWRITE | | ||
652 | 0; | ||
653 | |||
654 | cap->capabilities |= V4L2_CAP_TUNER; | ||
655 | cap->version = 0; | ||
656 | |||
657 | return 0; | ||
658 | } | ||
659 | |||
660 | static int vidioc_enum_fmt_vid_cap(struct file *file, void *priv, | ||
661 | struct v4l2_fmtdesc *f) | ||
662 | { | ||
663 | if (f->index != 0) | ||
664 | return -EINVAL; | ||
665 | |||
666 | strlcpy(f->description, "VBI", sizeof(f->description)); | ||
667 | f->pixelformat = V4L2_PIX_FMT_MPEG; | ||
668 | |||
669 | return 0; | ||
670 | } | ||
671 | |||
672 | static int vidioc_g_fmt_vid_cap(struct file *file, void *priv, | ||
673 | struct v4l2_format *f) | ||
674 | { | ||
675 | struct saa7164_vbi_fh *fh = file->private_data; | ||
676 | struct saa7164_port *port = fh->port; | ||
677 | struct saa7164_dev *dev = port->dev; | ||
678 | |||
679 | f->fmt.pix.pixelformat = V4L2_PIX_FMT_MPEG; | ||
680 | f->fmt.pix.bytesperline = 0; | ||
681 | f->fmt.pix.sizeimage = | ||
682 | port->ts_packet_size * port->ts_packet_count; | ||
683 | f->fmt.pix.colorspace = 0; | ||
684 | f->fmt.pix.width = port->width; | ||
685 | f->fmt.pix.height = port->height; | ||
686 | |||
687 | dprintk(DBGLVL_VBI, "VIDIOC_G_FMT: w: %d, h: %d\n", | ||
688 | port->width, port->height); | ||
689 | |||
690 | return 0; | ||
691 | } | ||
692 | |||
693 | static int vidioc_try_fmt_vid_cap(struct file *file, void *priv, | ||
694 | struct v4l2_format *f) | ||
695 | { | ||
696 | struct saa7164_vbi_fh *fh = file->private_data; | ||
697 | struct saa7164_port *port = fh->port; | ||
698 | struct saa7164_dev *dev = port->dev; | ||
699 | |||
700 | f->fmt.pix.pixelformat = V4L2_PIX_FMT_MPEG; | ||
701 | f->fmt.pix.bytesperline = 0; | ||
702 | f->fmt.pix.sizeimage = | ||
703 | port->ts_packet_size * port->ts_packet_count; | ||
704 | f->fmt.pix.colorspace = 0; | ||
705 | dprintk(DBGLVL_VBI, "VIDIOC_TRY_FMT: w: %d, h: %d\n", | ||
706 | port->width, port->height); | ||
707 | return 0; | ||
708 | } | ||
709 | |||
710 | static int vidioc_s_fmt_vid_cap(struct file *file, void *priv, | ||
711 | struct v4l2_format *f) | ||
712 | { | ||
713 | struct saa7164_vbi_fh *fh = file->private_data; | ||
714 | struct saa7164_port *port = fh->port; | ||
715 | struct saa7164_dev *dev = port->dev; | ||
716 | |||
717 | f->fmt.pix.pixelformat = V4L2_PIX_FMT_MPEG; | ||
718 | f->fmt.pix.bytesperline = 0; | ||
719 | f->fmt.pix.sizeimage = | ||
720 | port->ts_packet_size * port->ts_packet_count; | ||
721 | f->fmt.pix.colorspace = 0; | ||
722 | |||
723 | dprintk(DBGLVL_VBI, "VIDIOC_S_FMT: w: %d, h: %d, f: %d\n", | ||
724 | f->fmt.pix.width, f->fmt.pix.height, f->fmt.pix.field); | ||
725 | |||
726 | return 0; | ||
727 | } | ||
728 | |||
729 | static int vidioc_log_status(struct file *file, void *priv) | ||
730 | { | ||
731 | return 0; | ||
732 | } | ||
733 | |||
734 | static int fill_queryctrl(struct saa7164_vbi_params *params, | ||
735 | struct v4l2_queryctrl *c) | ||
736 | { | ||
737 | switch (c->id) { | ||
738 | case V4L2_CID_BRIGHTNESS: | ||
739 | return v4l2_ctrl_query_fill(c, 0x0, 0xff, 1, 127); | ||
740 | case V4L2_CID_CONTRAST: | ||
741 | return v4l2_ctrl_query_fill(c, 0x0, 0xff, 1, 66); | ||
742 | case V4L2_CID_SATURATION: | ||
743 | return v4l2_ctrl_query_fill(c, 0x0, 0xff, 1, 62); | ||
744 | case V4L2_CID_HUE: | ||
745 | return v4l2_ctrl_query_fill(c, 0x0, 0xff, 1, 128); | ||
746 | case V4L2_CID_SHARPNESS: | ||
747 | return v4l2_ctrl_query_fill(c, 0x0, 0x0f, 1, 8); | ||
748 | case V4L2_CID_MPEG_AUDIO_MUTE: | ||
749 | return v4l2_ctrl_query_fill(c, 0x0, 0x01, 1, 0); | ||
750 | case V4L2_CID_AUDIO_VOLUME: | ||
751 | return v4l2_ctrl_query_fill(c, -83, 24, 1, 20); | ||
752 | case V4L2_CID_MPEG_STREAM_TYPE: | ||
753 | return v4l2_ctrl_query_fill(c, | ||
754 | V4L2_MPEG_STREAM_TYPE_MPEG2_PS, | ||
755 | V4L2_MPEG_STREAM_TYPE_MPEG2_TS, | ||
756 | 1, V4L2_MPEG_STREAM_TYPE_MPEG2_PS); | ||
757 | case V4L2_CID_MPEG_VIDEO_ASPECT: | ||
758 | return v4l2_ctrl_query_fill(c, | ||
759 | V4L2_MPEG_VIDEO_ASPECT_1x1, | ||
760 | V4L2_MPEG_VIDEO_ASPECT_221x100, | ||
761 | 1, V4L2_MPEG_VIDEO_ASPECT_4x3); | ||
762 | case V4L2_CID_MPEG_VIDEO_GOP_SIZE: | ||
763 | return v4l2_ctrl_query_fill(c, 1, 255, 1, 15); | ||
764 | case V4L2_CID_MPEG_VIDEO_B_FRAMES: | ||
765 | return v4l2_ctrl_query_fill(c, | ||
766 | 1, 3, 1, 1); | ||
767 | default: | ||
768 | return -EINVAL; | ||
769 | } | ||
770 | } | ||
771 | |||
772 | static int vidioc_queryctrl(struct file *file, void *priv, | ||
773 | struct v4l2_queryctrl *c) | ||
774 | { | ||
775 | struct saa7164_vbi_fh *fh = priv; | ||
776 | struct saa7164_port *port = fh->port; | ||
777 | int i, next; | ||
778 | u32 id = c->id; | ||
779 | |||
780 | memset(c, 0, sizeof(*c)); | ||
781 | |||
782 | next = !!(id & V4L2_CTRL_FLAG_NEXT_CTRL); | ||
783 | c->id = id & ~V4L2_CTRL_FLAG_NEXT_CTRL; | ||
784 | |||
785 | for (i = 0; i < ARRAY_SIZE(saa7164_v4l2_ctrls); i++) { | ||
786 | if (next) { | ||
787 | if (c->id < saa7164_v4l2_ctrls[i]) | ||
788 | c->id = saa7164_v4l2_ctrls[i]; | ||
789 | else | ||
790 | continue; | ||
791 | } | ||
792 | |||
793 | if (c->id == saa7164_v4l2_ctrls[i]) | ||
794 | return fill_queryctrl(&port->vbi_params, c); | ||
795 | |||
796 | if (c->id < saa7164_v4l2_ctrls[i]) | ||
797 | break; | ||
798 | } | ||
799 | |||
800 | return -EINVAL; | ||
801 | } | ||
802 | |||
803 | static int saa7164_vbi_stop_port(struct saa7164_port *port) | ||
804 | { | ||
805 | struct saa7164_dev *dev = port->dev; | ||
806 | int ret; | ||
807 | |||
808 | ret = saa7164_api_transition_port(port, SAA_DMASTATE_STOP); | ||
809 | if ((ret != SAA_OK) && (ret != SAA_ERR_ALREADY_STOPPED)) { | ||
810 | printk(KERN_ERR "%s() stop transition failed, ret = 0x%x\n", | ||
811 | __func__, ret); | ||
812 | ret = -EIO; | ||
813 | } else { | ||
814 | dprintk(DBGLVL_VBI, "%s() Stopped\n", __func__); | ||
815 | ret = 0; | ||
816 | } | ||
817 | |||
818 | return ret; | ||
819 | } | ||
820 | |||
821 | static int saa7164_vbi_acquire_port(struct saa7164_port *port) | ||
822 | { | ||
823 | struct saa7164_dev *dev = port->dev; | ||
824 | int ret; | ||
825 | |||
826 | ret = saa7164_api_transition_port(port, SAA_DMASTATE_ACQUIRE); | ||
827 | if ((ret != SAA_OK) && (ret != SAA_ERR_ALREADY_STOPPED)) { | ||
828 | printk(KERN_ERR "%s() acquire transition failed, ret = 0x%x\n", | ||
829 | __func__, ret); | ||
830 | ret = -EIO; | ||
831 | } else { | ||
832 | dprintk(DBGLVL_VBI, "%s() Acquired\n", __func__); | ||
833 | ret = 0; | ||
834 | } | ||
835 | |||
836 | return ret; | ||
837 | } | ||
838 | |||
839 | static int saa7164_vbi_pause_port(struct saa7164_port *port) | ||
840 | { | ||
841 | struct saa7164_dev *dev = port->dev; | ||
842 | int ret; | ||
843 | |||
844 | ret = saa7164_api_transition_port(port, SAA_DMASTATE_PAUSE); | ||
845 | if ((ret != SAA_OK) && (ret != SAA_ERR_ALREADY_STOPPED)) { | ||
846 | printk(KERN_ERR "%s() pause transition failed, ret = 0x%x\n", | ||
847 | __func__, ret); | ||
848 | ret = -EIO; | ||
849 | } else { | ||
850 | dprintk(DBGLVL_VBI, "%s() Paused\n", __func__); | ||
851 | ret = 0; | ||
852 | } | ||
853 | |||
854 | return ret; | ||
855 | } | ||
856 | |||
857 | /* Firmware is very windows centric, meaning you have to transition | ||
858 | * the part through AVStream / KS Windows stages, forwards or backwards. | ||
859 | * States are: stopped, acquired (h/w), paused, started. | ||
860 | * We have to leave here will all of the soft buffers on the free list, | ||
861 | * else the cfg_post() func won't have soft buffers to correctly configure. | ||
862 | */ | ||
863 | static int saa7164_vbi_stop_streaming(struct saa7164_port *port) | ||
864 | { | ||
865 | struct saa7164_dev *dev = port->dev; | ||
866 | struct saa7164_buffer *buf; | ||
867 | struct saa7164_user_buffer *ubuf; | ||
868 | struct list_head *c, *n; | ||
869 | int ret; | ||
870 | |||
871 | dprintk(DBGLVL_VBI, "%s(port=%d)\n", __func__, port->nr); | ||
872 | |||
873 | ret = saa7164_vbi_pause_port(port); | ||
874 | ret = saa7164_vbi_acquire_port(port); | ||
875 | ret = saa7164_vbi_stop_port(port); | ||
876 | |||
877 | dprintk(DBGLVL_VBI, "%s(port=%d) Hardware stopped\n", __func__, | ||
878 | port->nr); | ||
879 | |||
880 | /* Reset the state of any allocated buffer resources */ | ||
881 | mutex_lock(&port->dmaqueue_lock); | ||
882 | |||
883 | /* Reset the hard and soft buffer state */ | ||
884 | list_for_each_safe(c, n, &port->dmaqueue.list) { | ||
885 | buf = list_entry(c, struct saa7164_buffer, list); | ||
886 | buf->flags = SAA7164_BUFFER_FREE; | ||
887 | buf->pos = 0; | ||
888 | } | ||
889 | |||
890 | list_for_each_safe(c, n, &port->list_buf_used.list) { | ||
891 | ubuf = list_entry(c, struct saa7164_user_buffer, list); | ||
892 | ubuf->pos = 0; | ||
893 | list_move_tail(&ubuf->list, &port->list_buf_free.list); | ||
894 | } | ||
895 | |||
896 | mutex_unlock(&port->dmaqueue_lock); | ||
897 | |||
898 | /* Free any allocated resources */ | ||
899 | saa7164_vbi_buffers_dealloc(port); | ||
900 | |||
901 | dprintk(DBGLVL_VBI, "%s(port=%d) Released\n", __func__, port->nr); | ||
902 | |||
903 | return ret; | ||
904 | } | ||
905 | |||
906 | static int saa7164_vbi_start_streaming(struct saa7164_port *port) | ||
907 | { | ||
908 | struct saa7164_dev *dev = port->dev; | ||
909 | int result, ret = 0; | ||
910 | |||
911 | dprintk(DBGLVL_VBI, "%s(port=%d)\n", __func__, port->nr); | ||
912 | |||
913 | port->done_first_interrupt = 0; | ||
914 | |||
915 | /* allocate all of the PCIe DMA buffer resources on the fly, | ||
916 | * allowing switching between TS and PS payloads without | ||
917 | * requiring a complete driver reload. | ||
918 | */ | ||
919 | saa7164_vbi_buffers_alloc(port); | ||
920 | |||
921 | /* Configure the encoder with any cache values */ | ||
922 | // saa7164_api_set_encoder(port); | ||
923 | // saa7164_api_get_encoder(port); | ||
924 | |||
925 | /* Place the empty buffers on the hardware */ | ||
926 | saa7164_buffer_cfg_port(port); | ||
927 | |||
928 | /* Negotiate format */ | ||
929 | if (saa7164_api_set_vbi_format(port) != SAA_OK) { | ||
930 | printk(KERN_ERR "%s() No supported VBI format\n", __func__); | ||
931 | ret = -EIO; | ||
932 | goto out; | ||
933 | } | ||
934 | |||
935 | /* Acquire the hardware */ | ||
936 | result = saa7164_api_transition_port(port, SAA_DMASTATE_ACQUIRE); | ||
937 | if ((result != SAA_OK) && (result != SAA_ERR_ALREADY_STOPPED)) { | ||
938 | printk(KERN_ERR "%s() acquire transition failed, res = 0x%x\n", | ||
939 | __func__, result); | ||
940 | |||
941 | ret = -EIO; | ||
942 | goto out; | ||
943 | } else | ||
944 | dprintk(DBGLVL_VBI, "%s() Acquired\n", __func__); | ||
945 | |||
946 | /* Pause the hardware */ | ||
947 | result = saa7164_api_transition_port(port, SAA_DMASTATE_PAUSE); | ||
948 | if ((result != SAA_OK) && (result != SAA_ERR_ALREADY_STOPPED)) { | ||
949 | printk(KERN_ERR "%s() pause transition failed, res = 0x%x\n", | ||
950 | __func__, result); | ||
951 | |||
952 | /* Stop the hardware, regardless */ | ||
953 | result = saa7164_vbi_stop_port(port); | ||
954 | if ((result != SAA_OK) && (result != SAA_ERR_ALREADY_STOPPED)) { | ||
955 | printk(KERN_ERR "%s() pause/forced stop transition " | ||
956 | "failed, res = 0x%x\n", __func__, result); | ||
957 | } | ||
958 | |||
959 | ret = -EIO; | ||
960 | goto out; | ||
961 | } else | ||
962 | dprintk(DBGLVL_VBI, "%s() Paused\n", __func__); | ||
963 | |||
964 | /* Start the hardware */ | ||
965 | result = saa7164_api_transition_port(port, SAA_DMASTATE_RUN); | ||
966 | if ((result != SAA_OK) && (result != SAA_ERR_ALREADY_STOPPED)) { | ||
967 | printk(KERN_ERR "%s() run transition failed, result = 0x%x\n", | ||
968 | __func__, result); | ||
969 | |||
970 | /* Stop the hardware, regardless */ | ||
971 | result = saa7164_vbi_acquire_port(port); | ||
972 | result = saa7164_vbi_stop_port(port); | ||
973 | if ((result != SAA_OK) && (result != SAA_ERR_ALREADY_STOPPED)) { | ||
974 | printk(KERN_ERR "%s() run/forced stop transition " | ||
975 | "failed, res = 0x%x\n", __func__, result); | ||
976 | } | ||
977 | |||
978 | ret = -EIO; | ||
979 | } else | ||
980 | dprintk(DBGLVL_VBI, "%s() Running\n", __func__); | ||
981 | |||
982 | out: | ||
983 | return ret; | ||
984 | } | ||
985 | |||
986 | int saa7164_vbi_fmt(struct file *file, void *priv, struct v4l2_format *f) | ||
987 | { | ||
988 | /* ntsc */ | ||
989 | f->fmt.vbi.samples_per_line = 1600; | ||
990 | f->fmt.vbi.samples_per_line = 1440; | ||
991 | f->fmt.vbi.sampling_rate = 27000000; | ||
992 | f->fmt.vbi.sample_format = V4L2_PIX_FMT_GREY; | ||
993 | f->fmt.vbi.offset = 0; | ||
994 | f->fmt.vbi.flags = 0; | ||
995 | f->fmt.vbi.start[0] = 10; | ||
996 | f->fmt.vbi.count[0] = 18; | ||
997 | f->fmt.vbi.start[1] = 263 + 10 + 1; | ||
998 | f->fmt.vbi.count[1] = 18; | ||
999 | return 0; | ||
1000 | } | ||
1001 | |||
1002 | static int fops_open(struct file *file) | ||
1003 | { | ||
1004 | struct saa7164_dev *dev; | ||
1005 | struct saa7164_port *port; | ||
1006 | struct saa7164_vbi_fh *fh; | ||
1007 | |||
1008 | port = (struct saa7164_port *)video_get_drvdata(video_devdata(file)); | ||
1009 | if (!port) | ||
1010 | return -ENODEV; | ||
1011 | |||
1012 | dev = port->dev; | ||
1013 | |||
1014 | dprintk(DBGLVL_VBI, "%s()\n", __func__); | ||
1015 | |||
1016 | /* allocate + initialize per filehandle data */ | ||
1017 | fh = kzalloc(sizeof(*fh), GFP_KERNEL); | ||
1018 | if (NULL == fh) | ||
1019 | return -ENOMEM; | ||
1020 | |||
1021 | file->private_data = fh; | ||
1022 | fh->port = port; | ||
1023 | |||
1024 | return 0; | ||
1025 | } | ||
1026 | |||
1027 | static int fops_release(struct file *file) | ||
1028 | { | ||
1029 | struct saa7164_vbi_fh *fh = file->private_data; | ||
1030 | struct saa7164_port *port = fh->port; | ||
1031 | struct saa7164_dev *dev = port->dev; | ||
1032 | |||
1033 | dprintk(DBGLVL_VBI, "%s()\n", __func__); | ||
1034 | |||
1035 | /* Shut device down on last close */ | ||
1036 | if (atomic_cmpxchg(&fh->v4l_reading, 1, 0) == 1) { | ||
1037 | if (atomic_dec_return(&port->v4l_reader_count) == 0) { | ||
1038 | /* stop vbi capture then cancel buffers */ | ||
1039 | saa7164_vbi_stop_streaming(port); | ||
1040 | } | ||
1041 | } | ||
1042 | |||
1043 | file->private_data = NULL; | ||
1044 | kfree(fh); | ||
1045 | |||
1046 | return 0; | ||
1047 | } | ||
1048 | |||
1049 | struct saa7164_user_buffer *saa7164_vbi_next_buf(struct saa7164_port *port) | ||
1050 | { | ||
1051 | struct saa7164_user_buffer *ubuf = 0; | ||
1052 | struct saa7164_dev *dev = port->dev; | ||
1053 | u32 crc; | ||
1054 | |||
1055 | mutex_lock(&port->dmaqueue_lock); | ||
1056 | if (!list_empty(&port->list_buf_used.list)) { | ||
1057 | ubuf = list_first_entry(&port->list_buf_used.list, | ||
1058 | struct saa7164_user_buffer, list); | ||
1059 | |||
1060 | if (crc_checking) { | ||
1061 | crc = crc32(0, ubuf->data, ubuf->actual_size); | ||
1062 | if (crc != ubuf->crc) { | ||
1063 | printk(KERN_ERR "%s() ubuf %p crc became invalid, was 0x%x became 0x%x\n", __func__, | ||
1064 | ubuf, ubuf->crc, crc); | ||
1065 | } | ||
1066 | } | ||
1067 | |||
1068 | } | ||
1069 | mutex_unlock(&port->dmaqueue_lock); | ||
1070 | |||
1071 | dprintk(DBGLVL_VBI, "%s() returns %p\n", __func__, ubuf); | ||
1072 | |||
1073 | return ubuf; | ||
1074 | } | ||
1075 | |||
1076 | static ssize_t fops_read(struct file *file, char __user *buffer, | ||
1077 | size_t count, loff_t *pos) | ||
1078 | { | ||
1079 | struct saa7164_vbi_fh *fh = file->private_data; | ||
1080 | struct saa7164_port *port = fh->port; | ||
1081 | struct saa7164_user_buffer *ubuf = NULL; | ||
1082 | struct saa7164_dev *dev = port->dev; | ||
1083 | int ret = 0; | ||
1084 | int rem, cnt; | ||
1085 | u8 *p; | ||
1086 | |||
1087 | port->last_read_msecs_diff = port->last_read_msecs; | ||
1088 | port->last_read_msecs = jiffies_to_msecs(jiffies); | ||
1089 | port->last_read_msecs_diff = port->last_read_msecs - | ||
1090 | port->last_read_msecs_diff; | ||
1091 | |||
1092 | saa7164_histogram_update(&port->read_interval, | ||
1093 | port->last_read_msecs_diff); | ||
1094 | |||
1095 | if (*pos) { | ||
1096 | printk(KERN_ERR "%s() ESPIPE\n", __func__); | ||
1097 | return -ESPIPE; | ||
1098 | } | ||
1099 | |||
1100 | if (atomic_cmpxchg(&fh->v4l_reading, 0, 1) == 0) { | ||
1101 | if (atomic_inc_return(&port->v4l_reader_count) == 1) { | ||
1102 | |||
1103 | if (saa7164_vbi_initialize(port) < 0) { | ||
1104 | printk(KERN_ERR "%s() EINVAL\n", __func__); | ||
1105 | return -EINVAL; | ||
1106 | } | ||
1107 | |||
1108 | saa7164_vbi_start_streaming(port); | ||
1109 | msleep(200); | ||
1110 | } | ||
1111 | } | ||
1112 | |||
1113 | /* blocking wait for buffer */ | ||
1114 | if ((file->f_flags & O_NONBLOCK) == 0) { | ||
1115 | if (wait_event_interruptible(port->wait_read, | ||
1116 | saa7164_vbi_next_buf(port))) { | ||
1117 | printk(KERN_ERR "%s() ERESTARTSYS\n", __func__); | ||
1118 | return -ERESTARTSYS; | ||
1119 | } | ||
1120 | } | ||
1121 | |||
1122 | /* Pull the first buffer from the used list */ | ||
1123 | ubuf = saa7164_vbi_next_buf(port); | ||
1124 | |||
1125 | while ((count > 0) && ubuf) { | ||
1126 | |||
1127 | /* set remaining bytes to copy */ | ||
1128 | rem = ubuf->actual_size - ubuf->pos; | ||
1129 | cnt = rem > count ? count : rem; | ||
1130 | |||
1131 | p = ubuf->data + ubuf->pos; | ||
1132 | |||
1133 | dprintk(DBGLVL_VBI, | ||
1134 | "%s() count=%d cnt=%d rem=%d buf=%p buf->pos=%d\n", | ||
1135 | __func__, (int)count, cnt, rem, ubuf, ubuf->pos); | ||
1136 | |||
1137 | if (copy_to_user(buffer, p, cnt)) { | ||
1138 | printk(KERN_ERR "%s() copy_to_user failed\n", __func__); | ||
1139 | if (!ret) { | ||
1140 | printk(KERN_ERR "%s() EFAULT\n", __func__); | ||
1141 | ret = -EFAULT; | ||
1142 | } | ||
1143 | goto err; | ||
1144 | } | ||
1145 | |||
1146 | ubuf->pos += cnt; | ||
1147 | count -= cnt; | ||
1148 | buffer += cnt; | ||
1149 | ret += cnt; | ||
1150 | |||
1151 | if (ubuf->pos > ubuf->actual_size) { | ||
1152 | printk(KERN_ERR "read() pos > actual, huh?\n"); | ||
1153 | } | ||
1154 | |||
1155 | if (ubuf->pos == ubuf->actual_size) { | ||
1156 | |||
1157 | /* finished with current buffer, take next buffer */ | ||
1158 | |||
1159 | /* Requeue the buffer on the free list */ | ||
1160 | ubuf->pos = 0; | ||
1161 | |||
1162 | mutex_lock(&port->dmaqueue_lock); | ||
1163 | list_move_tail(&ubuf->list, &port->list_buf_free.list); | ||
1164 | mutex_unlock(&port->dmaqueue_lock); | ||
1165 | |||
1166 | /* Dequeue next */ | ||
1167 | if ((file->f_flags & O_NONBLOCK) == 0) { | ||
1168 | if (wait_event_interruptible(port->wait_read, | ||
1169 | saa7164_vbi_next_buf(port))) { | ||
1170 | break; | ||
1171 | } | ||
1172 | } | ||
1173 | ubuf = saa7164_vbi_next_buf(port); | ||
1174 | } | ||
1175 | } | ||
1176 | err: | ||
1177 | if (!ret && !ubuf) { | ||
1178 | printk(KERN_ERR "%s() EAGAIN\n", __func__); | ||
1179 | ret = -EAGAIN; | ||
1180 | } | ||
1181 | |||
1182 | return ret; | ||
1183 | } | ||
1184 | |||
1185 | static unsigned int fops_poll(struct file *file, poll_table *wait) | ||
1186 | { | ||
1187 | struct saa7164_vbi_fh *fh = (struct saa7164_vbi_fh *)file->private_data; | ||
1188 | struct saa7164_port *port = fh->port; | ||
1189 | struct saa7164_user_buffer *ubuf; | ||
1190 | unsigned int mask = 0; | ||
1191 | |||
1192 | port->last_poll_msecs_diff = port->last_poll_msecs; | ||
1193 | port->last_poll_msecs = jiffies_to_msecs(jiffies); | ||
1194 | port->last_poll_msecs_diff = port->last_poll_msecs - | ||
1195 | port->last_poll_msecs_diff; | ||
1196 | |||
1197 | saa7164_histogram_update(&port->poll_interval, | ||
1198 | port->last_poll_msecs_diff); | ||
1199 | |||
1200 | if (!video_is_registered(port->v4l_device)) { | ||
1201 | return -EIO; | ||
1202 | } | ||
1203 | |||
1204 | if (atomic_cmpxchg(&fh->v4l_reading, 0, 1) == 0) { | ||
1205 | if (atomic_inc_return(&port->v4l_reader_count) == 1) { | ||
1206 | if (saa7164_vbi_initialize(port) < 0) | ||
1207 | return -EINVAL; | ||
1208 | saa7164_vbi_start_streaming(port); | ||
1209 | msleep(200); | ||
1210 | } | ||
1211 | } | ||
1212 | |||
1213 | /* blocking wait for buffer */ | ||
1214 | if ((file->f_flags & O_NONBLOCK) == 0) { | ||
1215 | if (wait_event_interruptible(port->wait_read, | ||
1216 | saa7164_vbi_next_buf(port))) { | ||
1217 | return -ERESTARTSYS; | ||
1218 | } | ||
1219 | } | ||
1220 | |||
1221 | /* Pull the first buffer from the used list */ | ||
1222 | ubuf = list_first_entry(&port->list_buf_used.list, | ||
1223 | struct saa7164_user_buffer, list); | ||
1224 | |||
1225 | if (ubuf) | ||
1226 | mask |= POLLIN | POLLRDNORM; | ||
1227 | |||
1228 | return mask; | ||
1229 | } | ||
1230 | static const struct v4l2_file_operations vbi_fops = { | ||
1231 | .owner = THIS_MODULE, | ||
1232 | .open = fops_open, | ||
1233 | .release = fops_release, | ||
1234 | .read = fops_read, | ||
1235 | .poll = fops_poll, | ||
1236 | .unlocked_ioctl = video_ioctl2, | ||
1237 | }; | ||
1238 | |||
1239 | static const struct v4l2_ioctl_ops vbi_ioctl_ops = { | ||
1240 | .vidioc_s_std = vidioc_s_std, | ||
1241 | .vidioc_enum_input = vidioc_enum_input, | ||
1242 | .vidioc_g_input = vidioc_g_input, | ||
1243 | .vidioc_s_input = vidioc_s_input, | ||
1244 | .vidioc_g_tuner = vidioc_g_tuner, | ||
1245 | .vidioc_s_tuner = vidioc_s_tuner, | ||
1246 | .vidioc_g_frequency = vidioc_g_frequency, | ||
1247 | .vidioc_s_frequency = vidioc_s_frequency, | ||
1248 | .vidioc_s_ctrl = vidioc_s_ctrl, | ||
1249 | .vidioc_g_ctrl = vidioc_g_ctrl, | ||
1250 | .vidioc_querycap = vidioc_querycap, | ||
1251 | .vidioc_enum_fmt_vid_cap = vidioc_enum_fmt_vid_cap, | ||
1252 | .vidioc_g_fmt_vid_cap = vidioc_g_fmt_vid_cap, | ||
1253 | .vidioc_try_fmt_vid_cap = vidioc_try_fmt_vid_cap, | ||
1254 | .vidioc_s_fmt_vid_cap = vidioc_s_fmt_vid_cap, | ||
1255 | .vidioc_g_ext_ctrls = vidioc_g_ext_ctrls, | ||
1256 | .vidioc_s_ext_ctrls = vidioc_s_ext_ctrls, | ||
1257 | .vidioc_try_ext_ctrls = vidioc_try_ext_ctrls, | ||
1258 | .vidioc_log_status = vidioc_log_status, | ||
1259 | .vidioc_queryctrl = vidioc_queryctrl, | ||
1260 | // .vidioc_g_chip_ident = saa7164_g_chip_ident, | ||
1261 | #ifdef CONFIG_VIDEO_ADV_DEBUG | ||
1262 | // .vidioc_g_register = saa7164_g_register, | ||
1263 | // .vidioc_s_register = saa7164_s_register, | ||
1264 | #endif | ||
1265 | .vidioc_g_fmt_vbi_cap = saa7164_vbi_fmt, | ||
1266 | .vidioc_try_fmt_vbi_cap = saa7164_vbi_fmt, | ||
1267 | .vidioc_s_fmt_vbi_cap = saa7164_vbi_fmt, | ||
1268 | }; | ||
1269 | |||
1270 | static struct video_device saa7164_vbi_template = { | ||
1271 | .name = "saa7164", | ||
1272 | .fops = &vbi_fops, | ||
1273 | .ioctl_ops = &vbi_ioctl_ops, | ||
1274 | .minor = -1, | ||
1275 | .tvnorms = SAA7164_NORMS, | ||
1276 | .current_norm = V4L2_STD_NTSC_M, | ||
1277 | }; | ||
1278 | |||
1279 | static struct video_device *saa7164_vbi_alloc( | ||
1280 | struct saa7164_port *port, | ||
1281 | struct pci_dev *pci, | ||
1282 | struct video_device *template, | ||
1283 | char *type) | ||
1284 | { | ||
1285 | struct video_device *vfd; | ||
1286 | struct saa7164_dev *dev = port->dev; | ||
1287 | |||
1288 | dprintk(DBGLVL_VBI, "%s()\n", __func__); | ||
1289 | |||
1290 | vfd = video_device_alloc(); | ||
1291 | if (NULL == vfd) | ||
1292 | return NULL; | ||
1293 | |||
1294 | *vfd = *template; | ||
1295 | snprintf(vfd->name, sizeof(vfd->name), "%s %s (%s)", dev->name, | ||
1296 | type, saa7164_boards[dev->board].name); | ||
1297 | |||
1298 | vfd->parent = &pci->dev; | ||
1299 | vfd->release = video_device_release; | ||
1300 | return vfd; | ||
1301 | } | ||
1302 | |||
1303 | int saa7164_vbi_register(struct saa7164_port *port) | ||
1304 | { | ||
1305 | struct saa7164_dev *dev = port->dev; | ||
1306 | int result = -ENODEV; | ||
1307 | |||
1308 | dprintk(DBGLVL_VBI, "%s()\n", __func__); | ||
1309 | |||
1310 | if (port->type != SAA7164_MPEG_VBI) | ||
1311 | BUG(); | ||
1312 | |||
1313 | /* Sanity check that the PCI configuration space is active */ | ||
1314 | if (port->hwcfg.BARLocation == 0) { | ||
1315 | printk(KERN_ERR "%s() failed " | ||
1316 | "(errno = %d), NO PCI configuration\n", | ||
1317 | __func__, result); | ||
1318 | result = -ENOMEM; | ||
1319 | goto failed; | ||
1320 | } | ||
1321 | |||
1322 | /* Establish VBI defaults here */ | ||
1323 | |||
1324 | /* Allocate and register the video device node */ | ||
1325 | port->v4l_device = saa7164_vbi_alloc(port, | ||
1326 | dev->pci, &saa7164_vbi_template, "vbi"); | ||
1327 | |||
1328 | if (port->v4l_device == NULL) { | ||
1329 | printk(KERN_INFO "%s: can't allocate vbi device\n", | ||
1330 | dev->name); | ||
1331 | result = -ENOMEM; | ||
1332 | goto failed; | ||
1333 | } | ||
1334 | |||
1335 | video_set_drvdata(port->v4l_device, port); | ||
1336 | result = video_register_device(port->v4l_device, | ||
1337 | VFL_TYPE_VBI, -1); | ||
1338 | if (result < 0) { | ||
1339 | printk(KERN_INFO "%s: can't register vbi device\n", | ||
1340 | dev->name); | ||
1341 | /* TODO: We're going to leak here if we don't dealloc | ||
1342 | The buffers above. The unreg function can't deal wit it. | ||
1343 | */ | ||
1344 | goto failed; | ||
1345 | } | ||
1346 | |||
1347 | printk(KERN_INFO "%s: registered device vbi%d [vbi]\n", | ||
1348 | dev->name, port->v4l_device->num); | ||
1349 | |||
1350 | /* Configure the hardware defaults */ | ||
1351 | |||
1352 | result = 0; | ||
1353 | failed: | ||
1354 | return result; | ||
1355 | } | ||
1356 | |||
1357 | void saa7164_vbi_unregister(struct saa7164_port *port) | ||
1358 | { | ||
1359 | struct saa7164_dev *dev = port->dev; | ||
1360 | |||
1361 | dprintk(DBGLVL_VBI, "%s(port=%d)\n", __func__, port->nr); | ||
1362 | |||
1363 | if (port->type != SAA7164_MPEG_VBI) | ||
1364 | BUG(); | ||
1365 | |||
1366 | if (port->v4l_device) { | ||
1367 | if (port->v4l_device->minor != -1) | ||
1368 | video_unregister_device(port->v4l_device); | ||
1369 | else | ||
1370 | video_device_release(port->v4l_device); | ||
1371 | |||
1372 | port->v4l_device = NULL; | ||
1373 | } | ||
1374 | |||
1375 | } | ||
diff --git a/drivers/media/video/saa7164/saa7164.h b/drivers/media/video/saa7164/saa7164.h index 42660b546f0e..1d9c5cbbbc52 100644 --- a/drivers/media/video/saa7164/saa7164.h +++ b/drivers/media/video/saa7164/saa7164.h | |||
@@ -1,7 +1,7 @@ | |||
1 | /* | 1 | /* |
2 | * Driver for the NXP SAA7164 PCIe bridge | 2 | * Driver for the NXP SAA7164 PCIe bridge |
3 | * | 3 | * |
4 | * Copyright (c) 2009 Steven Toth <stoth@kernellabs.com> | 4 | * Copyright (c) 2010 Steven Toth <stoth@kernellabs.com> |
5 | * | 5 | * |
6 | * This program is free software; you can redistribute it and/or modify | 6 | * This program is free software; you can redistribute it and/or modify |
7 | * it under the terms of the GNU General Public License as published by | 7 | * it under the terms of the GNU General Public License as published by |
@@ -48,18 +48,29 @@ | |||
48 | #include <linux/i2c.h> | 48 | #include <linux/i2c.h> |
49 | #include <linux/i2c-algo-bit.h> | 49 | #include <linux/i2c-algo-bit.h> |
50 | #include <linux/kdev_t.h> | 50 | #include <linux/kdev_t.h> |
51 | #include <linux/version.h> | ||
52 | #include <linux/mutex.h> | ||
53 | #include <linux/crc32.h> | ||
54 | #include <linux/kthread.h> | ||
55 | #include <linux/freezer.h> | ||
51 | 56 | ||
52 | #include <media/tuner.h> | 57 | #include <media/tuner.h> |
53 | #include <media/tveeprom.h> | 58 | #include <media/tveeprom.h> |
54 | #include <media/videobuf-dma-sg.h> | 59 | #include <media/videobuf-dma-sg.h> |
55 | #include <media/videobuf-dvb.h> | 60 | #include <media/videobuf-dvb.h> |
61 | #include <linux/smp_lock.h> | ||
62 | #include <dvb_demux.h> | ||
63 | #include <dvb_frontend.h> | ||
64 | #include <dvb_net.h> | ||
65 | #include <dvbdev.h> | ||
66 | #include <dmxdev.h> | ||
67 | #include <media/v4l2-common.h> | ||
68 | #include <media/v4l2-ioctl.h> | ||
69 | #include <media/v4l2-chip-ident.h> | ||
56 | 70 | ||
57 | #include "saa7164-reg.h" | 71 | #include "saa7164-reg.h" |
58 | #include "saa7164-types.h" | 72 | #include "saa7164-types.h" |
59 | 73 | ||
60 | #include <linux/version.h> | ||
61 | #include <linux/mutex.h> | ||
62 | |||
63 | #define SAA7164_MAXBOARDS 8 | 74 | #define SAA7164_MAXBOARDS 8 |
64 | 75 | ||
65 | #define UNSET (-1U) | 76 | #define UNSET (-1U) |
@@ -76,7 +87,19 @@ | |||
76 | 87 | ||
77 | #define SAA7164_MAX_UNITS 8 | 88 | #define SAA7164_MAX_UNITS 8 |
78 | #define SAA7164_TS_NUMBER_OF_LINES 312 | 89 | #define SAA7164_TS_NUMBER_OF_LINES 312 |
90 | #define SAA7164_PS_NUMBER_OF_LINES 256 | ||
79 | #define SAA7164_PT_ENTRIES 16 /* (312 * 188) / 4096 */ | 91 | #define SAA7164_PT_ENTRIES 16 /* (312 * 188) / 4096 */ |
92 | #define SAA7164_MAX_ENCODER_BUFFERS 64 /* max 5secs of latency at 6Mbps */ | ||
93 | #define SAA7164_MAX_VBI_BUFFERS 64 | ||
94 | |||
95 | /* Port related defines */ | ||
96 | #define SAA7164_PORT_TS1 (0) | ||
97 | #define SAA7164_PORT_TS2 (SAA7164_PORT_TS1 + 1) | ||
98 | #define SAA7164_PORT_ENC1 (SAA7164_PORT_TS2 + 1) | ||
99 | #define SAA7164_PORT_ENC2 (SAA7164_PORT_ENC1 + 1) | ||
100 | #define SAA7164_PORT_VBI1 (SAA7164_PORT_ENC2 + 1) | ||
101 | #define SAA7164_PORT_VBI2 (SAA7164_PORT_VBI1 + 1) | ||
102 | #define SAA7164_MAX_PORTS (SAA7164_PORT_VBI2 + 1) | ||
80 | 103 | ||
81 | #define DBGLVL_FW 4 | 104 | #define DBGLVL_FW 4 |
82 | #define DBGLVL_DVB 8 | 105 | #define DBGLVL_DVB 8 |
@@ -86,10 +109,18 @@ | |||
86 | #define DBGLVL_BUS 128 | 109 | #define DBGLVL_BUS 128 |
87 | #define DBGLVL_IRQ 256 | 110 | #define DBGLVL_IRQ 256 |
88 | #define DBGLVL_BUF 512 | 111 | #define DBGLVL_BUF 512 |
112 | #define DBGLVL_ENC 1024 | ||
113 | #define DBGLVL_VBI 2048 | ||
114 | #define DBGLVL_THR 4096 | ||
115 | #define DBGLVL_CPU 8192 | ||
116 | |||
117 | #define SAA7164_NORMS (V4L2_STD_NTSC_M | V4L2_STD_NTSC_M_JP | V4L2_STD_NTSC_443) | ||
89 | 118 | ||
90 | enum port_t { | 119 | enum port_t { |
91 | SAA7164_MPEG_UNDEFINED = 0, | 120 | SAA7164_MPEG_UNDEFINED = 0, |
92 | SAA7164_MPEG_DVB, | 121 | SAA7164_MPEG_DVB, |
122 | SAA7164_MPEG_ENCODER, | ||
123 | SAA7164_MPEG_VBI, | ||
93 | }; | 124 | }; |
94 | 125 | ||
95 | enum saa7164_i2c_bus_nr { | 126 | enum saa7164_i2c_bus_nr { |
@@ -134,7 +165,8 @@ struct saa7164_unit { | |||
134 | 165 | ||
135 | struct saa7164_board { | 166 | struct saa7164_board { |
136 | char *name; | 167 | char *name; |
137 | enum port_t porta, portb; | 168 | enum port_t porta, portb, portc, |
169 | portd, porte, portf; | ||
138 | enum { | 170 | enum { |
139 | SAA7164_CHIP_UNDEFINED = 0, | 171 | SAA7164_CHIP_UNDEFINED = 0, |
140 | SAA7164_CHIP_REV2, | 172 | SAA7164_CHIP_REV2, |
@@ -149,6 +181,42 @@ struct saa7164_subid { | |||
149 | u32 card; | 181 | u32 card; |
150 | }; | 182 | }; |
151 | 183 | ||
184 | struct saa7164_encoder_fh { | ||
185 | struct saa7164_port *port; | ||
186 | // u32 freq; | ||
187 | // u32 tuner_type; | ||
188 | atomic_t v4l_reading; | ||
189 | }; | ||
190 | |||
191 | struct saa7164_vbi_fh { | ||
192 | struct saa7164_port *port; | ||
193 | // u32 freq; | ||
194 | // u32 tuner_type; | ||
195 | atomic_t v4l_reading; | ||
196 | }; | ||
197 | |||
198 | struct saa7164_histogram_bucket { | ||
199 | u32 val; | ||
200 | u32 count; | ||
201 | u64 update_time; | ||
202 | }; | ||
203 | |||
204 | struct saa7164_histogram { | ||
205 | char name[32]; | ||
206 | struct saa7164_histogram_bucket counter1[64]; | ||
207 | }; | ||
208 | |||
209 | struct saa7164_user_buffer { | ||
210 | struct list_head list; | ||
211 | |||
212 | /* Attributes */ | ||
213 | u8 *data; | ||
214 | u32 pos; | ||
215 | u32 actual_size; | ||
216 | |||
217 | u32 crc; | ||
218 | }; | ||
219 | |||
152 | struct saa7164_fw_status { | 220 | struct saa7164_fw_status { |
153 | 221 | ||
154 | /* RISC Core details */ | 222 | /* RISC Core details */ |
@@ -191,14 +259,60 @@ struct saa7164_i2c { | |||
191 | u32 i2c_rc; | 259 | u32 i2c_rc; |
192 | }; | 260 | }; |
193 | 261 | ||
194 | struct saa7164_tsport; | 262 | struct saa7164_ctrl { |
263 | struct v4l2_queryctrl v; | ||
264 | }; | ||
265 | |||
266 | struct saa7164_tvnorm { | ||
267 | char *name; | ||
268 | v4l2_std_id id; | ||
269 | // u32 cxiformat; | ||
270 | // u32 cxoformat; | ||
271 | }; | ||
272 | |||
273 | struct saa7164_encoder_params { | ||
274 | struct saa7164_tvnorm encodernorm; | ||
275 | u32 height; | ||
276 | u32 width; | ||
277 | u32 is_50hz; | ||
278 | u32 bitrate; /* bps */ | ||
279 | u32 bitrate_peak; /* bps */ | ||
280 | u32 bitrate_mode; | ||
281 | u32 stream_type; /* V4L2_MPEG_STREAM_TYPE_MPEG2_TS */ | ||
282 | |||
283 | u32 audio_sampling_freq; | ||
284 | u32 ctl_mute; | ||
285 | u32 ctl_aspect; | ||
286 | u32 refdist; | ||
287 | u32 gop_size; | ||
288 | }; | ||
289 | |||
290 | struct saa7164_vbi_params { | ||
291 | struct saa7164_tvnorm encodernorm; | ||
292 | u32 height; | ||
293 | u32 width; | ||
294 | u32 is_50hz; | ||
295 | u32 bitrate; /* bps */ | ||
296 | u32 bitrate_peak; /* bps */ | ||
297 | u32 bitrate_mode; | ||
298 | u32 stream_type; /* V4L2_MPEG_STREAM_TYPE_MPEG2_TS */ | ||
299 | |||
300 | u32 audio_sampling_freq; | ||
301 | u32 ctl_mute; | ||
302 | u32 ctl_aspect; | ||
303 | u32 refdist; | ||
304 | u32 gop_size; | ||
305 | }; | ||
306 | |||
307 | struct saa7164_port; | ||
195 | 308 | ||
196 | struct saa7164_buffer { | 309 | struct saa7164_buffer { |
197 | struct list_head list; | 310 | struct list_head list; |
198 | 311 | ||
199 | u32 nr; | 312 | /* Note of which h/w buffer list index position we occupy */ |
313 | int idx; | ||
200 | 314 | ||
201 | struct saa7164_tsport *port; | 315 | struct saa7164_port *port; |
202 | 316 | ||
203 | /* Hardware Specific */ | 317 | /* Hardware Specific */ |
204 | /* PCI Memory allocations */ | 318 | /* PCI Memory allocations */ |
@@ -206,28 +320,33 @@ struct saa7164_buffer { | |||
206 | 320 | ||
207 | /* A block of page align PCI memory */ | 321 | /* A block of page align PCI memory */ |
208 | u32 pci_size; /* PCI allocation size in bytes */ | 322 | u32 pci_size; /* PCI allocation size in bytes */ |
209 | u64 *cpu; /* Virtual address */ | 323 | u64 __iomem *cpu; /* Virtual address */ |
210 | dma_addr_t dma; /* Physical address */ | 324 | dma_addr_t dma; /* Physical address */ |
325 | u32 crc; /* Checksum for the entire buffer data */ | ||
211 | 326 | ||
212 | /* A page table that splits the block into a number of entries */ | 327 | /* A page table that splits the block into a number of entries */ |
213 | u32 pt_size; /* PCI allocation size in bytes */ | 328 | u32 pt_size; /* PCI allocation size in bytes */ |
214 | u64 *pt_cpu; /* Virtual address */ | 329 | u64 __iomem *pt_cpu; /* Virtual address */ |
215 | dma_addr_t pt_dma; /* Physical address */ | 330 | dma_addr_t pt_dma; /* Physical address */ |
331 | |||
332 | /* Encoder fops */ | ||
333 | u32 pos; | ||
334 | u32 actual_size; | ||
216 | }; | 335 | }; |
217 | 336 | ||
218 | struct saa7164_tsport { | 337 | struct saa7164_port { |
219 | 338 | ||
220 | struct saa7164_dev *dev; | 339 | struct saa7164_dev *dev; |
221 | int nr; | ||
222 | enum port_t type; | 340 | enum port_t type; |
341 | int nr; | ||
223 | 342 | ||
224 | struct saa7164_dvb dvb; | 343 | /* --- Generic port attributes --- */ |
225 | 344 | ||
226 | /* HW related stream parameters */ | 345 | /* HW stream parameters */ |
227 | tmHWStreamParameters_t hw_streamingparams; | 346 | struct tmHWStreamParameters hw_streamingparams; |
228 | 347 | ||
229 | /* DMA configuration values, is seeded during initialization */ | 348 | /* DMA configuration values, is seeded during initialization */ |
230 | tmComResDMATermDescrHeader_t hwcfg; | 349 | struct tmComResDMATermDescrHeader hwcfg; |
231 | 350 | ||
232 | /* hardware specific registers */ | 351 | /* hardware specific registers */ |
233 | u32 bufcounter; | 352 | u32 bufcounter; |
@@ -239,11 +358,76 @@ struct saa7164_tsport { | |||
239 | u64 bufptr64; | 358 | u64 bufptr64; |
240 | 359 | ||
241 | u32 numpte; /* Number of entries in array, only valid in head */ | 360 | u32 numpte; /* Number of entries in array, only valid in head */ |
361 | |||
242 | struct mutex dmaqueue_lock; | 362 | struct mutex dmaqueue_lock; |
243 | struct mutex dummy_dmaqueue_lock; | ||
244 | struct saa7164_buffer dmaqueue; | 363 | struct saa7164_buffer dmaqueue; |
245 | struct saa7164_buffer dummy_dmaqueue; | ||
246 | 364 | ||
365 | u64 last_irq_msecs, last_svc_msecs; | ||
366 | u64 last_irq_msecs_diff, last_svc_msecs_diff; | ||
367 | u32 last_svc_wp; | ||
368 | u32 last_svc_rp; | ||
369 | u64 last_irq_svc_msecs_diff; | ||
370 | u64 last_read_msecs, last_read_msecs_diff; | ||
371 | u64 last_poll_msecs, last_poll_msecs_diff; | ||
372 | |||
373 | struct saa7164_histogram irq_interval; | ||
374 | struct saa7164_histogram svc_interval; | ||
375 | struct saa7164_histogram irq_svc_interval; | ||
376 | struct saa7164_histogram read_interval; | ||
377 | struct saa7164_histogram poll_interval; | ||
378 | |||
379 | /* --- DVB Transport Specific --- */ | ||
380 | struct saa7164_dvb dvb; | ||
381 | |||
382 | /* --- Encoder/V4L related attributes --- */ | ||
383 | /* Encoder */ | ||
384 | /* Defaults established in saa7164-encoder.c */ | ||
385 | struct saa7164_tvnorm encodernorm; | ||
386 | u32 height; | ||
387 | u32 width; | ||
388 | u32 freq; | ||
389 | u32 ts_packet_size; | ||
390 | u32 ts_packet_count; | ||
391 | u8 mux_input; | ||
392 | u8 encoder_profile; | ||
393 | u8 video_format; | ||
394 | u8 audio_format; | ||
395 | u8 video_resolution; | ||
396 | u16 ctl_brightness; | ||
397 | u16 ctl_contrast; | ||
398 | u16 ctl_hue; | ||
399 | u16 ctl_saturation; | ||
400 | u16 ctl_sharpness; | ||
401 | s8 ctl_volume; | ||
402 | |||
403 | struct tmComResAFeatureDescrHeader audfeat; | ||
404 | struct tmComResEncoderDescrHeader encunit; | ||
405 | struct tmComResProcDescrHeader vidproc; | ||
406 | struct tmComResExtDevDescrHeader ifunit; | ||
407 | struct tmComResTunerDescrHeader tunerunit; | ||
408 | |||
409 | struct work_struct workenc; | ||
410 | |||
411 | /* V4L Encoder Video */ | ||
412 | struct saa7164_encoder_params encoder_params; | ||
413 | struct video_device *v4l_device; | ||
414 | atomic_t v4l_reader_count; | ||
415 | |||
416 | struct saa7164_buffer list_buf_used; | ||
417 | struct saa7164_buffer list_buf_free; | ||
418 | wait_queue_head_t wait_read; | ||
419 | |||
420 | /* V4L VBI */ | ||
421 | struct tmComResVBIFormatDescrHeader vbi_fmt_ntsc; | ||
422 | struct saa7164_vbi_params vbi_params; | ||
423 | |||
424 | /* Debug */ | ||
425 | u32 sync_errors; | ||
426 | u32 v_cc_errors; | ||
427 | u32 a_cc_errors; | ||
428 | u8 last_v_cc; | ||
429 | u8 last_a_cc; | ||
430 | u32 done_first_interrupt; | ||
247 | }; | 431 | }; |
248 | 432 | ||
249 | struct saa7164_dev { | 433 | struct saa7164_dev { |
@@ -268,12 +452,13 @@ struct saa7164_dev { | |||
268 | 452 | ||
269 | /* firmware status */ | 453 | /* firmware status */ |
270 | struct saa7164_fw_status fw_status; | 454 | struct saa7164_fw_status fw_status; |
455 | u32 firmwareloaded; | ||
271 | 456 | ||
272 | tmComResHWDescr_t hwdesc; | 457 | struct tmComResHWDescr hwdesc; |
273 | tmComResInterfaceDescr_t intfdesc; | 458 | struct tmComResInterfaceDescr intfdesc; |
274 | tmComResBusDescr_t busdesc; | 459 | struct tmComResBusDescr busdesc; |
275 | 460 | ||
276 | tmComResBusInfo_t bus; | 461 | struct tmComResBusInfo bus; |
277 | 462 | ||
278 | /* Interrupt status and ack registers */ | 463 | /* Interrupt status and ack registers */ |
279 | u32 int_status; | 464 | u32 int_status; |
@@ -286,15 +471,22 @@ struct saa7164_dev { | |||
286 | struct saa7164_i2c i2c_bus[3]; | 471 | struct saa7164_i2c i2c_bus[3]; |
287 | 472 | ||
288 | /* Transport related */ | 473 | /* Transport related */ |
289 | struct saa7164_tsport ts1, ts2; | 474 | struct saa7164_port ports[SAA7164_MAX_PORTS]; |
290 | 475 | ||
291 | /* Deferred command/api interrupts handling */ | 476 | /* Deferred command/api interrupts handling */ |
292 | struct work_struct workcmd; | 477 | struct work_struct workcmd; |
293 | 478 | ||
479 | /* A kernel thread to monitor the firmware log, used | ||
480 | * only in debug mode. | ||
481 | */ | ||
482 | struct task_struct *kthread; | ||
483 | |||
294 | }; | 484 | }; |
295 | 485 | ||
296 | extern struct list_head saa7164_devlist; | 486 | extern struct list_head saa7164_devlist; |
297 | extern unsigned int waitsecs; | 487 | extern unsigned int waitsecs; |
488 | extern unsigned int encoder_buffers; | ||
489 | extern unsigned int vbi_buffers; | ||
298 | 490 | ||
299 | /* ----------------------------------------------------------- */ | 491 | /* ----------------------------------------------------------- */ |
300 | /* saa7164-core.c */ | 492 | /* saa7164-core.c */ |
@@ -302,6 +494,7 @@ void saa7164_dumpregs(struct saa7164_dev *dev, u32 addr); | |||
302 | void saa7164_dumphex16(struct saa7164_dev *dev, u8 *buf, int len); | 494 | void saa7164_dumphex16(struct saa7164_dev *dev, u8 *buf, int len); |
303 | void saa7164_getfirmwarestatus(struct saa7164_dev *dev); | 495 | void saa7164_getfirmwarestatus(struct saa7164_dev *dev); |
304 | u32 saa7164_getcurrentfirmwareversion(struct saa7164_dev *dev); | 496 | u32 saa7164_getcurrentfirmwareversion(struct saa7164_dev *dev); |
497 | void saa7164_histogram_update(struct saa7164_histogram *hg, u32 val); | ||
305 | 498 | ||
306 | /* ----------------------------------------------------------- */ | 499 | /* ----------------------------------------------------------- */ |
307 | /* saa7164-fw.c */ | 500 | /* saa7164-fw.c */ |
@@ -318,14 +511,14 @@ extern void saa7164_call_i2c_clients(struct saa7164_i2c *bus, | |||
318 | /* saa7164-bus.c */ | 511 | /* saa7164-bus.c */ |
319 | int saa7164_bus_setup(struct saa7164_dev *dev); | 512 | int saa7164_bus_setup(struct saa7164_dev *dev); |
320 | void saa7164_bus_dump(struct saa7164_dev *dev); | 513 | void saa7164_bus_dump(struct saa7164_dev *dev); |
321 | int saa7164_bus_set(struct saa7164_dev *dev, tmComResInfo_t* msg, void *buf); | 514 | int saa7164_bus_set(struct saa7164_dev *dev, struct tmComResInfo* msg, void *buf); |
322 | int saa7164_bus_get(struct saa7164_dev *dev, tmComResInfo_t* msg, | 515 | int saa7164_bus_get(struct saa7164_dev *dev, struct tmComResInfo* msg, |
323 | void *buf, int peekonly); | 516 | void *buf, int peekonly); |
324 | 517 | ||
325 | /* ----------------------------------------------------------- */ | 518 | /* ----------------------------------------------------------- */ |
326 | /* saa7164-cmd.c */ | 519 | /* saa7164-cmd.c */ |
327 | int saa7164_cmd_send(struct saa7164_dev *dev, | 520 | int saa7164_cmd_send(struct saa7164_dev *dev, |
328 | u8 id, tmComResCmd_t command, u16 controlselector, | 521 | u8 id, enum tmComResCmd command, u16 controlselector, |
329 | u16 size, void *buf); | 522 | u16 size, void *buf); |
330 | void saa7164_cmd_signal(struct saa7164_dev *dev, u8 seqno); | 523 | void saa7164_cmd_signal(struct saa7164_dev *dev, u8 seqno); |
331 | int saa7164_irq_dequeue(struct saa7164_dev *dev); | 524 | int saa7164_irq_dequeue(struct saa7164_dev *dev); |
@@ -343,7 +536,24 @@ int saa7164_api_dif_write(struct saa7164_i2c *bus, u8 addr, | |||
343 | int saa7164_api_read_eeprom(struct saa7164_dev *dev, u8 *buf, int buflen); | 536 | int saa7164_api_read_eeprom(struct saa7164_dev *dev, u8 *buf, int buflen); |
344 | int saa7164_api_set_gpiobit(struct saa7164_dev *dev, u8 unitid, u8 pin); | 537 | int saa7164_api_set_gpiobit(struct saa7164_dev *dev, u8 unitid, u8 pin); |
345 | int saa7164_api_clear_gpiobit(struct saa7164_dev *dev, u8 unitid, u8 pin); | 538 | int saa7164_api_clear_gpiobit(struct saa7164_dev *dev, u8 unitid, u8 pin); |
346 | int saa7164_api_transition_port(struct saa7164_tsport *port, u8 mode); | 539 | int saa7164_api_transition_port(struct saa7164_port *port, u8 mode); |
540 | int saa7164_api_initialize_dif(struct saa7164_port *port); | ||
541 | int saa7164_api_configure_dif(struct saa7164_port *port, u32 std); | ||
542 | int saa7164_api_set_encoder(struct saa7164_port *port); | ||
543 | int saa7164_api_get_encoder(struct saa7164_port *port); | ||
544 | int saa7164_api_set_aspect_ratio(struct saa7164_port *port); | ||
545 | int saa7164_api_set_usercontrol(struct saa7164_port *port, u8 ctl); | ||
546 | int saa7164_api_get_usercontrol(struct saa7164_port *port, u8 ctl); | ||
547 | int saa7164_api_set_videomux(struct saa7164_port *port); | ||
548 | int saa7164_api_audio_mute(struct saa7164_port *port, int mute); | ||
549 | int saa7164_api_set_audio_volume(struct saa7164_port *port, s8 level); | ||
550 | int saa7164_api_set_audio_std(struct saa7164_port *port); | ||
551 | int saa7164_api_set_audio_detection(struct saa7164_port *port, int autodetect); | ||
552 | int saa7164_api_get_videomux(struct saa7164_port *port); | ||
553 | int saa7164_api_set_vbi_format(struct saa7164_port *port); | ||
554 | int saa7164_api_set_debug(struct saa7164_dev *dev, u8 level); | ||
555 | int saa7164_api_collect_debug(struct saa7164_dev *dev); | ||
556 | int saa7164_api_get_load_info(struct saa7164_dev *dev, struct tmFwInfoStruct *i); | ||
347 | 557 | ||
348 | /* ----------------------------------------------------------- */ | 558 | /* ----------------------------------------------------------- */ |
349 | /* saa7164-cards.c */ | 559 | /* saa7164-cards.c */ |
@@ -363,18 +573,36 @@ extern char *saa7164_unitid_name(struct saa7164_dev *dev, u8 unitid); | |||
363 | 573 | ||
364 | /* ----------------------------------------------------------- */ | 574 | /* ----------------------------------------------------------- */ |
365 | /* saa7164-dvb.c */ | 575 | /* saa7164-dvb.c */ |
366 | extern int saa7164_dvb_register(struct saa7164_tsport *port); | 576 | extern int saa7164_dvb_register(struct saa7164_port *port); |
367 | extern int saa7164_dvb_unregister(struct saa7164_tsport *port); | 577 | extern int saa7164_dvb_unregister(struct saa7164_port *port); |
368 | 578 | ||
369 | /* ----------------------------------------------------------- */ | 579 | /* ----------------------------------------------------------- */ |
370 | /* saa7164-buffer.c */ | 580 | /* saa7164-buffer.c */ |
371 | extern struct saa7164_buffer *saa7164_buffer_alloc(struct saa7164_tsport *port, | 581 | extern struct saa7164_buffer *saa7164_buffer_alloc( |
372 | u32 len); | 582 | struct saa7164_port *port, u32 len); |
373 | extern int saa7164_buffer_dealloc(struct saa7164_tsport *port, | 583 | extern int saa7164_buffer_dealloc(struct saa7164_buffer *buf); |
374 | struct saa7164_buffer *buf); | 584 | extern void saa7164_buffer_display(struct saa7164_buffer *buf); |
585 | extern int saa7164_buffer_activate(struct saa7164_buffer *buf, int i); | ||
586 | extern int saa7164_buffer_cfg_port(struct saa7164_port *port); | ||
587 | extern struct saa7164_user_buffer *saa7164_buffer_alloc_user( | ||
588 | struct saa7164_dev *dev, u32 len); | ||
589 | extern void saa7164_buffer_dealloc_user(struct saa7164_user_buffer *buf); | ||
590 | extern int saa7164_buffer_zero_offsets(struct saa7164_port *port, int i); | ||
591 | |||
592 | /* ----------------------------------------------------------- */ | ||
593 | /* saa7164-encoder.c */ | ||
594 | int saa7164_encoder_register(struct saa7164_port *port); | ||
595 | void saa7164_encoder_unregister(struct saa7164_port *port); | ||
596 | |||
597 | /* ----------------------------------------------------------- */ | ||
598 | /* saa7164-vbi.c */ | ||
599 | int saa7164_vbi_register(struct saa7164_port *port); | ||
600 | void saa7164_vbi_unregister(struct saa7164_port *port); | ||
375 | 601 | ||
376 | /* ----------------------------------------------------------- */ | 602 | /* ----------------------------------------------------------- */ |
377 | 603 | ||
604 | extern unsigned int crc_checking; | ||
605 | |||
378 | extern unsigned int saa_debug; | 606 | extern unsigned int saa_debug; |
379 | #define dprintk(level, fmt, arg...)\ | 607 | #define dprintk(level, fmt, arg...)\ |
380 | do { if (saa_debug & level)\ | 608 | do { if (saa_debug & level)\ |
@@ -394,7 +622,6 @@ extern unsigned int saa_debug; | |||
394 | #define saa7164_readl(reg) readl(dev->lmmio + ((reg) >> 2)) | 622 | #define saa7164_readl(reg) readl(dev->lmmio + ((reg) >> 2)) |
395 | #define saa7164_writel(reg, value) writel((value), dev->lmmio + ((reg) >> 2)) | 623 | #define saa7164_writel(reg, value) writel((value), dev->lmmio + ((reg) >> 2)) |
396 | 624 | ||
397 | |||
398 | #define saa7164_readb(reg) readl(dev->bmmio + (reg)) | 625 | #define saa7164_readb(reg) readl(dev->bmmio + (reg)) |
399 | #define saa7164_writeb(reg, value) writel((value), dev->bmmio + (reg)) | 626 | #define saa7164_writeb(reg, value) writel((value), dev->bmmio + (reg)) |
400 | 627 | ||