diff options
author | Andy Walls <awalls@radix.net> | 2009-02-20 21:52:13 -0500 |
---|---|---|
committer | Mauro Carvalho Chehab <mchehab@redhat.com> | 2009-03-30 11:43:01 -0400 |
commit | ff2a20018094c593a35f4887bbdabf8926ddb6e6 (patch) | |
tree | e6c89f8e06e6006035420ea20a6754dd4ca7e89c /drivers/media/video/cx18 | |
parent | fa3e70360c86480acbaa54c9791e843196327a66 (diff) |
V4L/DVB (10758): cx18: Convert I2C devices to v4l2_subdevices
This is a major perturbation to cx18 I2C device handling to convert it to the
v4l2_device/subdeivce framework. This change breaks GPIO audio multiplexer
control for the time being. It will be fixed in a coming change.
Signed-off-by: Andy Walls <awalls@radix.net>
Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
Diffstat (limited to 'drivers/media/video/cx18')
-rw-r--r-- | drivers/media/video/cx18/cx18-audio.c | 50 | ||||
-rw-r--r-- | drivers/media/video/cx18/cx18-audio.h | 2 | ||||
-rw-r--r-- | drivers/media/video/cx18/cx18-av-core.c | 15 | ||||
-rw-r--r-- | drivers/media/video/cx18/cx18-av-core.h | 2 | ||||
-rw-r--r-- | drivers/media/video/cx18/cx18-cards.c | 32 | ||||
-rw-r--r-- | drivers/media/video/cx18/cx18-cards.h | 14 | ||||
-rw-r--r-- | drivers/media/video/cx18/cx18-controls.c | 15 | ||||
-rw-r--r-- | drivers/media/video/cx18/cx18-driver.c | 86 | ||||
-rw-r--r-- | drivers/media/video/cx18/cx18-driver.h | 24 | ||||
-rw-r--r-- | drivers/media/video/cx18/cx18-fileops.c | 6 | ||||
-rw-r--r-- | drivers/media/video/cx18/cx18-i2c.c | 284 | ||||
-rw-r--r-- | drivers/media/video/cx18/cx18-i2c.h | 5 | ||||
-rw-r--r-- | drivers/media/video/cx18/cx18-ioctl.c | 78 |
13 files changed, 250 insertions, 363 deletions
diff --git a/drivers/media/video/cx18/cx18-audio.c b/drivers/media/video/cx18/cx18-audio.c index d19bd778c6ac..ccd170887b89 100644 --- a/drivers/media/video/cx18/cx18-audio.c +++ b/drivers/media/video/cx18/cx18-audio.c | |||
@@ -23,9 +23,7 @@ | |||
23 | 23 | ||
24 | #include "cx18-driver.h" | 24 | #include "cx18-driver.h" |
25 | #include "cx18-io.h" | 25 | #include "cx18-io.h" |
26 | #include "cx18-i2c.h" | ||
27 | #include "cx18-cards.h" | 26 | #include "cx18-cards.h" |
28 | #include "cx18-audio.h" | ||
29 | 27 | ||
30 | #define CX18_AUDIO_ENABLE 0xc72014 | 28 | #define CX18_AUDIO_ENABLE 0xc72014 |
31 | 29 | ||
@@ -33,54 +31,32 @@ | |||
33 | settings. */ | 31 | settings. */ |
34 | int cx18_audio_set_io(struct cx18 *cx) | 32 | int cx18_audio_set_io(struct cx18 *cx) |
35 | { | 33 | { |
34 | const struct cx18_card_audio_input *in; | ||
36 | struct v4l2_routing route; | 35 | struct v4l2_routing route; |
37 | u32 audio_input; | ||
38 | u32 val; | 36 | u32 val; |
39 | int mux_input; | ||
40 | int err; | 37 | int err; |
41 | 38 | ||
42 | /* Determine which input to use */ | 39 | /* Determine which input to use */ |
43 | if (test_bit(CX18_F_I_RADIO_USER, &cx->i_flags)) { | 40 | if (test_bit(CX18_F_I_RADIO_USER, &cx->i_flags)) |
44 | audio_input = cx->card->radio_input.audio_input; | 41 | in = &cx->card->radio_input; |
45 | mux_input = cx->card->radio_input.muxer_input; | 42 | else |
46 | } else { | 43 | in = &cx->card->audio_inputs[cx->audio_input]; |
47 | audio_input = | ||
48 | cx->card->audio_inputs[cx->audio_input].audio_input; | ||
49 | mux_input = | ||
50 | cx->card->audio_inputs[cx->audio_input].muxer_input; | ||
51 | } | ||
52 | 44 | ||
53 | /* handle muxer chips */ | 45 | /* handle muxer chips */ |
54 | route.input = mux_input; | 46 | route.input = in->muxer_input; |
55 | route.output = 0; | 47 | route.output = 0; |
56 | cx18_i2c_hw(cx, cx->card->hw_muxer, VIDIOC_INT_S_AUDIO_ROUTING, &route); | 48 | v4l2_subdev_call(cx->sd_extmux, audio, s_routing, &route); |
57 | 49 | ||
58 | route.input = audio_input; | 50 | route.input = in->audio_input; |
59 | err = cx18_i2c_hw(cx, cx->card->hw_audio_ctrl, | 51 | err = cx18_call_hw_err(cx, cx->card->hw_audio_ctrl, |
60 | VIDIOC_INT_S_AUDIO_ROUTING, &route); | 52 | audio, s_routing, &route); |
61 | if (err) | 53 | if (err) |
62 | return err; | 54 | return err; |
63 | 55 | ||
56 | /* FIXME - this internal mux should be abstracted to a subdev */ | ||
64 | val = cx18_read_reg(cx, CX18_AUDIO_ENABLE) & ~0x30; | 57 | val = cx18_read_reg(cx, CX18_AUDIO_ENABLE) & ~0x30; |
65 | val |= (audio_input > CX18_AV_AUDIO_SERIAL2) ? 0x20 : | 58 | val |= (in->audio_input > CX18_AV_AUDIO_SERIAL2) ? 0x20 : |
66 | (audio_input << 4); | 59 | (in->audio_input << 4); |
67 | cx18_write_reg_expect(cx, val | 0xb00, CX18_AUDIO_ENABLE, val, 0x30); | 60 | cx18_write_reg_expect(cx, val | 0xb00, CX18_AUDIO_ENABLE, val, 0x30); |
68 | return 0; | 61 | return 0; |
69 | } | 62 | } |
70 | |||
71 | void cx18_audio_set_route(struct cx18 *cx, struct v4l2_routing *route) | ||
72 | { | ||
73 | cx18_i2c_hw(cx, cx->card->hw_audio_ctrl, | ||
74 | VIDIOC_INT_S_AUDIO_ROUTING, route); | ||
75 | } | ||
76 | |||
77 | void cx18_audio_set_audio_clock_freq(struct cx18 *cx, u8 freq) | ||
78 | { | ||
79 | static u32 freqs[3] = { 44100, 48000, 32000 }; | ||
80 | |||
81 | /* The audio clock of the digitizer must match the codec sample | ||
82 | rate otherwise you get some very strange effects. */ | ||
83 | if (freq > 2) | ||
84 | return; | ||
85 | cx18_call_i2c_clients(cx, VIDIOC_INT_AUDIO_CLOCK_FREQ, &freqs[freq]); | ||
86 | } | ||
diff --git a/drivers/media/video/cx18/cx18-audio.h b/drivers/media/video/cx18/cx18-audio.h index cb569a69379c..2731d29b0ab9 100644 --- a/drivers/media/video/cx18/cx18-audio.h +++ b/drivers/media/video/cx18/cx18-audio.h | |||
@@ -22,5 +22,3 @@ | |||
22 | */ | 22 | */ |
23 | 23 | ||
24 | int cx18_audio_set_io(struct cx18 *cx); | 24 | int cx18_audio_set_io(struct cx18 *cx); |
25 | void cx18_audio_set_route(struct cx18 *cx, struct v4l2_routing *route); | ||
26 | void cx18_audio_set_audio_clock_freq(struct cx18 *cx, u8 freq); | ||
diff --git a/drivers/media/video/cx18/cx18-av-core.c b/drivers/media/video/cx18/cx18-av-core.c index f9bb77a25ee9..2128070154d3 100644 --- a/drivers/media/video/cx18/cx18-av-core.c +++ b/drivers/media/video/cx18/cx18-av-core.c | |||
@@ -1209,9 +1209,10 @@ static const struct v4l2_subdev_ops cx18_av_ops = { | |||
1209 | .video = &cx18_av_video_ops, | 1209 | .video = &cx18_av_video_ops, |
1210 | }; | 1210 | }; |
1211 | 1211 | ||
1212 | int cx18_av_probe(struct cx18 *cx, struct v4l2_subdev **sd) | 1212 | int cx18_av_probe(struct cx18 *cx) |
1213 | { | 1213 | { |
1214 | struct cx18_av_state *state = &cx->av_state; | 1214 | struct cx18_av_state *state = &cx->av_state; |
1215 | struct v4l2_subdev *sd; | ||
1215 | 1216 | ||
1216 | state->rev = cx18_av_read4(cx, CXADEC_CHIP_CTRL) & 0xffff; | 1217 | state->rev = cx18_av_read4(cx, CXADEC_CHIP_CTRL) & 0xffff; |
1217 | state->id = ((state->rev >> 4) == CXADEC_CHIP_TYPE_MAKO) | 1218 | state->id = ((state->rev >> 4) == CXADEC_CHIP_TYPE_MAKO) |
@@ -1224,13 +1225,13 @@ int cx18_av_probe(struct cx18 *cx, struct v4l2_subdev **sd) | |||
1224 | state->slicer_line_delay = 0; | 1225 | state->slicer_line_delay = 0; |
1225 | state->slicer_line_offset = (10 + state->slicer_line_delay - 2); | 1226 | state->slicer_line_offset = (10 + state->slicer_line_delay - 2); |
1226 | 1227 | ||
1227 | *sd = &state->sd; | 1228 | sd = &state->sd; |
1228 | v4l2_subdev_init(*sd, &cx18_av_ops); | 1229 | v4l2_subdev_init(sd, &cx18_av_ops); |
1229 | v4l2_set_subdevdata(*sd, cx); | 1230 | v4l2_set_subdevdata(sd, cx); |
1230 | snprintf((*sd)->name, sizeof((*sd)->name), | 1231 | snprintf(sd->name, sizeof(sd->name), |
1231 | "%s internal A/V decoder", cx->v4l2_dev.name); | 1232 | "%s internal A/V decoder", cx->v4l2_dev.name); |
1232 | (*sd)->grp_id = CX18_HW_CX23418; | 1233 | sd->grp_id = CX18_HW_418_AV; |
1233 | return v4l2_device_register_subdev(&cx->v4l2_dev, *sd); | 1234 | return v4l2_device_register_subdev(&cx->v4l2_dev, sd); |
1234 | } | 1235 | } |
1235 | 1236 | ||
1236 | void cx18_av_exit(struct cx18 *cx, struct v4l2_subdev *sd) | 1237 | void cx18_av_exit(struct cx18 *cx, struct v4l2_subdev *sd) |
diff --git a/drivers/media/video/cx18/cx18-av-core.h b/drivers/media/video/cx18/cx18-av-core.h index 90bdca960292..cd9c0e70f1fc 100644 --- a/drivers/media/video/cx18/cx18-av-core.h +++ b/drivers/media/video/cx18/cx18-av-core.h | |||
@@ -342,7 +342,7 @@ int cx18_av_and_or(struct cx18 *cx, u16 addr, unsigned mask, u8 value); | |||
342 | int cx18_av_and_or4(struct cx18 *cx, u16 addr, u32 mask, u32 value); | 342 | int cx18_av_and_or4(struct cx18 *cx, u16 addr, u32 mask, u32 value); |
343 | void cx18_av_std_setup(struct cx18 *cx); | 343 | void cx18_av_std_setup(struct cx18 *cx); |
344 | 344 | ||
345 | int cx18_av_probe(struct cx18 *cx, struct v4l2_subdev **sd); | 345 | int cx18_av_probe(struct cx18 *cx); |
346 | void cx18_av_exit(struct cx18 *cx, struct v4l2_subdev *sd); | 346 | void cx18_av_exit(struct cx18 *cx, struct v4l2_subdev *sd); |
347 | 347 | ||
348 | /* ----------------------------------------------------------------------- */ | 348 | /* ----------------------------------------------------------------------- */ |
diff --git a/drivers/media/video/cx18/cx18-cards.c b/drivers/media/video/cx18/cx18-cards.c index 6e2105ac2bc4..6644534db564 100644 --- a/drivers/media/video/cx18/cx18-cards.c +++ b/drivers/media/video/cx18/cx18-cards.c | |||
@@ -53,9 +53,9 @@ static const struct cx18_card cx18_card_hvr1600_esmt = { | |||
53 | .name = "Hauppauge HVR-1600", | 53 | .name = "Hauppauge HVR-1600", |
54 | .comment = "Simultaneous Digital and Analog TV capture supported\n", | 54 | .comment = "Simultaneous Digital and Analog TV capture supported\n", |
55 | .v4l2_capabilities = CX18_CAP_ENCODER, | 55 | .v4l2_capabilities = CX18_CAP_ENCODER, |
56 | .hw_audio_ctrl = CX18_HW_CX23418, | 56 | .hw_audio_ctrl = CX18_HW_418_AV, |
57 | .hw_muxer = CX18_HW_CS5345, | 57 | .hw_muxer = CX18_HW_CS5345, |
58 | .hw_all = CX18_HW_TVEEPROM | CX18_HW_TUNER | | 58 | .hw_all = CX18_HW_TVEEPROM | CX18_HW_418_AV | CX18_HW_TUNER | |
59 | CX18_HW_CS5345 | CX18_HW_DVB, | 59 | CX18_HW_CS5345 | CX18_HW_DVB, |
60 | .video_inputs = { | 60 | .video_inputs = { |
61 | { CX18_CARD_INPUT_VID_TUNER, 0, CX18_AV_COMPOSITE7 }, | 61 | { CX18_CARD_INPUT_VID_TUNER, 0, CX18_AV_COMPOSITE7 }, |
@@ -99,9 +99,9 @@ static const struct cx18_card cx18_card_hvr1600_samsung = { | |||
99 | .name = "Hauppauge HVR-1600 (Preproduction)", | 99 | .name = "Hauppauge HVR-1600 (Preproduction)", |
100 | .comment = "Simultaneous Digital and Analog TV capture supported\n", | 100 | .comment = "Simultaneous Digital and Analog TV capture supported\n", |
101 | .v4l2_capabilities = CX18_CAP_ENCODER, | 101 | .v4l2_capabilities = CX18_CAP_ENCODER, |
102 | .hw_audio_ctrl = CX18_HW_CX23418, | 102 | .hw_audio_ctrl = CX18_HW_418_AV, |
103 | .hw_muxer = CX18_HW_CS5345, | 103 | .hw_muxer = CX18_HW_CS5345, |
104 | .hw_all = CX18_HW_TVEEPROM | CX18_HW_TUNER | | 104 | .hw_all = CX18_HW_TVEEPROM | CX18_HW_418_AV | CX18_HW_TUNER | |
105 | CX18_HW_CS5345 | CX18_HW_DVB, | 105 | CX18_HW_CS5345 | CX18_HW_DVB, |
106 | .video_inputs = { | 106 | .video_inputs = { |
107 | { CX18_CARD_INPUT_VID_TUNER, 0, CX18_AV_COMPOSITE7 }, | 107 | { CX18_CARD_INPUT_VID_TUNER, 0, CX18_AV_COMPOSITE7 }, |
@@ -154,8 +154,8 @@ static const struct cx18_card cx18_card_h900 = { | |||
154 | .name = "Compro VideoMate H900", | 154 | .name = "Compro VideoMate H900", |
155 | .comment = "Analog TV capture supported\n", | 155 | .comment = "Analog TV capture supported\n", |
156 | .v4l2_capabilities = CX18_CAP_ENCODER, | 156 | .v4l2_capabilities = CX18_CAP_ENCODER, |
157 | .hw_audio_ctrl = CX18_HW_CX23418, | 157 | .hw_audio_ctrl = CX18_HW_418_AV, |
158 | .hw_all = CX18_HW_TUNER, | 158 | .hw_all = CX18_HW_418_AV | CX18_HW_TUNER, |
159 | .video_inputs = { | 159 | .video_inputs = { |
160 | { CX18_CARD_INPUT_VID_TUNER, 0, CX18_AV_COMPOSITE2 }, | 160 | { CX18_CARD_INPUT_VID_TUNER, 0, CX18_AV_COMPOSITE2 }, |
161 | { CX18_CARD_INPUT_SVIDEO1, 1, | 161 | { CX18_CARD_INPUT_SVIDEO1, 1, |
@@ -201,8 +201,8 @@ static const struct cx18_card cx18_card_mpc718 = { | |||
201 | .name = "Yuan MPC718", | 201 | .name = "Yuan MPC718", |
202 | .comment = "Analog video capture works; some audio line in may not.\n", | 202 | .comment = "Analog video capture works; some audio line in may not.\n", |
203 | .v4l2_capabilities = CX18_CAP_ENCODER, | 203 | .v4l2_capabilities = CX18_CAP_ENCODER, |
204 | .hw_audio_ctrl = CX18_HW_CX23418, | 204 | .hw_audio_ctrl = CX18_HW_418_AV, |
205 | .hw_all = CX18_HW_TUNER, | 205 | .hw_all = CX18_HW_418_AV | CX18_HW_TUNER, |
206 | .video_inputs = { | 206 | .video_inputs = { |
207 | { CX18_CARD_INPUT_VID_TUNER, 0, CX18_AV_COMPOSITE2 }, | 207 | { CX18_CARD_INPUT_VID_TUNER, 0, CX18_AV_COMPOSITE2 }, |
208 | { CX18_CARD_INPUT_SVIDEO1, 1, | 208 | { CX18_CARD_INPUT_SVIDEO1, 1, |
@@ -251,9 +251,9 @@ static const struct cx18_card cx18_card_cnxt_raptor_pal = { | |||
251 | .name = "Conexant Raptor PAL/SECAM", | 251 | .name = "Conexant Raptor PAL/SECAM", |
252 | .comment = "Analog TV capture supported\n", | 252 | .comment = "Analog TV capture supported\n", |
253 | .v4l2_capabilities = CX18_CAP_ENCODER, | 253 | .v4l2_capabilities = CX18_CAP_ENCODER, |
254 | .hw_audio_ctrl = CX18_HW_CX23418, | 254 | .hw_audio_ctrl = CX18_HW_418_AV, |
255 | .hw_muxer = CX18_HW_GPIO, | 255 | .hw_muxer = CX18_HW_GPIO_AUDIO_MUX, |
256 | .hw_all = CX18_HW_TUNER | CX18_HW_GPIO, | 256 | .hw_all = CX18_HW_418_AV | CX18_HW_TUNER | CX18_HW_GPIO_AUDIO_MUX, |
257 | .video_inputs = { | 257 | .video_inputs = { |
258 | { CX18_CARD_INPUT_VID_TUNER, 0, CX18_AV_COMPOSITE2 }, | 258 | { CX18_CARD_INPUT_VID_TUNER, 0, CX18_AV_COMPOSITE2 }, |
259 | { CX18_CARD_INPUT_SVIDEO1, 1, | 259 | { CX18_CARD_INPUT_SVIDEO1, 1, |
@@ -306,8 +306,8 @@ static const struct cx18_card cx18_card_toshiba_qosmio_dvbt = { | |||
306 | .comment = "Experimenters and photos needed for device to work well.\n" | 306 | .comment = "Experimenters and photos needed for device to work well.\n" |
307 | "\tTo help, mail the ivtv-devel list (www.ivtvdriver.org).\n", | 307 | "\tTo help, mail the ivtv-devel list (www.ivtvdriver.org).\n", |
308 | .v4l2_capabilities = CX18_CAP_ENCODER, | 308 | .v4l2_capabilities = CX18_CAP_ENCODER, |
309 | .hw_audio_ctrl = CX18_HW_CX23418, | 309 | .hw_audio_ctrl = CX18_HW_418_AV, |
310 | .hw_all = CX18_HW_TUNER, | 310 | .hw_all = CX18_HW_418_AV | CX18_HW_TUNER, |
311 | .video_inputs = { | 311 | .video_inputs = { |
312 | { CX18_CARD_INPUT_VID_TUNER, 0, CX18_AV_COMPOSITE6 }, | 312 | { CX18_CARD_INPUT_VID_TUNER, 0, CX18_AV_COMPOSITE6 }, |
313 | { CX18_CARD_INPUT_SVIDEO1, 1, | 313 | { CX18_CARD_INPUT_SVIDEO1, 1, |
@@ -350,9 +350,9 @@ static const struct cx18_card cx18_card_leadtek_pvr2100 = { | |||
350 | .comment = "Experimenters and photos needed for device to work well.\n" | 350 | .comment = "Experimenters and photos needed for device to work well.\n" |
351 | "\tTo help, mail the ivtv-devel list (www.ivtvdriver.org).\n", | 351 | "\tTo help, mail the ivtv-devel list (www.ivtvdriver.org).\n", |
352 | .v4l2_capabilities = CX18_CAP_ENCODER, | 352 | .v4l2_capabilities = CX18_CAP_ENCODER, |
353 | .hw_audio_ctrl = CX18_HW_CX23418, | 353 | .hw_audio_ctrl = CX18_HW_418_AV, |
354 | .hw_muxer = CX18_HW_GPIO, | 354 | .hw_muxer = CX18_HW_GPIO_AUDIO_MUX, |
355 | .hw_all = CX18_HW_TUNER | CX18_HW_GPIO, | 355 | .hw_all = CX18_HW_418_AV | CX18_HW_TUNER | CX18_HW_GPIO_AUDIO_MUX, |
356 | .video_inputs = { | 356 | .video_inputs = { |
357 | { CX18_CARD_INPUT_VID_TUNER, 0, CX18_AV_COMPOSITE2 }, | 357 | { CX18_CARD_INPUT_VID_TUNER, 0, CX18_AV_COMPOSITE2 }, |
358 | { CX18_CARD_INPUT_SVIDEO1, 1, | 358 | { CX18_CARD_INPUT_SVIDEO1, 1, |
diff --git a/drivers/media/video/cx18/cx18-cards.h b/drivers/media/video/cx18/cx18-cards.h index f8ee29f102d4..bd7f9556f18c 100644 --- a/drivers/media/video/cx18/cx18-cards.h +++ b/drivers/media/video/cx18/cx18-cards.h | |||
@@ -22,12 +22,12 @@ | |||
22 | */ | 22 | */ |
23 | 23 | ||
24 | /* hardware flags */ | 24 | /* hardware flags */ |
25 | #define CX18_HW_TUNER (1 << 0) | 25 | #define CX18_HW_TUNER (1 << 0) |
26 | #define CX18_HW_TVEEPROM (1 << 1) | 26 | #define CX18_HW_TVEEPROM (1 << 1) |
27 | #define CX18_HW_CS5345 (1 << 2) | 27 | #define CX18_HW_CS5345 (1 << 2) |
28 | #define CX18_HW_GPIO (1 << 3) | 28 | #define CX18_HW_DVB (1 << 3) |
29 | #define CX18_HW_CX23418 (1 << 4) | 29 | #define CX18_HW_418_AV (1 << 4) |
30 | #define CX18_HW_DVB (1 << 5) | 30 | #define CX18_HW_GPIO_AUDIO_MUX (1 << 5) |
31 | 31 | ||
32 | /* video inputs */ | 32 | /* video inputs */ |
33 | #define CX18_CARD_INPUT_VID_TUNER 1 | 33 | #define CX18_CARD_INPUT_VID_TUNER 1 |
@@ -121,7 +121,7 @@ struct cx18_card { | |||
121 | char *comment; | 121 | char *comment; |
122 | u32 v4l2_capabilities; | 122 | u32 v4l2_capabilities; |
123 | u32 hw_audio_ctrl; /* hardware used for the V4L2 controls (only | 123 | u32 hw_audio_ctrl; /* hardware used for the V4L2 controls (only |
124 | 1 dev allowed) */ | 124 | 1 dev allowed currently) */ |
125 | u32 hw_muxer; /* hardware used to multiplex audio input */ | 125 | u32 hw_muxer; /* hardware used to multiplex audio input */ |
126 | u32 hw_all; /* all hardware used by the board */ | 126 | u32 hw_all; /* all hardware used by the board */ |
127 | struct cx18_card_video_input video_inputs[CX18_CARD_MAX_VIDEO_INPUTS]; | 127 | struct cx18_card_video_input video_inputs[CX18_CARD_MAX_VIDEO_INPUTS]; |
diff --git a/drivers/media/video/cx18/cx18-controls.c b/drivers/media/video/cx18/cx18-controls.c index 9505c417371d..e5604c2328ad 100644 --- a/drivers/media/video/cx18/cx18-controls.c +++ b/drivers/media/video/cx18/cx18-controls.c | |||
@@ -77,7 +77,7 @@ int cx18_queryctrl(struct file *file, void *fh, struct v4l2_queryctrl *qctrl) | |||
77 | case V4L2_CID_AUDIO_BASS: | 77 | case V4L2_CID_AUDIO_BASS: |
78 | case V4L2_CID_AUDIO_TREBLE: | 78 | case V4L2_CID_AUDIO_TREBLE: |
79 | case V4L2_CID_AUDIO_LOUDNESS: | 79 | case V4L2_CID_AUDIO_LOUDNESS: |
80 | if (cx18_i2c_hw(cx, cx->card->hw_audio_ctrl, VIDIOC_QUERYCTRL, qctrl)) | 80 | if (v4l2_subdev_call(cx->sd_av, core, queryctrl, qctrl)) |
81 | qctrl->flags |= V4L2_CTRL_FLAG_DISABLED; | 81 | qctrl->flags |= V4L2_CTRL_FLAG_DISABLED; |
82 | return 0; | 82 | return 0; |
83 | 83 | ||
@@ -134,7 +134,7 @@ static int cx18_s_ctrl(struct cx18 *cx, struct v4l2_control *vctrl) | |||
134 | case V4L2_CID_AUDIO_BASS: | 134 | case V4L2_CID_AUDIO_BASS: |
135 | case V4L2_CID_AUDIO_TREBLE: | 135 | case V4L2_CID_AUDIO_TREBLE: |
136 | case V4L2_CID_AUDIO_LOUDNESS: | 136 | case V4L2_CID_AUDIO_LOUDNESS: |
137 | return cx18_i2c_hw(cx, cx->card->hw_audio_ctrl, VIDIOC_S_CTRL, vctrl); | 137 | return v4l2_subdev_call(cx->sd_av, core, s_ctrl, vctrl); |
138 | 138 | ||
139 | default: | 139 | default: |
140 | CX18_DEBUG_IOCTL("invalid control 0x%x\n", vctrl->id); | 140 | CX18_DEBUG_IOCTL("invalid control 0x%x\n", vctrl->id); |
@@ -159,7 +159,8 @@ static int cx18_g_ctrl(struct cx18 *cx, struct v4l2_control *vctrl) | |||
159 | case V4L2_CID_AUDIO_BASS: | 159 | case V4L2_CID_AUDIO_BASS: |
160 | case V4L2_CID_AUDIO_TREBLE: | 160 | case V4L2_CID_AUDIO_TREBLE: |
161 | case V4L2_CID_AUDIO_LOUDNESS: | 161 | case V4L2_CID_AUDIO_LOUDNESS: |
162 | return cx18_i2c_hw(cx, cx->card->hw_audio_ctrl, VIDIOC_G_CTRL, vctrl); | 162 | return v4l2_subdev_call(cx->sd_av, core, g_ctrl, vctrl); |
163 | |||
163 | default: | 164 | default: |
164 | CX18_DEBUG_IOCTL("invalid control 0x%x\n", vctrl->id); | 165 | CX18_DEBUG_IOCTL("invalid control 0x%x\n", vctrl->id); |
165 | return -EINVAL; | 166 | return -EINVAL; |
@@ -260,10 +261,12 @@ int cx18_s_ext_ctrls(struct file *file, void *fh, struct v4l2_ext_controls *c) | |||
260 | return err; | 261 | return err; |
261 | } | 262 | } |
262 | if (c->ctrl_class == V4L2_CTRL_CLASS_MPEG) { | 263 | if (c->ctrl_class == V4L2_CTRL_CLASS_MPEG) { |
264 | static u32 freqs[3] = { 44100, 48000, 32000 }; | ||
263 | struct cx18_api_func_private priv; | 265 | struct cx18_api_func_private priv; |
264 | struct cx2341x_mpeg_params p = cx->params; | 266 | struct cx2341x_mpeg_params p = cx->params; |
265 | int err = cx2341x_ext_ctrls(&p, atomic_read(&cx->ana_capturing), | 267 | int err = cx2341x_ext_ctrls(&p, atomic_read(&cx->ana_capturing), |
266 | c, VIDIOC_S_EXT_CTRLS); | 268 | c, VIDIOC_S_EXT_CTRLS); |
269 | unsigned int idx; | ||
267 | 270 | ||
268 | if (err) | 271 | if (err) |
269 | return err; | 272 | return err; |
@@ -287,7 +290,11 @@ int cx18_s_ext_ctrls(struct file *file, void *fh, struct v4l2_ext_controls *c) | |||
287 | err = cx18_setup_vbi_fmt(cx, p.stream_vbi_fmt); | 290 | err = cx18_setup_vbi_fmt(cx, p.stream_vbi_fmt); |
288 | cx->params = p; | 291 | cx->params = p; |
289 | cx->dualwatch_stereo_mode = p.audio_properties & 0x0300; | 292 | cx->dualwatch_stereo_mode = p.audio_properties & 0x0300; |
290 | cx18_audio_set_audio_clock_freq(cx, p.audio_properties & 0x03); | 293 | idx = p.audio_properties & 0x03; |
294 | /* The audio clock of the digitizer must match the codec sample | ||
295 | rate otherwise you get some very strange effects. */ | ||
296 | if (idx < sizeof(freqs)) | ||
297 | cx18_call_all(cx, audio, s_clock_freq, freqs[idx]); | ||
291 | return err; | 298 | return err; |
292 | } | 299 | } |
293 | return -EINVAL; | 300 | return -EINVAL; |
diff --git a/drivers/media/video/cx18/cx18-driver.c b/drivers/media/video/cx18/cx18-driver.c index f5a41dd663dc..edbb83c4c564 100644 --- a/drivers/media/video/cx18/cx18-driver.c +++ b/drivers/media/video/cx18/cx18-driver.c | |||
@@ -269,11 +269,16 @@ static void cx18_iounmap(struct cx18 *cx) | |||
269 | /* Hauppauge card? get values from tveeprom */ | 269 | /* Hauppauge card? get values from tveeprom */ |
270 | void cx18_read_eeprom(struct cx18 *cx, struct tveeprom *tv) | 270 | void cx18_read_eeprom(struct cx18 *cx, struct tveeprom *tv) |
271 | { | 271 | { |
272 | struct i2c_client c; | ||
272 | u8 eedata[256]; | 273 | u8 eedata[256]; |
273 | 274 | ||
274 | cx->i2c_client[0].addr = 0xA0 >> 1; | 275 | strncpy(c.name, "cx18 tveeprom tmp", sizeof(c.name)); |
275 | tveeprom_read(&cx->i2c_client[0], eedata, sizeof(eedata)); | 276 | c.name[sizeof(c.name)-1] = '\0'; |
276 | tveeprom_hauppauge_analog(&cx->i2c_client[0], tv, eedata); | 277 | c.adapter = &cx->i2c_adap[0]; |
278 | c.addr = 0xA0 >> 1; | ||
279 | |||
280 | tveeprom_read(&c, eedata, sizeof(eedata)); | ||
281 | tveeprom_hauppauge_analog(&c, tv, eedata); | ||
277 | } | 282 | } |
278 | 283 | ||
279 | static void cx18_process_eeprom(struct cx18 *cx) | 284 | static void cx18_process_eeprom(struct cx18 *cx) |
@@ -553,8 +558,6 @@ static int __devinit cx18_init_struct1(struct cx18 *cx) | |||
553 | cx->base_addr = pci_resource_start(cx->pci_dev, 0); | 558 | cx->base_addr = pci_resource_start(cx->pci_dev, 0); |
554 | 559 | ||
555 | mutex_init(&cx->serialize_lock); | 560 | mutex_init(&cx->serialize_lock); |
556 | mutex_init(&cx->i2c_bus_lock[0]); | ||
557 | mutex_init(&cx->i2c_bus_lock[1]); | ||
558 | mutex_init(&cx->gpio_lock); | 561 | mutex_init(&cx->gpio_lock); |
559 | mutex_init(&cx->epu2apu_mb_lock); | 562 | mutex_init(&cx->epu2apu_mb_lock); |
560 | mutex_init(&cx->epu2cpu_mb_lock); | 563 | mutex_init(&cx->epu2cpu_mb_lock); |
@@ -669,54 +672,41 @@ static int cx18_setup_pci(struct cx18 *cx, struct pci_dev *pci_dev, | |||
669 | return 0; | 672 | return 0; |
670 | } | 673 | } |
671 | 674 | ||
672 | #ifdef MODULE | 675 | static void cx18_init_subdevs(struct cx18 *cx) |
673 | static u32 cx18_request_module(struct cx18 *cx, u32 hw, | ||
674 | const char *name, u32 id) | ||
675 | { | ||
676 | if ((hw & id) == 0) | ||
677 | return hw; | ||
678 | if (request_module("%s", name) != 0) { | ||
679 | CX18_ERR("Failed to load module %s\n", name); | ||
680 | return hw & ~id; | ||
681 | } | ||
682 | CX18_DEBUG_INFO("Loaded module %s\n", name); | ||
683 | return hw; | ||
684 | } | ||
685 | #endif | ||
686 | |||
687 | static void cx18_load_and_init_modules(struct cx18 *cx) | ||
688 | { | 676 | { |
689 | u32 hw = cx->card->hw_all; | 677 | u32 hw = cx->card->hw_all; |
678 | u32 device; | ||
690 | int i; | 679 | int i; |
691 | 680 | ||
692 | #ifdef MODULE | 681 | for (i = 0, device = 1; i < 32; i++, device <<= 1) { |
693 | /* load modules */ | ||
694 | #ifdef CONFIG_MEDIA_TUNER_MODULE | ||
695 | hw = cx18_request_module(cx, hw, "tuner", CX18_HW_TUNER); | ||
696 | #endif | ||
697 | #ifdef CONFIG_VIDEO_CS5345_MODULE | ||
698 | hw = cx18_request_module(cx, hw, "cs5345", CX18_HW_CS5345); | ||
699 | #endif | ||
700 | #endif | ||
701 | |||
702 | /* check which i2c devices are actually found */ | ||
703 | for (i = 0; i < 32; i++) { | ||
704 | u32 device = 1 << i; | ||
705 | 682 | ||
706 | if (!(device & hw)) | 683 | if (!(device & hw)) |
707 | continue; | 684 | continue; |
708 | if (device == CX18_HW_GPIO || device == CX18_HW_TVEEPROM || | 685 | |
709 | device == CX18_HW_CX23418 || device == CX18_HW_DVB) { | 686 | switch (device) { |
710 | /* These 'devices' do not use i2c probing */ | 687 | case CX18_HW_GPIO_AUDIO_MUX: |
688 | case CX18_HW_DVB: | ||
689 | case CX18_HW_TVEEPROM: | ||
690 | /* These subordinate devices do not use probing */ | ||
711 | cx->hw_flags |= device; | 691 | cx->hw_flags |= device; |
712 | continue; | 692 | break; |
713 | } | 693 | case CX18_HW_418_AV: |
714 | cx18_i2c_register(cx, i); | 694 | /* The A/V decoder gets probed earlier to set PLLs */ |
715 | if (cx18_i2c_hw_addr(cx, device) > 0) | 695 | /* Just note that the card uses it (i.e. has analog) */ |
716 | cx->hw_flags |= device; | 696 | cx->hw_flags |= device; |
697 | break; | ||
698 | default: | ||
699 | if (cx18_i2c_register(cx, i) == 0) | ||
700 | cx->hw_flags |= device; | ||
701 | break; | ||
702 | } | ||
717 | } | 703 | } |
718 | 704 | ||
719 | hw = cx->hw_flags; | 705 | if (cx->hw_flags & CX18_HW_418_AV) |
706 | cx->sd_av = cx18_find_hw(cx, CX18_HW_418_AV); | ||
707 | |||
708 | if (cx->card->hw_muxer != 0) | ||
709 | cx->sd_extmux = cx18_find_hw(cx, cx->card->hw_muxer); | ||
720 | } | 710 | } |
721 | 711 | ||
722 | static int __devinit cx18_probe(struct pci_dev *pci_dev, | 712 | static int __devinit cx18_probe(struct pci_dev *pci_dev, |
@@ -803,15 +793,17 @@ static int __devinit cx18_probe(struct pci_dev *pci_dev, | |||
803 | cx->scb = (struct cx18_scb __iomem *)(cx->enc_mem + SCB_OFFSET); | 793 | cx->scb = (struct cx18_scb __iomem *)(cx->enc_mem + SCB_OFFSET); |
804 | cx18_init_scb(cx); | 794 | cx18_init_scb(cx); |
805 | 795 | ||
796 | /* Initialize GPIO early so I2C device resets can be performed */ | ||
806 | cx18_gpio_init(cx); | 797 | cx18_gpio_init(cx); |
807 | 798 | ||
808 | retval = cx18_av_probe(cx, &cx->sd_av); | 799 | /* Initialize integrated A/V decoder early to set PLLs, just in case */ |
800 | retval = cx18_av_probe(cx); | ||
809 | if (retval) { | 801 | if (retval) { |
810 | CX18_ERR("Could not register A/V decoder subdevice\n"); | 802 | CX18_ERR("Could not register A/V decoder subdevice\n"); |
811 | goto free_map; | 803 | goto free_map; |
812 | } | 804 | } |
813 | /* Initialize the A/V decoder PLLs to sane defaults */ | 805 | /* Initialize the A/V decoder PLLs to sane defaults */ |
814 | v4l2_subdev_call(cx->sd_av, core, init, (u32) CX18_AV_INIT_PLLS); | 806 | cx18_call_hw(cx, CX18_HW_418_AV, core, init, (u32) CX18_AV_INIT_PLLS); |
815 | 807 | ||
816 | /* active i2c */ | 808 | /* active i2c */ |
817 | CX18_DEBUG_INFO("activating i2c...\n"); | 809 | CX18_DEBUG_INFO("activating i2c...\n"); |
@@ -873,7 +865,7 @@ static int __devinit cx18_probe(struct pci_dev *pci_dev, | |||
873 | initialization. */ | 865 | initialization. */ |
874 | cx18_init_struct2(cx); | 866 | cx18_init_struct2(cx); |
875 | 867 | ||
876 | cx18_load_and_init_modules(cx); | 868 | cx18_init_subdevs(cx); |
877 | 869 | ||
878 | if (cx->std & V4L2_STD_525_60) { | 870 | if (cx->std & V4L2_STD_525_60) { |
879 | cx->is_60hz = 1; | 871 | cx->is_60hz = 1; |
@@ -895,7 +887,7 @@ static int __devinit cx18_probe(struct pci_dev *pci_dev, | |||
895 | setup.mode_mask = T_ANALOG_TV; /* matches TV tuners */ | 887 | setup.mode_mask = T_ANALOG_TV; /* matches TV tuners */ |
896 | setup.tuner_callback = (setup.type == TUNER_XC2028) ? | 888 | setup.tuner_callback = (setup.type == TUNER_XC2028) ? |
897 | cx18_reset_tuner_gpio : NULL; | 889 | cx18_reset_tuner_gpio : NULL; |
898 | cx18_call_i2c_clients(cx, TUNER_SET_TYPE_ADDR, &setup); | 890 | cx18_call_all(cx, tuner, s_type_addr, &setup); |
899 | if (setup.type == TUNER_XC2028) { | 891 | if (setup.type == TUNER_XC2028) { |
900 | static struct xc2028_ctrl ctrl = { | 892 | static struct xc2028_ctrl ctrl = { |
901 | .fname = XC2028_DEFAULT_FIRMWARE, | 893 | .fname = XC2028_DEFAULT_FIRMWARE, |
@@ -905,7 +897,7 @@ static int __devinit cx18_probe(struct pci_dev *pci_dev, | |||
905 | .tuner = cx->options.tuner, | 897 | .tuner = cx->options.tuner, |
906 | .priv = &ctrl, | 898 | .priv = &ctrl, |
907 | }; | 899 | }; |
908 | cx18_call_i2c_clients(cx, TUNER_SET_CONFIG, &cfg); | 900 | cx18_call_all(cx, tuner, s_config, &cfg); |
909 | } | 901 | } |
910 | } | 902 | } |
911 | 903 | ||
diff --git a/drivers/media/video/cx18/cx18-driver.h b/drivers/media/video/cx18/cx18-driver.h index 4b50878fc265..b81106d682ae 100644 --- a/drivers/media/video/cx18/cx18-driver.h +++ b/drivers/media/video/cx18/cx18-driver.h | |||
@@ -448,7 +448,8 @@ struct cx18 { | |||
448 | int instance; | 448 | int instance; |
449 | struct pci_dev *pci_dev; | 449 | struct pci_dev *pci_dev; |
450 | struct v4l2_device v4l2_dev; | 450 | struct v4l2_device v4l2_dev; |
451 | struct v4l2_subdev *sd_av; | 451 | struct v4l2_subdev *sd_av; /* A/V decoder/digitizer sub-device */ |
452 | struct v4l2_subdev *sd_extmux; /* External audio multiplexer sub-dev */ | ||
452 | 453 | ||
453 | const struct cx18_card *card; /* card information */ | 454 | const struct cx18_card *card; /* card information */ |
454 | const char *card_name; /* full name of the card */ | 455 | const char *card_name; /* full name of the card */ |
@@ -528,9 +529,6 @@ struct cx18 { | |||
528 | struct i2c_adapter i2c_adap[2]; | 529 | struct i2c_adapter i2c_adap[2]; |
529 | struct i2c_algo_bit_data i2c_algo[2]; | 530 | struct i2c_algo_bit_data i2c_algo[2]; |
530 | struct cx18_i2c_algo_callback_data i2c_algo_cb_data[2]; | 531 | struct cx18_i2c_algo_callback_data i2c_algo_cb_data[2]; |
531 | struct i2c_client i2c_client[2]; | ||
532 | struct mutex i2c_bus_lock[2]; | ||
533 | struct i2c_client *i2c_clients[I2C_CLIENTS_MAX]; | ||
534 | 532 | ||
535 | /* gpio */ | 533 | /* gpio */ |
536 | u32 gpio_dir; | 534 | u32 gpio_dir; |
@@ -573,4 +571,22 @@ static inline int cx18_raw_vbi(const struct cx18 *cx) | |||
573 | return cx->vbi.in.type == V4L2_BUF_TYPE_VBI_CAPTURE; | 571 | return cx->vbi.in.type == V4L2_BUF_TYPE_VBI_CAPTURE; |
574 | } | 572 | } |
575 | 573 | ||
574 | /* Call the specified callback for all subdevs with a grp_id bit matching the | ||
575 | * mask in hw (if 0, then match them all). Ignore any errors. */ | ||
576 | #define cx18_call_hw(cx, hw, o, f, args...) \ | ||
577 | __v4l2_device_call_subdevs(&(cx)->v4l2_dev, \ | ||
578 | !(hw) || (sd->grp_id & (hw)), o, f , ##args) | ||
579 | |||
580 | #define cx18_call_all(cx, o, f, args...) cx18_call_hw(cx, 0, o, f , ##args) | ||
581 | |||
582 | /* Call the specified callback for all subdevs with a grp_id bit matching the | ||
583 | * mask in hw (if 0, then match them all). If the callback returns an error | ||
584 | * other than 0 or -ENOIOCTLCMD, then return with that error code. */ | ||
585 | #define cx18_call_hw_err(cx, hw, o, f, args...) \ | ||
586 | __v4l2_device_call_subdevs_until_err( \ | ||
587 | &(cx)->v4l2_dev, !(hw) || (sd->grp_id & (hw)), o, f , ##args) | ||
588 | |||
589 | #define cx18_call_all_err(cx, o, f, args...) \ | ||
590 | cx18_call_hw_err(cx, 0, o, f , ##args) | ||
591 | |||
576 | #endif /* CX18_DRIVER_H */ | 592 | #endif /* CX18_DRIVER_H */ |
diff --git a/drivers/media/video/cx18/cx18-fileops.c b/drivers/media/video/cx18/cx18-fileops.c index 757982ea3766..4d7d6d5a7f86 100644 --- a/drivers/media/video/cx18/cx18-fileops.c +++ b/drivers/media/video/cx18/cx18-fileops.c | |||
@@ -136,7 +136,7 @@ static void cx18_dualwatch(struct cx18 *cx) | |||
136 | 136 | ||
137 | new_stereo_mode = cx->params.audio_properties & stereo_mask; | 137 | new_stereo_mode = cx->params.audio_properties & stereo_mask; |
138 | memset(&vt, 0, sizeof(vt)); | 138 | memset(&vt, 0, sizeof(vt)); |
139 | cx18_call_i2c_clients(cx, VIDIOC_G_TUNER, &vt); | 139 | cx18_call_all(cx, tuner, g_tuner, &vt); |
140 | if (vt.audmode == V4L2_TUNER_MODE_LANG1_LANG2 && | 140 | if (vt.audmode == V4L2_TUNER_MODE_LANG1_LANG2 && |
141 | (vt.rxsubchans & V4L2_TUNER_SUB_LANG2)) | 141 | (vt.rxsubchans & V4L2_TUNER_SUB_LANG2)) |
142 | new_stereo_mode = dual; | 142 | new_stereo_mode = dual; |
@@ -608,7 +608,7 @@ int cx18_v4l2_close(struct file *filp) | |||
608 | /* Mark that the radio is no longer in use */ | 608 | /* Mark that the radio is no longer in use */ |
609 | clear_bit(CX18_F_I_RADIO_USER, &cx->i_flags); | 609 | clear_bit(CX18_F_I_RADIO_USER, &cx->i_flags); |
610 | /* Switch tuner to TV */ | 610 | /* Switch tuner to TV */ |
611 | cx18_call_i2c_clients(cx, VIDIOC_S_STD, &cx->std); | 611 | cx18_call_all(cx, tuner, s_std, cx->std); |
612 | /* Select correct audio input (i.e. TV tuner or Line in) */ | 612 | /* Select correct audio input (i.e. TV tuner or Line in) */ |
613 | cx18_audio_set_io(cx); | 613 | cx18_audio_set_io(cx); |
614 | if (atomic_read(&cx->ana_capturing) > 0) { | 614 | if (atomic_read(&cx->ana_capturing) > 0) { |
@@ -671,7 +671,7 @@ static int cx18_serialized_open(struct cx18_stream *s, struct file *filp) | |||
671 | /* We have the radio */ | 671 | /* We have the radio */ |
672 | cx18_mute(cx); | 672 | cx18_mute(cx); |
673 | /* Switch tuner to radio */ | 673 | /* Switch tuner to radio */ |
674 | cx18_call_i2c_clients(cx, AUDC_SET_RADIO, NULL); | 674 | cx18_call_all(cx, tuner, s_radio); |
675 | /* Select the correct audio input (i.e. radio tuner) */ | 675 | /* Select the correct audio input (i.e. radio tuner) */ |
676 | cx18_audio_set_io(cx); | 676 | cx18_audio_set_io(cx); |
677 | /* Done! Unmute and continue. */ | 677 | /* Done! Unmute and continue. */ |
diff --git a/drivers/media/video/cx18/cx18-i2c.c b/drivers/media/video/cx18/cx18-i2c.c index db7b55281f50..6357dc44ab5b 100644 --- a/drivers/media/video/cx18/cx18-i2c.c +++ b/drivers/media/video/cx18/cx18-i2c.c | |||
@@ -43,31 +43,34 @@ | |||
43 | #define CX18_CS5345_I2C_ADDR 0x4c | 43 | #define CX18_CS5345_I2C_ADDR 0x4c |
44 | 44 | ||
45 | /* This array should match the CX18_HW_ defines */ | 45 | /* This array should match the CX18_HW_ defines */ |
46 | static const u8 hw_driverids[] = { | ||
47 | I2C_DRIVERID_TUNER, | ||
48 | I2C_DRIVERID_TVEEPROM, | ||
49 | I2C_DRIVERID_CS5345, | ||
50 | 0, /* CX18_HW_GPIO dummy driver ID */ | ||
51 | 0 /* CX18_HW_CX23418 dummy driver ID */ | ||
52 | }; | ||
53 | |||
54 | /* This array should match the CX18_HW_ defines */ | ||
55 | static const u8 hw_addrs[] = { | 46 | static const u8 hw_addrs[] = { |
56 | 0, | 47 | 0, /* CX18_HW_TUNER */ |
57 | 0, | 48 | 0, /* CX18_HW_TVEEPROM */ |
58 | CX18_CS5345_I2C_ADDR, | 49 | CX18_CS5345_I2C_ADDR, /* CX18_HW_CS5345 */ |
59 | 0, /* CX18_HW_GPIO dummy driver ID */ | 50 | 0, /* CX18_HW_DVB */ |
60 | 0, /* CX18_HW_CX23418 dummy driver ID */ | 51 | 0, /* CX18_HW_418_AV */ |
52 | 0, /* CX18_HW_GPIO_AUDIO_MUX */ | ||
61 | }; | 53 | }; |
62 | 54 | ||
63 | /* This array should match the CX18_HW_ defines */ | 55 | /* This array should match the CX18_HW_ defines */ |
64 | /* This might well become a card-specific array */ | 56 | /* This might well become a card-specific array */ |
65 | static const u8 hw_bus[] = { | 57 | static const u8 hw_bus[] = { |
66 | 0, | 58 | 1, /* CX18_HW_TUNER */ |
67 | 0, | 59 | 0, /* CX18_HW_TVEEPROM */ |
68 | 0, | 60 | 0, /* CX18_HW_CS5345 */ |
69 | 0, /* CX18_HW_GPIO dummy driver ID */ | 61 | 0, /* CX18_HW_DVB */ |
70 | 0, /* CX18_HW_CX23418 dummy driver ID */ | 62 | 0, /* CX18_HW_418_AV */ |
63 | 0, /* CX18_HW_GPIO_AUDIO_MUX */ | ||
64 | }; | ||
65 | |||
66 | /* This array should match the CX18_HW_ defines */ | ||
67 | static const char * const hw_modules[] = { | ||
68 | "tuner", /* CX18_HW_TUNER */ | ||
69 | NULL, /* CX18_HW_TVEEPROM */ | ||
70 | "cs5345", /* CX18_HW_CS5345 */ | ||
71 | NULL, /* CX18_HW_DVB */ | ||
72 | NULL, /* CX18_HW_418_AV */ | ||
73 | NULL, /* CX18_HW_GPIO_AUDIO_MUX */ | ||
71 | }; | 74 | }; |
72 | 75 | ||
73 | /* This array should match the CX18_HW_ defines */ | 76 | /* This array should match the CX18_HW_ defines */ |
@@ -75,83 +78,66 @@ static const char * const hw_devicenames[] = { | |||
75 | "tuner", | 78 | "tuner", |
76 | "tveeprom", | 79 | "tveeprom", |
77 | "cs5345", | 80 | "cs5345", |
78 | "gpio", | 81 | "cx23418_DTV", |
79 | "cx23418", | 82 | "cx23418_AV", |
83 | "gpio_audio_mux", | ||
80 | }; | 84 | }; |
81 | 85 | ||
82 | int cx18_i2c_register(struct cx18 *cx, unsigned idx) | 86 | int cx18_i2c_register(struct cx18 *cx, unsigned idx) |
83 | { | 87 | { |
84 | struct i2c_board_info info; | 88 | struct v4l2_subdev *sd; |
85 | struct i2c_client *c; | 89 | int bus = hw_bus[idx]; |
86 | u8 id, bus; | 90 | struct i2c_adapter *adap = &cx->i2c_adap[bus]; |
87 | int i; | 91 | const char *mod = hw_modules[idx]; |
88 | 92 | const char *type = hw_devicenames[idx]; | |
89 | CX18_DEBUG_I2C("i2c client register\n"); | 93 | u32 hw = 1 << idx; |
90 | if (idx >= ARRAY_SIZE(hw_driverids) || hw_driverids[idx] == 0) | 94 | |
95 | if (idx >= ARRAY_SIZE(hw_addrs)) | ||
91 | return -1; | 96 | return -1; |
92 | id = hw_driverids[idx]; | ||
93 | bus = hw_bus[idx]; | ||
94 | memset(&info, 0, sizeof(info)); | ||
95 | strlcpy(info.type, hw_devicenames[idx], sizeof(info.type)); | ||
96 | info.addr = hw_addrs[idx]; | ||
97 | for (i = 0; i < I2C_CLIENTS_MAX; i++) | ||
98 | if (cx->i2c_clients[i] == NULL) | ||
99 | break; | ||
100 | |||
101 | if (i == I2C_CLIENTS_MAX) { | ||
102 | CX18_ERR("insufficient room for new I2C client!\n"); | ||
103 | return -ENOMEM; | ||
104 | } | ||
105 | 97 | ||
106 | if (id != I2C_DRIVERID_TUNER) { | 98 | if (hw == CX18_HW_TUNER) { |
107 | c = i2c_new_device(&cx->i2c_adap[bus], &info); | 99 | /* special tuner group handling */ |
108 | if (c->driver == NULL) | 100 | sd = v4l2_i2c_new_probed_subdev(adap, mod, type, |
109 | i2c_unregister_device(c); | 101 | cx->card_i2c->radio); |
110 | else | 102 | if (sd != NULL) |
111 | cx->i2c_clients[i] = c; | 103 | sd->grp_id = hw; |
112 | return cx->i2c_clients[i] ? 0 : -ENODEV; | 104 | sd = v4l2_i2c_new_probed_subdev(adap, mod, type, |
105 | cx->card_i2c->demod); | ||
106 | if (sd != NULL) | ||
107 | sd->grp_id = hw; | ||
108 | sd = v4l2_i2c_new_probed_subdev(adap, mod, type, | ||
109 | cx->card_i2c->tv); | ||
110 | if (sd != NULL) | ||
111 | sd->grp_id = hw; | ||
112 | return sd != NULL ? 0 : -1; | ||
113 | } | 113 | } |
114 | 114 | ||
115 | /* special tuner handling */ | 115 | /* Is it not an I2C device or one we do not wish to register? */ |
116 | c = i2c_new_probed_device(&cx->i2c_adap[1], &info, cx->card_i2c->radio); | 116 | if (!hw_addrs[idx]) |
117 | if (c && c->driver == NULL) | 117 | return -1; |
118 | i2c_unregister_device(c); | ||
119 | else if (c) | ||
120 | cx->i2c_clients[i++] = c; | ||
121 | c = i2c_new_probed_device(&cx->i2c_adap[1], &info, cx->card_i2c->demod); | ||
122 | if (c && c->driver == NULL) | ||
123 | i2c_unregister_device(c); | ||
124 | else if (c) | ||
125 | cx->i2c_clients[i++] = c; | ||
126 | c = i2c_new_probed_device(&cx->i2c_adap[1], &info, cx->card_i2c->tv); | ||
127 | if (c && c->driver == NULL) | ||
128 | i2c_unregister_device(c); | ||
129 | else if (c) | ||
130 | cx->i2c_clients[i++] = c; | ||
131 | return 0; | ||
132 | } | ||
133 | 118 | ||
134 | static int attach_inform(struct i2c_client *client) | 119 | /* It's an I2C device other than an analog tuner */ |
135 | { | 120 | sd = v4l2_i2c_new_subdev(adap, mod, type, hw_addrs[idx]); |
136 | return 0; | 121 | if (sd != NULL) |
122 | sd->grp_id = hw; | ||
123 | return sd != NULL ? 0 : -1; | ||
137 | } | 124 | } |
138 | 125 | ||
139 | static int detach_inform(struct i2c_client *client) | 126 | /* Find the first member of the subdev group id in hw */ |
127 | struct v4l2_subdev *cx18_find_hw(struct cx18 *cx, u32 hw) | ||
140 | { | 128 | { |
141 | int i; | 129 | struct v4l2_subdev *result = NULL; |
142 | struct cx18 *cx = (struct cx18 *)i2c_get_adapdata(client->adapter); | 130 | struct v4l2_subdev *sd; |
143 | 131 | ||
144 | CX18_DEBUG_I2C("i2c client detach\n"); | 132 | spin_lock(&cx->v4l2_dev.lock); |
145 | for (i = 0; i < I2C_CLIENTS_MAX; i++) { | 133 | v4l2_device_for_each_subdev(sd, &cx->v4l2_dev) { |
146 | if (cx->i2c_clients[i] == client) { | 134 | if (sd->grp_id == hw) { |
147 | cx->i2c_clients[i] = NULL; | 135 | result = sd; |
148 | break; | 136 | break; |
149 | } | 137 | } |
150 | } | 138 | } |
151 | CX18_DEBUG_I2C("i2c detach [client=%s,%s]\n", | 139 | spin_unlock(&cx->v4l2_dev.lock); |
152 | client->name, (i < I2C_CLIENTS_MAX) ? "ok" : "failed"); | 140 | return result; |
153 | |||
154 | return 0; | ||
155 | } | 141 | } |
156 | 142 | ||
157 | static void cx18_setscl(void *data, int state) | 143 | static void cx18_setscl(void *data, int state) |
@@ -204,8 +190,6 @@ static struct i2c_adapter cx18_i2c_adap_template = { | |||
204 | .id = I2C_HW_B_CX2341X, | 190 | .id = I2C_HW_B_CX2341X, |
205 | .algo = NULL, /* set by i2c-algo-bit */ | 191 | .algo = NULL, /* set by i2c-algo-bit */ |
206 | .algo_data = NULL, /* filled from template */ | 192 | .algo_data = NULL, /* filled from template */ |
207 | .client_register = attach_inform, | ||
208 | .client_unregister = detach_inform, | ||
209 | .owner = THIS_MODULE, | 193 | .owner = THIS_MODULE, |
210 | }; | 194 | }; |
211 | 195 | ||
@@ -221,151 +205,27 @@ static struct i2c_algo_bit_data cx18_i2c_algo_template = { | |||
221 | .timeout = CX18_ALGO_BIT_TIMEOUT*HZ /* jiffies */ | 205 | .timeout = CX18_ALGO_BIT_TIMEOUT*HZ /* jiffies */ |
222 | }; | 206 | }; |
223 | 207 | ||
224 | static struct i2c_client cx18_i2c_client_template = { | ||
225 | .name = "cx18 internal", | ||
226 | }; | ||
227 | |||
228 | int cx18_call_i2c_client(struct cx18 *cx, int addr, unsigned cmd, void *arg) | ||
229 | { | ||
230 | struct i2c_client *client; | ||
231 | int retval; | ||
232 | int i; | ||
233 | |||
234 | CX18_DEBUG_I2C("call_i2c_client addr=%02x\n", addr); | ||
235 | for (i = 0; i < I2C_CLIENTS_MAX; i++) { | ||
236 | client = cx->i2c_clients[i]; | ||
237 | if (client == NULL || client->driver == NULL || | ||
238 | client->driver->command == NULL) | ||
239 | continue; | ||
240 | if (addr == client->addr) { | ||
241 | retval = client->driver->command(client, cmd, arg); | ||
242 | return retval; | ||
243 | } | ||
244 | } | ||
245 | if (cmd != VIDIOC_DBG_G_CHIP_IDENT) | ||
246 | CX18_ERR("i2c addr 0x%02x not found for cmd 0x%x!\n", | ||
247 | addr, cmd); | ||
248 | return -ENODEV; | ||
249 | } | ||
250 | |||
251 | /* Find the i2c device based on the driver ID and return | ||
252 | its i2c address or -ENODEV if no matching device was found. */ | ||
253 | static int cx18_i2c_id_addr(struct cx18 *cx, u32 id) | ||
254 | { | ||
255 | struct i2c_client *client; | ||
256 | int retval = -ENODEV; | ||
257 | int i; | ||
258 | |||
259 | for (i = 0; i < I2C_CLIENTS_MAX; i++) { | ||
260 | client = cx->i2c_clients[i]; | ||
261 | if (client == NULL || client->driver == NULL) | ||
262 | continue; | ||
263 | if (id == client->driver->id) { | ||
264 | retval = client->addr; | ||
265 | break; | ||
266 | } | ||
267 | } | ||
268 | return retval; | ||
269 | } | ||
270 | |||
271 | /* Find the i2c device name matching the CX18_HW_ flag */ | ||
272 | static const char *cx18_i2c_hw_name(u32 hw) | ||
273 | { | ||
274 | int i; | ||
275 | |||
276 | for (i = 0; i < ARRAY_SIZE(hw_driverids); i++) | ||
277 | if (1 << i == hw) | ||
278 | return hw_devicenames[i]; | ||
279 | return "unknown device"; | ||
280 | } | ||
281 | |||
282 | /* Find the i2c device matching the CX18_HW_ flag and return | ||
283 | its i2c address or -ENODEV if no matching device was found. */ | ||
284 | int cx18_i2c_hw_addr(struct cx18 *cx, u32 hw) | ||
285 | { | ||
286 | int i; | ||
287 | |||
288 | for (i = 0; i < ARRAY_SIZE(hw_driverids); i++) | ||
289 | if (1 << i == hw) | ||
290 | return cx18_i2c_id_addr(cx, hw_driverids[i]); | ||
291 | return -ENODEV; | ||
292 | } | ||
293 | |||
294 | /* Calls i2c device based on CX18_HW_ flag. If hw == 0, then do nothing. | ||
295 | If hw == CX18_HW_GPIO then call the gpio handler. */ | ||
296 | int cx18_i2c_hw(struct cx18 *cx, u32 hw, unsigned int cmd, void *arg) | ||
297 | { | ||
298 | int addr; | ||
299 | |||
300 | if (hw == 0) | ||
301 | return 0; | ||
302 | |||
303 | if (hw == CX18_HW_GPIO) | ||
304 | return cx18_gpio(cx, cmd, arg); | ||
305 | |||
306 | if (hw == CX18_HW_CX23418) | ||
307 | return v4l2_subdev_command(cx->sd_av, cmd, arg); | ||
308 | |||
309 | addr = cx18_i2c_hw_addr(cx, hw); | ||
310 | if (addr < 0) { | ||
311 | CX18_ERR("i2c hardware 0x%08x (%s) not found for cmd 0x%x!\n", | ||
312 | hw, cx18_i2c_hw_name(hw), cmd); | ||
313 | return addr; | ||
314 | } | ||
315 | return cx18_call_i2c_client(cx, addr, cmd, arg); | ||
316 | } | ||
317 | |||
318 | /* broadcast cmd for all I2C clients and for the gpio subsystem */ | ||
319 | void cx18_call_i2c_clients(struct cx18 *cx, unsigned int cmd, void *arg) | ||
320 | { | ||
321 | if (cx->i2c_adap[0].algo == NULL || cx->i2c_adap[1].algo == NULL) { | ||
322 | CX18_ERR("adapter is not set\n"); | ||
323 | return; | ||
324 | } | ||
325 | v4l2_subdev_command(cx->sd_av, cmd, arg); | ||
326 | i2c_clients_command(&cx->i2c_adap[0], cmd, arg); | ||
327 | i2c_clients_command(&cx->i2c_adap[1], cmd, arg); | ||
328 | if (cx->hw_flags & CX18_HW_GPIO) | ||
329 | cx18_gpio(cx, cmd, arg); | ||
330 | } | ||
331 | |||
332 | /* init + register i2c algo-bit adapter */ | 208 | /* init + register i2c algo-bit adapter */ |
333 | int init_cx18_i2c(struct cx18 *cx) | 209 | int init_cx18_i2c(struct cx18 *cx) |
334 | { | 210 | { |
335 | int i; | 211 | int i; |
336 | CX18_DEBUG_I2C("i2c init\n"); | 212 | CX18_DEBUG_I2C("i2c init\n"); |
337 | 213 | ||
338 | /* Sanity checks for the I2C hardware arrays. They must be the | ||
339 | * same size and GPIO/CX23418 must be the last entries. | ||
340 | */ | ||
341 | if (ARRAY_SIZE(hw_driverids) != ARRAY_SIZE(hw_addrs) || | ||
342 | ARRAY_SIZE(hw_devicenames) != ARRAY_SIZE(hw_addrs) || | ||
343 | CX18_HW_GPIO != (1 << (ARRAY_SIZE(hw_addrs) - 2)) || | ||
344 | CX18_HW_CX23418 != (1 << (ARRAY_SIZE(hw_addrs) - 1)) || | ||
345 | hw_driverids[ARRAY_SIZE(hw_addrs) - 1]) { | ||
346 | CX18_ERR("Mismatched I2C hardware arrays\n"); | ||
347 | return -ENODEV; | ||
348 | } | ||
349 | |||
350 | for (i = 0; i < 2; i++) { | 214 | for (i = 0; i < 2; i++) { |
351 | memcpy(&cx->i2c_adap[i], &cx18_i2c_adap_template, | 215 | /* Setup algorithm for adapter */ |
352 | sizeof(struct i2c_adapter)); | ||
353 | memcpy(&cx->i2c_algo[i], &cx18_i2c_algo_template, | 216 | memcpy(&cx->i2c_algo[i], &cx18_i2c_algo_template, |
354 | sizeof(struct i2c_algo_bit_data)); | 217 | sizeof(struct i2c_algo_bit_data)); |
355 | cx->i2c_algo_cb_data[i].cx = cx; | 218 | cx->i2c_algo_cb_data[i].cx = cx; |
356 | cx->i2c_algo_cb_data[i].bus_index = i; | 219 | cx->i2c_algo_cb_data[i].bus_index = i; |
357 | cx->i2c_algo[i].data = &cx->i2c_algo_cb_data[i]; | 220 | cx->i2c_algo[i].data = &cx->i2c_algo_cb_data[i]; |
358 | cx->i2c_adap[i].algo_data = &cx->i2c_algo[i]; | ||
359 | 221 | ||
222 | /* Setup adapter */ | ||
223 | memcpy(&cx->i2c_adap[i], &cx18_i2c_adap_template, | ||
224 | sizeof(struct i2c_adapter)); | ||
225 | cx->i2c_adap[i].algo_data = &cx->i2c_algo[i]; | ||
360 | sprintf(cx->i2c_adap[i].name + strlen(cx->i2c_adap[i].name), | 226 | sprintf(cx->i2c_adap[i].name + strlen(cx->i2c_adap[i].name), |
361 | " #%d-%d", cx->instance, i); | 227 | " #%d-%d", cx->instance, i); |
362 | i2c_set_adapdata(&cx->i2c_adap[i], cx); | 228 | i2c_set_adapdata(&cx->i2c_adap[i], &cx->v4l2_dev); |
363 | |||
364 | memcpy(&cx->i2c_client[i], &cx18_i2c_client_template, | ||
365 | sizeof(struct i2c_client)); | ||
366 | sprintf(cx->i2c_client[i].name + | ||
367 | strlen(cx->i2c_client[i].name), "%d", i); | ||
368 | cx->i2c_client[i].adapter = &cx->i2c_adap[i]; | ||
369 | cx->i2c_adap[i].dev.parent = &cx->pci_dev->dev; | 229 | cx->i2c_adap[i].dev.parent = &cx->pci_dev->dev; |
370 | } | 230 | } |
371 | 231 | ||
diff --git a/drivers/media/video/cx18/cx18-i2c.h b/drivers/media/video/cx18/cx18-i2c.h index 4869739013bd..bdfd1921e300 100644 --- a/drivers/media/video/cx18/cx18-i2c.h +++ b/drivers/media/video/cx18/cx18-i2c.h | |||
@@ -21,11 +21,8 @@ | |||
21 | * 02111-1307 USA | 21 | * 02111-1307 USA |
22 | */ | 22 | */ |
23 | 23 | ||
24 | int cx18_i2c_hw_addr(struct cx18 *cx, u32 hw); | ||
25 | int cx18_i2c_hw(struct cx18 *cx, u32 hw, unsigned int cmd, void *arg); | ||
26 | int cx18_call_i2c_client(struct cx18 *cx, int addr, unsigned cmd, void *arg); | ||
27 | void cx18_call_i2c_clients(struct cx18 *cx, unsigned int cmd, void *arg); | ||
28 | int cx18_i2c_register(struct cx18 *cx, unsigned idx); | 24 | int cx18_i2c_register(struct cx18 *cx, unsigned idx); |
25 | struct v4l2_subdev *cx18_find_hw(struct cx18 *cx, u32 hw); | ||
29 | 26 | ||
30 | /* init + register i2c algo-bit adapter */ | 27 | /* init + register i2c algo-bit adapter */ |
31 | int init_cx18_i2c(struct cx18 *cx); | 28 | int init_cx18_i2c(struct cx18 *cx); |
diff --git a/drivers/media/video/cx18/cx18-ioctl.c b/drivers/media/video/cx18/cx18-ioctl.c index 0ddf4dd55308..13ebd4a70f0d 100644 --- a/drivers/media/video/cx18/cx18-ioctl.c +++ b/drivers/media/video/cx18/cx18-ioctl.c | |||
@@ -372,15 +372,52 @@ static int cx18_g_chip_ident(struct file *file, void *fh, | |||
372 | struct v4l2_dbg_chip_ident *chip) | 372 | struct v4l2_dbg_chip_ident *chip) |
373 | { | 373 | { |
374 | struct cx18 *cx = ((struct cx18_open_id *)fh)->cx; | 374 | struct cx18 *cx = ((struct cx18_open_id *)fh)->cx; |
375 | int err = 0; | ||
375 | 376 | ||
376 | chip->ident = V4L2_IDENT_NONE; | 377 | chip->ident = V4L2_IDENT_NONE; |
377 | chip->revision = 0; | 378 | chip->revision = 0; |
378 | if (v4l2_chip_match_host(&chip->match)) { | 379 | switch (chip->match.type) { |
379 | chip->ident = V4L2_IDENT_CX23418; | 380 | case V4L2_CHIP_MATCH_HOST: |
380 | return 0; | 381 | switch (chip->match.addr) { |
382 | case 0: | ||
383 | chip->ident = V4L2_IDENT_CX23418; | ||
384 | chip->revision = cx18_read_reg(cx, 0xC72028); | ||
385 | break; | ||
386 | case 1: | ||
387 | /* | ||
388 | * The A/V decoder is always present, but in the rare | ||
389 | * case that the card doesn't have analog, we don't | ||
390 | * use it. We find it w/o using the cx->sd_av pointer | ||
391 | */ | ||
392 | cx18_call_hw(cx, CX18_HW_418_AV, | ||
393 | core, g_chip_ident, chip); | ||
394 | break; | ||
395 | default: | ||
396 | /* | ||
397 | * Could return ident = V4L2_IDENT_UNKNOWN if we had | ||
398 | * other host chips at higher addresses, but we don't | ||
399 | */ | ||
400 | err = -EINVAL; /* per V4L2 spec */ | ||
401 | break; | ||
402 | } | ||
403 | break; | ||
404 | case V4L2_CHIP_MATCH_I2C_DRIVER: | ||
405 | /* If needed, returns V4L2_IDENT_AMBIGUOUS without extra work */ | ||
406 | cx18_call_all(cx, core, g_chip_ident, chip); | ||
407 | break; | ||
408 | case V4L2_CHIP_MATCH_I2C_ADDR: | ||
409 | /* | ||
410 | * We could return V4L2_IDENT_UNKNOWN, but we don't do the work | ||
411 | * to look if a chip is at the address with no driver. That's a | ||
412 | * dangerous thing to do with EEPROMs anyway. | ||
413 | */ | ||
414 | cx18_call_all(cx, core, g_chip_ident, chip); | ||
415 | break; | ||
416 | default: | ||
417 | err = -EINVAL; | ||
418 | break; | ||
381 | } | 419 | } |
382 | cx18_call_i2c_clients(cx, VIDIOC_DBG_G_CHIP_IDENT, chip); | 420 | return err; |
383 | return 0; | ||
384 | } | 421 | } |
385 | 422 | ||
386 | #ifdef CONFIG_VIDEO_ADV_DEBUG | 423 | #ifdef CONFIG_VIDEO_ADV_DEBUG |
@@ -394,10 +431,10 @@ static int cx18_cxc(struct cx18 *cx, unsigned int cmd, void *arg) | |||
394 | return -EINVAL; | 431 | return -EINVAL; |
395 | 432 | ||
396 | regs->size = 4; | 433 | regs->size = 4; |
397 | if (cmd == VIDIOC_DBG_G_REGISTER) | 434 | if (cmd == VIDIOC_DBG_S_REGISTER) |
398 | regs->val = cx18_read_enc(cx, regs->reg); | ||
399 | else | ||
400 | cx18_write_enc(cx, regs->val, regs->reg); | 435 | cx18_write_enc(cx, regs->val, regs->reg); |
436 | else | ||
437 | regs->val = cx18_read_enc(cx, regs->reg); | ||
401 | return 0; | 438 | return 0; |
402 | } | 439 | } |
403 | 440 | ||
@@ -408,7 +445,8 @@ static int cx18_g_register(struct file *file, void *fh, | |||
408 | 445 | ||
409 | if (v4l2_chip_match_host(®->match)) | 446 | if (v4l2_chip_match_host(®->match)) |
410 | return cx18_cxc(cx, VIDIOC_DBG_G_REGISTER, reg); | 447 | return cx18_cxc(cx, VIDIOC_DBG_G_REGISTER, reg); |
411 | cx18_call_i2c_clients(cx, VIDIOC_DBG_G_REGISTER, reg); | 448 | /* FIXME - errors shouldn't be ignored */ |
449 | cx18_call_all(cx, core, g_register, reg); | ||
412 | return 0; | 450 | return 0; |
413 | } | 451 | } |
414 | 452 | ||
@@ -419,7 +457,8 @@ static int cx18_s_register(struct file *file, void *fh, | |||
419 | 457 | ||
420 | if (v4l2_chip_match_host(®->match)) | 458 | if (v4l2_chip_match_host(®->match)) |
421 | return cx18_cxc(cx, VIDIOC_DBG_S_REGISTER, reg); | 459 | return cx18_cxc(cx, VIDIOC_DBG_S_REGISTER, reg); |
422 | cx18_call_i2c_clients(cx, VIDIOC_DBG_S_REGISTER, reg); | 460 | /* FIXME - errors shouldn't be ignored */ |
461 | cx18_call_all(cx, core, s_register, reg); | ||
423 | return 0; | 462 | return 0; |
424 | } | 463 | } |
425 | #endif | 464 | #endif |
@@ -598,7 +637,7 @@ static int cx18_g_frequency(struct file *file, void *fh, | |||
598 | if (vf->tuner != 0) | 637 | if (vf->tuner != 0) |
599 | return -EINVAL; | 638 | return -EINVAL; |
600 | 639 | ||
601 | cx18_call_i2c_clients(cx, VIDIOC_G_FREQUENCY, vf); | 640 | cx18_call_all(cx, tuner, g_frequency, vf); |
602 | return 0; | 641 | return 0; |
603 | } | 642 | } |
604 | 643 | ||
@@ -617,7 +656,7 @@ int cx18_s_frequency(struct file *file, void *fh, struct v4l2_frequency *vf) | |||
617 | 656 | ||
618 | cx18_mute(cx); | 657 | cx18_mute(cx); |
619 | CX18_DEBUG_INFO("v4l2 ioctl: set frequency %d\n", vf->frequency); | 658 | CX18_DEBUG_INFO("v4l2 ioctl: set frequency %d\n", vf->frequency); |
620 | cx18_call_i2c_clients(cx, VIDIOC_S_FREQUENCY, vf); | 659 | cx18_call_all(cx, tuner, s_frequency, vf); |
621 | cx18_unmute(cx); | 660 | cx18_unmute(cx); |
622 | return 0; | 661 | return 0; |
623 | } | 662 | } |
@@ -666,7 +705,7 @@ int cx18_s_std(struct file *file, void *fh, v4l2_std_id *std) | |||
666 | (unsigned long long) cx->std); | 705 | (unsigned long long) cx->std); |
667 | 706 | ||
668 | /* Tuner */ | 707 | /* Tuner */ |
669 | cx18_call_i2c_clients(cx, VIDIOC_S_STD, &cx->std); | 708 | cx18_call_all(cx, tuner, s_std, cx->std); |
670 | return 0; | 709 | return 0; |
671 | } | 710 | } |
672 | 711 | ||
@@ -683,9 +722,7 @@ static int cx18_s_tuner(struct file *file, void *fh, struct v4l2_tuner *vt) | |||
683 | if (vt->index != 0) | 722 | if (vt->index != 0) |
684 | return -EINVAL; | 723 | return -EINVAL; |
685 | 724 | ||
686 | /* Setting tuner can only set audio mode */ | 725 | cx18_call_all(cx, tuner, s_tuner, vt); |
687 | cx18_call_i2c_clients(cx, VIDIOC_S_TUNER, vt); | ||
688 | |||
689 | return 0; | 726 | return 0; |
690 | } | 727 | } |
691 | 728 | ||
@@ -696,7 +733,7 @@ static int cx18_g_tuner(struct file *file, void *fh, struct v4l2_tuner *vt) | |||
696 | if (vt->index != 0) | 733 | if (vt->index != 0) |
697 | return -EINVAL; | 734 | return -EINVAL; |
698 | 735 | ||
699 | cx18_call_i2c_clients(cx, VIDIOC_G_TUNER, vt); | 736 | cx18_call_all(cx, tuner, g_tuner, vt); |
700 | 737 | ||
701 | if (test_bit(CX18_F_I_RADIO_USER, &cx->i_flags)) { | 738 | if (test_bit(CX18_F_I_RADIO_USER, &cx->i_flags)) { |
702 | strlcpy(vt->name, "cx18 Radio Tuner", sizeof(vt->name)); | 739 | strlcpy(vt->name, "cx18 Radio Tuner", sizeof(vt->name)); |
@@ -853,7 +890,7 @@ static int cx18_log_status(struct file *file, void *fh) | |||
853 | 890 | ||
854 | cx18_read_eeprom(cx, &tv); | 891 | cx18_read_eeprom(cx, &tv); |
855 | } | 892 | } |
856 | cx18_call_i2c_clients(cx, VIDIOC_LOG_STATUS, NULL); | 893 | cx18_call_all(cx, core, log_status); |
857 | cx18_get_input(cx, cx->active_input, &vidin); | 894 | cx18_get_input(cx, cx->active_input, &vidin); |
858 | cx18_get_audio_input(cx, cx->audio_input, &audin); | 895 | cx18_get_audio_input(cx, cx->audio_input, &audin); |
859 | CX18_INFO("Video Input: %s\n", vidin.name); | 896 | CX18_INFO("Video Input: %s\n", vidin.name); |
@@ -894,7 +931,8 @@ static long cx18_default(struct file *file, void *fh, int cmd, void *arg) | |||
894 | 931 | ||
895 | CX18_DEBUG_IOCTL("VIDIOC_INT_S_AUDIO_ROUTING(%d, %d)\n", | 932 | CX18_DEBUG_IOCTL("VIDIOC_INT_S_AUDIO_ROUTING(%d, %d)\n", |
896 | route->input, route->output); | 933 | route->input, route->output); |
897 | cx18_audio_set_route(cx, route); | 934 | cx18_call_hw(cx, cx->card->hw_audio_ctrl, audio, s_routing, |
935 | route); | ||
898 | break; | 936 | break; |
899 | } | 937 | } |
900 | 938 | ||
@@ -922,6 +960,8 @@ long cx18_v4l2_ioctl(struct file *filp, unsigned int cmd, | |||
922 | 960 | ||
923 | mutex_lock(&cx->serialize_lock); | 961 | mutex_lock(&cx->serialize_lock); |
924 | 962 | ||
963 | /* FIXME - consolidate v4l2_prio_check()'s here */ | ||
964 | |||
925 | if (cx18_debug & CX18_DBGFLG_IOCTL) | 965 | if (cx18_debug & CX18_DBGFLG_IOCTL) |
926 | vfd->debug = V4L2_DEBUG_IOCTL | V4L2_DEBUG_IOCTL_ARG; | 966 | vfd->debug = V4L2_DEBUG_IOCTL | V4L2_DEBUG_IOCTL_ARG; |
927 | res = video_ioctl2(filp, cmd, arg); | 967 | res = video_ioctl2(filp, cmd, arg); |