1 | // SPDX-License-Identifier: GPL-2.0-or-later |
2 | /* |
3 | * Driver for the NXP SAA7164 PCIe bridge |
4 | * |
5 | * Copyright (c) 2010-2015 Steven Toth <stoth@kernellabs.com> |
6 | */ |
7 | |
8 | #include <linux/wait.h> |
9 | #include <linux/slab.h> |
10 | |
11 | #include "saa7164.h" |
12 | |
13 | int saa7164_api_get_load_info(struct saa7164_dev *dev, struct tmFwInfoStruct *i) |
14 | { |
15 | int ret; |
16 | |
17 | if (!(saa_debug & DBGLVL_CPU)) |
18 | return 0; |
19 | |
20 | dprintk(DBGLVL_API, "%s()\n" , __func__); |
21 | |
22 | i->deviceinst = 0; |
23 | i->devicespec = 0; |
24 | i->mode = 0; |
25 | i->status = 0; |
26 | |
27 | ret = saa7164_cmd_send(dev, id: 0, command: GET_CUR, |
28 | GET_FW_STATUS_CONTROL, size: sizeof(struct tmFwInfoStruct), buf: i); |
29 | if (ret != SAA_OK) |
30 | printk(KERN_ERR "%s() error, ret = 0x%x\n" , __func__, ret); |
31 | |
32 | printk(KERN_INFO "saa7164[%d]-CPU: %d percent" , dev->nr, i->CPULoad); |
33 | |
34 | return ret; |
35 | } |
36 | |
37 | int saa7164_api_collect_debug(struct saa7164_dev *dev) |
38 | { |
39 | struct tmComResDebugGetData d; |
40 | u8 more = 255; |
41 | int ret; |
42 | |
43 | dprintk(DBGLVL_API, "%s()\n" , __func__); |
44 | |
45 | while (more--) { |
46 | |
47 | memset(&d, 0, sizeof(d)); |
48 | |
49 | ret = saa7164_cmd_send(dev, id: 0, command: GET_CUR, |
50 | GET_DEBUG_DATA_CONTROL, size: sizeof(d), buf: &d); |
51 | if (ret != SAA_OK) |
52 | printk(KERN_ERR "%s() error, ret = 0x%x\n" , |
53 | __func__, ret); |
54 | |
55 | if (d.dwResult != SAA_OK) |
56 | break; |
57 | |
58 | printk(KERN_INFO "saa7164[%d]-FWMSG: %s" , dev->nr, |
59 | d.ucDebugData); |
60 | } |
61 | |
62 | return 0; |
63 | } |
64 | |
65 | int saa7164_api_set_debug(struct saa7164_dev *dev, u8 level) |
66 | { |
67 | struct tmComResDebugSetLevel lvl; |
68 | int ret; |
69 | |
70 | dprintk(DBGLVL_API, "%s(level=%d)\n" , __func__, level); |
71 | |
72 | /* Retrieve current state */ |
73 | ret = saa7164_cmd_send(dev, id: 0, command: GET_CUR, |
74 | SET_DEBUG_LEVEL_CONTROL, size: sizeof(lvl), buf: &lvl); |
75 | if (ret != SAA_OK) |
76 | printk(KERN_ERR "%s() error, ret = 0x%x\n" , __func__, ret); |
77 | |
78 | dprintk(DBGLVL_API, "%s() Was %d\n" , __func__, lvl.dwDebugLevel); |
79 | |
80 | lvl.dwDebugLevel = level; |
81 | |
82 | /* set new state */ |
83 | ret = saa7164_cmd_send(dev, id: 0, command: SET_CUR, |
84 | SET_DEBUG_LEVEL_CONTROL, size: sizeof(lvl), buf: &lvl); |
85 | if (ret != SAA_OK) |
86 | printk(KERN_ERR "%s() error, ret = 0x%x\n" , __func__, ret); |
87 | |
88 | return ret; |
89 | } |
90 | |
91 | int saa7164_api_set_vbi_format(struct saa7164_port *port) |
92 | { |
93 | struct saa7164_dev *dev = port->dev; |
94 | struct tmComResProbeCommit fmt, rsp; |
95 | int ret; |
96 | |
97 | dprintk(DBGLVL_API, "%s(nr=%d, unitid=0x%x)\n" , __func__, |
98 | port->nr, port->hwcfg.unitid); |
99 | |
100 | fmt.bmHint = 0; |
101 | fmt.bFormatIndex = 1; |
102 | fmt.bFrameIndex = 1; |
103 | |
104 | /* Probe, see if it can support this format */ |
105 | ret = saa7164_cmd_send(dev: port->dev, id: port->hwcfg.unitid, |
106 | command: SET_CUR, SAA_PROBE_CONTROL, size: sizeof(fmt), buf: &fmt); |
107 | if (ret != SAA_OK) |
108 | printk(KERN_ERR "%s() set error, ret = 0x%x\n" , __func__, ret); |
109 | |
110 | /* See of the format change was successful */ |
111 | ret = saa7164_cmd_send(dev: port->dev, id: port->hwcfg.unitid, |
112 | command: GET_CUR, SAA_PROBE_CONTROL, size: sizeof(rsp), buf: &rsp); |
113 | if (ret != SAA_OK) { |
114 | printk(KERN_ERR "%s() get error, ret = 0x%x\n" , __func__, ret); |
115 | } else { |
116 | /* Compare requested vs received, should be same */ |
117 | if (memcmp(p: &fmt, q: &rsp, size: sizeof(rsp)) == 0) { |
118 | dprintk(DBGLVL_API, "SET/PROBE Verified\n" ); |
119 | |
120 | /* Ask the device to select the negotiated format */ |
121 | ret = saa7164_cmd_send(dev: port->dev, id: port->hwcfg.unitid, |
122 | command: SET_CUR, SAA_COMMIT_CONTROL, size: sizeof(fmt), buf: &fmt); |
123 | if (ret != SAA_OK) |
124 | printk(KERN_ERR "%s() commit error, ret = 0x%x\n" , |
125 | __func__, ret); |
126 | |
127 | ret = saa7164_cmd_send(dev: port->dev, id: port->hwcfg.unitid, |
128 | command: GET_CUR, SAA_COMMIT_CONTROL, size: sizeof(rsp), buf: &rsp); |
129 | if (ret != SAA_OK) |
130 | printk(KERN_ERR "%s() GET commit error, ret = 0x%x\n" , |
131 | __func__, ret); |
132 | |
133 | if (memcmp(p: &fmt, q: &rsp, size: sizeof(rsp)) != 0) { |
134 | printk(KERN_ERR "%s() memcmp error, ret = 0x%x\n" , |
135 | __func__, ret); |
136 | } else |
137 | dprintk(DBGLVL_API, "SET/COMMIT Verified\n" ); |
138 | |
139 | dprintk(DBGLVL_API, "rsp.bmHint = 0x%x\n" , rsp.bmHint); |
140 | dprintk(DBGLVL_API, "rsp.bFormatIndex = 0x%x\n" , |
141 | rsp.bFormatIndex); |
142 | dprintk(DBGLVL_API, "rsp.bFrameIndex = 0x%x\n" , |
143 | rsp.bFrameIndex); |
144 | } else |
145 | printk(KERN_ERR "%s() compare failed\n" , __func__); |
146 | } |
147 | |
148 | if (ret == SAA_OK) |
149 | dprintk(DBGLVL_API, "%s(nr=%d) Success\n" , __func__, port->nr); |
150 | |
151 | return ret; |
152 | } |
153 | |
154 | static int saa7164_api_set_gop_size(struct saa7164_port *port) |
155 | { |
156 | struct saa7164_dev *dev = port->dev; |
157 | struct tmComResEncVideoGopStructure gs; |
158 | int ret; |
159 | |
160 | dprintk(DBGLVL_ENC, "%s()\n" , __func__); |
161 | |
162 | gs.ucRefFrameDist = port->encoder_params.refdist; |
163 | gs.ucGOPSize = port->encoder_params.gop_size; |
164 | ret = saa7164_cmd_send(dev: port->dev, id: port->hwcfg.sourceid, command: SET_CUR, |
165 | EU_VIDEO_GOP_STRUCTURE_CONTROL, |
166 | size: sizeof(gs), buf: &gs); |
167 | if (ret != SAA_OK) |
168 | printk(KERN_ERR "%s() error, ret = 0x%x\n" , __func__, ret); |
169 | |
170 | return ret; |
171 | } |
172 | |
173 | int saa7164_api_set_encoder(struct saa7164_port *port) |
174 | { |
175 | struct saa7164_dev *dev = port->dev; |
176 | struct tmComResEncVideoBitRate vb; |
177 | struct tmComResEncAudioBitRate ab; |
178 | int ret; |
179 | |
180 | dprintk(DBGLVL_ENC, "%s() unitid=0x%x\n" , __func__, |
181 | port->hwcfg.sourceid); |
182 | |
183 | if (port->encoder_params.stream_type == V4L2_MPEG_STREAM_TYPE_MPEG2_PS) |
184 | port->encoder_profile = EU_PROFILE_PS_DVD; |
185 | else |
186 | port->encoder_profile = EU_PROFILE_TS_HQ; |
187 | |
188 | ret = saa7164_cmd_send(dev: port->dev, id: port->hwcfg.sourceid, command: SET_CUR, |
189 | EU_PROFILE_CONTROL, size: sizeof(u8), buf: &port->encoder_profile); |
190 | if (ret != SAA_OK) |
191 | printk(KERN_ERR "%s() error, ret = 0x%x\n" , __func__, ret); |
192 | |
193 | /* Resolution */ |
194 | ret = saa7164_cmd_send(dev: port->dev, id: port->hwcfg.sourceid, command: SET_CUR, |
195 | EU_PROFILE_CONTROL, size: sizeof(u8), buf: &port->encoder_profile); |
196 | if (ret != SAA_OK) |
197 | printk(KERN_ERR "%s() error, ret = 0x%x\n" , __func__, ret); |
198 | |
199 | /* Establish video bitrates */ |
200 | if (port->encoder_params.bitrate_mode == |
201 | V4L2_MPEG_VIDEO_BITRATE_MODE_CBR) |
202 | vb.ucVideoBitRateMode = EU_VIDEO_BIT_RATE_MODE_CONSTANT; |
203 | else |
204 | vb.ucVideoBitRateMode = EU_VIDEO_BIT_RATE_MODE_VARIABLE_PEAK; |
205 | vb.dwVideoBitRate = port->encoder_params.bitrate; |
206 | vb.dwVideoBitRatePeak = port->encoder_params.bitrate_peak; |
207 | ret = saa7164_cmd_send(dev: port->dev, id: port->hwcfg.sourceid, command: SET_CUR, |
208 | EU_VIDEO_BIT_RATE_CONTROL, |
209 | size: sizeof(struct tmComResEncVideoBitRate), |
210 | buf: &vb); |
211 | if (ret != SAA_OK) |
212 | printk(KERN_ERR "%s() error, ret = 0x%x\n" , __func__, ret); |
213 | |
214 | /* Establish audio bitrates */ |
215 | ab.ucAudioBitRateMode = 0; |
216 | ab.dwAudioBitRate = 384000; |
217 | ab.dwAudioBitRatePeak = ab.dwAudioBitRate; |
218 | ret = saa7164_cmd_send(dev: port->dev, id: port->hwcfg.sourceid, command: SET_CUR, |
219 | EU_AUDIO_BIT_RATE_CONTROL, |
220 | size: sizeof(struct tmComResEncAudioBitRate), |
221 | buf: &ab); |
222 | if (ret != SAA_OK) |
223 | printk(KERN_ERR "%s() error, ret = 0x%x\n" , __func__, |
224 | ret); |
225 | |
226 | saa7164_api_set_aspect_ratio(port); |
227 | saa7164_api_set_gop_size(port); |
228 | |
229 | return ret; |
230 | } |
231 | |
232 | int saa7164_api_get_encoder(struct saa7164_port *port) |
233 | { |
234 | struct saa7164_dev *dev = port->dev; |
235 | struct tmComResEncVideoBitRate v; |
236 | struct tmComResEncAudioBitRate a; |
237 | struct tmComResEncVideoInputAspectRatio ar; |
238 | int ret; |
239 | |
240 | dprintk(DBGLVL_ENC, "%s() unitid=0x%x\n" , __func__, |
241 | port->hwcfg.sourceid); |
242 | |
243 | port->encoder_profile = 0; |
244 | port->video_format = 0; |
245 | port->video_resolution = 0; |
246 | port->audio_format = 0; |
247 | |
248 | ret = saa7164_cmd_send(dev: port->dev, id: port->hwcfg.sourceid, command: GET_CUR, |
249 | EU_PROFILE_CONTROL, size: sizeof(u8), buf: &port->encoder_profile); |
250 | if (ret != SAA_OK) |
251 | printk(KERN_ERR "%s() error, ret = 0x%x\n" , __func__, ret); |
252 | |
253 | ret = saa7164_cmd_send(dev: port->dev, id: port->hwcfg.sourceid, command: GET_CUR, |
254 | EU_VIDEO_RESOLUTION_CONTROL, size: sizeof(u8), |
255 | buf: &port->video_resolution); |
256 | if (ret != SAA_OK) |
257 | printk(KERN_ERR "%s() error, ret = 0x%x\n" , __func__, ret); |
258 | |
259 | ret = saa7164_cmd_send(dev: port->dev, id: port->hwcfg.sourceid, command: GET_CUR, |
260 | EU_VIDEO_FORMAT_CONTROL, size: sizeof(u8), buf: &port->video_format); |
261 | if (ret != SAA_OK) |
262 | printk(KERN_ERR "%s() error, ret = 0x%x\n" , __func__, ret); |
263 | |
264 | ret = saa7164_cmd_send(dev: port->dev, id: port->hwcfg.sourceid, command: GET_CUR, |
265 | EU_VIDEO_BIT_RATE_CONTROL, size: sizeof(v), buf: &v); |
266 | if (ret != SAA_OK) |
267 | printk(KERN_ERR "%s() error, ret = 0x%x\n" , __func__, ret); |
268 | |
269 | ret = saa7164_cmd_send(dev: port->dev, id: port->hwcfg.sourceid, command: GET_CUR, |
270 | EU_AUDIO_FORMAT_CONTROL, size: sizeof(u8), buf: &port->audio_format); |
271 | if (ret != SAA_OK) |
272 | printk(KERN_ERR "%s() error, ret = 0x%x\n" , __func__, ret); |
273 | |
274 | ret = saa7164_cmd_send(dev: port->dev, id: port->hwcfg.sourceid, command: GET_CUR, |
275 | EU_AUDIO_BIT_RATE_CONTROL, size: sizeof(a), buf: &a); |
276 | if (ret != SAA_OK) |
277 | printk(KERN_ERR "%s() error, ret = 0x%x\n" , __func__, ret); |
278 | |
279 | /* Aspect Ratio */ |
280 | ar.width = 0; |
281 | ar.height = 0; |
282 | ret = saa7164_cmd_send(dev: port->dev, id: port->hwcfg.sourceid, command: GET_CUR, |
283 | EU_VIDEO_INPUT_ASPECT_CONTROL, |
284 | size: sizeof(struct tmComResEncVideoInputAspectRatio), buf: &ar); |
285 | if (ret != SAA_OK) |
286 | printk(KERN_ERR "%s() error, ret = 0x%x\n" , __func__, ret); |
287 | |
288 | dprintk(DBGLVL_ENC, "encoder_profile = %d\n" , port->encoder_profile); |
289 | dprintk(DBGLVL_ENC, "video_format = %d\n" , port->video_format); |
290 | dprintk(DBGLVL_ENC, "audio_format = %d\n" , port->audio_format); |
291 | dprintk(DBGLVL_ENC, "video_resolution= %d\n" , port->video_resolution); |
292 | dprintk(DBGLVL_ENC, "v.ucVideoBitRateMode = %d\n" , |
293 | v.ucVideoBitRateMode); |
294 | dprintk(DBGLVL_ENC, "v.dwVideoBitRate = %d\n" , |
295 | v.dwVideoBitRate); |
296 | dprintk(DBGLVL_ENC, "v.dwVideoBitRatePeak = %d\n" , |
297 | v.dwVideoBitRatePeak); |
298 | dprintk(DBGLVL_ENC, "a.ucVideoBitRateMode = %d\n" , |
299 | a.ucAudioBitRateMode); |
300 | dprintk(DBGLVL_ENC, "a.dwVideoBitRate = %d\n" , |
301 | a.dwAudioBitRate); |
302 | dprintk(DBGLVL_ENC, "a.dwVideoBitRatePeak = %d\n" , |
303 | a.dwAudioBitRatePeak); |
304 | dprintk(DBGLVL_ENC, "aspect.width / height = %d:%d\n" , |
305 | ar.width, ar.height); |
306 | |
307 | return ret; |
308 | } |
309 | |
310 | int saa7164_api_set_aspect_ratio(struct saa7164_port *port) |
311 | { |
312 | struct saa7164_dev *dev = port->dev; |
313 | struct tmComResEncVideoInputAspectRatio ar; |
314 | int ret; |
315 | |
316 | dprintk(DBGLVL_ENC, "%s(%d)\n" , __func__, |
317 | port->encoder_params.ctl_aspect); |
318 | |
319 | switch (port->encoder_params.ctl_aspect) { |
320 | case V4L2_MPEG_VIDEO_ASPECT_1x1: |
321 | ar.width = 1; |
322 | ar.height = 1; |
323 | break; |
324 | case V4L2_MPEG_VIDEO_ASPECT_4x3: |
325 | ar.width = 4; |
326 | ar.height = 3; |
327 | break; |
328 | case V4L2_MPEG_VIDEO_ASPECT_16x9: |
329 | ar.width = 16; |
330 | ar.height = 9; |
331 | break; |
332 | case V4L2_MPEG_VIDEO_ASPECT_221x100: |
333 | ar.width = 221; |
334 | ar.height = 100; |
335 | break; |
336 | default: |
337 | BUG(); |
338 | } |
339 | |
340 | dprintk(DBGLVL_ENC, "%s(%d) now %d:%d\n" , __func__, |
341 | port->encoder_params.ctl_aspect, |
342 | ar.width, ar.height); |
343 | |
344 | /* Aspect Ratio */ |
345 | ret = saa7164_cmd_send(dev: port->dev, id: port->hwcfg.sourceid, command: SET_CUR, |
346 | EU_VIDEO_INPUT_ASPECT_CONTROL, |
347 | size: sizeof(struct tmComResEncVideoInputAspectRatio), buf: &ar); |
348 | if (ret != SAA_OK) |
349 | printk(KERN_ERR "%s() error, ret = 0x%x\n" , __func__, ret); |
350 | |
351 | return ret; |
352 | } |
353 | |
354 | int saa7164_api_set_usercontrol(struct saa7164_port *port, u8 ctl) |
355 | { |
356 | struct saa7164_dev *dev = port->dev; |
357 | int ret; |
358 | u16 val; |
359 | |
360 | if (ctl == PU_BRIGHTNESS_CONTROL) |
361 | val = port->ctl_brightness; |
362 | else |
363 | if (ctl == PU_CONTRAST_CONTROL) |
364 | val = port->ctl_contrast; |
365 | else |
366 | if (ctl == PU_HUE_CONTROL) |
367 | val = port->ctl_hue; |
368 | else |
369 | if (ctl == PU_SATURATION_CONTROL) |
370 | val = port->ctl_saturation; |
371 | else |
372 | if (ctl == PU_SHARPNESS_CONTROL) |
373 | val = port->ctl_sharpness; |
374 | else |
375 | return -EINVAL; |
376 | |
377 | dprintk(DBGLVL_ENC, "%s() unitid=0x%x ctl=%d, val=%d\n" , |
378 | __func__, port->encunit.vsourceid, ctl, val); |
379 | |
380 | ret = saa7164_cmd_send(dev: port->dev, id: port->encunit.vsourceid, command: SET_CUR, |
381 | controlselector: ctl, size: sizeof(u16), buf: &val); |
382 | if (ret != SAA_OK) |
383 | printk(KERN_ERR "%s() error, ret = 0x%x\n" , __func__, ret); |
384 | |
385 | return ret; |
386 | } |
387 | |
388 | int saa7164_api_get_usercontrol(struct saa7164_port *port, u8 ctl) |
389 | { |
390 | struct saa7164_dev *dev = port->dev; |
391 | int ret; |
392 | u16 val; |
393 | |
394 | ret = saa7164_cmd_send(dev: port->dev, id: port->encunit.vsourceid, command: GET_CUR, |
395 | controlselector: ctl, size: sizeof(u16), buf: &val); |
396 | if (ret != SAA_OK) { |
397 | printk(KERN_ERR "%s() error, ret = 0x%x\n" , __func__, ret); |
398 | return ret; |
399 | } |
400 | |
401 | dprintk(DBGLVL_ENC, "%s() ctl=%d, val=%d\n" , |
402 | __func__, ctl, val); |
403 | |
404 | if (ctl == PU_BRIGHTNESS_CONTROL) |
405 | port->ctl_brightness = val; |
406 | else |
407 | if (ctl == PU_CONTRAST_CONTROL) |
408 | port->ctl_contrast = val; |
409 | else |
410 | if (ctl == PU_HUE_CONTROL) |
411 | port->ctl_hue = val; |
412 | else |
413 | if (ctl == PU_SATURATION_CONTROL) |
414 | port->ctl_saturation = val; |
415 | else |
416 | if (ctl == PU_SHARPNESS_CONTROL) |
417 | port->ctl_sharpness = val; |
418 | |
419 | return ret; |
420 | } |
421 | |
422 | int saa7164_api_set_videomux(struct saa7164_port *port) |
423 | { |
424 | struct saa7164_dev *dev = port->dev; |
425 | u8 inputs[] = { 1, 2, 2, 2, 5, 5, 5 }; |
426 | int ret; |
427 | |
428 | dprintk(DBGLVL_ENC, "%s() v_mux=%d a_mux=%d\n" , |
429 | __func__, port->mux_input, inputs[port->mux_input - 1]); |
430 | |
431 | /* Audio Mute */ |
432 | ret = saa7164_api_audio_mute(port, mute: 1); |
433 | if (ret != SAA_OK) |
434 | printk(KERN_ERR "%s() error, ret = 0x%x\n" , __func__, ret); |
435 | |
436 | /* Video Mux */ |
437 | ret = saa7164_cmd_send(dev: port->dev, id: port->vidproc.sourceid, command: SET_CUR, |
438 | SU_INPUT_SELECT_CONTROL, size: sizeof(u8), buf: &port->mux_input); |
439 | if (ret != SAA_OK) |
440 | printk(KERN_ERR "%s() error, ret = 0x%x\n" , __func__, ret); |
441 | |
442 | /* Audio Mux */ |
443 | ret = saa7164_cmd_send(dev: port->dev, id: port->audfeat.sourceid, command: SET_CUR, |
444 | SU_INPUT_SELECT_CONTROL, size: sizeof(u8), |
445 | buf: &inputs[port->mux_input - 1]); |
446 | if (ret != SAA_OK) |
447 | printk(KERN_ERR "%s() error, ret = 0x%x\n" , __func__, ret); |
448 | |
449 | /* Audio UnMute */ |
450 | ret = saa7164_api_audio_mute(port, mute: 0); |
451 | if (ret != SAA_OK) |
452 | printk(KERN_ERR "%s() error, ret = 0x%x\n" , __func__, ret); |
453 | |
454 | return ret; |
455 | } |
456 | |
457 | int saa7164_api_audio_mute(struct saa7164_port *port, int mute) |
458 | { |
459 | struct saa7164_dev *dev = port->dev; |
460 | u8 v = mute; |
461 | int ret; |
462 | |
463 | dprintk(DBGLVL_API, "%s(%d)\n" , __func__, mute); |
464 | |
465 | ret = saa7164_cmd_send(dev: port->dev, id: port->audfeat.unitid, command: SET_CUR, |
466 | MUTE_CONTROL, size: sizeof(u8), buf: &v); |
467 | if (ret != SAA_OK) |
468 | printk(KERN_ERR "%s() error, ret = 0x%x\n" , __func__, ret); |
469 | |
470 | return ret; |
471 | } |
472 | |
473 | /* 0 = silence, 0xff = full */ |
474 | int saa7164_api_set_audio_volume(struct saa7164_port *port, s8 level) |
475 | { |
476 | struct saa7164_dev *dev = port->dev; |
477 | s16 v, min, max; |
478 | int ret; |
479 | |
480 | dprintk(DBGLVL_API, "%s(%d)\n" , __func__, level); |
481 | |
482 | /* Obtain the min/max ranges */ |
483 | ret = saa7164_cmd_send(dev: port->dev, id: port->audfeat.unitid, command: GET_MIN, |
484 | VOLUME_CONTROL, size: sizeof(u16), buf: &min); |
485 | if (ret != SAA_OK) |
486 | printk(KERN_ERR "%s() error, ret = 0x%x\n" , __func__, ret); |
487 | |
488 | ret = saa7164_cmd_send(dev: port->dev, id: port->audfeat.unitid, command: GET_MAX, |
489 | VOLUME_CONTROL, size: sizeof(u16), buf: &max); |
490 | if (ret != SAA_OK) |
491 | printk(KERN_ERR "%s() error, ret = 0x%x\n" , __func__, ret); |
492 | |
493 | ret = saa7164_cmd_send(dev: port->dev, id: port->audfeat.unitid, command: GET_CUR, |
494 | controlselector: (0x01 << 8) | VOLUME_CONTROL, size: sizeof(u16), buf: &v); |
495 | if (ret != SAA_OK) |
496 | printk(KERN_ERR "%s() error, ret = 0x%x\n" , __func__, ret); |
497 | |
498 | dprintk(DBGLVL_API, "%s(%d) min=%d max=%d cur=%d\n" , __func__, |
499 | level, min, max, v); |
500 | |
501 | v = level; |
502 | if (v < min) |
503 | v = min; |
504 | if (v > max) |
505 | v = max; |
506 | |
507 | /* Left */ |
508 | ret = saa7164_cmd_send(dev: port->dev, id: port->audfeat.unitid, command: SET_CUR, |
509 | controlselector: (0x01 << 8) | VOLUME_CONTROL, size: sizeof(s16), buf: &v); |
510 | if (ret != SAA_OK) |
511 | printk(KERN_ERR "%s() error, ret = 0x%x\n" , __func__, ret); |
512 | |
513 | /* Right */ |
514 | ret = saa7164_cmd_send(dev: port->dev, id: port->audfeat.unitid, command: SET_CUR, |
515 | controlselector: (0x02 << 8) | VOLUME_CONTROL, size: sizeof(s16), buf: &v); |
516 | if (ret != SAA_OK) |
517 | printk(KERN_ERR "%s() error, ret = 0x%x\n" , __func__, ret); |
518 | |
519 | ret = saa7164_cmd_send(dev: port->dev, id: port->audfeat.unitid, command: GET_CUR, |
520 | controlselector: (0x01 << 8) | VOLUME_CONTROL, size: sizeof(u16), buf: &v); |
521 | if (ret != SAA_OK) |
522 | printk(KERN_ERR "%s() error, ret = 0x%x\n" , __func__, ret); |
523 | |
524 | dprintk(DBGLVL_API, "%s(%d) min=%d max=%d cur=%d\n" , __func__, |
525 | level, min, max, v); |
526 | |
527 | return ret; |
528 | } |
529 | |
530 | int saa7164_api_set_audio_std(struct saa7164_port *port) |
531 | { |
532 | struct saa7164_dev *dev = port->dev; |
533 | struct tmComResAudioDefaults lvl; |
534 | struct tmComResTunerStandard tvaudio; |
535 | int ret; |
536 | |
537 | dprintk(DBGLVL_API, "%s()\n" , __func__); |
538 | |
539 | /* Establish default levels */ |
540 | lvl.ucDecoderLevel = TMHW_LEV_ADJ_DECLEV_DEFAULT; |
541 | lvl.ucDecoderFM_Level = TMHW_LEV_ADJ_DECLEV_DEFAULT; |
542 | lvl.ucMonoLevel = TMHW_LEV_ADJ_MONOLEV_DEFAULT; |
543 | lvl.ucNICAM_Level = TMHW_LEV_ADJ_NICLEV_DEFAULT; |
544 | lvl.ucSAP_Level = TMHW_LEV_ADJ_SAPLEV_DEFAULT; |
545 | lvl.ucADC_Level = TMHW_LEV_ADJ_ADCLEV_DEFAULT; |
546 | ret = saa7164_cmd_send(dev: port->dev, id: port->audfeat.unitid, command: SET_CUR, |
547 | AUDIO_DEFAULT_CONTROL, size: sizeof(struct tmComResAudioDefaults), |
548 | buf: &lvl); |
549 | if (ret != SAA_OK) |
550 | printk(KERN_ERR "%s() error, ret = 0x%x\n" , __func__, ret); |
551 | |
552 | /* Manually select the appropriate TV audio standard */ |
553 | if (port->encodernorm.id & V4L2_STD_NTSC) { |
554 | tvaudio.std = TU_STANDARD_NTSC_M; |
555 | tvaudio.country = 1; |
556 | } else { |
557 | tvaudio.std = TU_STANDARD_PAL_I; |
558 | tvaudio.country = 44; |
559 | } |
560 | |
561 | ret = saa7164_cmd_send(dev: port->dev, id: port->tunerunit.unitid, command: SET_CUR, |
562 | TU_STANDARD_CONTROL, size: sizeof(tvaudio), buf: &tvaudio); |
563 | if (ret != SAA_OK) |
564 | printk(KERN_ERR "%s() TU_STANDARD_CONTROL error, ret = 0x%x\n" , |
565 | __func__, ret); |
566 | return ret; |
567 | } |
568 | |
569 | int saa7164_api_set_audio_detection(struct saa7164_port *port, int autodetect) |
570 | { |
571 | struct saa7164_dev *dev = port->dev; |
572 | struct tmComResTunerStandardAuto p; |
573 | int ret; |
574 | |
575 | dprintk(DBGLVL_API, "%s(%d)\n" , __func__, autodetect); |
576 | |
577 | /* Disable TV Audio autodetect if not already set (buggy) */ |
578 | if (autodetect) |
579 | p.mode = TU_STANDARD_AUTO; |
580 | else |
581 | p.mode = TU_STANDARD_MANUAL; |
582 | ret = saa7164_cmd_send(dev: port->dev, id: port->tunerunit.unitid, command: SET_CUR, |
583 | TU_STANDARD_AUTO_CONTROL, size: sizeof(p), buf: &p); |
584 | if (ret != SAA_OK) |
585 | printk(KERN_ERR |
586 | "%s() TU_STANDARD_AUTO_CONTROL error, ret = 0x%x\n" , |
587 | __func__, ret); |
588 | |
589 | return ret; |
590 | } |
591 | |
592 | int saa7164_api_get_videomux(struct saa7164_port *port) |
593 | { |
594 | struct saa7164_dev *dev = port->dev; |
595 | int ret; |
596 | |
597 | ret = saa7164_cmd_send(dev: port->dev, id: port->vidproc.sourceid, command: GET_CUR, |
598 | SU_INPUT_SELECT_CONTROL, size: sizeof(u8), buf: &port->mux_input); |
599 | if (ret != SAA_OK) |
600 | printk(KERN_ERR "%s() error, ret = 0x%x\n" , __func__, ret); |
601 | |
602 | dprintk(DBGLVL_ENC, "%s() v_mux=%d\n" , |
603 | __func__, port->mux_input); |
604 | |
605 | return ret; |
606 | } |
607 | |
608 | static int saa7164_api_set_dif(struct saa7164_port *port, u8 reg, u8 val) |
609 | { |
610 | struct saa7164_dev *dev = port->dev; |
611 | |
612 | u16 len = 0; |
613 | u8 buf[256]; |
614 | int ret; |
615 | u8 mas; |
616 | |
617 | dprintk(DBGLVL_API, "%s(nr=%d type=%d val=%x)\n" , __func__, |
618 | port->nr, port->type, val); |
619 | |
620 | if (port->nr == 0) |
621 | mas = 0xd0; |
622 | else |
623 | mas = 0xe0; |
624 | |
625 | memset(buf, 0, sizeof(buf)); |
626 | |
627 | buf[0x00] = 0x04; |
628 | buf[0x01] = 0x00; |
629 | buf[0x02] = 0x00; |
630 | buf[0x03] = 0x00; |
631 | |
632 | buf[0x04] = 0x04; |
633 | buf[0x05] = 0x00; |
634 | buf[0x06] = 0x00; |
635 | buf[0x07] = 0x00; |
636 | |
637 | buf[0x08] = reg; |
638 | buf[0x09] = 0x26; |
639 | buf[0x0a] = mas; |
640 | buf[0x0b] = 0xb0; |
641 | |
642 | buf[0x0c] = val; |
643 | buf[0x0d] = 0x00; |
644 | buf[0x0e] = 0x00; |
645 | buf[0x0f] = 0x00; |
646 | |
647 | ret = saa7164_cmd_send(dev, id: port->ifunit.unitid, command: GET_LEN, |
648 | EXU_REGISTER_ACCESS_CONTROL, size: sizeof(len), buf: &len); |
649 | if (ret != SAA_OK) { |
650 | printk(KERN_ERR "%s() error, ret(1) = 0x%x\n" , __func__, ret); |
651 | return -EIO; |
652 | } |
653 | |
654 | ret = saa7164_cmd_send(dev, id: port->ifunit.unitid, command: SET_CUR, |
655 | EXU_REGISTER_ACCESS_CONTROL, size: len, buf: &buf); |
656 | if (ret != SAA_OK) |
657 | printk(KERN_ERR "%s() error, ret(2) = 0x%x\n" , __func__, ret); |
658 | #if 0 |
659 | print_hex_dump(KERN_INFO, "" , DUMP_PREFIX_OFFSET, 16, 1, buf, 16, |
660 | false); |
661 | #endif |
662 | return ret == SAA_OK ? 0 : -EIO; |
663 | } |
664 | |
665 | /* Disable the IF block AGC controls */ |
666 | int saa7164_api_configure_dif(struct saa7164_port *port, u32 std) |
667 | { |
668 | struct saa7164_dev *dev = port->dev; |
669 | u8 agc_disable; |
670 | |
671 | dprintk(DBGLVL_API, "%s(nr=%d, 0x%x)\n" , __func__, port->nr, std); |
672 | |
673 | if (std & V4L2_STD_NTSC) { |
674 | dprintk(DBGLVL_API, " NTSC\n" ); |
675 | saa7164_api_set_dif(port, reg: 0x00, val: 0x01); /* Video Standard */ |
676 | agc_disable = 0; |
677 | } else if (std & V4L2_STD_PAL_I) { |
678 | dprintk(DBGLVL_API, " PAL-I\n" ); |
679 | saa7164_api_set_dif(port, reg: 0x00, val: 0x08); /* Video Standard */ |
680 | agc_disable = 0; |
681 | } else if (std & V4L2_STD_PAL_M) { |
682 | dprintk(DBGLVL_API, " PAL-M\n" ); |
683 | saa7164_api_set_dif(port, reg: 0x00, val: 0x01); /* Video Standard */ |
684 | agc_disable = 0; |
685 | } else if (std & V4L2_STD_PAL_N) { |
686 | dprintk(DBGLVL_API, " PAL-N\n" ); |
687 | saa7164_api_set_dif(port, reg: 0x00, val: 0x01); /* Video Standard */ |
688 | agc_disable = 0; |
689 | } else if (std & V4L2_STD_PAL_Nc) { |
690 | dprintk(DBGLVL_API, " PAL-Nc\n" ); |
691 | saa7164_api_set_dif(port, reg: 0x00, val: 0x01); /* Video Standard */ |
692 | agc_disable = 0; |
693 | } else if (std & V4L2_STD_PAL_B) { |
694 | dprintk(DBGLVL_API, " PAL-B\n" ); |
695 | saa7164_api_set_dif(port, reg: 0x00, val: 0x02); /* Video Standard */ |
696 | agc_disable = 0; |
697 | } else if (std & V4L2_STD_PAL_DK) { |
698 | dprintk(DBGLVL_API, " PAL-DK\n" ); |
699 | saa7164_api_set_dif(port, reg: 0x00, val: 0x10); /* Video Standard */ |
700 | agc_disable = 0; |
701 | } else if (std & V4L2_STD_SECAM_L) { |
702 | dprintk(DBGLVL_API, " SECAM-L\n" ); |
703 | saa7164_api_set_dif(port, reg: 0x00, val: 0x20); /* Video Standard */ |
704 | agc_disable = 0; |
705 | } else { |
706 | /* Unknown standard, assume DTV */ |
707 | dprintk(DBGLVL_API, " Unknown (assuming DTV)\n" ); |
708 | /* Undefinded Video Standard */ |
709 | saa7164_api_set_dif(port, reg: 0x00, val: 0x80); |
710 | agc_disable = 1; |
711 | } |
712 | |
713 | saa7164_api_set_dif(port, reg: 0x48, val: 0xa0); /* AGC Functions 1 */ |
714 | saa7164_api_set_dif(port, reg: 0xc0, val: agc_disable); /* AGC Output Disable */ |
715 | saa7164_api_set_dif(port, reg: 0x7c, val: 0x04); /* CVBS EQ */ |
716 | saa7164_api_set_dif(port, reg: 0x04, val: 0x01); /* Active */ |
717 | msleep(msecs: 100); |
718 | saa7164_api_set_dif(port, reg: 0x04, val: 0x00); /* Active (again) */ |
719 | msleep(msecs: 100); |
720 | |
721 | return 0; |
722 | } |
723 | |
724 | /* Ensure the dif is in the correct state for the operating mode |
725 | * (analog / dtv). We only configure the diff through the analog encoder |
726 | * so when we're in digital mode we need to find the appropriate encoder |
727 | * and use it to configure the DIF. |
728 | */ |
729 | int saa7164_api_initialize_dif(struct saa7164_port *port) |
730 | { |
731 | struct saa7164_dev *dev = port->dev; |
732 | struct saa7164_port *p = NULL; |
733 | int ret = -EINVAL; |
734 | u32 std = 0; |
735 | |
736 | dprintk(DBGLVL_API, "%s(nr=%d type=%d)\n" , __func__, |
737 | port->nr, port->type); |
738 | |
739 | if (port->type == SAA7164_MPEG_ENCODER) { |
740 | /* Pick any analog standard to init the diff. |
741 | * we'll come back during encoder_init' |
742 | * and set the correct standard if required. |
743 | */ |
744 | std = V4L2_STD_NTSC; |
745 | } else |
746 | if (port->type == SAA7164_MPEG_DVB) { |
747 | if (port->nr == SAA7164_PORT_TS1) |
748 | p = &dev->ports[SAA7164_PORT_ENC1]; |
749 | else |
750 | p = &dev->ports[SAA7164_PORT_ENC2]; |
751 | } else |
752 | if (port->type == SAA7164_MPEG_VBI) { |
753 | std = V4L2_STD_NTSC; |
754 | if (port->nr == SAA7164_PORT_VBI1) |
755 | p = &dev->ports[SAA7164_PORT_ENC1]; |
756 | else |
757 | p = &dev->ports[SAA7164_PORT_ENC2]; |
758 | } else |
759 | BUG(); |
760 | |
761 | if (p) |
762 | ret = saa7164_api_configure_dif(port: p, std); |
763 | |
764 | return ret; |
765 | } |
766 | |
767 | int saa7164_api_transition_port(struct saa7164_port *port, u8 mode) |
768 | { |
769 | struct saa7164_dev *dev = port->dev; |
770 | |
771 | int ret; |
772 | |
773 | dprintk(DBGLVL_API, "%s(nr=%d unitid=0x%x,%d)\n" , |
774 | __func__, port->nr, port->hwcfg.unitid, mode); |
775 | |
776 | ret = saa7164_cmd_send(dev: port->dev, id: port->hwcfg.unitid, command: SET_CUR, |
777 | SAA_STATE_CONTROL, size: sizeof(mode), buf: &mode); |
778 | if (ret != SAA_OK) |
779 | printk(KERN_ERR "%s(portnr %d unitid 0x%x) error, ret = 0x%x\n" , |
780 | __func__, port->nr, port->hwcfg.unitid, ret); |
781 | |
782 | return ret; |
783 | } |
784 | |
785 | int saa7164_api_get_fw_version(struct saa7164_dev *dev, u32 *version) |
786 | { |
787 | int ret; |
788 | |
789 | ret = saa7164_cmd_send(dev, id: 0, command: GET_CUR, |
790 | GET_FW_VERSION_CONTROL, size: sizeof(u32), buf: version); |
791 | if (ret != SAA_OK) |
792 | printk(KERN_ERR "%s() error, ret = 0x%x\n" , __func__, ret); |
793 | |
794 | return ret; |
795 | } |
796 | |
797 | int saa7164_api_read_eeprom(struct saa7164_dev *dev, u8 *buf, int buflen) |
798 | { |
799 | u8 reg[] = { 0x0f, 0x00 }; |
800 | |
801 | if (buflen < 128) |
802 | return -ENOMEM; |
803 | |
804 | /* Assumption: Hauppauge eeprom is at 0xa0 on bus 0 */ |
805 | /* TODO: Pull the details from the boards struct */ |
806 | return saa7164_api_i2c_read(bus: &dev->i2c_bus[0], addr: 0xa0 >> 1, reglen: sizeof(reg), |
807 | reg: ®[0], datalen: 128, data: buf); |
808 | } |
809 | |
810 | static int saa7164_api_configure_port_vbi(struct saa7164_dev *dev, |
811 | struct saa7164_port *port) |
812 | { |
813 | struct tmComResVBIFormatDescrHeader *fmt = &port->vbi_fmt_ntsc; |
814 | |
815 | dprintk(DBGLVL_API, " bFormatIndex = 0x%x\n" , fmt->bFormatIndex); |
816 | dprintk(DBGLVL_API, " VideoStandard = 0x%x\n" , fmt->VideoStandard); |
817 | dprintk(DBGLVL_API, " StartLine = %d\n" , fmt->StartLine); |
818 | dprintk(DBGLVL_API, " EndLine = %d\n" , fmt->EndLine); |
819 | dprintk(DBGLVL_API, " FieldRate = %d\n" , fmt->FieldRate); |
820 | dprintk(DBGLVL_API, " bNumLines = %d\n" , fmt->bNumLines); |
821 | |
822 | /* Cache the hardware configuration in the port */ |
823 | |
824 | port->bufcounter = port->hwcfg.BARLocation; |
825 | port->pitch = port->hwcfg.BARLocation + (2 * sizeof(u32)); |
826 | port->bufsize = port->hwcfg.BARLocation + (3 * sizeof(u32)); |
827 | port->bufoffset = port->hwcfg.BARLocation + (4 * sizeof(u32)); |
828 | port->bufptr32l = port->hwcfg.BARLocation + |
829 | (4 * sizeof(u32)) + |
830 | (sizeof(u32) * port->hwcfg.buffercount) + sizeof(u32); |
831 | port->bufptr32h = port->hwcfg.BARLocation + |
832 | (4 * sizeof(u32)) + |
833 | (sizeof(u32) * port->hwcfg.buffercount); |
834 | port->bufptr64 = port->hwcfg.BARLocation + |
835 | (4 * sizeof(u32)) + |
836 | (sizeof(u32) * port->hwcfg.buffercount); |
837 | dprintk(DBGLVL_API, " = port->hwcfg.BARLocation = 0x%x\n" , |
838 | port->hwcfg.BARLocation); |
839 | |
840 | dprintk(DBGLVL_API, " = VS_FORMAT_VBI (becomes dev->en[%d])\n" , |
841 | port->nr); |
842 | |
843 | return 0; |
844 | } |
845 | |
846 | static int |
847 | saa7164_api_configure_port_mpeg2ts(struct saa7164_dev *dev, |
848 | struct saa7164_port *port, |
849 | struct tmComResTSFormatDescrHeader *tsfmt) |
850 | { |
851 | dprintk(DBGLVL_API, " bFormatIndex = 0x%x\n" , tsfmt->bFormatIndex); |
852 | dprintk(DBGLVL_API, " bDataOffset = 0x%x\n" , tsfmt->bDataOffset); |
853 | dprintk(DBGLVL_API, " bPacketLength= 0x%x\n" , tsfmt->bPacketLength); |
854 | dprintk(DBGLVL_API, " bStrideLength= 0x%x\n" , tsfmt->bStrideLength); |
855 | dprintk(DBGLVL_API, " bguid = (....)\n" ); |
856 | |
857 | /* Cache the hardware configuration in the port */ |
858 | |
859 | port->bufcounter = port->hwcfg.BARLocation; |
860 | port->pitch = port->hwcfg.BARLocation + (2 * sizeof(u32)); |
861 | port->bufsize = port->hwcfg.BARLocation + (3 * sizeof(u32)); |
862 | port->bufoffset = port->hwcfg.BARLocation + (4 * sizeof(u32)); |
863 | port->bufptr32l = port->hwcfg.BARLocation + |
864 | (4 * sizeof(u32)) + |
865 | (sizeof(u32) * port->hwcfg.buffercount) + sizeof(u32); |
866 | port->bufptr32h = port->hwcfg.BARLocation + |
867 | (4 * sizeof(u32)) + |
868 | (sizeof(u32) * port->hwcfg.buffercount); |
869 | port->bufptr64 = port->hwcfg.BARLocation + |
870 | (4 * sizeof(u32)) + |
871 | (sizeof(u32) * port->hwcfg.buffercount); |
872 | dprintk(DBGLVL_API, " = port->hwcfg.BARLocation = 0x%x\n" , |
873 | port->hwcfg.BARLocation); |
874 | |
875 | dprintk(DBGLVL_API, " = VS_FORMAT_MPEGTS (becomes dev->ts[%d])\n" , |
876 | port->nr); |
877 | |
878 | return 0; |
879 | } |
880 | |
881 | static int |
882 | saa7164_api_configure_port_mpeg2ps(struct saa7164_dev *dev, |
883 | struct saa7164_port *port, |
884 | struct tmComResPSFormatDescrHeader *fmt) |
885 | { |
886 | dprintk(DBGLVL_API, " bFormatIndex = 0x%x\n" , fmt->bFormatIndex); |
887 | dprintk(DBGLVL_API, " wPacketLength= 0x%x\n" , fmt->wPacketLength); |
888 | dprintk(DBGLVL_API, " wPackLength= 0x%x\n" , fmt->wPackLength); |
889 | dprintk(DBGLVL_API, " bPackDataType= 0x%x\n" , fmt->bPackDataType); |
890 | |
891 | /* Cache the hardware configuration in the port */ |
892 | /* TODO: CHECK THIS in the port config */ |
893 | port->bufcounter = port->hwcfg.BARLocation; |
894 | port->pitch = port->hwcfg.BARLocation + (2 * sizeof(u32)); |
895 | port->bufsize = port->hwcfg.BARLocation + (3 * sizeof(u32)); |
896 | port->bufoffset = port->hwcfg.BARLocation + (4 * sizeof(u32)); |
897 | port->bufptr32l = port->hwcfg.BARLocation + |
898 | (4 * sizeof(u32)) + |
899 | (sizeof(u32) * port->hwcfg.buffercount) + sizeof(u32); |
900 | port->bufptr32h = port->hwcfg.BARLocation + |
901 | (4 * sizeof(u32)) + |
902 | (sizeof(u32) * port->hwcfg.buffercount); |
903 | port->bufptr64 = port->hwcfg.BARLocation + |
904 | (4 * sizeof(u32)) + |
905 | (sizeof(u32) * port->hwcfg.buffercount); |
906 | dprintk(DBGLVL_API, " = port->hwcfg.BARLocation = 0x%x\n" , |
907 | port->hwcfg.BARLocation); |
908 | |
909 | dprintk(DBGLVL_API, " = VS_FORMAT_MPEGPS (becomes dev->enc[%d])\n" , |
910 | port->nr); |
911 | |
912 | return 0; |
913 | } |
914 | |
915 | static int saa7164_api_dump_subdevs(struct saa7164_dev *dev, u8 *buf, int len) |
916 | { |
917 | struct saa7164_port *tsport = NULL; |
918 | struct saa7164_port *encport = NULL; |
919 | struct saa7164_port *vbiport = NULL; |
920 | u32 idx, next_offset; |
921 | int i; |
922 | struct tmComResDescrHeader *hdr, *t; |
923 | struct tmComResExtDevDescrHeader *exthdr; |
924 | struct tmComResPathDescrHeader *pathhdr; |
925 | struct tmComResAntTermDescrHeader *anttermhdr; |
926 | struct tmComResTunerDescrHeader *tunerunithdr; |
927 | struct tmComResDMATermDescrHeader *vcoutputtermhdr; |
928 | struct tmComResTSFormatDescrHeader *tsfmt; |
929 | struct tmComResPSFormatDescrHeader *psfmt; |
930 | struct tmComResSelDescrHeader *psel; |
931 | struct tmComResProcDescrHeader *pdh; |
932 | struct tmComResAFeatureDescrHeader *afd; |
933 | struct tmComResEncoderDescrHeader *edh; |
934 | struct tmComResVBIFormatDescrHeader *vbifmt; |
935 | u32 currpath = 0; |
936 | |
937 | dprintk(DBGLVL_API, |
938 | "%s(?,?,%d) sizeof(struct tmComResDescrHeader) = %d bytes\n" , |
939 | __func__, len, (u32)sizeof(struct tmComResDescrHeader)); |
940 | |
941 | for (idx = 0; idx < (len - sizeof(struct tmComResDescrHeader));) { |
942 | |
943 | hdr = (struct tmComResDescrHeader *)(buf + idx); |
944 | |
945 | if (hdr->type != CS_INTERFACE) |
946 | return SAA_ERR_NOT_SUPPORTED; |
947 | |
948 | dprintk(DBGLVL_API, "@ 0x%x =\n" , idx); |
949 | switch (hdr->subtype) { |
950 | case GENERAL_REQUEST: |
951 | dprintk(DBGLVL_API, " GENERAL_REQUEST\n" ); |
952 | break; |
953 | case VC_TUNER_PATH: |
954 | dprintk(DBGLVL_API, " VC_TUNER_PATH\n" ); |
955 | pathhdr = (struct tmComResPathDescrHeader *)(buf + idx); |
956 | dprintk(DBGLVL_API, " pathid = 0x%x\n" , |
957 | pathhdr->pathid); |
958 | currpath = pathhdr->pathid; |
959 | break; |
960 | case VC_INPUT_TERMINAL: |
961 | dprintk(DBGLVL_API, " VC_INPUT_TERMINAL\n" ); |
962 | anttermhdr = |
963 | (struct tmComResAntTermDescrHeader *)(buf + idx); |
964 | dprintk(DBGLVL_API, " terminalid = 0x%x\n" , |
965 | anttermhdr->terminalid); |
966 | dprintk(DBGLVL_API, " terminaltype = 0x%x\n" , |
967 | anttermhdr->terminaltype); |
968 | switch (anttermhdr->terminaltype) { |
969 | case ITT_ANTENNA: |
970 | dprintk(DBGLVL_API, " = ITT_ANTENNA\n" ); |
971 | break; |
972 | case LINE_CONNECTOR: |
973 | dprintk(DBGLVL_API, " = LINE_CONNECTOR\n" ); |
974 | break; |
975 | case SPDIF_CONNECTOR: |
976 | dprintk(DBGLVL_API, " = SPDIF_CONNECTOR\n" ); |
977 | break; |
978 | case COMPOSITE_CONNECTOR: |
979 | dprintk(DBGLVL_API, |
980 | " = COMPOSITE_CONNECTOR\n" ); |
981 | break; |
982 | case SVIDEO_CONNECTOR: |
983 | dprintk(DBGLVL_API, " = SVIDEO_CONNECTOR\n" ); |
984 | break; |
985 | case COMPONENT_CONNECTOR: |
986 | dprintk(DBGLVL_API, |
987 | " = COMPONENT_CONNECTOR\n" ); |
988 | break; |
989 | case STANDARD_DMA: |
990 | dprintk(DBGLVL_API, " = STANDARD_DMA\n" ); |
991 | break; |
992 | default: |
993 | dprintk(DBGLVL_API, " = undefined (0x%x)\n" , |
994 | anttermhdr->terminaltype); |
995 | } |
996 | dprintk(DBGLVL_API, " assocterminal= 0x%x\n" , |
997 | anttermhdr->assocterminal); |
998 | dprintk(DBGLVL_API, " iterminal = 0x%x\n" , |
999 | anttermhdr->iterminal); |
1000 | dprintk(DBGLVL_API, " controlsize = 0x%x\n" , |
1001 | anttermhdr->controlsize); |
1002 | break; |
1003 | case VC_OUTPUT_TERMINAL: |
1004 | dprintk(DBGLVL_API, " VC_OUTPUT_TERMINAL\n" ); |
1005 | vcoutputtermhdr = |
1006 | (struct tmComResDMATermDescrHeader *)(buf + idx); |
1007 | dprintk(DBGLVL_API, " unitid = 0x%x\n" , |
1008 | vcoutputtermhdr->unitid); |
1009 | dprintk(DBGLVL_API, " terminaltype = 0x%x\n" , |
1010 | vcoutputtermhdr->terminaltype); |
1011 | switch (vcoutputtermhdr->terminaltype) { |
1012 | case ITT_ANTENNA: |
1013 | dprintk(DBGLVL_API, " = ITT_ANTENNA\n" ); |
1014 | break; |
1015 | case LINE_CONNECTOR: |
1016 | dprintk(DBGLVL_API, " = LINE_CONNECTOR\n" ); |
1017 | break; |
1018 | case SPDIF_CONNECTOR: |
1019 | dprintk(DBGLVL_API, " = SPDIF_CONNECTOR\n" ); |
1020 | break; |
1021 | case COMPOSITE_CONNECTOR: |
1022 | dprintk(DBGLVL_API, |
1023 | " = COMPOSITE_CONNECTOR\n" ); |
1024 | break; |
1025 | case SVIDEO_CONNECTOR: |
1026 | dprintk(DBGLVL_API, " = SVIDEO_CONNECTOR\n" ); |
1027 | break; |
1028 | case COMPONENT_CONNECTOR: |
1029 | dprintk(DBGLVL_API, |
1030 | " = COMPONENT_CONNECTOR\n" ); |
1031 | break; |
1032 | case STANDARD_DMA: |
1033 | dprintk(DBGLVL_API, " = STANDARD_DMA\n" ); |
1034 | break; |
1035 | default: |
1036 | dprintk(DBGLVL_API, " = undefined (0x%x)\n" , |
1037 | vcoutputtermhdr->terminaltype); |
1038 | } |
1039 | dprintk(DBGLVL_API, " assocterminal= 0x%x\n" , |
1040 | vcoutputtermhdr->assocterminal); |
1041 | dprintk(DBGLVL_API, " sourceid = 0x%x\n" , |
1042 | vcoutputtermhdr->sourceid); |
1043 | dprintk(DBGLVL_API, " iterminal = 0x%x\n" , |
1044 | vcoutputtermhdr->iterminal); |
1045 | dprintk(DBGLVL_API, " BARLocation = 0x%x\n" , |
1046 | vcoutputtermhdr->BARLocation); |
1047 | dprintk(DBGLVL_API, " flags = 0x%x\n" , |
1048 | vcoutputtermhdr->flags); |
1049 | dprintk(DBGLVL_API, " interruptid = 0x%x\n" , |
1050 | vcoutputtermhdr->interruptid); |
1051 | dprintk(DBGLVL_API, " buffercount = 0x%x\n" , |
1052 | vcoutputtermhdr->buffercount); |
1053 | dprintk(DBGLVL_API, " metadatasize = 0x%x\n" , |
1054 | vcoutputtermhdr->metadatasize); |
1055 | dprintk(DBGLVL_API, " controlsize = 0x%x\n" , |
1056 | vcoutputtermhdr->controlsize); |
1057 | dprintk(DBGLVL_API, " numformats = 0x%x\n" , |
1058 | vcoutputtermhdr->numformats); |
1059 | |
1060 | next_offset = idx + (vcoutputtermhdr->len); |
1061 | for (i = 0; i < vcoutputtermhdr->numformats; i++) { |
1062 | t = (struct tmComResDescrHeader *) |
1063 | (buf + next_offset); |
1064 | switch (t->subtype) { |
1065 | case VS_FORMAT_MPEG2TS: |
1066 | tsfmt = |
1067 | (struct tmComResTSFormatDescrHeader *)t; |
1068 | if (currpath == 1) |
1069 | tsport = &dev->ports[SAA7164_PORT_TS1]; |
1070 | else |
1071 | tsport = &dev->ports[SAA7164_PORT_TS2]; |
1072 | memcpy(&tsport->hwcfg, vcoutputtermhdr, |
1073 | sizeof(*vcoutputtermhdr)); |
1074 | saa7164_api_configure_port_mpeg2ts(dev, |
1075 | port: tsport, tsfmt); |
1076 | break; |
1077 | case VS_FORMAT_MPEG2PS: |
1078 | psfmt = |
1079 | (struct tmComResPSFormatDescrHeader *)t; |
1080 | if (currpath == 1) |
1081 | encport = &dev->ports[SAA7164_PORT_ENC1]; |
1082 | else |
1083 | encport = &dev->ports[SAA7164_PORT_ENC2]; |
1084 | memcpy(&encport->hwcfg, vcoutputtermhdr, |
1085 | sizeof(*vcoutputtermhdr)); |
1086 | saa7164_api_configure_port_mpeg2ps(dev, |
1087 | port: encport, fmt: psfmt); |
1088 | break; |
1089 | case VS_FORMAT_VBI: |
1090 | vbifmt = |
1091 | (struct tmComResVBIFormatDescrHeader *)t; |
1092 | if (currpath == 1) |
1093 | vbiport = &dev->ports[SAA7164_PORT_VBI1]; |
1094 | else |
1095 | vbiport = &dev->ports[SAA7164_PORT_VBI2]; |
1096 | memcpy(&vbiport->hwcfg, vcoutputtermhdr, |
1097 | sizeof(*vcoutputtermhdr)); |
1098 | memcpy(&vbiport->vbi_fmt_ntsc, vbifmt, |
1099 | sizeof(*vbifmt)); |
1100 | saa7164_api_configure_port_vbi(dev, |
1101 | port: vbiport); |
1102 | break; |
1103 | case VS_FORMAT_RDS: |
1104 | dprintk(DBGLVL_API, |
1105 | " = VS_FORMAT_RDS\n" ); |
1106 | break; |
1107 | case VS_FORMAT_UNCOMPRESSED: |
1108 | dprintk(DBGLVL_API, |
1109 | " = VS_FORMAT_UNCOMPRESSED\n" ); |
1110 | break; |
1111 | case VS_FORMAT_TYPE: |
1112 | dprintk(DBGLVL_API, |
1113 | " = VS_FORMAT_TYPE\n" ); |
1114 | break; |
1115 | default: |
1116 | dprintk(DBGLVL_API, |
1117 | " = undefined (0x%x)\n" , |
1118 | t->subtype); |
1119 | } |
1120 | next_offset += t->len; |
1121 | } |
1122 | |
1123 | break; |
1124 | case TUNER_UNIT: |
1125 | dprintk(DBGLVL_API, " TUNER_UNIT\n" ); |
1126 | tunerunithdr = |
1127 | (struct tmComResTunerDescrHeader *)(buf + idx); |
1128 | dprintk(DBGLVL_API, " unitid = 0x%x\n" , |
1129 | tunerunithdr->unitid); |
1130 | dprintk(DBGLVL_API, " sourceid = 0x%x\n" , |
1131 | tunerunithdr->sourceid); |
1132 | dprintk(DBGLVL_API, " iunit = 0x%x\n" , |
1133 | tunerunithdr->iunit); |
1134 | dprintk(DBGLVL_API, " tuningstandards = 0x%x\n" , |
1135 | tunerunithdr->tuningstandards); |
1136 | dprintk(DBGLVL_API, " controlsize = 0x%x\n" , |
1137 | tunerunithdr->controlsize); |
1138 | dprintk(DBGLVL_API, " controls = 0x%x\n" , |
1139 | tunerunithdr->controls); |
1140 | |
1141 | if (tunerunithdr->unitid == tunerunithdr->iunit) { |
1142 | if (currpath == 1) |
1143 | encport = &dev->ports[SAA7164_PORT_ENC1]; |
1144 | else |
1145 | encport = &dev->ports[SAA7164_PORT_ENC2]; |
1146 | memcpy(&encport->tunerunit, tunerunithdr, |
1147 | sizeof(struct tmComResTunerDescrHeader)); |
1148 | dprintk(DBGLVL_API, |
1149 | " (becomes dev->enc[%d] tuner)\n" , |
1150 | encport->nr); |
1151 | } |
1152 | break; |
1153 | case VC_SELECTOR_UNIT: |
1154 | psel = (struct tmComResSelDescrHeader *)(buf + idx); |
1155 | dprintk(DBGLVL_API, " VC_SELECTOR_UNIT\n" ); |
1156 | dprintk(DBGLVL_API, " unitid = 0x%x\n" , |
1157 | psel->unitid); |
1158 | dprintk(DBGLVL_API, " nrinpins = 0x%x\n" , |
1159 | psel->nrinpins); |
1160 | dprintk(DBGLVL_API, " sourceid = 0x%x\n" , |
1161 | psel->sourceid); |
1162 | break; |
1163 | case VC_PROCESSING_UNIT: |
1164 | pdh = (struct tmComResProcDescrHeader *)(buf + idx); |
1165 | dprintk(DBGLVL_API, " VC_PROCESSING_UNIT\n" ); |
1166 | dprintk(DBGLVL_API, " unitid = 0x%x\n" , |
1167 | pdh->unitid); |
1168 | dprintk(DBGLVL_API, " sourceid = 0x%x\n" , |
1169 | pdh->sourceid); |
1170 | dprintk(DBGLVL_API, " controlsize = 0x%x\n" , |
1171 | pdh->controlsize); |
1172 | if (pdh->controlsize == 0x04) { |
1173 | if (currpath == 1) |
1174 | encport = &dev->ports[SAA7164_PORT_ENC1]; |
1175 | else |
1176 | encport = &dev->ports[SAA7164_PORT_ENC2]; |
1177 | memcpy(&encport->vidproc, pdh, |
1178 | sizeof(struct tmComResProcDescrHeader)); |
1179 | dprintk(DBGLVL_API, " (becomes dev->enc[%d])\n" , |
1180 | encport->nr); |
1181 | } |
1182 | break; |
1183 | case FEATURE_UNIT: |
1184 | afd = (struct tmComResAFeatureDescrHeader *)(buf + idx); |
1185 | dprintk(DBGLVL_API, " FEATURE_UNIT\n" ); |
1186 | dprintk(DBGLVL_API, " unitid = 0x%x\n" , |
1187 | afd->unitid); |
1188 | dprintk(DBGLVL_API, " sourceid = 0x%x\n" , |
1189 | afd->sourceid); |
1190 | dprintk(DBGLVL_API, " controlsize = 0x%x\n" , |
1191 | afd->controlsize); |
1192 | if (currpath == 1) |
1193 | encport = &dev->ports[SAA7164_PORT_ENC1]; |
1194 | else |
1195 | encport = &dev->ports[SAA7164_PORT_ENC2]; |
1196 | memcpy(&encport->audfeat, afd, |
1197 | sizeof(struct tmComResAFeatureDescrHeader)); |
1198 | dprintk(DBGLVL_API, " (becomes dev->enc[%d])\n" , |
1199 | encport->nr); |
1200 | break; |
1201 | case ENCODER_UNIT: |
1202 | edh = (struct tmComResEncoderDescrHeader *)(buf + idx); |
1203 | dprintk(DBGLVL_API, " ENCODER_UNIT\n" ); |
1204 | dprintk(DBGLVL_API, " subtype = 0x%x\n" , edh->subtype); |
1205 | dprintk(DBGLVL_API, " unitid = 0x%x\n" , edh->unitid); |
1206 | dprintk(DBGLVL_API, " vsourceid = 0x%x\n" , |
1207 | edh->vsourceid); |
1208 | dprintk(DBGLVL_API, " asourceid = 0x%x\n" , |
1209 | edh->asourceid); |
1210 | dprintk(DBGLVL_API, " iunit = 0x%x\n" , edh->iunit); |
1211 | if (edh->iunit == edh->unitid) { |
1212 | if (currpath == 1) |
1213 | encport = &dev->ports[SAA7164_PORT_ENC1]; |
1214 | else |
1215 | encport = &dev->ports[SAA7164_PORT_ENC2]; |
1216 | memcpy(&encport->encunit, edh, |
1217 | sizeof(struct tmComResEncoderDescrHeader)); |
1218 | dprintk(DBGLVL_API, |
1219 | " (becomes dev->enc[%d])\n" , |
1220 | encport->nr); |
1221 | } |
1222 | break; |
1223 | case EXTENSION_UNIT: |
1224 | dprintk(DBGLVL_API, " EXTENSION_UNIT\n" ); |
1225 | exthdr = (struct tmComResExtDevDescrHeader *)(buf + idx); |
1226 | dprintk(DBGLVL_API, " unitid = 0x%x\n" , |
1227 | exthdr->unitid); |
1228 | dprintk(DBGLVL_API, " deviceid = 0x%x\n" , |
1229 | exthdr->deviceid); |
1230 | dprintk(DBGLVL_API, " devicetype = 0x%x\n" , |
1231 | exthdr->devicetype); |
1232 | if (exthdr->devicetype & 0x1) |
1233 | dprintk(DBGLVL_API, " = Decoder Device\n" ); |
1234 | if (exthdr->devicetype & 0x2) |
1235 | dprintk(DBGLVL_API, " = GPIO Source\n" ); |
1236 | if (exthdr->devicetype & 0x4) |
1237 | dprintk(DBGLVL_API, " = Video Decoder\n" ); |
1238 | if (exthdr->devicetype & 0x8) |
1239 | dprintk(DBGLVL_API, " = Audio Decoder\n" ); |
1240 | if (exthdr->devicetype & 0x20) |
1241 | dprintk(DBGLVL_API, " = Crossbar\n" ); |
1242 | if (exthdr->devicetype & 0x40) |
1243 | dprintk(DBGLVL_API, " = Tuner\n" ); |
1244 | if (exthdr->devicetype & 0x80) |
1245 | dprintk(DBGLVL_API, " = IF PLL\n" ); |
1246 | if (exthdr->devicetype & 0x100) |
1247 | dprintk(DBGLVL_API, " = Demodulator\n" ); |
1248 | if (exthdr->devicetype & 0x200) |
1249 | dprintk(DBGLVL_API, " = RDS Decoder\n" ); |
1250 | if (exthdr->devicetype & 0x400) |
1251 | dprintk(DBGLVL_API, " = Encoder\n" ); |
1252 | if (exthdr->devicetype & 0x800) |
1253 | dprintk(DBGLVL_API, " = IR Decoder\n" ); |
1254 | if (exthdr->devicetype & 0x1000) |
1255 | dprintk(DBGLVL_API, " = EEPROM\n" ); |
1256 | if (exthdr->devicetype & 0x2000) |
1257 | dprintk(DBGLVL_API, |
1258 | " = VBI Decoder\n" ); |
1259 | if (exthdr->devicetype & 0x10000) |
1260 | dprintk(DBGLVL_API, |
1261 | " = Streaming Device\n" ); |
1262 | if (exthdr->devicetype & 0x20000) |
1263 | dprintk(DBGLVL_API, |
1264 | " = DRM Device\n" ); |
1265 | if (exthdr->devicetype & 0x40000000) |
1266 | dprintk(DBGLVL_API, |
1267 | " = Generic Device\n" ); |
1268 | if (exthdr->devicetype & 0x80000000) |
1269 | dprintk(DBGLVL_API, |
1270 | " = Config Space Device\n" ); |
1271 | dprintk(DBGLVL_API, " numgpiopins = 0x%x\n" , |
1272 | exthdr->numgpiopins); |
1273 | dprintk(DBGLVL_API, " numgpiogroups = 0x%x\n" , |
1274 | exthdr->numgpiogroups); |
1275 | dprintk(DBGLVL_API, " controlsize = 0x%x\n" , |
1276 | exthdr->controlsize); |
1277 | if (exthdr->devicetype & 0x80) { |
1278 | if (currpath == 1) |
1279 | encport = &dev->ports[SAA7164_PORT_ENC1]; |
1280 | else |
1281 | encport = &dev->ports[SAA7164_PORT_ENC2]; |
1282 | memcpy(&encport->ifunit, exthdr, |
1283 | sizeof(struct tmComResExtDevDescrHeader)); |
1284 | dprintk(DBGLVL_API, |
1285 | " (becomes dev->enc[%d])\n" , |
1286 | encport->nr); |
1287 | } |
1288 | break; |
1289 | case PVC_INFRARED_UNIT: |
1290 | dprintk(DBGLVL_API, " PVC_INFRARED_UNIT\n" ); |
1291 | break; |
1292 | case DRM_UNIT: |
1293 | dprintk(DBGLVL_API, " DRM_UNIT\n" ); |
1294 | break; |
1295 | default: |
1296 | dprintk(DBGLVL_API, "default %d\n" , hdr->subtype); |
1297 | } |
1298 | |
1299 | dprintk(DBGLVL_API, " 1.%x\n" , hdr->len); |
1300 | dprintk(DBGLVL_API, " 2.%x\n" , hdr->type); |
1301 | dprintk(DBGLVL_API, " 3.%x\n" , hdr->subtype); |
1302 | dprintk(DBGLVL_API, " 4.%x\n" , hdr->unitid); |
1303 | |
1304 | idx += hdr->len; |
1305 | } |
1306 | |
1307 | return 0; |
1308 | } |
1309 | |
1310 | int saa7164_api_enum_subdevs(struct saa7164_dev *dev) |
1311 | { |
1312 | int ret; |
1313 | u32 buflen = 0; |
1314 | u8 *buf; |
1315 | |
1316 | dprintk(DBGLVL_API, "%s()\n" , __func__); |
1317 | |
1318 | /* Get the total descriptor length */ |
1319 | ret = saa7164_cmd_send(dev, id: 0, command: GET_LEN, |
1320 | GET_DESCRIPTORS_CONTROL, size: sizeof(buflen), buf: &buflen); |
1321 | if (ret != SAA_OK) |
1322 | printk(KERN_ERR "%s() error, ret = 0x%x\n" , __func__, ret); |
1323 | |
1324 | dprintk(DBGLVL_API, "%s() total descriptor size = %d bytes.\n" , |
1325 | __func__, buflen); |
1326 | |
1327 | /* Allocate enough storage for all of the descs */ |
1328 | buf = kzalloc(size: buflen, GFP_KERNEL); |
1329 | if (!buf) |
1330 | return SAA_ERR_NO_RESOURCES; |
1331 | |
1332 | /* Retrieve them */ |
1333 | ret = saa7164_cmd_send(dev, id: 0, command: GET_CUR, |
1334 | GET_DESCRIPTORS_CONTROL, size: buflen, buf); |
1335 | if (ret != SAA_OK) { |
1336 | printk(KERN_ERR "%s() error, ret = 0x%x\n" , __func__, ret); |
1337 | goto out; |
1338 | } |
1339 | |
1340 | if (saa_debug & DBGLVL_API) |
1341 | print_hex_dump(KERN_INFO, prefix_str: "" , prefix_type: DUMP_PREFIX_OFFSET, rowsize: 16, groupsize: 1, buf, |
1342 | len: buflen & ~15, ascii: false); |
1343 | |
1344 | saa7164_api_dump_subdevs(dev, buf, len: buflen); |
1345 | |
1346 | out: |
1347 | kfree(objp: buf); |
1348 | return ret; |
1349 | } |
1350 | |
1351 | int saa7164_api_i2c_read(struct saa7164_i2c *bus, u8 addr, u32 reglen, u8 *reg, |
1352 | u32 datalen, u8 *data) |
1353 | { |
1354 | struct saa7164_dev *dev = bus->dev; |
1355 | u16 len = 0; |
1356 | int unitid; |
1357 | u8 buf[256]; |
1358 | int ret; |
1359 | |
1360 | dprintk(DBGLVL_API, "%s() addr=%x reglen=%d datalen=%d\n" , |
1361 | __func__, addr, reglen, datalen); |
1362 | |
1363 | if (reglen > 4) |
1364 | return -EIO; |
1365 | |
1366 | /* Prepare the send buffer */ |
1367 | /* Bytes 00-03 source register length |
1368 | * 04-07 source bytes to read |
1369 | * 08... register address |
1370 | */ |
1371 | memset(buf, 0, sizeof(buf)); |
1372 | memcpy((buf + 2 * sizeof(u32) + 0), reg, reglen); |
1373 | *((u32 *)(buf + 0 * sizeof(u32))) = reglen; |
1374 | *((u32 *)(buf + 1 * sizeof(u32))) = datalen; |
1375 | |
1376 | unitid = saa7164_i2caddr_to_unitid(bus, addr); |
1377 | if (unitid < 0) { |
1378 | printk(KERN_ERR |
1379 | "%s() error, cannot translate regaddr 0x%x to unitid\n" , |
1380 | __func__, addr); |
1381 | return -EIO; |
1382 | } |
1383 | |
1384 | ret = saa7164_cmd_send(dev: bus->dev, id: unitid, command: GET_LEN, |
1385 | EXU_REGISTER_ACCESS_CONTROL, size: sizeof(len), buf: &len); |
1386 | if (ret != SAA_OK) { |
1387 | printk(KERN_ERR "%s() error, ret(1) = 0x%x\n" , __func__, ret); |
1388 | return -EIO; |
1389 | } |
1390 | |
1391 | dprintk(DBGLVL_API, "%s() len = %d bytes\n" , __func__, len); |
1392 | |
1393 | if (saa_debug & DBGLVL_I2C) |
1394 | print_hex_dump(KERN_INFO, prefix_str: "" , prefix_type: DUMP_PREFIX_OFFSET, rowsize: 16, groupsize: 1, buf, |
1395 | len: 32, ascii: false); |
1396 | |
1397 | ret = saa7164_cmd_send(dev: bus->dev, id: unitid, command: GET_CUR, |
1398 | EXU_REGISTER_ACCESS_CONTROL, size: len, buf: &buf); |
1399 | if (ret != SAA_OK) |
1400 | printk(KERN_ERR "%s() error, ret(2) = 0x%x\n" , __func__, ret); |
1401 | else { |
1402 | if (saa_debug & DBGLVL_I2C) |
1403 | print_hex_dump(KERN_INFO, prefix_str: "" , prefix_type: DUMP_PREFIX_OFFSET, rowsize: 16, groupsize: 1, |
1404 | buf, len: sizeof(buf), ascii: false); |
1405 | memcpy(data, (buf + 2 * sizeof(u32) + reglen), datalen); |
1406 | } |
1407 | |
1408 | return ret == SAA_OK ? 0 : -EIO; |
1409 | } |
1410 | |
1411 | /* For a given 8 bit i2c address device, write the buffer */ |
1412 | int saa7164_api_i2c_write(struct saa7164_i2c *bus, u8 addr, u32 datalen, |
1413 | u8 *data) |
1414 | { |
1415 | struct saa7164_dev *dev = bus->dev; |
1416 | u16 len = 0; |
1417 | int unitid; |
1418 | int reglen; |
1419 | u8 buf[256]; |
1420 | int ret; |
1421 | |
1422 | dprintk(DBGLVL_API, "%s() addr=0x%2x len=0x%x\n" , |
1423 | __func__, addr, datalen); |
1424 | |
1425 | if ((datalen == 0) || (datalen > 232)) |
1426 | return -EIO; |
1427 | |
1428 | memset(buf, 0, sizeof(buf)); |
1429 | |
1430 | unitid = saa7164_i2caddr_to_unitid(bus, addr); |
1431 | if (unitid < 0) { |
1432 | printk(KERN_ERR |
1433 | "%s() error, cannot translate regaddr 0x%x to unitid\n" , |
1434 | __func__, addr); |
1435 | return -EIO; |
1436 | } |
1437 | |
1438 | reglen = saa7164_i2caddr_to_reglen(bus, addr); |
1439 | if (reglen < 0) { |
1440 | printk(KERN_ERR |
1441 | "%s() error, cannot translate regaddr to reglen\n" , |
1442 | __func__); |
1443 | return -EIO; |
1444 | } |
1445 | |
1446 | ret = saa7164_cmd_send(dev: bus->dev, id: unitid, command: GET_LEN, |
1447 | EXU_REGISTER_ACCESS_CONTROL, size: sizeof(len), buf: &len); |
1448 | if (ret != SAA_OK) { |
1449 | printk(KERN_ERR "%s() error, ret(1) = 0x%x\n" , __func__, ret); |
1450 | return -EIO; |
1451 | } |
1452 | |
1453 | dprintk(DBGLVL_API, "%s() len = %d bytes unitid=0x%x\n" , __func__, |
1454 | len, unitid); |
1455 | |
1456 | /* Prepare the send buffer */ |
1457 | /* Bytes 00-03 dest register length |
1458 | * 04-07 dest bytes to write |
1459 | * 08... register address |
1460 | */ |
1461 | *((u32 *)(buf + 0 * sizeof(u32))) = reglen; |
1462 | *((u32 *)(buf + 1 * sizeof(u32))) = datalen - reglen; |
1463 | memcpy((buf + 2 * sizeof(u32)), data, datalen); |
1464 | |
1465 | if (saa_debug & DBGLVL_I2C) |
1466 | print_hex_dump(KERN_INFO, prefix_str: "" , prefix_type: DUMP_PREFIX_OFFSET, rowsize: 16, groupsize: 1, |
1467 | buf, len: sizeof(buf), ascii: false); |
1468 | |
1469 | ret = saa7164_cmd_send(dev: bus->dev, id: unitid, command: SET_CUR, |
1470 | EXU_REGISTER_ACCESS_CONTROL, size: len, buf: &buf); |
1471 | if (ret != SAA_OK) |
1472 | printk(KERN_ERR "%s() error, ret(2) = 0x%x\n" , __func__, ret); |
1473 | |
1474 | return ret == SAA_OK ? 0 : -EIO; |
1475 | } |
1476 | |
1477 | static int saa7164_api_modify_gpio(struct saa7164_dev *dev, u8 unitid, |
1478 | u8 pin, u8 state) |
1479 | { |
1480 | int ret; |
1481 | struct tmComResGPIO t; |
1482 | |
1483 | dprintk(DBGLVL_API, "%s(0x%x, %d, %d)\n" , |
1484 | __func__, unitid, pin, state); |
1485 | |
1486 | if ((pin > 7) || (state > 2)) |
1487 | return SAA_ERR_BAD_PARAMETER; |
1488 | |
1489 | t.pin = pin; |
1490 | t.state = state; |
1491 | |
1492 | ret = saa7164_cmd_send(dev, id: unitid, command: SET_CUR, |
1493 | EXU_GPIO_CONTROL, size: sizeof(t), buf: &t); |
1494 | if (ret != SAA_OK) |
1495 | printk(KERN_ERR "%s() error, ret = 0x%x\n" , |
1496 | __func__, ret); |
1497 | |
1498 | return ret; |
1499 | } |
1500 | |
1501 | int saa7164_api_set_gpiobit(struct saa7164_dev *dev, u8 unitid, |
1502 | u8 pin) |
1503 | { |
1504 | return saa7164_api_modify_gpio(dev, unitid, pin, state: 1); |
1505 | } |
1506 | |
1507 | int saa7164_api_clear_gpiobit(struct saa7164_dev *dev, u8 unitid, |
1508 | u8 pin) |
1509 | { |
1510 | return saa7164_api_modify_gpio(dev, unitid, pin, state: 0); |
1511 | } |
1512 | |
1513 | |