From: Antti Palosaari Date: Wed, 20 Jun 2012 01:21:34 +0000 (-0300) Subject: [media] dvb_usb_v2: merge files dvb_usb_init.c and dvb_usb_dvb.c X-Git-Url: https://git.stricted.de/?a=commitdiff_plain;h=41a0abf7100928b412be4d35d62fd77c83064a9b;p=GitHub%2FLineageOS%2Fandroid_kernel_motorola_exynos9610.git [media] dvb_usb_v2: merge files dvb_usb_init.c and dvb_usb_dvb.c Merge files dvb_usb_init.c and dvb_usb_dvb.c to dvb_usb_core.c. It is still under 1000 lines of code after all the optimization so put it one file. Signed-off-by: Antti Palosaari Signed-off-by: Mauro Carvalho Chehab --- diff --git a/drivers/media/dvb/dvb-usb/Makefile b/drivers/media/dvb/dvb-usb/Makefile index 490e2a295f3f..50f506e0632a 100644 --- a/drivers/media/dvb/dvb-usb/Makefile +++ b/drivers/media/dvb/dvb-usb/Makefile @@ -1,7 +1,7 @@ dvb-usb-objs = dvb-usb-firmware.o dvb-usb-init.o dvb-usb-urb.o dvb-usb-i2c.o dvb-usb-dvb.o dvb-usb-remote.o usb-urb.o obj-$(CONFIG_DVB_USB) += dvb-usb.o -dvb_usbv2-objs = dvb_usb_init.o dvb_usb_urb.o dvb_usb_dvb.o usb_urb.o +dvb_usbv2-objs = dvb_usb_core.o dvb_usb_urb.o usb_urb.o obj-$(CONFIG_DVB_USB_V2) += dvb_usbv2.o obj-$(CONFIG_DVB_USB_FIRMWARE) += dvb_usb_firmware.o diff --git a/drivers/media/dvb/dvb-usb/dvb_usb_common.h b/drivers/media/dvb/dvb-usb/dvb_usb_common.h index c94a900c3264..80c8bd3079c5 100644 --- a/drivers/media/dvb/dvb-usb/dvb_usb_common.h +++ b/drivers/media/dvb/dvb-usb/dvb_usb_common.h @@ -11,11 +11,7 @@ #include "dvb_usb.h" -extern int dvb_usbv2_disable_rc_polling; - /* commonly used methods */ -extern int dvb_usbv2_device_power_ctrl(struct dvb_usb_device *d, int onoff); - extern int usb_urb_initv2(struct usb_data_stream *stream, const struct usb_data_stream_properties *props); extern int usb_urb_exitv2(struct usb_data_stream *stream); @@ -23,12 +19,4 @@ extern int usb_urb_submitv2(struct usb_data_stream *stream, struct usb_data_stream_properties *props); extern int usb_urb_killv2(struct usb_data_stream *stream); -extern int dvb_usbv2_adapter_stream_init(struct dvb_usb_adapter *adap); -extern int dvb_usbv2_adapter_stream_exit(struct dvb_usb_adapter *adap); - -extern int dvb_usbv2_adapter_dvb_init(struct dvb_usb_adapter *adap); -extern int dvb_usbv2_adapter_dvb_exit(struct dvb_usb_adapter *adap); -extern int dvb_usbv2_adapter_frontend_init(struct dvb_usb_adapter *adap); -extern int dvb_usbv2_adapter_frontend_exit(struct dvb_usb_adapter *adap); - #endif diff --git a/drivers/media/dvb/dvb-usb/dvb_usb_core.c b/drivers/media/dvb/dvb-usb/dvb_usb_core.c new file mode 100644 index 000000000000..f3e1ec2c473e --- /dev/null +++ b/drivers/media/dvb/dvb-usb/dvb_usb_core.c @@ -0,0 +1,980 @@ +/* + * DVB USB library - provides a generic interface for a DVB USB device driver. + * + * dvb-usb-init.c + * + * Copyright (C) 2004-6 Patrick Boettcher (patrick.boettcher@desy.de) + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation, version 2. + * + * see Documentation/dvb/README.dvb-usb for more information + */ +#include "dvb_usb_common.h" +#include + +int dvb_usbv2_disable_rc_polling; +module_param_named(disable_rc_polling, dvb_usbv2_disable_rc_polling, int, 0644); +MODULE_PARM_DESC(disable_rc_polling, + "disable remote control polling (default: 0)."); +static int dvb_usb_force_pid_filter_usage; +module_param_named(force_pid_filter_usage, dvb_usb_force_pid_filter_usage, + int, 0444); +MODULE_PARM_DESC(force_pid_filter_usage, "force all dvb-usb-devices to use a" \ + " PID filter, if any (default: 0)."); + +static int dvb_usbv2_download_firmware(struct dvb_usb_device *d, const char *name) +{ + int ret; + const struct firmware *fw; + + if (!d->props->download_firmware) { + ret = -EINVAL; + goto err; + } + + ret = request_firmware(&fw, name, &d->udev->dev); + if (ret < 0) { + pr_err("%s: did not find the firmware file. (%s) " \ + "Please see linux/Documentation/dvb/ for " \ + "more details on firmware-problems. (%d)\n", + KBUILD_MODNAME, name, ret); + goto err; + } + + pr_info("%s: downloading firmware from file '%s'\n", KBUILD_MODNAME, + name); + + ret = d->props->download_firmware(d, fw); + + release_firmware(fw); + + if (ret < 0) + goto err; + + return ret; +err: + pr_debug("%s: failed=%d\n", __func__, ret); + return ret; +} + +static int dvb_usbv2_i2c_init(struct dvb_usb_device *d) +{ + int ret; + + pr_debug("%s:\n", __func__); + + if (!d->props->i2c_algo) + return 0; + + strlcpy(d->i2c_adap.name, d->name, sizeof(d->i2c_adap.name)); + d->i2c_adap.algo = d->props->i2c_algo; + d->i2c_adap.dev.parent = &d->udev->dev; + i2c_set_adapdata(&d->i2c_adap, d); + + ret = i2c_add_adapter(&d->i2c_adap); + if (ret < 0) { + d->i2c_adap.algo = NULL; + pr_err("%s: i2c_add_adapter() failed=%d\n", KBUILD_MODNAME, + ret); + goto err; + } + + return 0; +err: + pr_debug("%s: failed=%d\n", __func__, ret); + return ret; +} + +static int dvb_usbv2_i2c_exit(struct dvb_usb_device *d) +{ + pr_debug("%s:\n", __func__); + + if (d->i2c_adap.algo) + i2c_del_adapter(&d->i2c_adap); + + return 0; +} + +static void dvb_usb_read_remote_control(struct work_struct *work) +{ + struct dvb_usb_device *d = container_of(work, + struct dvb_usb_device, rc_query_work.work); + int ret; + + /* TODO: need a lock here. We can simply skip checking for the remote + control if we're busy. */ + + /* when the parameter has been set to 1 via sysfs while the + * driver was running, or when bulk mode is enabled after IR init + */ + if (dvb_usbv2_disable_rc_polling || d->rc.bulk_mode) + return; + + ret = d->rc.query(d); + if (ret < 0) + pr_err("%s: error %d while querying for an remote control " \ + "event\n", KBUILD_MODNAME, ret); + + schedule_delayed_work(&d->rc_query_work, + msecs_to_jiffies(d->rc.interval)); +} + +static int dvb_usbv2_remote_init(struct dvb_usb_device *d) +{ + int ret; + struct rc_dev *dev; + + pr_debug("%s:\n", __func__); + + if (dvb_usbv2_disable_rc_polling || !d->props->get_rc_config) + return 0; + + ret = d->props->get_rc_config(d, &d->rc); + if (ret < 0) + goto err; + + dev = rc_allocate_device(); + if (!dev) { + ret = -ENOMEM; + goto err; + } + + dev->dev.parent = &d->udev->dev; + dev->input_name = "IR-receiver inside an USB DVB receiver"; + usb_make_path(d->udev, d->rc_phys, sizeof(d->rc_phys)); + strlcat(d->rc_phys, "/ir0", sizeof(d->rc_phys)); + dev->input_phys = d->rc_phys; + usb_to_input_id(d->udev, &dev->input_id); + /* TODO: likely RC-core should took const char * */ + dev->driver_name = (char *) d->props->driver_name; + dev->driver_type = d->rc.driver_type; + dev->allowed_protos = d->rc.allowed_protos; + dev->change_protocol = d->rc.change_protocol; + dev->priv = d; + /* select used keymap */ + if (d->rc.map_name) + dev->map_name = d->rc.map_name; + else if (d->rc_map) + dev->map_name = d->rc_map; + else + dev->map_name = RC_MAP_EMPTY; /* keep rc enabled */ + + ret = rc_register_device(dev); + if (ret < 0) { + rc_free_device(dev); + goto err; + } + + d->input_dev = NULL; + d->rc_dev = dev; + + /* start polling if needed */ + if (d->rc.query && !d->rc.bulk_mode) { + /* initialize a work queue for handling polling */ + INIT_DELAYED_WORK(&d->rc_query_work, + dvb_usb_read_remote_control); + pr_info("%s: schedule remote query interval to %d msecs\n", + KBUILD_MODNAME, d->rc.interval); + schedule_delayed_work(&d->rc_query_work, + msecs_to_jiffies(d->rc.interval)); + } + + return 0; +err: + pr_debug("%s: failed=%d\n", __func__, ret); + return ret; +} + +static int dvb_usbv2_remote_exit(struct dvb_usb_device *d) +{ + pr_debug("%s:\n", __func__); + + if (d->rc_dev) { + cancel_delayed_work_sync(&d->rc_query_work); + rc_unregister_device(d->rc_dev); + d->rc_dev = NULL; + } + + return 0; +} + +static void dvb_usb_data_complete(struct usb_data_stream *stream, u8 *buf, + size_t len) +{ + struct dvb_usb_adapter *adap = stream->user_priv; + dvb_dmx_swfilter(&adap->demux, buf, len); +} + +static void dvb_usb_data_complete_204(struct usb_data_stream *stream, u8 *buf, + size_t len) +{ + struct dvb_usb_adapter *adap = stream->user_priv; + dvb_dmx_swfilter_204(&adap->demux, buf, len); +} + +static void dvb_usb_data_complete_raw(struct usb_data_stream *stream, u8 *buf, + size_t len) +{ + struct dvb_usb_adapter *adap = stream->user_priv; + dvb_dmx_swfilter_raw(&adap->demux, buf, len); +} + +int dvb_usbv2_adapter_stream_init(struct dvb_usb_adapter *adap) +{ + pr_debug("%s: adap=%d\n", __func__, adap->id); + + adap->stream.udev = adap_to_d(adap)->udev; + adap->stream.user_priv = adap; + adap->stream.complete = dvb_usb_data_complete; + + return usb_urb_initv2(&adap->stream, &adap->props->stream); +} + +int dvb_usbv2_adapter_stream_exit(struct dvb_usb_adapter *adap) +{ + pr_debug("%s: adap=%d\n", __func__, adap->id); + usb_urb_exitv2(&adap->stream); + + return 0; +} + +static inline int dvb_usb_ctrl_feed(struct dvb_demux_feed *dvbdmxfeed, + int count) +{ + struct dvb_usb_adapter *adap = dvbdmxfeed->demux->priv; + struct dvb_usb_device *d = adap_to_d(adap); + int ret; + pr_debug("%s: adap=%d active_fe=%d feed_type=%d setting pid [%s]: " \ + "%04x (%04d) at index %d '%s'\n", __func__, adap->id, + adap->active_fe, dvbdmxfeed->type, + adap->pid_filtering ? "yes" : "no", dvbdmxfeed->pid, + dvbdmxfeed->pid, dvbdmxfeed->index, + (count == 1) ? "on" : "off"); + + if (adap->active_fe == -1) + return -EINVAL; + + adap->feed_count += count; + + /* stop feeding if it is last pid */ + if (adap->feed_count == 0) { + pr_debug("%s: stop feeding\n", __func__); + usb_urb_killv2(&adap->stream); + + if (d->props->streaming_ctrl) { + ret = d->props->streaming_ctrl(adap, 0); + if (ret < 0) { + pr_err("%s: streaming_ctrl() failed=%d\n", + KBUILD_MODNAME, ret); + goto err_mutex_unlock; + } + } + mutex_unlock(&adap->sync_mutex); + } + + /* activate the pid on the device pid filter */ + if (adap->props->caps & DVB_USB_ADAP_HAS_PID_FILTER && + adap->pid_filtering && + adap->props->pid_filter) + ret = adap->props->pid_filter(adap, dvbdmxfeed->index, + dvbdmxfeed->pid, (count == 1) ? 1 : 0); + if (ret < 0) + pr_err("%s: pid_filter() failed=%d\n", + KBUILD_MODNAME, ret); + + /* start feeding if it is first pid */ + if (adap->feed_count == 1 && count == 1) { + struct usb_data_stream_properties stream_props; + mutex_lock(&adap->sync_mutex); + pr_debug("%s: start feeding\n", __func__); + + /* resolve input and output streaming paramters */ + if (d->props->get_stream_config) { + memcpy(&stream_props, &adap->props->stream, + sizeof(struct usb_data_stream_properties)); + ret = d->props->get_stream_config( + adap->fe[adap->active_fe], + &adap->ts_type, &stream_props); + if (ret < 0) + goto err_mutex_unlock; + } else { + stream_props = adap->props->stream; + } + + switch (adap->ts_type) { + case DVB_USB_FE_TS_TYPE_204: + adap->stream.complete = dvb_usb_data_complete_204; + break; + case DVB_USB_FE_TS_TYPE_RAW: + adap->stream.complete = dvb_usb_data_complete_raw; + break; + case DVB_USB_FE_TS_TYPE_188: + default: + adap->stream.complete = dvb_usb_data_complete; + break; + } + + usb_urb_submitv2(&adap->stream, &stream_props); + + if (adap->props->caps & DVB_USB_ADAP_HAS_PID_FILTER && + adap->props->caps & + DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF && + adap->props->pid_filter_ctrl) { + ret = adap->props->pid_filter_ctrl(adap, + adap->pid_filtering); + if (ret < 0) { + pr_err("%s: pid_filter_ctrl() failed=%d\n", + KBUILD_MODNAME, ret); + goto err_mutex_unlock; + } + } + + if (d->props->streaming_ctrl) { + ret = d->props->streaming_ctrl(adap, 1); + if (ret < 0) { + pr_err("%s: streaming_ctrl() failed=%d\n", + KBUILD_MODNAME, ret); + goto err_mutex_unlock; + } + } + } + + return 0; +err_mutex_unlock: + mutex_unlock(&adap->sync_mutex); + pr_debug("%s: failed=%d\n", __func__, ret); + return ret; +} + +static int dvb_usb_start_feed(struct dvb_demux_feed *dvbdmxfeed) +{ + return dvb_usb_ctrl_feed(dvbdmxfeed, 1); +} + +static int dvb_usb_stop_feed(struct dvb_demux_feed *dvbdmxfeed) +{ + return dvb_usb_ctrl_feed(dvbdmxfeed, -1); +} + +int dvb_usbv2_adapter_dvb_init(struct dvb_usb_adapter *adap) +{ + int ret; + struct dvb_usb_device *d = adap_to_d(adap); + pr_debug("%s: adap=%d\n", __func__, adap->id); + + ret = dvb_register_adapter(&adap->dvb_adap, d->name, d->props->owner, + &d->udev->dev, d->props->adapter_nr); + if (ret < 0) { + pr_debug("%s: dvb_register_adapter() failed=%d\n", __func__, + ret); + goto err; + } + + adap->dvb_adap.priv = adap; + + if (d->props->read_mac_address) { + ret = d->props->read_mac_address(adap, + adap->dvb_adap.proposed_mac); + if (ret < 0) + goto err_dmx; + + pr_info("%s: MAC address: %pM\n", KBUILD_MODNAME, + adap->dvb_adap.proposed_mac); + } + + adap->demux.dmx.capabilities = DMX_TS_FILTERING | DMX_SECTION_FILTERING; + adap->demux.priv = adap; + adap->demux.filternum = 0; + if (adap->demux.filternum < adap->max_feed_count) + adap->demux.filternum = adap->max_feed_count; + adap->demux.feednum = adap->demux.filternum; + adap->demux.start_feed = dvb_usb_start_feed; + adap->demux.stop_feed = dvb_usb_stop_feed; + adap->demux.write_to_decoder = NULL; + ret = dvb_dmx_init(&adap->demux); + if (ret < 0) { + pr_err("%s: dvb_dmx_init() failed=%d\n", KBUILD_MODNAME, ret); + goto err_dmx; + } + + adap->dmxdev.filternum = adap->demux.filternum; + adap->dmxdev.demux = &adap->demux.dmx; + adap->dmxdev.capabilities = 0; + ret = dvb_dmxdev_init(&adap->dmxdev, &adap->dvb_adap); + if (ret < 0) { + pr_err("%s: dvb_dmxdev_init() failed=%d\n", KBUILD_MODNAME, + ret); + goto err_dmx_dev; + } + + ret = dvb_net_init(&adap->dvb_adap, &adap->dvb_net, &adap->demux.dmx); + if (ret < 0) { + pr_err("%s: dvb_net_init() failed=%d\n", KBUILD_MODNAME, ret); + goto err_net_init; + } + + mutex_init(&adap->sync_mutex); + + return 0; +err_net_init: + dvb_dmxdev_release(&adap->dmxdev); +err_dmx_dev: + dvb_dmx_release(&adap->demux); +err_dmx: + dvb_unregister_adapter(&adap->dvb_adap); +err: + adap->dvb_adap.priv = NULL; + return ret; +} + +int dvb_usbv2_adapter_dvb_exit(struct dvb_usb_adapter *adap) +{ + pr_debug("%s: adap=%d\n", __func__, adap->id); + + if (adap->dvb_adap.priv) { + dvb_net_release(&adap->dvb_net); + adap->demux.dmx.close(&adap->demux.dmx); + dvb_dmxdev_release(&adap->dmxdev); + dvb_dmx_release(&adap->demux); + dvb_unregister_adapter(&adap->dvb_adap); + } + + return 0; +} + +int dvb_usbv2_device_power_ctrl(struct dvb_usb_device *d, int onoff) +{ + int ret; + + if (onoff) + d->powered++; + else + d->powered--; + + if (d->powered == 0 || (onoff && d->powered == 1)) { + /* when switching from 1 to 0 or from 0 to 1 */ + pr_debug("%s: power control=%d\n", __func__, onoff); + if (d->props->power_ctrl) { + ret = d->props->power_ctrl(d, onoff); + goto err; + } + } + + return 0; +err: + pr_debug("%s: failed=%d\n", __func__, ret); + return ret; +} + +static int dvb_usb_fe_wakeup(struct dvb_frontend *fe) +{ + int ret; + struct dvb_usb_adapter *adap = fe->dvb->priv; + struct dvb_usb_device *d = adap_to_d(adap); + mutex_lock(&adap->sync_mutex); + pr_debug("%s: adap=%d fe=%d\n", __func__, adap->id, fe->id); + + ret = dvb_usbv2_device_power_ctrl(d, 1); + if (ret < 0) + goto err; + + if (d->props->frontend_ctrl) { + ret = d->props->frontend_ctrl(fe, 1); + if (ret < 0) + goto err; + } + + if (adap->fe_init[fe->id]) { + ret = adap->fe_init[fe->id](fe); + if (ret < 0) + goto err; + } + + adap->active_fe = fe->id; + mutex_unlock(&adap->sync_mutex); + + return 0; +err: + mutex_unlock(&adap->sync_mutex); + pr_debug("%s: failed=%d\n", __func__, ret); + return ret; +} + +static int dvb_usb_fe_sleep(struct dvb_frontend *fe) +{ + int ret; + struct dvb_usb_adapter *adap = fe->dvb->priv; + struct dvb_usb_device *d = adap_to_d(adap); + mutex_lock(&adap->sync_mutex); + pr_debug("%s: adap=%d fe=%d\n", __func__, adap->id, fe->id); + + if (adap->fe_sleep[fe->id]) { + ret = adap->fe_sleep[fe->id](fe); + if (ret < 0) + goto err; + } + + if (d->props->frontend_ctrl) { + ret = d->props->frontend_ctrl(fe, 0); + if (ret < 0) + goto err; + } + + ret = dvb_usbv2_device_power_ctrl(d, 0); + if (ret < 0) + goto err; + + adap->active_fe = -1; + mutex_unlock(&adap->sync_mutex); + + return 0; +err: + mutex_unlock(&adap->sync_mutex); + pr_debug("%s: failed=%d\n", __func__, ret); + return ret; +} + +int dvb_usbv2_adapter_frontend_init(struct dvb_usb_adapter *adap) +{ + int ret, i, count_registered = 0; + struct dvb_usb_device *d = adap_to_d(adap); + pr_debug("%s: adap=%d\n", __func__, adap->id); + + memset(adap->fe, 0, sizeof(adap->fe)); + adap->active_fe = -1; + + if (d->props->frontend_attach) { + ret = d->props->frontend_attach(adap); + if (ret < 0) { + pr_debug("%s: frontend_attach() failed=%d\n", __func__, + ret); + goto err_dvb_frontend_detach; + } + } else { + pr_debug("%s: frontend_attach() do not exists\n", __func__); + ret = 0; + goto err; + } + + for (i = 0; i < MAX_NO_OF_FE_PER_ADAP && adap->fe[i]; i++) { + adap->fe[i]->id = i; + + /* re-assign sleep and wakeup functions */ + adap->fe_init[i] = adap->fe[i]->ops.init; + adap->fe[i]->ops.init = dvb_usb_fe_wakeup; + adap->fe_sleep[i] = adap->fe[i]->ops.sleep; + adap->fe[i]->ops.sleep = dvb_usb_fe_sleep; + + ret = dvb_register_frontend(&adap->dvb_adap, adap->fe[i]); + if (ret < 0) { + pr_err("%s: frontend%d registration failed\n", + KBUILD_MODNAME, i); + goto err_dvb_unregister_frontend; + } + + count_registered++; + } + + if (d->props->tuner_attach) { + ret = d->props->tuner_attach(adap); + if (ret < 0) { + pr_debug("%s: tuner_attach() failed=%d\n", __func__, + ret); + goto err_dvb_unregister_frontend; + } + } + + return 0; + +err_dvb_unregister_frontend: + for (i = count_registered - 1; i >= 0; i--) + dvb_unregister_frontend(adap->fe[i]); + +err_dvb_frontend_detach: + for (i = MAX_NO_OF_FE_PER_ADAP - 1; i >= 0; i--) { + if (adap->fe[i]) + dvb_frontend_detach(adap->fe[i]); + } + +err: + pr_debug("%s: failed=%d\n", __func__, ret); + return ret; +} + +int dvb_usbv2_adapter_frontend_exit(struct dvb_usb_adapter *adap) +{ + int i; + pr_debug("%s: adap=%d\n", __func__, adap->id); + + for (i = MAX_NO_OF_FE_PER_ADAP - 1; i >= 0; i--) { + if (adap->fe[i]) { + dvb_unregister_frontend(adap->fe[i]); + dvb_frontend_detach(adap->fe[i]); + } + } + + return 0; +} + +static int dvb_usbv2_adapter_init(struct dvb_usb_device *d) +{ + struct dvb_usb_adapter *adap; + int ret, i, adapter_count; + + /* resolve adapter count */ + adapter_count = d->props->num_adapters; + if (d->props->get_adapter_count) { + ret = d->props->get_adapter_count(d); + if (ret < 0) + goto err; + + adapter_count = ret; + } + + for (i = 0; i < adapter_count; i++) { + adap = &d->adapter[i]; + adap->id = i; + adap->props = &d->props->adapter[i]; + + /* speed - when running at FULL speed we need a HW PID filter */ + if (d->udev->speed == USB_SPEED_FULL && + !(adap->props->caps & DVB_USB_ADAP_HAS_PID_FILTER)) { + pr_err("%s: this USB2.0 device cannot be run on a " \ + "USB1.1 port (it lacks a hardware " \ + "PID filter)\n", KBUILD_MODNAME); + ret = -ENODEV; + goto err; + } else if ((d->udev->speed == USB_SPEED_FULL && + adap->props->caps & DVB_USB_ADAP_HAS_PID_FILTER) || + (adap->props->caps & DVB_USB_ADAP_NEED_PID_FILTERING)) { + pr_info("%s: will use the device's hardware PID " \ + "filter (table count: %d)\n", + KBUILD_MODNAME, + adap->props->pid_filter_count); + adap->pid_filtering = 1; + adap->max_feed_count = adap->props->pid_filter_count; + } else { + pr_info("%s: will pass the complete MPEG2 transport " \ + "stream to the software demuxer\n", + KBUILD_MODNAME); + adap->pid_filtering = 0; + adap->max_feed_count = 255; + } + + if (!adap->pid_filtering && dvb_usb_force_pid_filter_usage && + adap->props->caps & DVB_USB_ADAP_HAS_PID_FILTER) { + pr_info("%s: pid filter enabled by module option\n", + KBUILD_MODNAME); + adap->pid_filtering = 1; + adap->max_feed_count = adap->props->pid_filter_count; + } + + ret = dvb_usbv2_adapter_stream_init(adap); + if (ret) + goto err; + + ret = dvb_usbv2_adapter_dvb_init(adap); + if (ret) + goto err; + + ret = dvb_usbv2_adapter_frontend_init(adap); + if (ret) + goto err; + + /* use exclusive FE lock if there is multiple shared FEs */ + if (adap->fe[1]) + adap->dvb_adap.mfe_shared = 1; + + adap->dvb_adap.fe_ioctl_override = d->props->fe_ioctl_override; + } + + return 0; +err: + pr_debug("%s: failed=%d\n", __func__, ret); + return ret; +} + +static int dvb_usbv2_adapter_exit(struct dvb_usb_device *d) +{ + int i; + + pr_debug("%s:\n", __func__); + + for (i = MAX_NO_OF_ADAPTER_PER_DEVICE - 1; i >= 0; i--) { + dvb_usbv2_adapter_frontend_exit(&d->adapter[i]); + dvb_usbv2_adapter_dvb_exit(&d->adapter[i]); + dvb_usbv2_adapter_stream_exit(&d->adapter[i]); + } + + return 0; +} + +/* general initialization functions */ +static int dvb_usbv2_exit(struct dvb_usb_device *d) +{ + pr_debug("%s:\n", __func__); + + dvb_usbv2_remote_exit(d); + dvb_usbv2_adapter_exit(d); + dvb_usbv2_i2c_exit(d); + kfree(d->priv); + kfree(d); + + return 0; +} + +static int dvb_usbv2_init(struct dvb_usb_device *d) +{ + int ret = 0; + + dvb_usbv2_device_power_ctrl(d, 1); + + if (d->props->read_config) { + ret = d->props->read_config(d); + if (ret < 0) + goto err; + } + + ret = dvb_usbv2_i2c_init(d); + if (ret < 0) + goto err; + + ret = dvb_usbv2_adapter_init(d); + if (ret < 0) + goto err; + + if (d->props->init) { + ret = d->props->init(d); + if (ret < 0) + goto err; + } + + ret = dvb_usbv2_remote_init(d); + if (ret < 0) + goto err; + + dvb_usbv2_device_power_ctrl(d, 0); + + return 0; +err: + dvb_usbv2_device_power_ctrl(d, 0); + pr_debug("%s: failed=%d\n", __func__, ret); + return ret; +} + +/* + * udev, which is used for the firmware downloading, requires we cannot + * block during module_init(). module_init() calls USB probe() which + * is this routine. Due to that we delay actual operation using workqueue + * and return always success here. + */ + +static void dvb_usbv2_init_work(struct work_struct *work) +{ + int ret; + struct dvb_usb_device *d = + container_of(work, struct dvb_usb_device, probe_work); + + d->work_pid = current->pid; + + pr_debug("%s: work_pid=%d\n", __func__, d->work_pid); + + if (d->props->size_of_priv) { + d->priv = kzalloc(d->props->size_of_priv, GFP_KERNEL); + if (!d->priv) { + pr_err("%s: kzalloc() failed\n", KBUILD_MODNAME); + ret = -ENOMEM; + goto err_usb_driver_release_interface; + } + } + + if (d->props->identify_state) { + const char *name = NULL; + ret = d->props->identify_state(d, &name); + if (ret == 0) { + ; + } else if (ret == COLD) { + pr_info("%s: found a '%s' in cold state\n", + KBUILD_MODNAME, d->name); + + if (!name) + name = d->props->firmware; + + ret = dvb_usbv2_download_firmware(d, name); + if (ret == 0) { + /* device is warm, continue initialization */ + ; + } else if (ret == RECONNECTS_USB) { + /* + * USB core will call disconnect() and then + * probe() as device reconnects itself from the + * USB bus. disconnect() will release all driver + * resources and probe() is called for 'new' + * device. As 'new' device is warm we should + * never go here again. + */ + return; + } else { + /* Unexpected error. We must unregister driver + * manually from the device, because device is + * already register by returning from probe() + * with success. usb_driver_release_interface() + * finally calls disconnect() in order to free + * resources. + */ + goto err_usb_driver_release_interface; + } + } else { + goto err_usb_driver_release_interface; + } + } + + pr_info("%s: found a '%s' in warm state\n", KBUILD_MODNAME, d->name); + + ret = dvb_usbv2_init(d); + if (ret < 0) + goto err_usb_driver_release_interface; + + pr_info("%s: '%s' successfully initialized and connected\n", + KBUILD_MODNAME, d->name); + + return; +err_usb_driver_release_interface: + pr_info("%s: '%s' error while loading driver (%d)\n", KBUILD_MODNAME, + d->name, ret); + /* it finally calls disconnect() which frees mem */ + usb_driver_release_interface(to_usb_driver(d->intf->dev.driver), + d->intf); + pr_debug("%s: failed=%d\n", __func__, ret); + return; +} + +int dvb_usbv2_probe(struct usb_interface *intf, + const struct usb_device_id *id) +{ + int ret; + struct dvb_usb_device *d; + struct dvb_usb_driver_info *driver_info = + (struct dvb_usb_driver_info *) id->driver_info; + + pr_debug("%s: bInterfaceNumber=%d\n", __func__, + intf->cur_altsetting->desc.bInterfaceNumber); + + if (!id->driver_info) { + pr_err("%s: driver_info failed\n", KBUILD_MODNAME); + ret = -ENODEV; + goto err; + } + + d = kzalloc(sizeof(struct dvb_usb_device), GFP_KERNEL); + if (!d) { + pr_err("%s: kzalloc() failed\n", KBUILD_MODNAME); + ret = -ENOMEM; + goto err; + } + + d->name = driver_info->name; + d->rc_map = driver_info->rc_map; + d->udev = interface_to_usbdev(intf); + d->intf = intf; + d->props = driver_info->props; + + if (d->intf->cur_altsetting->desc.bInterfaceNumber != + d->props->bInterfaceNumber) { + ret = -ENODEV; + goto err_kfree; + } + + mutex_init(&d->usb_mutex); + mutex_init(&d->i2c_mutex); + INIT_WORK(&d->probe_work, dvb_usbv2_init_work); + usb_set_intfdata(intf, d); + ret = schedule_work(&d->probe_work); + if (ret < 0) { + pr_err("%s: schedule_work() failed\n", KBUILD_MODNAME); + goto err_kfree; + } + + return 0; +err_kfree: + kfree(d); +err: + pr_debug("%s: failed=%d\n", __func__, ret); + return ret; +} +EXPORT_SYMBOL(dvb_usbv2_probe); + +void dvb_usbv2_disconnect(struct usb_interface *intf) +{ + struct dvb_usb_device *d = usb_get_intfdata(intf); + const char *name; + + pr_debug("%s: pid=%d work_pid=%d\n", __func__, current->pid, + d->work_pid); + + /* ensure initialization work is finished until release resources */ + if (d->work_pid != current->pid) + cancel_work_sync(&d->probe_work); + + if (d->props->disconnect) + d->props->disconnect(d); + + name = d->name; + dvb_usbv2_exit(d); + + pr_info("%s: '%s' successfully deinitialized and disconnected\n", + KBUILD_MODNAME, name); +} +EXPORT_SYMBOL(dvb_usbv2_disconnect); + +int dvb_usbv2_suspend(struct usb_interface *intf, pm_message_t msg) +{ + struct dvb_usb_device *d = usb_get_intfdata(intf); + int i; + + pr_debug("%s:\n", __func__); + + /* stop remote controller poll */ + if (d->rc.query && !d->rc.bulk_mode) + cancel_delayed_work_sync(&d->rc_query_work); + + /* stop streaming */ + for (i = MAX_NO_OF_ADAPTER_PER_DEVICE - 1; i >= 0; i--) { + if (d->adapter[i].dvb_adap.priv && + d->adapter[i].active_fe != -1) + usb_urb_killv2(&d->adapter[i].stream); + } + + return 0; +} +EXPORT_SYMBOL(dvb_usbv2_suspend); + +int dvb_usbv2_resume(struct usb_interface *intf) +{ + struct dvb_usb_device *d = usb_get_intfdata(intf); + int i; + + pr_debug("%s:\n", __func__); + + /* start streaming */ + for (i = 0; i < MAX_NO_OF_ADAPTER_PER_DEVICE; i++) { + if (d->adapter[i].dvb_adap.priv && + d->adapter[i].active_fe != -1) + usb_urb_submitv2(&d->adapter[i].stream, NULL); + } + + /* start remote controller poll */ + if (d->rc.query && !d->rc.bulk_mode) + schedule_delayed_work(&d->rc_query_work, + msecs_to_jiffies(d->rc.interval)); + + return 0; +} +EXPORT_SYMBOL(dvb_usbv2_resume); + +MODULE_VERSION("1.0"); +MODULE_AUTHOR("Patrick Boettcher "); +MODULE_DESCRIPTION("A library module containing commonly used USB and DVB function USB DVB devices"); +MODULE_LICENSE("GPL"); diff --git a/drivers/media/dvb/dvb-usb/dvb_usb_init.c b/drivers/media/dvb/dvb-usb/dvb_usb_init.c deleted file mode 100644 index 1d92d831ab27..000000000000 --- a/drivers/media/dvb/dvb-usb/dvb_usb_init.c +++ /dev/null @@ -1,586 +0,0 @@ -/* - * DVB USB library - provides a generic interface for a DVB USB device driver. - * - * dvb-usb-init.c - * - * Copyright (C) 2004-6 Patrick Boettcher (patrick.boettcher@desy.de) - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation, version 2. - * - * see Documentation/dvb/README.dvb-usb for more information - */ -#include "dvb_usb_common.h" -#include - -int dvb_usbv2_disable_rc_polling; -module_param_named(disable_rc_polling, dvb_usbv2_disable_rc_polling, int, 0644); -MODULE_PARM_DESC(disable_rc_polling, - "disable remote control polling (default: 0)."); -static int dvb_usb_force_pid_filter_usage; -module_param_named(force_pid_filter_usage, dvb_usb_force_pid_filter_usage, - int, 0444); -MODULE_PARM_DESC(force_pid_filter_usage, "force all dvb-usb-devices to use a" \ - " PID filter, if any (default: 0)."); - -static int dvb_usbv2_download_firmware(struct dvb_usb_device *d, const char *name) -{ - int ret; - const struct firmware *fw; - - if (!d->props->download_firmware) { - ret = -EINVAL; - goto err; - } - - ret = request_firmware(&fw, name, &d->udev->dev); - if (ret < 0) { - pr_err("%s: did not find the firmware file. (%s) " \ - "Please see linux/Documentation/dvb/ for " \ - "more details on firmware-problems. (%d)\n", - KBUILD_MODNAME, name, ret); - goto err; - } - - pr_info("%s: downloading firmware from file '%s'\n", KBUILD_MODNAME, - name); - - ret = d->props->download_firmware(d, fw); - - release_firmware(fw); - - if (ret < 0) - goto err; - - return ret; -err: - pr_debug("%s: failed=%d\n", __func__, ret); - return ret; -} - -static int dvb_usbv2_i2c_init(struct dvb_usb_device *d) -{ - int ret; - - pr_debug("%s:\n", __func__); - - if (!d->props->i2c_algo) - return 0; - - strlcpy(d->i2c_adap.name, d->name, sizeof(d->i2c_adap.name)); - d->i2c_adap.algo = d->props->i2c_algo; - d->i2c_adap.dev.parent = &d->udev->dev; - i2c_set_adapdata(&d->i2c_adap, d); - - ret = i2c_add_adapter(&d->i2c_adap); - if (ret < 0) { - d->i2c_adap.algo = NULL; - pr_err("%s: i2c_add_adapter() failed=%d\n", KBUILD_MODNAME, - ret); - goto err; - } - - return 0; -err: - pr_debug("%s: failed=%d\n", __func__, ret); - return ret; -} - -static int dvb_usbv2_i2c_exit(struct dvb_usb_device *d) -{ - pr_debug("%s:\n", __func__); - - if (d->i2c_adap.algo) - i2c_del_adapter(&d->i2c_adap); - - return 0; -} - -static void dvb_usb_read_remote_control(struct work_struct *work) -{ - struct dvb_usb_device *d = container_of(work, - struct dvb_usb_device, rc_query_work.work); - int ret; - - /* TODO: need a lock here. We can simply skip checking for the remote - control if we're busy. */ - - /* when the parameter has been set to 1 via sysfs while the - * driver was running, or when bulk mode is enabled after IR init - */ - if (dvb_usbv2_disable_rc_polling || d->rc.bulk_mode) - return; - - ret = d->rc.query(d); - if (ret < 0) - pr_err("%s: error %d while querying for an remote control " \ - "event\n", KBUILD_MODNAME, ret); - - schedule_delayed_work(&d->rc_query_work, - msecs_to_jiffies(d->rc.interval)); -} - -static int dvb_usbv2_remote_init(struct dvb_usb_device *d) -{ - int ret; - struct rc_dev *dev; - - pr_debug("%s:\n", __func__); - - if (dvb_usbv2_disable_rc_polling || !d->props->get_rc_config) - return 0; - - ret = d->props->get_rc_config(d, &d->rc); - if (ret < 0) - goto err; - - dev = rc_allocate_device(); - if (!dev) { - ret = -ENOMEM; - goto err; - } - - dev->dev.parent = &d->udev->dev; - dev->input_name = "IR-receiver inside an USB DVB receiver"; - usb_make_path(d->udev, d->rc_phys, sizeof(d->rc_phys)); - strlcat(d->rc_phys, "/ir0", sizeof(d->rc_phys)); - dev->input_phys = d->rc_phys; - usb_to_input_id(d->udev, &dev->input_id); - /* TODO: likely RC-core should took const char * */ - dev->driver_name = (char *) d->props->driver_name; - dev->driver_type = d->rc.driver_type; - dev->allowed_protos = d->rc.allowed_protos; - dev->change_protocol = d->rc.change_protocol; - dev->priv = d; - /* select used keymap */ - if (d->rc.map_name) - dev->map_name = d->rc.map_name; - else if (d->rc_map) - dev->map_name = d->rc_map; - else - dev->map_name = RC_MAP_EMPTY; /* keep rc enabled */ - - ret = rc_register_device(dev); - if (ret < 0) { - rc_free_device(dev); - goto err; - } - - d->input_dev = NULL; - d->rc_dev = dev; - - /* start polling if needed */ - if (d->rc.query && !d->rc.bulk_mode) { - /* initialize a work queue for handling polling */ - INIT_DELAYED_WORK(&d->rc_query_work, - dvb_usb_read_remote_control); - pr_info("%s: schedule remote query interval to %d msecs\n", - KBUILD_MODNAME, d->rc.interval); - schedule_delayed_work(&d->rc_query_work, - msecs_to_jiffies(d->rc.interval)); - } - - return 0; -err: - pr_debug("%s: failed=%d\n", __func__, ret); - return ret; -} - -static int dvb_usbv2_remote_exit(struct dvb_usb_device *d) -{ - pr_debug("%s:\n", __func__); - - if (d->rc_dev) { - cancel_delayed_work_sync(&d->rc_query_work); - rc_unregister_device(d->rc_dev); - d->rc_dev = NULL; - } - - return 0; -} - -static int dvb_usbv2_adapter_init(struct dvb_usb_device *d) -{ - struct dvb_usb_adapter *adap; - int ret, i, adapter_count; - - /* resolve adapter count */ - adapter_count = d->props->num_adapters; - if (d->props->get_adapter_count) { - ret = d->props->get_adapter_count(d); - if (ret < 0) - goto err; - - adapter_count = ret; - } - - for (i = 0; i < adapter_count; i++) { - adap = &d->adapter[i]; - adap->id = i; - adap->props = &d->props->adapter[i]; - - /* speed - when running at FULL speed we need a HW PID filter */ - if (d->udev->speed == USB_SPEED_FULL && - !(adap->props->caps & DVB_USB_ADAP_HAS_PID_FILTER)) { - pr_err("%s: this USB2.0 device cannot be run on a " \ - "USB1.1 port (it lacks a hardware " \ - "PID filter)\n", KBUILD_MODNAME); - ret = -ENODEV; - goto err; - } else if ((d->udev->speed == USB_SPEED_FULL && - adap->props->caps & DVB_USB_ADAP_HAS_PID_FILTER) || - (adap->props->caps & DVB_USB_ADAP_NEED_PID_FILTERING)) { - pr_info("%s: will use the device's hardware PID " \ - "filter (table count: %d)\n", - KBUILD_MODNAME, - adap->props->pid_filter_count); - adap->pid_filtering = 1; - adap->max_feed_count = adap->props->pid_filter_count; - } else { - pr_info("%s: will pass the complete MPEG2 transport " \ - "stream to the software demuxer\n", - KBUILD_MODNAME); - adap->pid_filtering = 0; - adap->max_feed_count = 255; - } - - if (!adap->pid_filtering && dvb_usb_force_pid_filter_usage && - adap->props->caps & DVB_USB_ADAP_HAS_PID_FILTER) { - pr_info("%s: pid filter enabled by module option\n", - KBUILD_MODNAME); - adap->pid_filtering = 1; - adap->max_feed_count = adap->props->pid_filter_count; - } - - ret = dvb_usbv2_adapter_stream_init(adap); - if (ret) - goto err; - - ret = dvb_usbv2_adapter_dvb_init(adap); - if (ret) - goto err; - - ret = dvb_usbv2_adapter_frontend_init(adap); - if (ret) - goto err; - - /* use exclusive FE lock if there is multiple shared FEs */ - if (adap->fe[1]) - adap->dvb_adap.mfe_shared = 1; - - adap->dvb_adap.fe_ioctl_override = d->props->fe_ioctl_override; - } - - return 0; -err: - pr_debug("%s: failed=%d\n", __func__, ret); - return ret; -} - -static int dvb_usbv2_adapter_exit(struct dvb_usb_device *d) -{ - int i; - - pr_debug("%s:\n", __func__); - - for (i = MAX_NO_OF_ADAPTER_PER_DEVICE - 1; i >= 0; i--) { - dvb_usbv2_adapter_frontend_exit(&d->adapter[i]); - dvb_usbv2_adapter_dvb_exit(&d->adapter[i]); - dvb_usbv2_adapter_stream_exit(&d->adapter[i]); - } - - return 0; -} - -/* general initialization functions */ -static int dvb_usbv2_exit(struct dvb_usb_device *d) -{ - pr_debug("%s:\n", __func__); - - dvb_usbv2_remote_exit(d); - dvb_usbv2_adapter_exit(d); - dvb_usbv2_i2c_exit(d); - kfree(d->priv); - kfree(d); - - return 0; -} - -static int dvb_usbv2_init(struct dvb_usb_device *d) -{ - int ret = 0; - - dvb_usbv2_device_power_ctrl(d, 1); - - if (d->props->read_config) { - ret = d->props->read_config(d); - if (ret < 0) - goto err; - } - - ret = dvb_usbv2_i2c_init(d); - if (ret < 0) - goto err; - - ret = dvb_usbv2_adapter_init(d); - if (ret < 0) - goto err; - - if (d->props->init) { - ret = d->props->init(d); - if (ret < 0) - goto err; - } - - ret = dvb_usbv2_remote_init(d); - if (ret < 0) - goto err; - - dvb_usbv2_device_power_ctrl(d, 0); - - return 0; -err: - dvb_usbv2_device_power_ctrl(d, 0); - pr_debug("%s: failed=%d\n", __func__, ret); - return ret; -} - -int dvb_usbv2_device_power_ctrl(struct dvb_usb_device *d, int onoff) -{ - int ret; - - if (onoff) - d->powered++; - else - d->powered--; - - if (d->powered == 0 || (onoff && d->powered == 1)) { - /* when switching from 1 to 0 or from 0 to 1 */ - pr_debug("%s: power control=%d\n", __func__, onoff); - if (d->props->power_ctrl) { - ret = d->props->power_ctrl(d, onoff); - goto err; - } - } - - return 0; -err: - pr_debug("%s: failed=%d\n", __func__, ret); - return ret; -} - -/* - * udev, which is used for the firmware downloading, requires we cannot - * block during module_init(). module_init() calls USB probe() which - * is this routine. Due to that we delay actual operation using workqueue - * and return always success here. - */ - -static void dvb_usbv2_init_work(struct work_struct *work) -{ - int ret; - struct dvb_usb_device *d = - container_of(work, struct dvb_usb_device, probe_work); - - d->work_pid = current->pid; - - pr_debug("%s: work_pid=%d\n", __func__, d->work_pid); - - if (d->props->size_of_priv) { - d->priv = kzalloc(d->props->size_of_priv, GFP_KERNEL); - if (!d->priv) { - pr_err("%s: kzalloc() failed\n", KBUILD_MODNAME); - ret = -ENOMEM; - goto err_usb_driver_release_interface; - } - } - - if (d->props->identify_state) { - const char *name = NULL; - ret = d->props->identify_state(d, &name); - if (ret == 0) { - ; - } else if (ret == COLD) { - pr_info("%s: found a '%s' in cold state\n", - KBUILD_MODNAME, d->name); - - if (!name) - name = d->props->firmware; - - ret = dvb_usbv2_download_firmware(d, name); - if (ret == 0) { - /* device is warm, continue initialization */ - ; - } else if (ret == RECONNECTS_USB) { - /* - * USB core will call disconnect() and then - * probe() as device reconnects itself from the - * USB bus. disconnect() will release all driver - * resources and probe() is called for 'new' - * device. As 'new' device is warm we should - * never go here again. - */ - return; - } else { - /* Unexpected error. We must unregister driver - * manually from the device, because device is - * already register by returning from probe() - * with success. usb_driver_release_interface() - * finally calls disconnect() in order to free - * resources. - */ - goto err_usb_driver_release_interface; - } - } else { - goto err_usb_driver_release_interface; - } - } - - pr_info("%s: found a '%s' in warm state\n", KBUILD_MODNAME, d->name); - - ret = dvb_usbv2_init(d); - if (ret < 0) - goto err_usb_driver_release_interface; - - pr_info("%s: '%s' successfully initialized and connected\n", - KBUILD_MODNAME, d->name); - - return; -err_usb_driver_release_interface: - pr_info("%s: '%s' error while loading driver (%d)\n", KBUILD_MODNAME, - d->name, ret); - /* it finally calls disconnect() which frees mem */ - usb_driver_release_interface(to_usb_driver(d->intf->dev.driver), - d->intf); - pr_debug("%s: failed=%d\n", __func__, ret); - return; -} - -int dvb_usbv2_probe(struct usb_interface *intf, - const struct usb_device_id *id) -{ - int ret; - struct dvb_usb_device *d; - struct dvb_usb_driver_info *driver_info = - (struct dvb_usb_driver_info *) id->driver_info; - - pr_debug("%s: bInterfaceNumber=%d\n", __func__, - intf->cur_altsetting->desc.bInterfaceNumber); - - if (!id->driver_info) { - pr_err("%s: driver_info failed\n", KBUILD_MODNAME); - ret = -ENODEV; - goto err; - } - - d = kzalloc(sizeof(struct dvb_usb_device), GFP_KERNEL); - if (!d) { - pr_err("%s: kzalloc() failed\n", KBUILD_MODNAME); - ret = -ENOMEM; - goto err; - } - - d->name = driver_info->name; - d->rc_map = driver_info->rc_map; - d->udev = interface_to_usbdev(intf); - d->intf = intf; - d->props = driver_info->props; - - if (d->intf->cur_altsetting->desc.bInterfaceNumber != - d->props->bInterfaceNumber) { - ret = -ENODEV; - goto err_kfree; - } - - mutex_init(&d->usb_mutex); - mutex_init(&d->i2c_mutex); - INIT_WORK(&d->probe_work, dvb_usbv2_init_work); - usb_set_intfdata(intf, d); - ret = schedule_work(&d->probe_work); - if (ret < 0) { - pr_err("%s: schedule_work() failed\n", KBUILD_MODNAME); - goto err_kfree; - } - - return 0; -err_kfree: - kfree(d); -err: - pr_debug("%s: failed=%d\n", __func__, ret); - return ret; -} -EXPORT_SYMBOL(dvb_usbv2_probe); - -void dvb_usbv2_disconnect(struct usb_interface *intf) -{ - struct dvb_usb_device *d = usb_get_intfdata(intf); - const char *name; - - pr_debug("%s: pid=%d work_pid=%d\n", __func__, current->pid, - d->work_pid); - - /* ensure initialization work is finished until release resources */ - if (d->work_pid != current->pid) - cancel_work_sync(&d->probe_work); - - if (d->props->disconnect) - d->props->disconnect(d); - - name = d->name; - dvb_usbv2_exit(d); - - pr_info("%s: '%s' successfully deinitialized and disconnected\n", - KBUILD_MODNAME, name); -} -EXPORT_SYMBOL(dvb_usbv2_disconnect); - -int dvb_usbv2_suspend(struct usb_interface *intf, pm_message_t msg) -{ - struct dvb_usb_device *d = usb_get_intfdata(intf); - int i; - - pr_debug("%s:\n", __func__); - - /* stop remote controller poll */ - if (d->rc.query && !d->rc.bulk_mode) - cancel_delayed_work_sync(&d->rc_query_work); - - /* stop streaming */ - for (i = MAX_NO_OF_ADAPTER_PER_DEVICE - 1; i >= 0; i--) { - if (d->adapter[i].dvb_adap.priv && - d->adapter[i].active_fe != -1) - usb_urb_killv2(&d->adapter[i].stream); - } - - return 0; -} -EXPORT_SYMBOL(dvb_usbv2_suspend); - -int dvb_usbv2_resume(struct usb_interface *intf) -{ - struct dvb_usb_device *d = usb_get_intfdata(intf); - int i; - - pr_debug("%s:\n", __func__); - - /* start streaming */ - for (i = 0; i < MAX_NO_OF_ADAPTER_PER_DEVICE; i++) { - if (d->adapter[i].dvb_adap.priv && - d->adapter[i].active_fe != -1) - usb_urb_submitv2(&d->adapter[i].stream, NULL); - } - - /* start remote controller poll */ - if (d->rc.query && !d->rc.bulk_mode) - schedule_delayed_work(&d->rc_query_work, - msecs_to_jiffies(d->rc.interval)); - - return 0; -} -EXPORT_SYMBOL(dvb_usbv2_resume); - -MODULE_VERSION("1.0"); -MODULE_AUTHOR("Patrick Boettcher "); -MODULE_DESCRIPTION("A library module containing commonly used USB and DVB function USB DVB devices"); -MODULE_LICENSE("GPL");