dvb_frontend.c
来自「V4l driver for DVB HD」· C语言 代码 · 共 1,104 行 · 第 1/3 页
C
1,104 行
} else { if (fe->ops->read_status) fe->ops->read_status(fe, &s); if (s != fepriv->status) { dvb_frontend_add_event(fe, s); fepriv->status = s; } } /* if we're not tuned, and we have a lock, move to the TUNED state */ if ((fepriv->state & FESTATE_WAITFORLOCK) && (s & FE_HAS_LOCK)) { dvb_frontend_swzigzag_update_delay(fepriv, s & FE_HAS_LOCK); fepriv->state = FESTATE_TUNED; /* if we're tuned, then we have determined the correct inversion */ if ((!(fe->ops->info.caps & FE_CAN_INVERSION_AUTO)) && (fepriv->parameters.inversion == INVERSION_AUTO)) { fepriv->parameters.inversion = fepriv->inversion; } return; } /* if we are tuned already, check we're still locked */ if (fepriv->state & FESTATE_TUNED) { dvb_frontend_swzigzag_update_delay(fepriv, s & FE_HAS_LOCK); /* we're tuned, and the lock is still good... */ if (s & FE_HAS_LOCK) { return; } else { /* if we _WERE_ tuned, but now don't have a lock */ fepriv->state = FESTATE_ZIGZAG_FAST; fepriv->started_auto_step = fepriv->auto_step; fepriv->check_wrapped = 0; } } /* don't actually do anything if we're in the LOSTLOCK state, * the frontend is set to FE_CAN_RECOVER, and the max_drift is 0 */ if ((fepriv->state & FESTATE_LOSTLOCK) && (fe->ops->info.caps & FE_CAN_RECOVER) && (fepriv->max_drift == 0)) { dvb_frontend_swzigzag_update_delay(fepriv, s & FE_HAS_LOCK); return; } /* don't do anything if we're in the DISEQC state, since this * might be someone with a motorized dish controlled by DISEQC. * If its actually a re-tune, there will be a SET_FRONTEND soon enough. */ if (fepriv->state & FESTATE_DISEQC) { dvb_frontend_swzigzag_update_delay(fepriv, s & FE_HAS_LOCK); return; } /* if we're in the RETUNE state, set everything up for a brand * new scan, keeping the current inversion setting, as the next * tune is _very_ likely to require the same */ if (fepriv->state & FESTATE_RETUNE) { fepriv->lnb_drift = 0; fepriv->auto_step = 0; fepriv->auto_sub_step = 0; fepriv->started_auto_step = 0; fepriv->check_wrapped = 0; } /* fast zigzag. */ if ((fepriv->state & FESTATE_SEARCHING_FAST) || (fepriv->state & FESTATE_RETUNE)) { fepriv->delay = fepriv->min_delay; /* peform a tune */ if (dvb_frontend_swzigzag_autotune(fe, fepriv->check_wrapped)) { /* OK, if we've run out of trials at the fast speed. * Drop back to slow for the _next_ attempt */ fepriv->state = FESTATE_SEARCHING_SLOW; fepriv->started_auto_step = fepriv->auto_step; return; } fepriv->check_wrapped = 1; /* if we've just retuned, enter the ZIGZAG_FAST state. * This ensures we cannot return from an * FE_SET_FRONTEND ioctl before the first frontend tune * occurs */ if (fepriv->state & FESTATE_RETUNE) { fepriv->state = FESTATE_TUNING_FAST; } } /* slow zigzag */ if (fepriv->state & FESTATE_SEARCHING_SLOW) { dvb_frontend_swzigzag_update_delay(fepriv, s & FE_HAS_LOCK); /* Note: don't bother checking for wrapping; we stay in this * state until we get a lock */ dvb_frontend_swzigzag_autotune(fe, 0); }}static int dvb_frontend_is_exiting(struct dvb_frontend *fe){ struct dvb_frontend_private *fepriv = fe->frontend_priv; if (fepriv->exit) return 1; if (fepriv->dvbdev->writers == 1) if (time_after(jiffies, fepriv->release_jiffies + dvb_shutdown_timeout * HZ)) return 1; return 0;}static int dvb_frontend_should_wakeup(struct dvb_frontend *fe){ struct dvb_frontend_private *fepriv = fe->frontend_priv; if (fepriv->wakeup) { fepriv->wakeup = 0; return 1; } return dvb_frontend_is_exiting(fe);}static void dvb_frontend_wakeup(struct dvb_frontend *fe){ struct dvb_frontend_private *fepriv = fe->frontend_priv; fepriv->wakeup = 1; wake_up_interruptible(&fepriv->wait_queue);}static int dvb_frontend_thread(void *data){ struct dvb_frontend *fe = data; struct dvb_frontend_private *fepriv = fe->frontend_priv; unsigned long timeout; char name [15]; fe_status_t s; struct dvb_frontend_parameters *params; dprintk("%s\n", __FUNCTION__); snprintf (name, sizeof(name), "kdvb-fe-%i", fe->dvb->num); lock_kernel(); daemonize(name); sigfillset(¤t->blocked); unlock_kernel(); fepriv->check_wrapped = 0; fepriv->quality = 0; fepriv->delay = 3*HZ; fepriv->status = 0; fepriv->wakeup = 0; fepriv->reinitialise = 1; while (1) { up(&fepriv->sem); /* is locked when we enter the thread... */ timeout = wait_event_interruptible_timeout(fepriv->wait_queue, dvb_frontend_should_wakeup(fe), fepriv->delay); if (0 != dvb_frontend_is_exiting(fe)) { /* got signal or quitting */ break; }#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,13) try_to_freeze();#else if (current->flags & PF_FREEZE) { refrigerator (PF_FREEZE); }#endif if (down_interruptible(&fepriv->sem)) break; if (fepriv->reinitialise) { dvb_frontend_init(fe); if (fepriv->tone != -1) { fe->ops->set_tone(fe, fepriv->tone); } if (fepriv->voltage != -1) { fe->ops->set_voltage(fe, fepriv->voltage); } fepriv->reinitialise = 0; } /* do an iteration of the tuning loop */ if (fe->ops->tune) { /* have we been asked to retune? */ params = NULL; if (fepriv->state & FESTATE_RETUNE) { params = &fepriv->parameters; fepriv->state = FESTATE_TUNED; } fe->ops->tune(fe, params, fepriv->tune_mode_flags, &fepriv->delay, &s); if (s != fepriv->status) { dvb_frontend_add_event(fe, s); fepriv->status = s; } } else { dvb_frontend_swzigzag(fe); } } if (dvb_shutdown_timeout) { if (dvb_powerdown_on_sleep) if (fe->ops->set_voltage) fe->ops->set_voltage(fe, SEC_VOLTAGE_OFF); if (fe->ops->sleep) fe->ops->sleep(fe); } fepriv->thread_pid = 0; mb(); dvb_frontend_wakeup(fe); return 0;}static void dvb_frontend_stop(struct dvb_frontend *fe){ unsigned long ret; struct dvb_frontend_private *fepriv = fe->frontend_priv; dprintk ("%s\n", __FUNCTION__); fepriv->exit = 1; mb(); if (!fepriv->thread_pid) return; /* check if the thread is really alive */ if (kill_proc(fepriv->thread_pid, 0, 1) == -ESRCH) { printk("dvb_frontend_stop: thread PID %d already died\n", fepriv->thread_pid); /* make sure the mutex was not held by the thread */ init_MUTEX (&fepriv->sem); return; } /* wake up the frontend thread, so it notices that fe->exit == 1 */ dvb_frontend_wakeup(fe); /* wait until the frontend thread has exited */ ret = wait_event_interruptible(fepriv->wait_queue,0 == fepriv->thread_pid); if (-ERESTARTSYS != ret) { fepriv->state = FESTATE_IDLE; return; } fepriv->state = FESTATE_IDLE; /* paranoia check in case a signal arrived */ if (fepriv->thread_pid) printk("dvb_frontend_stop: warning: thread PID %d won't exit\n", fepriv->thread_pid);}s32 timeval_usec_diff(struct timeval lasttime, struct timeval curtime){ return ((curtime.tv_usec < lasttime.tv_usec) ? 1000000 - lasttime.tv_usec + curtime.tv_usec : curtime.tv_usec - lasttime.tv_usec);}EXPORT_SYMBOL(timeval_usec_diff);static inline void timeval_usec_add(struct timeval *curtime, u32 add_usec){ curtime->tv_usec += add_usec; if (curtime->tv_usec >= 1000000) { curtime->tv_usec -= 1000000; curtime->tv_sec++; }}/* * Sleep until gettimeofday() > waketime + add_usec * This needs to be as precise as possible, but as the delay is * usually between 2ms and 32ms, it is done using a scheduled msleep * followed by usleep (normally a busy-wait loop) for the remainder */void dvb_frontend_sleep_until(struct timeval *waketime, u32 add_usec){ struct timeval lasttime; s32 delta, newdelta; timeval_usec_add(waketime, add_usec); do_gettimeofday(&lasttime); delta = timeval_usec_diff(lasttime, *waketime); if (delta > 2500) { msleep((delta - 1500) / 1000); do_gettimeofday(&lasttime); newdelta = timeval_usec_diff(lasttime, *waketime); delta = (newdelta > delta) ? 0 : newdelta; } if (delta > 0) udelay(delta);}EXPORT_SYMBOL(dvb_frontend_sleep_until);static int dvb_frontend_start(struct dvb_frontend *fe){ int ret; struct dvb_frontend_private *fepriv = fe->frontend_priv; dprintk ("%s\n", __FUNCTION__); if (fepriv->thread_pid) { if (!fepriv->exit) return 0; else dvb_frontend_stop (fe); } if (signal_pending(current)) return -EINTR; if (down_interruptible (&fepriv->sem)) return -EINTR; fepriv->state = FESTATE_IDLE; fepriv->exit = 0; fepriv->thread_pid = 0; mb(); ret = kernel_thread (dvb_frontend_thread, fe, 0); if (ret < 0) { printk("dvb_frontend_start: failed to start kernel_thread (%d)\n", ret); up(&fepriv->sem); return ret; } fepriv->thread_pid = ret; return 0;}static int dvb_frontend_ioctl(struct inode *inode, struct file *file, unsigned int cmd, void *parg){ struct dvb_device *dvbdev = file->private_data; struct dvb_frontend *fe = dvbdev->priv; struct dvb_frontend_private *fepriv = fe->frontend_priv; int err = -EOPNOTSUPP; dprintk ("%s\n", __FUNCTION__); if (!fe || fepriv->exit) return -ENODEV; if ((file->f_flags & O_ACCMODE) == O_RDONLY && (_IOC_DIR(cmd) != _IOC_READ || cmd == FE_GET_EVENT || cmd == FE_DISEQC_RECV_SLAVE_REPLY)) return -EPERM; if (down_interruptible (&fepriv->sem)) return -ERESTARTSYS; switch (cmd) { case FE_GET_INFO: { struct dvb_frontend_info* info = parg; memcpy(info, &fe->ops->info, sizeof(struct dvb_frontend_info)); /* Force the CAN_INVERSION_AUTO bit on. If the frontend doesn't * do it, it is done for it. */
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?