1 | // SPDX-License-Identifier: GPL-2.0 |
2 | /* dvb-usb-dvb.c is part of the DVB USB library. |
3 | * |
4 | * Copyright (C) 2004-6 Patrick Boettcher (patrick.boettcher@posteo.de) |
5 | * see dvb-usb-init.c for copyright information. |
6 | * |
7 | * This file contains functions for initializing and handling the |
8 | * linux-dvb API. |
9 | */ |
10 | #include "dvb-usb-common.h" |
11 | #include <media/media-device.h> |
12 | |
13 | /* does the complete input transfer handling */ |
14 | static int dvb_usb_ctrl_feed(struct dvb_demux_feed *dvbdmxfeed, int onoff) |
15 | { |
16 | struct dvb_usb_adapter *adap = dvbdmxfeed->demux->priv; |
17 | int newfeedcount, ret; |
18 | |
19 | if (adap == NULL) |
20 | return -ENODEV; |
21 | |
22 | if ((adap->active_fe < 0) || |
23 | (adap->active_fe >= adap->num_frontends_initialized)) { |
24 | return -EINVAL; |
25 | } |
26 | |
27 | newfeedcount = adap->feedcount + (onoff ? 1 : -1); |
28 | |
29 | /* stop feed before setting a new pid if there will be no pid anymore */ |
30 | if (newfeedcount == 0) { |
31 | deb_ts("stop feeding\n" ); |
32 | usb_urb_kill(stream: &adap->fe_adap[adap->active_fe].stream); |
33 | |
34 | if (adap->props.fe[adap->active_fe].streaming_ctrl != NULL) { |
35 | ret = adap->props.fe[adap->active_fe].streaming_ctrl(adap, 0); |
36 | if (ret < 0) { |
37 | err("error while stopping stream." ); |
38 | return ret; |
39 | } |
40 | } |
41 | } |
42 | |
43 | adap->feedcount = newfeedcount; |
44 | |
45 | /* activate the pid on the device specific pid_filter */ |
46 | deb_ts("setting pid (%s): %5d %04x at index %d '%s'\n" , |
47 | adap->fe_adap[adap->active_fe].pid_filtering ? |
48 | "yes" : "no" , dvbdmxfeed->pid, dvbdmxfeed->pid, |
49 | dvbdmxfeed->index, onoff ? "on" : "off" ); |
50 | if (adap->props.fe[adap->active_fe].caps & DVB_USB_ADAP_HAS_PID_FILTER && |
51 | adap->fe_adap[adap->active_fe].pid_filtering && |
52 | adap->props.fe[adap->active_fe].pid_filter != NULL) |
53 | adap->props.fe[adap->active_fe].pid_filter(adap, dvbdmxfeed->index, dvbdmxfeed->pid, onoff); |
54 | |
55 | /* start the feed if this was the first feed and there is still a feed |
56 | * for reception. |
57 | */ |
58 | if (adap->feedcount == onoff && adap->feedcount > 0) { |
59 | deb_ts("controlling pid parser\n" ); |
60 | if (adap->props.fe[adap->active_fe].caps & DVB_USB_ADAP_HAS_PID_FILTER && |
61 | adap->props.fe[adap->active_fe].caps & |
62 | DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF && |
63 | adap->props.fe[adap->active_fe].pid_filter_ctrl != NULL) { |
64 | ret = adap->props.fe[adap->active_fe].pid_filter_ctrl(adap, |
65 | adap->fe_adap[adap->active_fe].pid_filtering); |
66 | if (ret < 0) { |
67 | err("could not handle pid_parser" ); |
68 | return ret; |
69 | } |
70 | } |
71 | deb_ts("start feeding\n" ); |
72 | if (adap->props.fe[adap->active_fe].streaming_ctrl != NULL) { |
73 | ret = adap->props.fe[adap->active_fe].streaming_ctrl(adap, 1); |
74 | if (ret < 0) { |
75 | err("error while enabling fifo." ); |
76 | return ret; |
77 | } |
78 | } |
79 | |
80 | deb_ts("submitting all URBs\n" ); |
81 | usb_urb_submit(stream: &adap->fe_adap[adap->active_fe].stream); |
82 | } |
83 | return 0; |
84 | } |
85 | |
86 | static int dvb_usb_start_feed(struct dvb_demux_feed *dvbdmxfeed) |
87 | { |
88 | deb_ts("start pid: 0x%04x, feedtype: %d\n" , dvbdmxfeed->pid, |
89 | dvbdmxfeed->type); |
90 | return dvb_usb_ctrl_feed(dvbdmxfeed, onoff: 1); |
91 | } |
92 | |
93 | static int dvb_usb_stop_feed(struct dvb_demux_feed *dvbdmxfeed) |
94 | { |
95 | deb_ts("stop pid: 0x%04x, feedtype: %d\n" , dvbdmxfeed->pid, dvbdmxfeed->type); |
96 | return dvb_usb_ctrl_feed(dvbdmxfeed, onoff: 0); |
97 | } |
98 | |
99 | static int dvb_usb_media_device_init(struct dvb_usb_adapter *adap) |
100 | { |
101 | #ifdef CONFIG_MEDIA_CONTROLLER_DVB |
102 | struct media_device *mdev; |
103 | struct dvb_usb_device *d = adap->dev; |
104 | struct usb_device *udev = d->udev; |
105 | |
106 | mdev = kzalloc(size: sizeof(*mdev), GFP_KERNEL); |
107 | if (!mdev) |
108 | return -ENOMEM; |
109 | |
110 | media_device_usb_init(mdev, udev, d->desc->name); |
111 | |
112 | dvb_register_media_controller(adap: &adap->dvb_adap, mdev); |
113 | |
114 | dev_info(&d->udev->dev, "media controller created\n" ); |
115 | #endif |
116 | return 0; |
117 | } |
118 | |
119 | static int dvb_usb_media_device_register(struct dvb_usb_adapter *adap) |
120 | { |
121 | #ifdef CONFIG_MEDIA_CONTROLLER_DVB |
122 | return media_device_register(adap->dvb_adap.mdev); |
123 | #else |
124 | return 0; |
125 | #endif |
126 | } |
127 | |
128 | static void dvb_usb_media_device_unregister(struct dvb_usb_adapter *adap) |
129 | { |
130 | #ifdef CONFIG_MEDIA_CONTROLLER_DVB |
131 | if (!adap->dvb_adap.mdev) |
132 | return; |
133 | |
134 | mutex_lock(&adap->dvb_adap.mdev_lock); |
135 | |
136 | media_device_unregister(mdev: adap->dvb_adap.mdev); |
137 | media_device_cleanup(mdev: adap->dvb_adap.mdev); |
138 | kfree(objp: adap->dvb_adap.mdev); |
139 | adap->dvb_adap.mdev = NULL; |
140 | |
141 | mutex_unlock(lock: &adap->dvb_adap.mdev_lock); |
142 | #endif |
143 | } |
144 | |
145 | int dvb_usb_adapter_dvb_init(struct dvb_usb_adapter *adap, short *adapter_nums) |
146 | { |
147 | int i; |
148 | int ret = dvb_register_adapter(adap: &adap->dvb_adap, name: adap->dev->desc->name, |
149 | module: adap->dev->owner, device: &adap->dev->udev->dev, |
150 | adapter_nums); |
151 | |
152 | if (ret < 0) { |
153 | deb_info("dvb_register_adapter failed: error %d" , ret); |
154 | goto err; |
155 | } |
156 | adap->dvb_adap.priv = adap; |
157 | |
158 | ret = dvb_usb_media_device_init(adap); |
159 | if (ret < 0) { |
160 | deb_info("dvb_usb_media_device_init failed: error %d" , ret); |
161 | goto err_mc; |
162 | } |
163 | |
164 | if (adap->dev->props.read_mac_address) { |
165 | if (adap->dev->props.read_mac_address(adap->dev, adap->dvb_adap.proposed_mac) == 0) |
166 | info("MAC address: %pM" , adap->dvb_adap.proposed_mac); |
167 | else |
168 | err("MAC address reading failed." ); |
169 | } |
170 | |
171 | |
172 | adap->demux.dmx.capabilities = DMX_TS_FILTERING | DMX_SECTION_FILTERING; |
173 | adap->demux.priv = adap; |
174 | |
175 | adap->demux.filternum = 0; |
176 | for (i = 0; i < adap->props.num_frontends; i++) { |
177 | if (adap->demux.filternum < adap->fe_adap[i].max_feed_count) |
178 | adap->demux.filternum = adap->fe_adap[i].max_feed_count; |
179 | } |
180 | adap->demux.feednum = adap->demux.filternum; |
181 | adap->demux.start_feed = dvb_usb_start_feed; |
182 | adap->demux.stop_feed = dvb_usb_stop_feed; |
183 | adap->demux.write_to_decoder = NULL; |
184 | if ((ret = dvb_dmx_init(demux: &adap->demux)) < 0) { |
185 | err("dvb_dmx_init failed: error %d" , ret); |
186 | goto err_dmx; |
187 | } |
188 | |
189 | adap->dmxdev.filternum = adap->demux.filternum; |
190 | adap->dmxdev.demux = &adap->demux.dmx; |
191 | adap->dmxdev.capabilities = 0; |
192 | if ((ret = dvb_dmxdev_init(dmxdev: &adap->dmxdev, adap: &adap->dvb_adap)) < 0) { |
193 | err("dvb_dmxdev_init failed: error %d" , ret); |
194 | goto err_dmx_dev; |
195 | } |
196 | |
197 | if ((ret = dvb_net_init(adap: &adap->dvb_adap, dvbnet: &adap->dvb_net, |
198 | dmxdemux: &adap->demux.dmx)) < 0) { |
199 | err("dvb_net_init failed: error %d" , ret); |
200 | goto err_net_init; |
201 | } |
202 | |
203 | adap->state |= DVB_USB_ADAP_STATE_DVB; |
204 | return 0; |
205 | |
206 | err_net_init: |
207 | dvb_dmxdev_release(dmxdev: &adap->dmxdev); |
208 | err_dmx_dev: |
209 | dvb_dmx_release(demux: &adap->demux); |
210 | err_dmx: |
211 | dvb_usb_media_device_unregister(adap); |
212 | err_mc: |
213 | dvb_unregister_adapter(adap: &adap->dvb_adap); |
214 | err: |
215 | return ret; |
216 | } |
217 | |
218 | int dvb_usb_adapter_dvb_exit(struct dvb_usb_adapter *adap) |
219 | { |
220 | if (adap->state & DVB_USB_ADAP_STATE_DVB) { |
221 | deb_info("unregistering DVB part\n" ); |
222 | dvb_net_release(dvbnet: &adap->dvb_net); |
223 | adap->demux.dmx.close(&adap->demux.dmx); |
224 | dvb_dmxdev_release(dmxdev: &adap->dmxdev); |
225 | dvb_dmx_release(demux: &adap->demux); |
226 | dvb_usb_media_device_unregister(adap); |
227 | dvb_unregister_adapter(adap: &adap->dvb_adap); |
228 | adap->state &= ~DVB_USB_ADAP_STATE_DVB; |
229 | } |
230 | return 0; |
231 | } |
232 | |
233 | static int dvb_usb_set_active_fe(struct dvb_frontend *fe, int onoff) |
234 | { |
235 | struct dvb_usb_adapter *adap = fe->dvb->priv; |
236 | |
237 | int ret = (adap->props.frontend_ctrl) ? |
238 | adap->props.frontend_ctrl(fe, onoff) : 0; |
239 | |
240 | if (ret < 0) { |
241 | err("frontend_ctrl request failed" ); |
242 | return ret; |
243 | } |
244 | if (onoff) |
245 | adap->active_fe = fe->id; |
246 | |
247 | return 0; |
248 | } |
249 | |
250 | static int dvb_usb_fe_wakeup(struct dvb_frontend *fe) |
251 | { |
252 | struct dvb_usb_adapter *adap = fe->dvb->priv; |
253 | |
254 | dvb_usb_device_power_ctrl(d: adap->dev, onoff: 1); |
255 | |
256 | dvb_usb_set_active_fe(fe, onoff: 1); |
257 | |
258 | if (adap->fe_adap[fe->id].fe_init) |
259 | adap->fe_adap[fe->id].fe_init(fe); |
260 | |
261 | return 0; |
262 | } |
263 | |
264 | static int dvb_usb_fe_sleep(struct dvb_frontend *fe) |
265 | { |
266 | struct dvb_usb_adapter *adap = fe->dvb->priv; |
267 | |
268 | if (adap->fe_adap[fe->id].fe_sleep) |
269 | adap->fe_adap[fe->id].fe_sleep(fe); |
270 | |
271 | dvb_usb_set_active_fe(fe, onoff: 0); |
272 | |
273 | return dvb_usb_device_power_ctrl(d: adap->dev, onoff: 0); |
274 | } |
275 | |
276 | int dvb_usb_adapter_frontend_init(struct dvb_usb_adapter *adap) |
277 | { |
278 | int ret, i; |
279 | |
280 | /* register all given adapter frontends */ |
281 | for (i = 0; i < adap->props.num_frontends; i++) { |
282 | |
283 | if (adap->props.fe[i].frontend_attach == NULL) { |
284 | err("strange: '%s' #%d,%d doesn't want to attach a frontend." , |
285 | adap->dev->desc->name, adap->id, i); |
286 | |
287 | return 0; |
288 | } |
289 | |
290 | ret = adap->props.fe[i].frontend_attach(adap); |
291 | if (ret || adap->fe_adap[i].fe == NULL) { |
292 | /* only print error when there is no FE at all */ |
293 | if (i == 0) |
294 | err("no frontend was attached by '%s'" , |
295 | adap->dev->desc->name); |
296 | |
297 | return 0; |
298 | } |
299 | |
300 | adap->fe_adap[i].fe->id = i; |
301 | |
302 | /* re-assign sleep and wakeup functions */ |
303 | adap->fe_adap[i].fe_init = adap->fe_adap[i].fe->ops.init; |
304 | adap->fe_adap[i].fe->ops.init = dvb_usb_fe_wakeup; |
305 | adap->fe_adap[i].fe_sleep = adap->fe_adap[i].fe->ops.sleep; |
306 | adap->fe_adap[i].fe->ops.sleep = dvb_usb_fe_sleep; |
307 | |
308 | if (dvb_register_frontend(dvb: &adap->dvb_adap, fe: adap->fe_adap[i].fe)) { |
309 | err("Frontend %d registration failed." , i); |
310 | dvb_frontend_detach(fe: adap->fe_adap[i].fe); |
311 | adap->fe_adap[i].fe = NULL; |
312 | /* In error case, do not try register more FEs, |
313 | * still leaving already registered FEs alive. */ |
314 | if (i == 0) |
315 | return -ENODEV; |
316 | else |
317 | return 0; |
318 | } |
319 | |
320 | /* only attach the tuner if the demod is there */ |
321 | if (adap->props.fe[i].tuner_attach != NULL) |
322 | adap->props.fe[i].tuner_attach(adap); |
323 | |
324 | adap->num_frontends_initialized++; |
325 | } |
326 | |
327 | ret = dvb_create_media_graph(adap: &adap->dvb_adap, create_rf_connector: true); |
328 | if (ret) |
329 | return ret; |
330 | |
331 | ret = dvb_usb_media_device_register(adap); |
332 | |
333 | return ret; |
334 | } |
335 | |
336 | int dvb_usb_adapter_frontend_exit(struct dvb_usb_adapter *adap) |
337 | { |
338 | int i = adap->num_frontends_initialized - 1; |
339 | |
340 | /* unregister all given adapter frontends */ |
341 | for (; i >= 0; i--) { |
342 | if (adap->fe_adap[i].fe != NULL) { |
343 | dvb_unregister_frontend(fe: adap->fe_adap[i].fe); |
344 | dvb_frontend_detach(fe: adap->fe_adap[i].fe); |
345 | } |
346 | } |
347 | adap->num_frontends_initialized = 0; |
348 | |
349 | return 0; |
350 | } |
351 | |