From aa6f5ffbdba45aa8e19e5048648fc6c7b25376d3 Mon Sep 17 00:00:00 2001 From: merge Date: Thu, 22 Jan 2009 13:55:32 +0000 Subject: MERGE-via-pending-tracking-hist-MERGE-via-stable-tracking-MERGE-via-mokopatches-tracking-fix-stray-endmenu-patch-1232632040-1232632141 pending-tracking-hist top was MERGE-via-stable-tracking-MERGE-via-mokopatches-tracking-fix-stray-endmenu-patch-1232632040-1232632141 / fdf777a63bcb59e0dfd78bfe2c6242e01f6d4eb9 ... parent commitmessage: From: merge MERGE-via-stable-tracking-hist-MERGE-via-mokopatches-tracking-fix-stray-endmenu-patch-1232632040 stable-tracking-hist top was MERGE-via-mokopatches-tracking-fix-stray-endmenu-patch-1232632040 / 90463bfd2d5a3c8b52f6e6d71024a00e052b0ced ... parent commitmessage: From: merge MERGE-via-mokopatches-tracking-hist-fix-stray-endmenu-patch mokopatches-tracking-hist top was fix-stray-endmenu-patch / 3630e0be570de8057e7f8d2fe501ed353cdf34e6 ... parent commitmessage: From: Andy Green fix-stray-endmenu.patch Signed-off-by: Andy Green --- drivers/media/dvb/dvb-core/dvb_frontend.c | 110 +++++++++++++++++++----- drivers/media/dvb/dvb-core/dvb_frontend.h | 134 +++++++++++++++++++++++++++++- drivers/media/dvb/dvb-core/dvb_net.c | 82 +++++++++--------- drivers/media/dvb/dvb-core/dvbdev.c | 77 ++++++++++++----- drivers/media/dvb/dvb-core/dvbdev.h | 1 + 5 files changed, 322 insertions(+), 82 deletions(-) (limited to 'drivers/media/dvb/dvb-core') diff --git a/drivers/media/dvb/dvb-core/dvb_frontend.c b/drivers/media/dvb/dvb-core/dvb_frontend.c index 5689d1f1d44..84340778508 100644 --- a/drivers/media/dvb/dvb-core/dvb_frontend.c +++ b/drivers/media/dvb/dvb-core/dvb_frontend.c @@ -128,6 +128,7 @@ struct dvb_frontend_private { unsigned int step_size; int quality; unsigned int check_wrapped; + enum dvbfe_search algo_status; }; static void dvb_frontend_wakeup(struct dvb_frontend *fe); @@ -223,6 +224,8 @@ static void dvb_frontend_init(struct dvb_frontend *fe) if (fe->ops.init) fe->ops.init(fe); if (fe->ops.tuner_ops.init) { + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 1); fe->ops.tuner_ops.init(fe); if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0); @@ -514,6 +517,8 @@ static int dvb_frontend_thread(void *data) struct dvb_frontend_private *fepriv = fe->frontend_priv; unsigned long timeout; fe_status_t s; + enum dvbfe_algo algo; + struct dvb_frontend_parameters *params; dprintk("%s\n", __func__); @@ -560,29 +565,88 @@ restart: /* do an iteration of the tuning loop */ if (fe->ops.get_frontend_algo) { - if (fe->ops.get_frontend_algo(fe) == FE_ALGO_HW) { - /* have we been asked to retune? */ - params = NULL; + algo = fe->ops.get_frontend_algo(fe); + switch (algo) { + case DVBFE_ALGO_HW: + dprintk("%s: Frontend ALGO = DVBFE_ALGO_HW\n", __func__); + params = NULL; /* have we been asked to RETUNE ? */ + if (fepriv->state & FESTATE_RETUNE) { + dprintk("%s: Retune requested, FESTATE_RETUNE\n", __func__); params = &fepriv->parameters; fepriv->state = FESTATE_TUNED; } - fe->ops.tune(fe, params, fepriv->tune_mode_flags, &fepriv->delay, &s); - if (s != fepriv->status) { + if (fe->ops.tune) + fe->ops.tune(fe, params, fepriv->tune_mode_flags, &fepriv->delay, &s); + + if (s != fepriv->status && !(fepriv->tune_mode_flags & FE_TUNE_MODE_ONESHOT)) { + dprintk("%s: state changed, adding current state\n", __func__); dvb_frontend_add_event(fe, s); fepriv->status = s; } - } else + break; + case DVBFE_ALGO_SW: + dprintk("%s: Frontend ALGO = DVBFE_ALGO_SW\n", __func__); dvb_frontend_swzigzag(fe); - } else + break; + case DVBFE_ALGO_CUSTOM: + params = NULL; /* have we been asked to RETUNE ? */ + dprintk("%s: Frontend ALGO = DVBFE_ALGO_CUSTOM, state=%d\n", __func__, fepriv->state); + if (fepriv->state & FESTATE_RETUNE) { + dprintk("%s: Retune requested, FESTAT_RETUNE\n", __func__); + params = &fepriv->parameters; + fepriv->state = FESTATE_TUNED; + } + /* Case where we are going to search for a carrier + * User asked us to retune again for some reason, possibly + * requesting a search with a new set of parameters + */ + if (fepriv->algo_status & DVBFE_ALGO_SEARCH_AGAIN) { + if (fe->ops.search) { + fepriv->algo_status = fe->ops.search(fe, &fepriv->parameters); + /* We did do a search as was requested, the flags are + * now unset as well and has the flags wrt to search. + */ + } else { + fepriv->algo_status &= ~DVBFE_ALGO_SEARCH_AGAIN; + } + } + /* Track the carrier if the search was successful */ + if (fepriv->algo_status == DVBFE_ALGO_SEARCH_SUCCESS) { + if (fe->ops.track) + fe->ops.track(fe, &fepriv->parameters); + } else { + fepriv->algo_status |= DVBFE_ALGO_SEARCH_AGAIN; + fepriv->delay = HZ / 2; + } + fe->ops.read_status(fe, &s); + if (s != fepriv->status) { + dvb_frontend_add_event(fe, s); /* update event list */ + fepriv->status = s; + if (!(s & FE_HAS_LOCK)) { + fepriv->delay = HZ / 10; + fepriv->algo_status |= DVBFE_ALGO_SEARCH_AGAIN; + } else { + fepriv->delay = 60 * HZ; + } + } + break; + default: + dprintk("%s: UNDEFINED ALGO !\n", __func__); + break; + } + } else { dvb_frontend_swzigzag(fe); + } } if (dvb_powerdown_on_sleep) { if (fe->ops.set_voltage) fe->ops.set_voltage(fe, SEC_VOLTAGE_OFF); if (fe->ops.tuner_ops.sleep) { + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 1); fe->ops.tuner_ops.sleep(fe); if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0); @@ -760,7 +824,7 @@ static int dvb_frontend_check_parameters(struct dvb_frontend *fe, return 0; } -struct dtv_cmds_h dtv_cmds[] = { +static struct dtv_cmds_h dtv_cmds[] = { [DTV_TUNE] = { .name = "DTV_TUNE", .cmd = DTV_TUNE, @@ -898,7 +962,7 @@ struct dtv_cmds_h dtv_cmds[] = { }, }; -void dtv_property_dump(struct dtv_property *tvp) +static void dtv_property_dump(struct dtv_property *tvp) { int i; @@ -929,10 +993,11 @@ void dtv_property_dump(struct dtv_property *tvp) dprintk("%s() tvp.u.data = 0x%08x\n", __func__, tvp->u.data); } -int is_legacy_delivery_system(fe_delivery_system_t s) +static int is_legacy_delivery_system(fe_delivery_system_t s) { if((s == SYS_UNDEFINED) || (s == SYS_DVBC_ANNEX_AC) || - (s == SYS_DVBC_ANNEX_B) || (s == SYS_DVBT) || (s == SYS_DVBS)) + (s == SYS_DVBC_ANNEX_B) || (s == SYS_DVBT) || (s == SYS_DVBS) || + (s == SYS_ATSC)) return 1; return 0; @@ -942,7 +1007,8 @@ int is_legacy_delivery_system(fe_delivery_system_t s) * drivers can use a single set_frontend tuning function, regardless of whether * it's being used for the legacy or new API, reducing code and complexity. */ -void dtv_property_cache_sync(struct dvb_frontend *fe, struct dvb_frontend_parameters *p) +static void dtv_property_cache_sync(struct dvb_frontend *fe, + struct dvb_frontend_parameters *p) { struct dtv_frontend_properties *c = &fe->dtv_property_cache; @@ -994,7 +1060,7 @@ void dtv_property_cache_sync(struct dvb_frontend *fe, struct dvb_frontend_parame /* Ensure the cached values are set correctly in the frontend * legacy tuning structures, for the advanced tuning API. */ -void dtv_property_legacy_params_sync(struct dvb_frontend *fe) +static void dtv_property_legacy_params_sync(struct dvb_frontend *fe) { struct dtv_frontend_properties *c = &fe->dtv_property_cache; struct dvb_frontend_private *fepriv = fe->frontend_priv; @@ -1049,7 +1115,7 @@ void dtv_property_legacy_params_sync(struct dvb_frontend *fe) /* Ensure the cached values are set correctly in the frontend * legacy tuning structures, for the legacy tuning API. */ -void dtv_property_adv_params_sync(struct dvb_frontend *fe) +static void dtv_property_adv_params_sync(struct dvb_frontend *fe) { struct dtv_frontend_properties *c = &fe->dtv_property_cache; struct dvb_frontend_private *fepriv = fe->frontend_priv; @@ -1084,7 +1150,7 @@ void dtv_property_adv_params_sync(struct dvb_frontend *fe) } } -void dtv_property_cache_submit(struct dvb_frontend *fe) +static void dtv_property_cache_submit(struct dvb_frontend *fe) { struct dtv_frontend_properties *c = &fe->dtv_property_cache; @@ -1115,8 +1181,9 @@ static int dvb_frontend_ioctl_legacy(struct inode *inode, struct file *file, static int dvb_frontend_ioctl_properties(struct inode *inode, struct file *file, unsigned int cmd, void *parg); -int dtv_property_process_get(struct dvb_frontend *fe, struct dtv_property *tvp, - struct inode *inode, struct file *file) +static int dtv_property_process_get(struct dvb_frontend *fe, + struct dtv_property *tvp, + struct inode *inode, struct file *file) { int r = 0; @@ -1188,8 +1255,10 @@ int dtv_property_process_get(struct dvb_frontend *fe, struct dtv_property *tvp, return r; } -int dtv_property_process_set(struct dvb_frontend *fe, struct dtv_property *tvp, - struct inode *inode, struct file *file) +static int dtv_property_process_set(struct dvb_frontend *fe, + struct dtv_property *tvp, + struct inode *inode, + struct file *file) { int r = 0; struct dvb_frontend_private *fepriv = fe->frontend_priv; @@ -1221,6 +1290,9 @@ int dtv_property_process_set(struct dvb_frontend *fe, struct dtv_property *tvp, dprintk("%s() Finalised property cache\n", __func__); dtv_property_cache_submit(fe); + /* Request the search algorithm to search */ + fepriv->algo_status |= DVBFE_ALGO_SEARCH_AGAIN; + r |= dvb_frontend_ioctl_legacy(inode, file, FE_SET_FRONTEND, &fepriv->parameters); break; diff --git a/drivers/media/dvb/dvb-core/dvb_frontend.h b/drivers/media/dvb/dvb-core/dvb_frontend.h index db4a63b0a32..e176da472d7 100644 --- a/drivers/media/dvb/dvb-core/dvb_frontend.h +++ b/drivers/media/dvb/dvb-core/dvb_frontend.h @@ -69,6 +69,125 @@ struct analog_parameters { u64 std; }; +enum dvbfe_modcod { + DVBFE_MODCOD_DUMMY_PLFRAME = 0, + DVBFE_MODCOD_QPSK_1_4, + DVBFE_MODCOD_QPSK_1_3, + DVBFE_MODCOD_QPSK_2_5, + DVBFE_MODCOD_QPSK_1_2, + DVBFE_MODCOD_QPSK_3_5, + DVBFE_MODCOD_QPSK_2_3, + DVBFE_MODCOD_QPSK_3_4, + DVBFE_MODCOD_QPSK_4_5, + DVBFE_MODCOD_QPSK_5_6, + DVBFE_MODCOD_QPSK_8_9, + DVBFE_MODCOD_QPSK_9_10, + DVBFE_MODCOD_8PSK_3_5, + DVBFE_MODCOD_8PSK_2_3, + DVBFE_MODCOD_8PSK_3_4, + DVBFE_MODCOD_8PSK_5_6, + DVBFE_MODCOD_8PSK_8_9, + DVBFE_MODCOD_8PSK_9_10, + DVBFE_MODCOD_16APSK_2_3, + DVBFE_MODCOD_16APSK_3_4, + DVBFE_MODCOD_16APSK_4_5, + DVBFE_MODCOD_16APSK_5_6, + DVBFE_MODCOD_16APSK_8_9, + DVBFE_MODCOD_16APSK_9_10, + DVBFE_MODCOD_32APSK_3_4, + DVBFE_MODCOD_32APSK_4_5, + DVBFE_MODCOD_32APSK_5_6, + DVBFE_MODCOD_32APSK_8_9, + DVBFE_MODCOD_32APSK_9_10, + DVBFE_MODCOD_RESERVED_1, + DVBFE_MODCOD_BPSK_1_3, + DVBFE_MODCOD_BPSK_1_4, + DVBFE_MODCOD_RESERVED_2 +}; + +enum tuner_param { + DVBFE_TUNER_FREQUENCY = (1 << 0), + DVBFE_TUNER_TUNERSTEP = (1 << 1), + DVBFE_TUNER_IFFREQ = (1 << 2), + DVBFE_TUNER_BANDWIDTH = (1 << 3), + DVBFE_TUNER_REFCLOCK = (1 << 4), + DVBFE_TUNER_IQSENSE = (1 << 5), + DVBFE_TUNER_DUMMY = (1 << 31) +}; + +/* + * ALGO_HW: (Hardware Algorithm) + * ---------------------------------------------------------------- + * Devices that support this algorithm do everything in hardware + * and no software support is needed to handle them. + * Requesting these devices to LOCK is the only thing required, + * device is supposed to do everything in the hardware. + * + * ALGO_SW: (Software Algorithm) + * ---------------------------------------------------------------- + * These are dumb devices, that require software to do everything + * + * ALGO_CUSTOM: (Customizable Agorithm) + * ---------------------------------------------------------------- + * Devices having this algorithm can be customized to have specific + * algorithms in the frontend driver, rather than simply doing a + * software zig-zag. In this case the zigzag maybe hardware assisted + * or it maybe completely done in hardware. In all cases, usage of + * this algorithm, in conjunction with the search and track + * callbacks, utilizes the driver specific algorithm. + * + * ALGO_RECOVERY: (Recovery Algorithm) + * ---------------------------------------------------------------- + * These devices have AUTO recovery capabilities from LOCK failure + */ +enum dvbfe_algo { + DVBFE_ALGO_HW = (1 << 0), + DVBFE_ALGO_SW = (1 << 1), + DVBFE_ALGO_CUSTOM = (1 << 2), + DVBFE_ALGO_RECOVERY = (1 << 31) +}; + +struct tuner_state { + u32 frequency; + u32 tunerstep; + u32 ifreq; + u32 bandwidth; + u32 iqsense; + u32 refclock; +}; + +/* + * search callback possible return status + * + * DVBFE_ALGO_SEARCH_SUCCESS + * The frontend search algorithm completed and returned succesfully + * + * DVBFE_ALGO_SEARCH_ASLEEP + * The frontend search algorithm is sleeping + * + * DVBFE_ALGO_SEARCH_FAILED + * The frontend search for a signal failed + * + * DVBFE_ALGO_SEARCH_INVALID + * The frontend search algorith was probably supplied with invalid + * parameters and the search is an invalid one + * + * DVBFE_ALGO_SEARCH_ERROR + * The frontend search algorithm failed due to some error + * + * DVBFE_ALGO_SEARCH_AGAIN + * The frontend search algorithm was requested to search again + */ +enum dvbfe_search { + DVBFE_ALGO_SEARCH_SUCCESS = (1 << 0), + DVBFE_ALGO_SEARCH_ASLEEP = (1 << 1), + DVBFE_ALGO_SEARCH_FAILED = (1 << 2), + DVBFE_ALGO_SEARCH_INVALID = (1 << 3), + DVBFE_ALGO_SEARCH_AGAIN = (1 << 4), + DVBFE_ALGO_SEARCH_ERROR = (1 << 31), +}; + + struct dvb_tuner_ops { struct dvb_tuner_info info; @@ -99,6 +218,13 @@ struct dvb_tuner_ops { * tuners which require sophisticated tuning loops, controlling each parameter seperately. */ int (*set_frequency)(struct dvb_frontend *fe, u32 frequency); int (*set_bandwidth)(struct dvb_frontend *fe, u32 bandwidth); + + /* + * These are provided seperately from set_params in order to facilitate silicon + * tuners which require sophisticated tuning loops, controlling each parameter seperately. + */ + int (*set_state)(struct dvb_frontend *fe, enum tuner_param param, struct tuner_state *state); + int (*get_state)(struct dvb_frontend *fe, enum tuner_param param, struct tuner_state *state); }; struct analog_demod_info { @@ -142,7 +268,7 @@ struct dvb_frontend_ops { unsigned int *delay, fe_status_t *status); /* get frontend tuning algorithm from the module */ - int (*get_frontend_algo)(struct dvb_frontend *fe); + enum dvbfe_algo (*get_frontend_algo)(struct dvb_frontend *fe); /* these two are only used for the swzigzag code */ int (*set_frontend)(struct dvb_frontend* fe, struct dvb_frontend_parameters* params); @@ -167,6 +293,12 @@ struct dvb_frontend_ops { int (*i2c_gate_ctrl)(struct dvb_frontend* fe, int enable); int (*ts_bus_ctrl)(struct dvb_frontend* fe, int acquire); + /* These callbacks are for devices that implement their own + * tuning algorithms, rather than a simple swzigzag + */ + enum dvbfe_search (*search)(struct dvb_frontend *fe, struct dvb_frontend_parameters *p); + int (*track)(struct dvb_frontend *fe, struct dvb_frontend_parameters *p); + struct dvb_tuner_ops tuner_ops; struct analog_demod_ops analog_ops; diff --git a/drivers/media/dvb/dvb-core/dvb_net.c b/drivers/media/dvb/dvb-core/dvb_net.c index c93019ca519..f6ba8468858 100644 --- a/drivers/media/dvb/dvb-core/dvb_net.c +++ b/drivers/media/dvb/dvb-core/dvb_net.c @@ -125,7 +125,6 @@ static void hexdump( const unsigned char *buf, unsigned short len ) struct dvb_net_priv { int in_use; - struct net_device_stats stats; u16 pid; struct net_device *net; struct dvb_net *host; @@ -345,7 +344,7 @@ static inline void reset_ule( struct dvb_net_priv *p ) */ static void dvb_net_ule( struct net_device *dev, const u8 *buf, size_t buf_len ) { - struct dvb_net_priv *priv = dev->priv; + struct dvb_net_priv *priv = netdev_priv(dev); unsigned long skipped = 0L; const u8 *ts, *ts_end, *from_where = NULL; u8 ts_remain = 0, how_much = 0, new_ts = 1; @@ -384,8 +383,8 @@ static void dvb_net_ule( struct net_device *dev, const u8 *buf, size_t buf_len ) if (priv->ule_skb) { dev_kfree_skb( priv->ule_skb ); /* Prepare for next SNDU. */ - priv->stats.rx_errors++; - priv->stats.rx_frame_errors++; + dev->stats.rx_errors++; + dev->stats.rx_frame_errors++; } reset_ule(priv); priv->need_pusi = 1; @@ -438,8 +437,8 @@ static void dvb_net_ule( struct net_device *dev, const u8 *buf, size_t buf_len ) dev_kfree_skb( priv->ule_skb ); /* Prepare for next SNDU. */ // reset_ule(priv); moved to below. - priv->stats.rx_errors++; - priv->stats.rx_frame_errors++; + dev->stats.rx_errors++; + dev->stats.rx_frame_errors++; } reset_ule(priv); /* skip to next PUSI. */ @@ -460,8 +459,8 @@ static void dvb_net_ule( struct net_device *dev, const u8 *buf, size_t buf_len ) /* Drop partly decoded SNDU, reset state, resync on PUSI. */ if (priv->ule_skb) { dev_kfree_skb( priv->ule_skb ); - ((struct dvb_net_priv *) dev->priv)->stats.rx_errors++; - ((struct dvb_net_priv *) dev->priv)->stats.rx_frame_errors++; + dev->stats.rx_errors++; + dev->stats.rx_frame_errors++; } reset_ule(priv); priv->need_pusi = 1; @@ -477,8 +476,8 @@ static void dvb_net_ule( struct net_device *dev, const u8 *buf, size_t buf_len ) if (priv->ule_sndu_remain > 183) { /* Current SNDU lacks more data than there could be available in the * current TS cell. */ - priv->stats.rx_errors++; - priv->stats.rx_length_errors++; + dev->stats.rx_errors++; + dev->stats.rx_length_errors++; printk(KERN_WARNING "%lu: Expected %d more SNDU bytes, but " "got PUSI (pf %d, ts_remain %d). Flushing incomplete payload.\n", priv->ts_count, priv->ule_sndu_remain, ts[4], ts_remain); @@ -520,8 +519,8 @@ static void dvb_net_ule( struct net_device *dev, const u8 *buf, size_t buf_len ) if (priv->ule_sndu_len < 5) { printk(KERN_WARNING "%lu: Invalid ULE SNDU length %u. " "Resyncing.\n", priv->ts_count, priv->ule_sndu_len); - priv->stats.rx_errors++; - priv->stats.rx_length_errors++; + dev->stats.rx_errors++; + dev->stats.rx_length_errors++; priv->ule_sndu_len = 0; priv->need_pusi = 1; new_ts = 1; @@ -573,7 +572,7 @@ static void dvb_net_ule( struct net_device *dev, const u8 *buf, size_t buf_len ) if (priv->ule_skb == NULL) { printk(KERN_NOTICE "%s: Memory squeeze, dropping packet.\n", dev->name); - ((struct dvb_net_priv *)dev->priv)->stats.rx_dropped++; + dev->stats.rx_dropped++; return; } @@ -637,8 +636,8 @@ static void dvb_net_ule( struct net_device *dev, const u8 *buf, size_t buf_len ) ule_dump = 1; #endif - priv->stats.rx_errors++; - priv->stats.rx_crc_errors++; + dev->stats.rx_errors++; + dev->stats.rx_crc_errors++; dev_kfree_skb(priv->ule_skb); } else { /* CRC32 verified OK. */ @@ -744,8 +743,8 @@ static void dvb_net_ule( struct net_device *dev, const u8 *buf, size_t buf_len ) * receive the packet anyhow. */ /* if (priv->ule_dbit && skb->pkt_type == PACKET_OTHERHOST) priv->ule_skb->pkt_type = PACKET_HOST; */ - priv->stats.rx_packets++; - priv->stats.rx_bytes += priv->ule_skb->len; + dev->stats.rx_packets++; + dev->stats.rx_bytes += priv->ule_skb->len; netif_rx(priv->ule_skb); } sndu_done: @@ -800,7 +799,7 @@ static void dvb_net_sec(struct net_device *dev, { u8 *eth; struct sk_buff *skb; - struct net_device_stats *stats = &(((struct dvb_net_priv *) dev->priv)->stats); + struct net_device_stats *stats = &dev->stats; int snap = 0; /* note: pkt_len includes a 32bit checksum */ @@ -917,7 +916,7 @@ static int dvb_net_filter_sec_set(struct net_device *dev, struct dmx_section_filter **secfilter, u8 *mac, u8 *mac_mask) { - struct dvb_net_priv *priv = dev->priv; + struct dvb_net_priv *priv = netdev_priv(dev); int ret; *secfilter=NULL; @@ -961,7 +960,7 @@ static int dvb_net_filter_sec_set(struct net_device *dev, static int dvb_net_feed_start(struct net_device *dev) { int ret = 0, i; - struct dvb_net_priv *priv = dev->priv; + struct dvb_net_priv *priv = netdev_priv(dev); struct dmx_demux *demux = priv->demux; unsigned char *mac = (unsigned char *) dev->dev_addr; @@ -1060,7 +1059,7 @@ error: static int dvb_net_feed_stop(struct net_device *dev) { - struct dvb_net_priv *priv = dev->priv; + struct dvb_net_priv *priv = netdev_priv(dev); int i, ret = 0; dprintk("%s\n", __func__); @@ -1113,7 +1112,7 @@ static int dvb_net_feed_stop(struct net_device *dev) static int dvb_set_mc_filter (struct net_device *dev, struct dev_mc_list *mc) { - struct dvb_net_priv *priv = dev->priv; + struct dvb_net_priv *priv = netdev_priv(dev); if (priv->multi_num == DVB_NET_MULTICAST_MAX) return -ENOMEM; @@ -1165,7 +1164,7 @@ static void wq_set_multicast_list (struct work_struct *work) static void dvb_net_set_multicast_list (struct net_device *dev) { - struct dvb_net_priv *priv = dev->priv; + struct dvb_net_priv *priv = netdev_priv(dev); schedule_work(&priv->set_multicast_list_wq); } @@ -1185,7 +1184,7 @@ static void wq_restart_net_feed (struct work_struct *work) static int dvb_net_set_mac (struct net_device *dev, void *p) { - struct dvb_net_priv *priv = dev->priv; + struct dvb_net_priv *priv = netdev_priv(dev); struct sockaddr *addr=p; memcpy(dev->dev_addr, addr->sa_data, dev->addr_len); @@ -1199,7 +1198,7 @@ static int dvb_net_set_mac (struct net_device *dev, void *p) static int dvb_net_open(struct net_device *dev) { - struct dvb_net_priv *priv = dev->priv; + struct dvb_net_priv *priv = netdev_priv(dev); priv->in_use++; dvb_net_feed_start(dev); @@ -1209,34 +1208,35 @@ static int dvb_net_open(struct net_device *dev) static int dvb_net_stop(struct net_device *dev) { - struct dvb_net_priv *priv = dev->priv; + struct dvb_net_priv *priv = netdev_priv(dev); priv->in_use--; return dvb_net_feed_stop(dev); } -static struct net_device_stats * dvb_net_get_stats(struct net_device *dev) -{ - return &((struct dvb_net_priv*) dev->priv)->stats; -} - static const struct header_ops dvb_header_ops = { .create = eth_header, .parse = eth_header_parse, .rebuild = eth_rebuild_header, }; + +static const struct net_device_ops dvb_netdev_ops = { + .ndo_open = dvb_net_open, + .ndo_stop = dvb_net_stop, + .ndo_start_xmit = dvb_net_tx, + .ndo_set_multicast_list = dvb_net_set_multicast_list, + .ndo_set_mac_address = dvb_net_set_mac, + .ndo_change_mtu = eth_change_mtu, + .ndo_validate_addr = eth_validate_addr, +}; + static void dvb_net_setup(struct net_device *dev) { ether_setup(dev); dev->header_ops = &dvb_header_ops; - dev->open = dvb_net_open; - dev->stop = dvb_net_stop; - dev->hard_start_xmit = dvb_net_tx; - dev->get_stats = dvb_net_get_stats; - dev->set_multicast_list = dvb_net_set_multicast_list; - dev->set_mac_address = dvb_net_set_mac; + dev->netdev_ops = &dvb_netdev_ops; dev->mtu = 4096; dev->mc_count = 0; @@ -1287,7 +1287,7 @@ static int dvb_net_add_if(struct dvb_net *dvbnet, u16 pid, u8 feedtype) dvbnet->device[if_num] = net; - priv = net->priv; + priv = netdev_priv(net); priv->net = net; priv->demux = dvbnet->demux; priv->pid = pid; @@ -1320,7 +1320,7 @@ static int dvb_net_remove_if(struct dvb_net *dvbnet, unsigned long num) if (!dvbnet->state[num]) return -EINVAL; - priv = net->priv; + priv = netdev_priv(net); if (priv->in_use) return -EBUSY; @@ -1376,7 +1376,7 @@ static int dvb_net_do_ioctl(struct inode *inode, struct file *file, netdev = dvbnet->device[dvbnetif->if_num]; - priv_data = netdev->priv; + priv_data = netdev_priv(netdev); dvbnetif->pid=priv_data->pid; dvbnetif->feedtype=priv_data->feedtype; break; @@ -1427,7 +1427,7 @@ static int dvb_net_do_ioctl(struct inode *inode, struct file *file, netdev = dvbnet->device[dvbnetif->if_num]; - priv_data = netdev->priv; + priv_data = netdev_priv(netdev); dvbnetif->pid=priv_data->pid; break; } diff --git a/drivers/media/dvb/dvb-core/dvbdev.c b/drivers/media/dvb/dvb-core/dvbdev.c index a113744a56c..6a32680dbb1 100644 --- a/drivers/media/dvb/dvb-core/dvbdev.c +++ b/drivers/media/dvb/dvb-core/dvbdev.c @@ -50,33 +50,27 @@ static const char * const dnames[] = { "net", "osd" }; +#ifdef CONFIG_DVB_DYNAMIC_MINORS +#define MAX_DVB_MINORS 256 +#define DVB_MAX_IDS MAX_DVB_MINORS +#else #define DVB_MAX_IDS 4 #define nums2minor(num,type,id) ((num << 6) | (id << 4) | type) #define MAX_DVB_MINORS (DVB_MAX_ADAPTERS*64) +#endif static struct class *dvb_class; -static struct dvb_device* dvbdev_find_device (int minor) -{ - struct dvb_adapter *adap; - - list_for_each_entry(adap, &dvb_adapter_list, list_head) { - struct dvb_device *dev; - list_for_each_entry(dev, &adap->device_list, list_head) - if (nums2minor(adap->num, dev->type, dev->id) == minor) - return dev; - } - - return NULL; -} - +static struct dvb_device *dvb_minors[MAX_DVB_MINORS]; +static DECLARE_RWSEM(minor_rwsem); static int dvb_device_open(struct inode *inode, struct file *file) { struct dvb_device *dvbdev; lock_kernel(); - dvbdev = dvbdev_find_device (iminor(inode)); + down_read(&minor_rwsem); + dvbdev = dvb_minors[iminor(inode)]; if (dvbdev && dvbdev->fops) { int err = 0; @@ -85,6 +79,10 @@ static int dvb_device_open(struct inode *inode, struct file *file) file->private_data = dvbdev; old_fops = file->f_op; file->f_op = fops_get(dvbdev->fops); + if (file->f_op == NULL) { + file->f_op = old_fops; + goto fail; + } if(file->f_op->open) err = file->f_op->open(inode,file); if (err) { @@ -92,9 +90,12 @@ static int dvb_device_open(struct inode *inode, struct file *file) file->f_op = fops_get(old_fops); } fops_put(old_fops); + up_read(&minor_rwsem); unlock_kernel(); return err; } +fail: + up_read(&minor_rwsem); unlock_kernel(); return -ENODEV; } @@ -192,6 +193,7 @@ int dvb_register_device(struct dvb_adapter *adap, struct dvb_device **pdvbdev, struct dvb_device *dvbdev; struct file_operations *dvbdevfops; struct device *clsdev; + int minor; int id; mutex_lock(&dvbdev_register_lock); @@ -231,11 +233,31 @@ int dvb_register_device(struct dvb_adapter *adap, struct dvb_device **pdvbdev, list_add_tail (&dvbdev->list_head, &adap->device_list); + down_write(&minor_rwsem); +#ifdef CONFIG_DVB_DYNAMIC_MINORS + for (minor = 0; minor < MAX_DVB_MINORS; minor++) + if (dvb_minors[minor] == NULL) + break; + + if (minor == MAX_DVB_MINORS) { + kfree(dvbdevfops); + kfree(dvbdev); + mutex_unlock(&dvbdev_register_lock); + return -EINVAL; + } +#else + minor = nums2minor(adap->num, type, id); +#endif + + dvbdev->minor = minor; + dvb_minors[minor] = dvbdev; + up_write(&minor_rwsem); + mutex_unlock(&dvbdev_register_lock); clsdev = device_create(dvb_class, adap->device, - MKDEV(DVB_MAJOR, nums2minor(adap->num, type, id)), - NULL, "dvb%d.%s%d", adap->num, dnames[type], id); + MKDEV(DVB_MAJOR, minor), + dvbdev, "dvb%d.%s%d", adap->num, dnames[type], id); if (IS_ERR(clsdev)) { printk(KERN_ERR "%s: failed to create device dvb%d.%s%d (%ld)\n", __func__, adap->num, dnames[type], id, PTR_ERR(clsdev)); @@ -243,8 +265,7 @@ int dvb_register_device(struct dvb_adapter *adap, struct dvb_device **pdvbdev, } dprintk(KERN_DEBUG "DVB: register adapter%d/%s%d @ minor: %i (0x%02x)\n", - adap->num, dnames[type], id, nums2minor(adap->num, type, id), - nums2minor(adap->num, type, id)); + adap->num, dnames[type], id, minor, minor); return 0; } @@ -256,8 +277,11 @@ void dvb_unregister_device(struct dvb_device *dvbdev) if (!dvbdev) return; - device_destroy(dvb_class, MKDEV(DVB_MAJOR, nums2minor(dvbdev->adapter->num, - dvbdev->type, dvbdev->id))); + down_write(&minor_rwsem); + dvb_minors[dvbdev->minor] = NULL; + up_write(&minor_rwsem); + + device_destroy(dvb_class, MKDEV(DVB_MAJOR, dvbdev->minor)); list_del (&dvbdev->list_head); kfree (dvbdev->fops); @@ -413,6 +437,16 @@ out: return err; } +static int dvb_uevent(struct device *dev, struct kobj_uevent_env *env) +{ + struct dvb_device *dvbdev = dev_get_drvdata(dev); + + add_uevent_var(env, "DVB_ADAPTER_NUM=%d", dvbdev->adapter->num); + add_uevent_var(env, "DVB_DEVICE_TYPE=%s", dnames[dvbdev->type]); + add_uevent_var(env, "DVB_DEVICE_NUM=%d", dvbdev->id); + return 0; +} + static int __init init_dvbdev(void) { int retval; @@ -434,6 +468,7 @@ static int __init init_dvbdev(void) retval = PTR_ERR(dvb_class); goto error; } + dvb_class->dev_uevent = dvb_uevent; return 0; error: diff --git a/drivers/media/dvb/dvb-core/dvbdev.h b/drivers/media/dvb/dvb-core/dvbdev.h index 574e336bac3..dca49cf962e 100644 --- a/drivers/media/dvb/dvb-core/dvbdev.h +++ b/drivers/media/dvb/dvb-core/dvbdev.h @@ -74,6 +74,7 @@ struct dvb_device { struct file_operations *fops; struct dvb_adapter *adapter; int type; + int minor; u32 id; /* in theory, 'users' can vanish now, -- cgit v1.2.3