diff options
author | Antti Palosaari <crope@iki.fi> | 2011-07-25 19:16:13 -0400 |
---|---|---|
committer | Mauro Carvalho Chehab <mchehab@redhat.com> | 2011-07-31 00:41:32 -0400 |
commit | 9bd9e3bd2c57530dfe3057dd0aa9bdb37824925d (patch) | |
tree | 5ca8af70f78533698257caddccac7ab05ce02c94 | |
parent | bfd4500c9abf3e70e9c563bcba5675bd302f5a4e (diff) |
[media] dvb-usb: multi-frontend support (MFE)
Signed-off-by: Antti Palosaari <crope@iki.fi>
Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
-rw-r--r-- | drivers/media/dvb/dvb-usb/dvb-usb-dvb.c | 85 | ||||
-rw-r--r-- | drivers/media/dvb/dvb-usb/dvb-usb-init.c | 4 | ||||
-rw-r--r-- | drivers/media/dvb/dvb-usb/dvb-usb.h | 11 |
3 files changed, 78 insertions, 22 deletions
diff --git a/drivers/media/dvb/dvb-usb/dvb-usb-dvb.c b/drivers/media/dvb/dvb-usb/dvb-usb-dvb.c index d8c0bd9107f3..5e34df70ad6e 100644 --- a/drivers/media/dvb/dvb-usb/dvb-usb-dvb.c +++ b/drivers/media/dvb/dvb-usb/dvb-usb-dvb.c | |||
@@ -162,8 +162,11 @@ static int dvb_usb_fe_wakeup(struct dvb_frontend *fe) | |||
162 | 162 | ||
163 | dvb_usb_device_power_ctrl(adap->dev, 1); | 163 | dvb_usb_device_power_ctrl(adap->dev, 1); |
164 | 164 | ||
165 | if (adap->fe_init) | 165 | if (adap->props.frontend_ctrl) |
166 | adap->fe_init(fe); | 166 | adap->props.frontend_ctrl(fe, 1); |
167 | |||
168 | if (adap->fe_init[fe->id]) | ||
169 | adap->fe_init[fe->id](fe); | ||
167 | 170 | ||
168 | return 0; | 171 | return 0; |
169 | } | 172 | } |
@@ -172,45 +175,89 @@ static int dvb_usb_fe_sleep(struct dvb_frontend *fe) | |||
172 | { | 175 | { |
173 | struct dvb_usb_adapter *adap = fe->dvb->priv; | 176 | struct dvb_usb_adapter *adap = fe->dvb->priv; |
174 | 177 | ||
175 | if (adap->fe_sleep) | 178 | if (adap->fe_sleep[fe->id]) |
176 | adap->fe_sleep(fe); | 179 | adap->fe_sleep[fe->id](fe); |
180 | |||
181 | if (adap->props.frontend_ctrl) | ||
182 | adap->props.frontend_ctrl(fe, 0); | ||
177 | 183 | ||
178 | return dvb_usb_device_power_ctrl(adap->dev, 0); | 184 | return dvb_usb_device_power_ctrl(adap->dev, 0); |
179 | } | 185 | } |
180 | 186 | ||
181 | int dvb_usb_adapter_frontend_init(struct dvb_usb_adapter *adap) | 187 | int dvb_usb_adapter_frontend_init(struct dvb_usb_adapter *adap) |
182 | { | 188 | { |
189 | int ret, i, x; | ||
190 | |||
191 | memset(adap->fe, 0, sizeof(adap->fe)); | ||
192 | |||
183 | if (adap->props.frontend_attach == NULL) { | 193 | if (adap->props.frontend_attach == NULL) { |
184 | err("strange: '%s' #%d doesn't want to attach a frontend.",adap->dev->desc->name, adap->id); | 194 | err("strange: '%s' #%d doesn't want to attach a frontend.", |
195 | adap->dev->desc->name, adap->id); | ||
196 | |||
185 | return 0; | 197 | return 0; |
186 | } | 198 | } |
187 | 199 | ||
188 | /* re-assign sleep and wakeup functions */ | 200 | /* register all given adapter frontends */ |
189 | if (adap->props.frontend_attach(adap) == 0 && adap->fe[0] != NULL) { | 201 | if (adap->props.num_frontends) |
190 | adap->fe_init = adap->fe[0]->ops.init; adap->fe[0]->ops.init = dvb_usb_fe_wakeup; | 202 | x = adap->props.num_frontends - 1; |
191 | adap->fe_sleep = adap->fe[0]->ops.sleep; adap->fe[0]->ops.sleep = dvb_usb_fe_sleep; | 203 | else |
204 | x = 0; | ||
205 | |||
206 | for (i = 0; i <= x; i++) { | ||
207 | ret = adap->props.frontend_attach(adap); | ||
208 | if (ret || adap->fe[i] == NULL) { | ||
209 | /* only print error when there is no FE at all */ | ||
210 | if (i == 0) | ||
211 | err("no frontend was attached by '%s'", | ||
212 | adap->dev->desc->name); | ||
213 | |||
214 | return 0; | ||
215 | } | ||
192 | 216 | ||
193 | if (dvb_register_frontend(&adap->dvb_adap, adap->fe[0])) { | 217 | adap->fe[i]->id = i; |
194 | err("Frontend registration failed."); | 218 | |
195 | dvb_frontend_detach(adap->fe[0]); | 219 | /* re-assign sleep and wakeup functions */ |
196 | adap->fe[0] = NULL; | 220 | adap->fe_init[i] = adap->fe[i]->ops.init; |
197 | return -ENODEV; | 221 | adap->fe[i]->ops.init = dvb_usb_fe_wakeup; |
222 | adap->fe_sleep[i] = adap->fe[i]->ops.sleep; | ||
223 | adap->fe[i]->ops.sleep = dvb_usb_fe_sleep; | ||
224 | |||
225 | if (dvb_register_frontend(&adap->dvb_adap, adap->fe[i])) { | ||
226 | err("Frontend %d registration failed.", i); | ||
227 | dvb_frontend_detach(adap->fe[i]); | ||
228 | adap->fe[i] = NULL; | ||
229 | /* In error case, do not try register more FEs, | ||
230 | * still leaving already registered FEs alive. */ | ||
231 | if (i == 0) | ||
232 | return -ENODEV; | ||
233 | else | ||
234 | return 0; | ||
198 | } | 235 | } |
199 | 236 | ||
200 | /* only attach the tuner if the demod is there */ | 237 | /* only attach the tuner if the demod is there */ |
201 | if (adap->props.tuner_attach != NULL) | 238 | if (adap->props.tuner_attach != NULL) |
202 | adap->props.tuner_attach(adap); | 239 | adap->props.tuner_attach(adap); |
203 | } else | 240 | } |
204 | err("no frontend was attached by '%s'",adap->dev->desc->name); | ||
205 | 241 | ||
206 | return 0; | 242 | return 0; |
207 | } | 243 | } |
208 | 244 | ||
209 | int dvb_usb_adapter_frontend_exit(struct dvb_usb_adapter *adap) | 245 | int dvb_usb_adapter_frontend_exit(struct dvb_usb_adapter *adap) |
210 | { | 246 | { |
211 | if (adap->fe[0] != NULL) { | 247 | int i; |
212 | dvb_unregister_frontend(adap->fe[0]); | 248 | |
213 | dvb_frontend_detach(adap->fe[0]); | 249 | /* unregister all given adapter frontends */ |
250 | if (adap->props.num_frontends) | ||
251 | i = adap->props.num_frontends - 1; | ||
252 | else | ||
253 | i = 0; | ||
254 | |||
255 | for (; i >= 0; i--) { | ||
256 | if (adap->fe[i] != NULL) { | ||
257 | dvb_unregister_frontend(adap->fe[i]); | ||
258 | dvb_frontend_detach(adap->fe[i]); | ||
259 | } | ||
214 | } | 260 | } |
261 | |||
215 | return 0; | 262 | return 0; |
216 | } | 263 | } |
diff --git a/drivers/media/dvb/dvb-usb/dvb-usb-init.c b/drivers/media/dvb/dvb-usb/dvb-usb-init.c index 2e3ea0fa28e0..f9af3484834f 100644 --- a/drivers/media/dvb/dvb-usb/dvb-usb-init.c +++ b/drivers/media/dvb/dvb-usb/dvb-usb-init.c | |||
@@ -77,6 +77,10 @@ static int dvb_usb_adapter_init(struct dvb_usb_device *d, short *adapter_nrs) | |||
77 | return ret; | 77 | return ret; |
78 | } | 78 | } |
79 | 79 | ||
80 | /* use exclusive FE lock if there is multiple shared FEs */ | ||
81 | if (adap->fe[1]) | ||
82 | adap->dvb_adap.mfe_shared = 1; | ||
83 | |||
80 | d->num_adapters_initialized++; | 84 | d->num_adapters_initialized++; |
81 | d->state |= DVB_USB_STATE_DVB; | 85 | d->state |= DVB_USB_STATE_DVB; |
82 | } | 86 | } |
diff --git a/drivers/media/dvb/dvb-usb/dvb-usb.h b/drivers/media/dvb/dvb-usb/dvb-usb.h index 2e57bffad3e3..a3e77b2e2261 100644 --- a/drivers/media/dvb/dvb-usb/dvb-usb.h +++ b/drivers/media/dvb/dvb-usb/dvb-usb.h | |||
@@ -124,6 +124,8 @@ struct usb_data_stream_properties { | |||
124 | * @caps: capabilities of the DVB USB device. | 124 | * @caps: capabilities of the DVB USB device. |
125 | * @pid_filter_count: number of PID filter position in the optional hardware | 125 | * @pid_filter_count: number of PID filter position in the optional hardware |
126 | * PID-filter. | 126 | * PID-filter. |
127 | * @num_frontends: number of frontends of the DVB USB adapter. | ||
128 | * @frontend_ctrl: called to power on/off active frontend. | ||
127 | * @streaming_ctrl: called to start and stop the MPEG2-TS streaming of the | 129 | * @streaming_ctrl: called to start and stop the MPEG2-TS streaming of the |
128 | * device (not URB submitting/killing). | 130 | * device (not URB submitting/killing). |
129 | * @pid_filter_ctrl: called to en/disable the PID filter, if any. | 131 | * @pid_filter_ctrl: called to en/disable the PID filter, if any. |
@@ -141,7 +143,9 @@ struct dvb_usb_adapter_properties { | |||
141 | #define DVB_USB_ADAP_RECEIVES_204_BYTE_TS 0x08 | 143 | #define DVB_USB_ADAP_RECEIVES_204_BYTE_TS 0x08 |
142 | int caps; | 144 | int caps; |
143 | int pid_filter_count; | 145 | int pid_filter_count; |
146 | int num_frontends; | ||
144 | 147 | ||
148 | int (*frontend_ctrl) (struct dvb_frontend *, int); | ||
145 | int (*streaming_ctrl) (struct dvb_usb_adapter *, int); | 149 | int (*streaming_ctrl) (struct dvb_usb_adapter *, int); |
146 | int (*pid_filter_ctrl) (struct dvb_usb_adapter *, int); | 150 | int (*pid_filter_ctrl) (struct dvb_usb_adapter *, int); |
147 | int (*pid_filter) (struct dvb_usb_adapter *, int, u16, int); | 151 | int (*pid_filter) (struct dvb_usb_adapter *, int, u16, int); |
@@ -345,6 +349,7 @@ struct usb_data_stream { | |||
345 | * | 349 | * |
346 | * @stream: the usb data stream. | 350 | * @stream: the usb data stream. |
347 | */ | 351 | */ |
352 | #define MAX_NO_OF_FE_PER_ADAP 2 | ||
348 | struct dvb_usb_adapter { | 353 | struct dvb_usb_adapter { |
349 | struct dvb_usb_device *dev; | 354 | struct dvb_usb_device *dev; |
350 | struct dvb_usb_adapter_properties props; | 355 | struct dvb_usb_adapter_properties props; |
@@ -363,11 +368,11 @@ struct dvb_usb_adapter { | |||
363 | struct dmxdev dmxdev; | 368 | struct dmxdev dmxdev; |
364 | struct dvb_demux demux; | 369 | struct dvb_demux demux; |
365 | struct dvb_net dvb_net; | 370 | struct dvb_net dvb_net; |
366 | struct dvb_frontend *fe[1]; | 371 | struct dvb_frontend *fe[MAX_NO_OF_FE_PER_ADAP]; |
367 | int max_feed_count; | 372 | int max_feed_count; |
368 | 373 | ||
369 | int (*fe_init) (struct dvb_frontend *); | 374 | int (*fe_init[MAX_NO_OF_FE_PER_ADAP]) (struct dvb_frontend *); |
370 | int (*fe_sleep) (struct dvb_frontend *); | 375 | int (*fe_sleep[MAX_NO_OF_FE_PER_ADAP]) (struct dvb_frontend *); |
371 | 376 | ||
372 | struct usb_data_stream stream; | 377 | struct usb_data_stream stream; |
373 | 378 | ||