dvb_frontend.c
来自「Linux Kernel 2.6.9 for OMAP1710」· C语言 代码 · 共 1,190 行 · 第 1/3 页
C
1,190 行
fe->inversion = (fe->inversion == INVERSION_OFF) ? INVERSION_ON : INVERSION_OFF; ready = 1; break; case 2: if (fe->lnb_drift == 0) break; fe->lnb_drift = -fe->lnb_drift; ready = 1; break; case 3: if (fe->lnb_drift == 0) break; if (!autoinversion) break; fe->inversion = (fe->inversion == INVERSION_OFF) ? INVERSION_ON : INVERSION_OFF; fe->lnb_drift = -fe->lnb_drift; ready = 1; break; default: fe->auto_step++; fe->auto_sub_step = -1; // it'll be incremented to 0 in a moment break; } if (!ready) fe->auto_sub_step++; } // if this attempt would hit where we started, indicate a complete iteration has occurred if ((fe->auto_step == fe->started_auto_step) && (fe->auto_sub_step == 0) && check_wrapped) { return 1; } // perform frequency bending if necessary if ((dvb_override_frequency_bending != 1) && do_frequency_bending) dvb_bend_frequency(fe, 0); // instrumentation dprintk("%s: drift:%i bending:%i inversion:%i auto_step:%i auto_sub_step:%i started_auto_step:%i\n", __FUNCTION__, fe->lnb_drift, fe->bending, fe->inversion, fe->auto_step, fe->auto_sub_step, fe->started_auto_step); // set the frontend itself fe->parameters.frequency += fe->lnb_drift + fe->bending; if (autoinversion) fe->parameters.inversion = fe->inversion; dvb_frontend_internal_ioctl (&fe->frontend, FE_SET_FRONTEND, &fe->parameters); fe->parameters.frequency = original_frequency; fe->parameters.inversion = original_inversion; // normal return fe->auto_sub_step++; return 0;}static int dvb_frontend_is_exiting (struct dvb_frontend_data *fe){ if (fe->exit) return 1; if (fe->dvbdev->writers == 1) if (jiffies - fe->release_jiffies > dvb_shutdown_timeout * HZ) return 1; return 0;}static int dvb_frontend_should_wakeup (struct dvb_frontend_data *fe){ if (fe->wakeup) { fe->wakeup = 0; return 1; } return dvb_frontend_is_exiting(fe);}static void dvb_frontend_wakeup (struct dvb_frontend_data *fe) { fe->wakeup = 1; wake_up_interruptible(&fe->wait_queue);}static int dvb_frontend_thread (void *data){ struct dvb_frontend_data *fe = (struct dvb_frontend_data *) data; unsigned long timeout; char name [15]; int quality = 0, delay = 3*HZ; fe_status_t s; int check_wrapped = 0; dprintk ("%s\n", __FUNCTION__); snprintf (name, sizeof(name), "kdvb-fe-%i:%i", fe->frontend.i2c->adapter->num, fe->frontend.i2c->id); dvb_kernel_thread_setup (name); dvb_call_frontend_notifiers (fe, 0); dvb_frontend_init (fe); fe->wakeup = 0; while (1) { up (&fe->sem); /* is locked when we enter the thread... */ timeout = wait_event_interruptible_timeout(fe->wait_queue,0 != dvb_frontend_should_wakeup (fe), delay); if (-ERESTARTSYS == timeout || 0 != dvb_frontend_is_exiting (fe)) { /* got signal or quitting */ break; } if (down_interruptible (&fe->sem)) break; // if we've got no parameters, just keep idling if (fe->state & FESTATE_IDLE) { delay = 3*HZ; quality = 0; continue; } // get the frontend status dvb_frontend_internal_ioctl (&fe->frontend, FE_READ_STATUS, &s); if (s != fe->status) dvb_frontend_add_event (fe, s); // if we're not tuned, and we have a lock, move to the TUNED state if ((fe->state & FESTATE_WAITFORLOCK) && (s & FE_HAS_LOCK)) { update_delay(&quality, &delay, fe->min_delay, s & FE_HAS_LOCK); fe->state = FESTATE_TUNED; // if we're tuned, then we have determined the correct inversion if ((!(fe->info->caps & FE_CAN_INVERSION_AUTO)) && (fe->parameters.inversion == INVERSION_AUTO)) { fe->parameters.inversion = fe->inversion; } continue; } // if we are tuned already, check we're still locked if (fe->state & FESTATE_TUNED) { update_delay(&quality, &delay, fe->min_delay, s & FE_HAS_LOCK); // we're tuned, and the lock is still good... if (s & FE_HAS_LOCK) { continue; } else { // if we _WERE_ tuned, but now don't have a lock, need to zigzag fe->state = FESTATE_ZIGZAG_FAST; fe->started_auto_step = fe->auto_step; check_wrapped = 0; // fallthrough } } // 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 ((fe->state & FESTATE_LOSTLOCK) && (fe->info->caps & FE_CAN_RECOVER) && (fe->max_drift == 0)) { update_delay(&quality, &delay, fe->min_delay, s & FE_HAS_LOCK); continue; } // 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 (fe->state & FESTATE_DISEQC) { update_delay(&quality, &delay, fe->min_delay, s & FE_HAS_LOCK); continue; } // 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 (fe->state & FESTATE_RETUNE) { fe->lnb_drift = 0; fe->auto_step = 0; fe->auto_sub_step = 0; fe->started_auto_step = 0; check_wrapped = 0; } // fast zigzag. if ((fe->state & FESTATE_SEARCHING_FAST) || (fe->state & FESTATE_RETUNE)) { delay = fe->min_delay; // peform a tune if (dvb_frontend_autotune(fe, check_wrapped)) { // OK, if we've run out of trials at the fast speed. Drop back to // slow for the _next_ attempt fe->state = FESTATE_SEARCHING_SLOW; fe->started_auto_step = fe->auto_step; continue; } 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 (fe->state & FESTATE_RETUNE) { fe->state = FESTATE_TUNING_FAST; wake_up_interruptible(&fe->wait_queue); } } // slow zigzag if (fe->state & FESTATE_SEARCHING_SLOW) { update_delay(&quality, &delay, fe->min_delay, s & FE_HAS_LOCK); // Note: don't bother checking for wrapping; we stay in this state // until we get a lock dvb_frontend_autotune(fe, 0); } }; if (dvb_shutdown_timeout) dvb_frontend_internal_ioctl (&fe->frontend, FE_SLEEP, NULL); up (&fe->sem); fe->thread_pid = 0; mb(); dvb_frontend_wakeup(fe); return 0;}static void dvb_frontend_stop (struct dvb_frontend_data *fe){ unsigned long ret; dprintk ("%s\n", __FUNCTION__); fe->exit = 1; mb(); if (!fe->thread_pid) return; /* check if the thread is really alive */ if (kill_proc(fe->thread_pid, 0, 1) == -ESRCH) { printk("dvb_frontend_stop: thread PID %d already died\n", fe->thread_pid); /* make sure the mutex was not held by the thread */ init_MUTEX (&fe->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(fe->wait_queue,0 == fe->thread_pid); if (-ERESTARTSYS != ret) { fe->state = FESTATE_IDLE; return; } fe->state = FESTATE_IDLE; /* paranoia check in case a signal arrived */ if (fe->thread_pid) printk("dvb_frontend_stop: warning: thread PID %d won't exit\n", fe->thread_pid);}static int dvb_frontend_start (struct dvb_frontend_data *fe){ int ret; dprintk ("%s\n", __FUNCTION__); if (fe->thread_pid) { if (!fe->exit) return 0; else dvb_frontend_stop (fe); } if (signal_pending(current)) return -EINTR; if (down_interruptible (&fe->sem)) return -EINTR; fe->state = FESTATE_IDLE; fe->exit = 0; fe->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(&fe->sem); return ret; } fe->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_data *fe = dvbdev->priv; struct dvb_frontend_tune_settings fetunesettings; int err = 0; dprintk ("%s\n", __FUNCTION__); if (!fe || !fe->frontend.ioctl || fe->exit) return -ENODEV; if (down_interruptible (&fe->sem)) return -ERESTARTSYS; switch (cmd) { case FE_DISEQC_SEND_MASTER_CMD: case FE_DISEQC_SEND_BURST: case FE_SET_TONE: if (fe->status) dvb_call_frontend_notifiers (fe, 0); dvb_frontend_internal_ioctl (&fe->frontend, cmd, parg); fe->state = FESTATE_DISEQC; break; case FE_SET_FRONTEND: fe->state = FESTATE_RETUNE; memcpy (&fe->parameters, parg, sizeof (struct dvb_frontend_parameters)); memset(&fetunesettings, 0, sizeof(struct dvb_frontend_tune_settings)); memcpy(&fetunesettings.parameters, parg, sizeof (struct dvb_frontend_parameters)); // force auto frequency inversion if requested if (dvb_force_auto_inversion) { fe->parameters.inversion = INVERSION_AUTO; fetunesettings.parameters.inversion = INVERSION_AUTO; } // get frontend-specific tuning settings if (dvb_frontend_internal_ioctl(&fe->frontend, FE_GET_TUNE_SETTINGS, &fetunesettings) == 0) { fe->min_delay = (fetunesettings.min_delay_ms * HZ) / 1000; fe->max_drift = fetunesettings.max_drift; fe->step_size = fetunesettings.step_size; } else { // default values switch(fe->info->type) { case FE_QPSK: fe->min_delay = HZ/20; // default mindelay of 50ms fe->step_size = fe->parameters.u.qpsk.symbol_rate / 16000; fe->max_drift = fe->parameters.u.qpsk.symbol_rate / 2000; break; case FE_QAM: fe->min_delay = HZ/20; // default mindelay of 50ms fe->step_size = 0; fe->max_drift = 0; // don't want any zigzagging under DVB-C frontends break; case FE_OFDM: fe->min_delay = HZ/20; // default mindelay of 50ms fe->step_size = fe->info->frequency_stepsize * 2; fe->max_drift = (fe->info->frequency_stepsize * 2) + 1; break; } } if (dvb_override_tune_delay > 0) { fe->min_delay = (dvb_override_tune_delay * HZ) / 1000; } dvb_frontend_add_event (fe, 0); break; case FE_GET_EVENT: err = dvb_frontend_get_event (fe, parg, file->f_flags); break; case FE_GET_FRONTEND: memcpy (parg, &fe->parameters, sizeof (struct dvb_frontend_parameters)); /* fall-through... */ default: err = dvb_frontend_internal_ioctl (&fe->frontend, cmd, parg); }; up (&fe->sem); if (err < 0) return err; // Force the CAN_INVERSION_AUTO bit on. If the frontend doesn't do it, it is done for it. if ((cmd == FE_GET_INFO) && (err == 0)) { struct dvb_frontend_info* tmp = (struct dvb_frontend_info*) parg;
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?