15b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijie#include "pd-common.h"
25b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijie#include <linux/kernel.h>
35b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijie#include <linux/usb.h>
45b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijie#include <linux/dvb/dmx.h>
55b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijie#include <linux/delay.h>
65a0e3ad6af8660be21ca98a971cd00f331318c05Tejun Heo#include <linux/gfp.h>
75b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijie
85b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijie#include "vendorcmds.h"
95b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijie#include <linux/sched.h>
1060063497a95e716c9a689af3be2687d261f115b4Arun Sharma#include <linux/atomic.h>
115b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijie
125b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijiestatic void dvb_urb_cleanup(struct pd_dvb_adapter *pd_dvb);
135b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijie
145b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijiestatic int dvb_bandwidth[][2] = {
152827e1ff8692289a9767ab15be9671bb8df77f79Mauro Carvalho Chehab	{ TLG_BW_8, 8000000 },
162827e1ff8692289a9767ab15be9671bb8df77f79Mauro Carvalho Chehab	{ TLG_BW_7, 7000000 },
172827e1ff8692289a9767ab15be9671bb8df77f79Mauro Carvalho Chehab	{ TLG_BW_6, 6000000 }
185b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijie};
195b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijiestatic int dvb_bandwidth_length = ARRAY_SIZE(dvb_bandwidth);
205b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijie
215b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijiestatic s32 dvb_start_streaming(struct pd_dvb_adapter *pd_dvb);
225b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijiestatic int poseidon_check_mode_dvbt(struct poseidon *pd)
235b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijie{
245b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijie	s32 ret = 0, cmd_status = 0;
255b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijie
265b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijie	set_current_state(TASK_INTERRUPTIBLE);
275b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijie	schedule_timeout(HZ/4);
285b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijie
295b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijie	ret = usb_set_interface(pd->udev, 0, BULK_ALTERNATE_IFACE);
305b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijie	if (ret != 0)
315b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijie		return ret;
325b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijie
335b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijie	ret = set_tuner_mode(pd, TLG_MODE_CAPS_DVB_T);
345b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijie	if (ret)
355b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijie		return ret;
365b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijie
375b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijie	/* signal source */
385b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijie	ret = send_set_req(pd, SGNL_SRC_SEL, TLG_SIG_SRC_ANTENNA, &cmd_status);
395b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijie	if (ret|cmd_status)
405b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijie		return ret;
415b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijie
425b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijie	return 0;
435b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijie}
445b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijie
455b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijie/* acquire :
465b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijie * 	1 == open
475b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijie * 	0 == release
485b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijie */
495b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijiestatic int poseidon_ts_bus_ctrl(struct dvb_frontend *fe, int acquire)
505b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijie{
515b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijie	struct poseidon *pd = fe->demodulator_priv;
525b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijie	struct pd_dvb_adapter *pd_dvb;
535b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijie	int ret = 0;
545b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijie
555b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijie	if (!pd)
565b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijie		return -ENODEV;
575b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijie
585b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijie	pd_dvb = container_of(fe, struct pd_dvb_adapter, dvb_fe);
595b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijie	if (acquire) {
605b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijie		mutex_lock(&pd->lock);
615b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijie		if (pd->state & POSEIDON_STATE_DISCONNECT) {
625b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijie			ret = -ENODEV;
635b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijie			goto open_out;
645b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijie		}
655b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijie
665b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijie		if (pd->state && !(pd->state & POSEIDON_STATE_DVBT)) {
675b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijie			ret = -EBUSY;
685b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijie			goto open_out;
695b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijie		}
705b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijie
715b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijie		usb_autopm_get_interface(pd->interface);
725b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijie		if (0 == pd->state) {
735b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijie			ret = poseidon_check_mode_dvbt(pd);
745b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijie			if (ret < 0) {
755b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijie				usb_autopm_put_interface(pd->interface);
765b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijie				goto open_out;
775b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijie			}
785b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijie			pd->state |= POSEIDON_STATE_DVBT;
795b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijie			pd_dvb->bandwidth = 0;
805b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijie			pd_dvb->prev_freq = 0;
815b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijie		}
825b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijie		atomic_inc(&pd_dvb->users);
835b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijie		kref_get(&pd->kref);
845b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijieopen_out:
855b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijie		mutex_unlock(&pd->lock);
865b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijie	} else {
875b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijie		dvb_stop_streaming(pd_dvb);
885b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijie
895b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijie		if (atomic_dec_and_test(&pd_dvb->users)) {
905b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijie			mutex_lock(&pd->lock);
915b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijie			pd->state &= ~POSEIDON_STATE_DVBT;
925b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijie			mutex_unlock(&pd->lock);
935b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijie		}
945b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijie		kref_put(&pd->kref, poseidon_delete);
955b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijie		usb_autopm_put_interface(pd->interface);
965b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijie	}
975b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijie	return ret;
985b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijie}
995b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijie
1006c9eaa82da53676db830572f5a41aa9ffea133a1Márton Németh#ifdef CONFIG_PM
1015b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijiestatic void poseidon_fe_release(struct dvb_frontend *fe)
1025b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijie{
1035b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijie	struct poseidon *pd = fe->demodulator_priv;
1045b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijie
1055b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijie	pd->pm_suspend = NULL;
1065b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijie	pd->pm_resume  = NULL;
1075b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijie}
1086c9eaa82da53676db830572f5a41aa9ffea133a1Márton Németh#else
1096c9eaa82da53676db830572f5a41aa9ffea133a1Márton Németh#define poseidon_fe_release NULL
1106c9eaa82da53676db830572f5a41aa9ffea133a1Márton Németh#endif
1115b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijie
1125b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijiestatic s32 poseidon_fe_sleep(struct dvb_frontend *fe)
1135b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijie{
1145b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijie	return 0;
1155b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijie}
1165b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijie
1175b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijie/*
1185b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijie * return true if we can satisfy the conditions, else return false.
1195b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijie */
1205b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijiestatic bool check_scan_ok(__u32 freq, int bandwidth,
1215b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijie			struct pd_dvb_adapter *adapter)
1225b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijie{
1235b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijie	if (bandwidth < 0)
1245b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijie		return false;
1255b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijie
1265b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijie	if (adapter->prev_freq == freq
1275b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijie		&& adapter->bandwidth == bandwidth) {
1285b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijie		long nl = jiffies - adapter->last_jiffies;
1295b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijie		unsigned int msec ;
1305b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijie
1315b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijie		msec = jiffies_to_msecs(abs(nl));
1325b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijie		return msec > 15000 ? true : false;
1335b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijie	}
1345b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijie	return true;
1355b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijie}
1365b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijie
1375b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijie/*
1385b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijie * Check if the firmware delays too long for an invalid frequency.
1395b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijie */
1405b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijiestatic int fw_delay_overflow(struct pd_dvb_adapter *adapter)
1415b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijie{
1425b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijie	long nl = jiffies - adapter->last_jiffies;
1435b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijie	unsigned int msec ;
1445b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijie
1455b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijie	msec = jiffies_to_msecs(abs(nl));
1465b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijie	return msec > 800 ? true : false;
1475b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijie}
1485b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijie
1492827e1ff8692289a9767ab15be9671bb8df77f79Mauro Carvalho Chehabstatic int poseidon_set_fe(struct dvb_frontend *fe)
1505b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijie{
1512827e1ff8692289a9767ab15be9671bb8df77f79Mauro Carvalho Chehab	struct dtv_frontend_properties *fep = &fe->dtv_property_cache;
1525b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijie	s32 ret = 0, cmd_status = 0;
1535b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijie	s32 i, bandwidth = -1;
1545b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijie	struct poseidon *pd = fe->demodulator_priv;
1555b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijie	struct pd_dvb_adapter *pd_dvb = &pd->dvb_data;
1565b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijie
1575b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijie	if (in_hibernation(pd))
1585b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijie		return -EBUSY;
1595b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijie
1605b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijie	mutex_lock(&pd->lock);
1615b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijie	for (i = 0; i < dvb_bandwidth_length; i++)
1622827e1ff8692289a9767ab15be9671bb8df77f79Mauro Carvalho Chehab		if (fep->bandwidth_hz == dvb_bandwidth[i][1])
1635b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijie			bandwidth = dvb_bandwidth[i][0];
1645b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijie
1655b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijie	if (check_scan_ok(fep->frequency, bandwidth, pd_dvb)) {
1665b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijie		ret = send_set_req(pd, TUNE_FREQ_SELECT,
1675b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijie					fep->frequency / 1000, &cmd_status);
1685b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijie		if (ret | cmd_status) {
1695b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijie			log("error line");
1705b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijie			goto front_out;
1715b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijie		}
1725b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijie
1735b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijie		ret = send_set_req(pd, DVBT_BANDW_SEL,
1745b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijie						bandwidth, &cmd_status);
1755b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijie		if (ret | cmd_status) {
1765b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijie			log("error line");
1775b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijie			goto front_out;
1785b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijie		}
1795b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijie
1805b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijie		ret = send_set_req(pd, TAKE_REQUEST, 0, &cmd_status);
1815b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijie		if (ret | cmd_status) {
1825b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijie			log("error line");
1835b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijie			goto front_out;
1845b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijie		}
1855b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijie
1865b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijie		/* save the context for future */
1875b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijie		memcpy(&pd_dvb->fe_param, fep, sizeof(*fep));
1885b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijie		pd_dvb->bandwidth = bandwidth;
1895b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijie		pd_dvb->prev_freq = fep->frequency;
1905b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijie		pd_dvb->last_jiffies = jiffies;
1915b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijie	}
1925b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijiefront_out:
1935b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijie	mutex_unlock(&pd->lock);
1945b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijie	return ret;
1955b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijie}
1965b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijie
1975b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijie#ifdef CONFIG_PM
1985b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijiestatic int pm_dvb_suspend(struct poseidon *pd)
1995b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijie{
2005b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijie	struct pd_dvb_adapter *pd_dvb = &pd->dvb_data;
2015b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijie	dvb_stop_streaming(pd_dvb);
2025b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijie	dvb_urb_cleanup(pd_dvb);
2035b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijie	msleep(500);
2045b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijie	return 0;
2055b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijie}
2065b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijie
2075b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijiestatic int pm_dvb_resume(struct poseidon *pd)
2085b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijie{
2095b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijie	struct pd_dvb_adapter *pd_dvb = &pd->dvb_data;
2105b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijie
2115b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijie	poseidon_check_mode_dvbt(pd);
2125b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijie	msleep(300);
2132827e1ff8692289a9767ab15be9671bb8df77f79Mauro Carvalho Chehab	poseidon_set_fe(&pd_dvb->dvb_fe);
2145b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijie
2155b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijie	dvb_start_streaming(pd_dvb);
2165b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijie	return 0;
2175b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijie}
2185b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijie#endif
2195b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijie
2205b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijiestatic s32 poseidon_fe_init(struct dvb_frontend *fe)
2215b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijie{
2225b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijie	struct poseidon *pd = fe->demodulator_priv;
2235b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijie	struct pd_dvb_adapter *pd_dvb = &pd->dvb_data;
2245b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijie
2255b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijie#ifdef CONFIG_PM
2265b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijie	pd->pm_suspend = pm_dvb_suspend;
2275b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijie	pd->pm_resume  = pm_dvb_resume;
2285b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijie#endif
2295b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijie	memset(&pd_dvb->fe_param, 0,
2302827e1ff8692289a9767ab15be9671bb8df77f79Mauro Carvalho Chehab			sizeof(struct dtv_frontend_properties));
2315b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijie	return 0;
2325b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijie}
2335b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijie
2347c61d80a9bcfc3fdec8ffd75756cad6a64678229Mauro Carvalho Chehabstatic int poseidon_get_fe(struct dvb_frontend *fe)
2355b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijie{
2367c61d80a9bcfc3fdec8ffd75756cad6a64678229Mauro Carvalho Chehab	struct dtv_frontend_properties *fep = &fe->dtv_property_cache;
2375b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijie	struct poseidon *pd = fe->demodulator_priv;
2385b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijie	struct pd_dvb_adapter *pd_dvb = &pd->dvb_data;
2395b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijie
2405b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijie	memcpy(fep, &pd_dvb->fe_param, sizeof(*fep));
2415b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijie	return 0;
2425b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijie}
2435b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijie
2445b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijiestatic int poseidon_fe_get_tune_settings(struct dvb_frontend *fe,
2455b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijie				struct dvb_frontend_tune_settings *tune)
2465b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijie{
2475b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijie	tune->min_delay_ms = 1000;
2485b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijie	return 0;
2495b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijie}
2505b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijie
2515b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijiestatic int poseidon_read_status(struct dvb_frontend *fe, fe_status_t *stat)
2525b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijie{
2535b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijie	struct poseidon *pd = fe->demodulator_priv;
2545b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijie	s32 ret = -1, cmd_status;
2555b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijie	struct tuner_dtv_sig_stat_s status = {};
2565b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijie
2575b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijie	if (in_hibernation(pd))
2585b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijie		return -EBUSY;
2595b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijie	mutex_lock(&pd->lock);
2605b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijie
2615b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijie	ret = send_get_req(pd, TUNER_STATUS, TLG_MODE_DVB_T,
2625b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijie				&status, &cmd_status, sizeof(status));
2635b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijie	if (ret | cmd_status) {
2645b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijie		log("get tuner status error");
2655b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijie		goto out;
2665b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijie	}
2675b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijie
2685b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijie	if (debug_mode)
2695b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijie		log("P : %d, L %d, LB :%d", status.sig_present,
2705b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijie			status.sig_locked, status.sig_lock_busy);
2715b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijie
2725b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijie	if (status.sig_lock_busy) {
2735b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijie		goto out;
2745b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijie	} else if (status.sig_present || status.sig_locked) {
2755b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijie		*stat |= FE_HAS_LOCK | FE_HAS_SIGNAL | FE_HAS_CARRIER
2765b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijie				| FE_HAS_SYNC | FE_HAS_VITERBI;
2775b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijie	} else {
2785b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijie		if (fw_delay_overflow(&pd->dvb_data))
2795b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijie			*stat |= FE_TIMEDOUT;
2805b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijie	}
2815b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijieout:
2825b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijie	mutex_unlock(&pd->lock);
2835b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijie	return ret;
2845b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijie}
2855b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijie
2865b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijiestatic int poseidon_read_ber(struct dvb_frontend *fe, u32 *ber)
2875b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijie{
2885b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijie	struct poseidon *pd = fe->demodulator_priv;
2895b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijie	struct tuner_ber_rate_s tlg_ber = {};
2905b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijie	s32 ret = -1, cmd_status;
2915b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijie
2925b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijie	mutex_lock(&pd->lock);
2935b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijie	ret = send_get_req(pd, TUNER_BER_RATE, 0,
2945b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijie				&tlg_ber, &cmd_status, sizeof(tlg_ber));
2955b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijie	if (ret | cmd_status)
2965b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijie		goto out;
2975b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijie	*ber = tlg_ber.ber_rate;
2985b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijieout:
2995b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijie	mutex_unlock(&pd->lock);
3005b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijie	return ret;
3015b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijie}
3025b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijie
3035b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijiestatic s32 poseidon_read_signal_strength(struct dvb_frontend *fe, u16 *strength)
3045b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijie{
3055b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijie	struct poseidon *pd = fe->demodulator_priv;
3065b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijie	struct tuner_dtv_sig_stat_s status = {};
3075b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijie	s32 ret = 0, cmd_status;
3085b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijie
3095b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijie	mutex_lock(&pd->lock);
3105b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijie	ret = send_get_req(pd, TUNER_STATUS, TLG_MODE_DVB_T,
3115b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijie				&status, &cmd_status, sizeof(status));
3125b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijie	if (ret | cmd_status)
3135b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijie		goto out;
3145b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijie	if ((status.sig_present || status.sig_locked) && !status.sig_strength)
3155b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijie		*strength = 0xFFFF;
3165b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijie	else
3175b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijie		*strength = status.sig_strength;
3185b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijieout:
3195b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijie	mutex_unlock(&pd->lock);
3205b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijie	return ret;
3215b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijie}
3225b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijie
3235b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijiestatic int poseidon_read_snr(struct dvb_frontend *fe, u16 *snr)
3245b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijie{
3255b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijie	return 0;
3265b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijie}
3275b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijie
3285b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijiestatic int poseidon_read_unc_blocks(struct dvb_frontend *fe, u32 *unc)
3295b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijie{
3305b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijie	*unc = 0;
3315b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijie	return 0;
3325b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijie}
3335b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijie
3345b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijiestatic struct dvb_frontend_ops poseidon_frontend_ops = {
3352827e1ff8692289a9767ab15be9671bb8df77f79Mauro Carvalho Chehab	.delsys = { SYS_DVBT },
3365b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijie	.info = {
3375b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijie		.name		= "Poseidon DVB-T",
3385b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijie		.frequency_min	= 174000000,
3395b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijie		.frequency_max  = 862000000,
3405b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijie		.frequency_stepsize	  = 62500,/* FIXME */
3415b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijie		.caps = FE_CAN_INVERSION_AUTO |
3425b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijie			FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 |
3435b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijie			FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO |
3445b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijie			FE_CAN_QPSK | FE_CAN_QAM_16 | FE_CAN_QAM_64 |
3455b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijie			FE_CAN_QAM_AUTO | FE_CAN_TRANSMISSION_MODE_AUTO |
3465b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijie			FE_CAN_GUARD_INTERVAL_AUTO |
3475b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijie			FE_CAN_RECOVER |
3485b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijie			FE_CAN_HIERARCHY_AUTO,
3495b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijie	},
3505b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijie
3515b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijie	.release = poseidon_fe_release,
3525b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijie
3535b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijie	.init = poseidon_fe_init,
3545b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijie	.sleep = poseidon_fe_sleep,
3555b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijie
3562827e1ff8692289a9767ab15be9671bb8df77f79Mauro Carvalho Chehab	.set_frontend = poseidon_set_fe,
3572827e1ff8692289a9767ab15be9671bb8df77f79Mauro Carvalho Chehab	.get_frontend = poseidon_get_fe,
3585b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijie	.get_tune_settings = poseidon_fe_get_tune_settings,
3595b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijie
3605b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijie	.read_status	= poseidon_read_status,
3615b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijie	.read_ber	= poseidon_read_ber,
3625b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijie	.read_signal_strength = poseidon_read_signal_strength,
3635b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijie	.read_snr	= poseidon_read_snr,
3645b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijie	.read_ucblocks	= poseidon_read_unc_blocks,
3655b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijie
3665b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijie	.ts_bus_ctrl = poseidon_ts_bus_ctrl,
3675b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijie};
3685b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijie
3695b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijiestatic void dvb_urb_irq(struct urb *urb)
3705b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijie{
3715b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijie	struct pd_dvb_adapter *pd_dvb = urb->context;
3725b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijie	int len = urb->transfer_buffer_length;
3735b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijie	struct dvb_demux *demux = &pd_dvb->demux;
3745b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijie	s32 ret;
3755b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijie
3765b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijie	if (!pd_dvb->is_streaming || urb->status) {
3775b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijie		if (urb->status == -EPROTO)
3785b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijie			goto resend;
3795b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijie		return;
3805b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijie	}
3815b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijie
3825b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijie	if (urb->actual_length == len)
3835b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijie		dvb_dmx_swfilter(demux, urb->transfer_buffer, len);
3845b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijie	else if (urb->actual_length == len - 4) {
3855b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijie		int offset;
3865b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijie		u8 *buf = urb->transfer_buffer;
3875b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijie
3885b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijie		/*
3895b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijie		 * The packet size is 512,
3905b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijie		 * last packet contains 456 bytes tsp data
3915b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijie		 */
3925b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijie		for (offset = 456; offset < len; offset += 512) {
3935b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijie			if (!strncmp(buf + offset, "DVHS", 4)) {
3945b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijie				dvb_dmx_swfilter(demux, buf, offset);
3955b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijie				if (len > offset + 52 + 4) {
3965b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijie					/*16 bytes trailer + 36 bytes padding */
3975b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijie					buf += offset + 52;
3985b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijie					len -= offset + 52 + 4;
3995b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijie					dvb_dmx_swfilter(demux, buf, len);
4005b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijie				}
4015b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijie				break;
4025b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijie			}
4035b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijie		}
4045b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijie	}
4055b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijie
4065b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijieresend:
4075b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijie	ret = usb_submit_urb(urb, GFP_ATOMIC);
4085b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijie	if (ret)
4095b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijie		log(" usb_submit_urb failed: error %d", ret);
4105b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijie}
4115b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijie
4125b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijiestatic int dvb_urb_init(struct pd_dvb_adapter *pd_dvb)
4135b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijie{
4145b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijie	if (pd_dvb->urb_array[0])
4155b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijie		return 0;
4165b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijie
4175b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijie	alloc_bulk_urbs_generic(pd_dvb->urb_array, DVB_SBUF_NUM,
4185b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijie			pd_dvb->pd_device->udev, pd_dvb->ep_addr,
4195b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijie			DVB_URB_BUF_SIZE, GFP_KERNEL,
4205b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijie			dvb_urb_irq, pd_dvb);
4215b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijie	return 0;
4225b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijie}
4235b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijie
4245b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijiestatic void dvb_urb_cleanup(struct pd_dvb_adapter *pd_dvb)
4255b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijie{
4265b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijie	free_all_urb_generic(pd_dvb->urb_array, DVB_SBUF_NUM);
4275b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijie}
4285b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijie
4295b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijiestatic s32 dvb_start_streaming(struct pd_dvb_adapter *pd_dvb)
4305b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijie{
4315b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijie	struct poseidon *pd = pd_dvb->pd_device;
4325b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijie	int ret = 0;
4335b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijie
4345b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijie	if (pd->state & POSEIDON_STATE_DISCONNECT)
4355b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijie		return -ENODEV;
4365b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijie
4375b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijie	mutex_lock(&pd->lock);
4385b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijie	if (!pd_dvb->is_streaming) {
4395b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijie		s32 i, cmd_status = 0;
4405b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijie		/*
4415b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijie		 * Once upon a time, there was a difficult bug lying here.
4425b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijie		 * ret = send_set_req(pd, TAKE_REQUEST, 0, &cmd_status);
4435b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijie		 */
4445b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijie
4455b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijie		ret = send_set_req(pd, PLAY_SERVICE, 1, &cmd_status);
4465b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijie		if (ret | cmd_status)
4475b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijie			goto out;
4485b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijie
4495b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijie		ret = dvb_urb_init(pd_dvb);
4505b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijie		if (ret < 0)
4515b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijie			goto out;
4525b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijie
4535b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijie		pd_dvb->is_streaming = 1;
4545b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijie		for (i = 0; i < DVB_SBUF_NUM; i++) {
4555b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijie			ret = usb_submit_urb(pd_dvb->urb_array[i],
4565b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijie						       GFP_KERNEL);
4575b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijie			if (ret) {
4585b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijie				log(" submit urb error %d", ret);
4595b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijie				goto out;
4605b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijie			}
4615b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijie		}
4625b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijie	}
4635b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijieout:
4645b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijie	mutex_unlock(&pd->lock);
4655b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijie	return ret;
4665b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijie}
4675b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijie
4685b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijievoid dvb_stop_streaming(struct pd_dvb_adapter *pd_dvb)
4695b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijie{
4705b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijie	struct poseidon *pd = pd_dvb->pd_device;
4715b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijie
4725b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijie	mutex_lock(&pd->lock);
4735b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijie	if (pd_dvb->is_streaming) {
4745b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijie		s32 i, ret, cmd_status = 0;
4755b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijie
4765b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijie		pd_dvb->is_streaming = 0;
4775b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijie
4785b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijie		for (i = 0; i < DVB_SBUF_NUM; i++)
4795b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijie			if (pd_dvb->urb_array[i])
4805b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijie				usb_kill_urb(pd_dvb->urb_array[i]);
4815b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijie
4825b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijie		ret = send_set_req(pd, PLAY_SERVICE, TLG_TUNE_PLAY_SVC_STOP,
4835b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijie					&cmd_status);
4845b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijie		if (ret | cmd_status)
4855b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijie			log("error");
4865b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijie	}
4875b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijie	mutex_unlock(&pd->lock);
4885b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijie}
4895b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijie
4905b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijiestatic int pd_start_feed(struct dvb_demux_feed *feed)
4915b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijie{
4925b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijie	struct pd_dvb_adapter *pd_dvb = feed->demux->priv;
4935b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijie	int ret = 0;
4945b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijie
4955b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijie	if (!pd_dvb)
4965b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijie		return -1;
4975b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijie	if (atomic_inc_return(&pd_dvb->active_feed) == 1)
4985b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijie		ret = dvb_start_streaming(pd_dvb);
4995b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijie	return ret;
5005b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijie}
5015b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijie
5025b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijiestatic int pd_stop_feed(struct dvb_demux_feed *feed)
5035b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijie{
5045b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijie	struct pd_dvb_adapter *pd_dvb = feed->demux->priv;
5055b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijie
5065b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijie	if (!pd_dvb)
5075b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijie		return -1;
5085b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijie	if (atomic_dec_and_test(&pd_dvb->active_feed))
5095b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijie		dvb_stop_streaming(pd_dvb);
5105b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijie	return 0;
5115b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijie}
5125b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijie
5135b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang ShijieDVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
5145b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijieint pd_dvb_usb_device_init(struct poseidon *pd)
5155b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijie{
5165b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijie	struct pd_dvb_adapter *pd_dvb = &pd->dvb_data;
5175b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijie	struct dvb_demux *dvbdemux;
5185b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijie	int ret = 0;
5195b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijie
5205b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijie	pd_dvb->ep_addr = 0x82;
5215b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijie	atomic_set(&pd_dvb->users, 0);
5225b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijie	atomic_set(&pd_dvb->active_feed, 0);
5235b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijie	pd_dvb->pd_device = pd;
5245b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijie
5255b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijie	ret = dvb_register_adapter(&pd_dvb->dvb_adap,
5265b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijie				"Poseidon dvbt adapter",
5275b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijie				THIS_MODULE,
5285b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijie				NULL /* for hibernation correctly*/,
5295b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijie				adapter_nr);
5305b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijie	if (ret < 0)
5315b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijie		goto error1;
5325b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijie
5335b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijie	/* register frontend */
5345b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijie	pd_dvb->dvb_fe.demodulator_priv = pd;
5355b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijie	memcpy(&pd_dvb->dvb_fe.ops, &poseidon_frontend_ops,
5365b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijie			sizeof(struct dvb_frontend_ops));
5375b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijie	ret = dvb_register_frontend(&pd_dvb->dvb_adap, &pd_dvb->dvb_fe);
5385b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijie	if (ret < 0)
5395b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijie		goto error2;
5405b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijie
5415b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijie	/* register demux device */
5425b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijie	dvbdemux = &pd_dvb->demux;
5435b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijie	dvbdemux->dmx.capabilities = DMX_TS_FILTERING | DMX_SECTION_FILTERING;
5445b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijie	dvbdemux->priv = pd_dvb;
5455b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijie	dvbdemux->feednum = dvbdemux->filternum = 64;
5465b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijie	dvbdemux->start_feed = pd_start_feed;
5475b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijie	dvbdemux->stop_feed = pd_stop_feed;
5485b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijie	dvbdemux->write_to_decoder = NULL;
5495b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijie
5505b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijie	ret = dvb_dmx_init(dvbdemux);
5515b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijie	if (ret < 0)
5525b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijie		goto error3;
5535b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijie
5545b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijie	pd_dvb->dmxdev.filternum = pd_dvb->demux.filternum;
5555b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijie	pd_dvb->dmxdev.demux = &pd_dvb->demux.dmx;
5565b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijie	pd_dvb->dmxdev.capabilities = 0;
5575b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijie
5585b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijie	ret = dvb_dmxdev_init(&pd_dvb->dmxdev, &pd_dvb->dvb_adap);
5595b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijie	if (ret < 0)
5605b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijie		goto error3;
5615b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijie	return 0;
5625b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijie
5635b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijieerror3:
5645b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijie	dvb_unregister_frontend(&pd_dvb->dvb_fe);
5655b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijieerror2:
5665b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijie	dvb_unregister_adapter(&pd_dvb->dvb_adap);
5675b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijieerror1:
5685b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijie	return ret;
5695b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijie}
5705b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijie
5715b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijievoid pd_dvb_usb_device_exit(struct poseidon *pd)
5725b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijie{
5735b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijie	struct pd_dvb_adapter *pd_dvb = &pd->dvb_data;
5745b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijie
5755b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijie	while (atomic_read(&pd_dvb->users) != 0
5765b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijie		|| atomic_read(&pd_dvb->active_feed) != 0) {
5775b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijie		set_current_state(TASK_INTERRUPTIBLE);
5785b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijie		schedule_timeout(HZ);
5795b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijie	}
5805b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijie	dvb_dmxdev_release(&pd_dvb->dmxdev);
5815b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijie	dvb_unregister_frontend(&pd_dvb->dvb_fe);
5825b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijie	dvb_unregister_adapter(&pd_dvb->dvb_adap);
5835b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijie	pd_dvb_usb_device_cleanup(pd);
5845b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijie}
5855b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijie
5865b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijievoid pd_dvb_usb_device_cleanup(struct poseidon *pd)
5875b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijie{
5885b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijie	struct pd_dvb_adapter *pd_dvb = &pd->dvb_data;
5895b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijie
5905b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijie	dvb_urb_cleanup(pd_dvb);
5915b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijie}
5925b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijie
5935b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijieint pd_dvb_get_adapter_num(struct pd_dvb_adapter *pd_dvb)
5945b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijie{
5955b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijie	return pd_dvb->dvb_adap.num;
5965b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89fHuang Shijie}
597