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