📄 dvb_frontend.c
字号:
default: printk("Unknown frontend type %i\n", fe->info->type); return 0; } // are we using autoinversion? autoinversion = ((!(fe->info->caps & FE_CAN_INVERSION_AUTO)) && (fe->parameters.inversion == INVERSION_AUTO)); // setup parameters correctly while(!ready) { // wrap the count if we've reached the maximum drift fe->lnb_drift = (fe->auto_count / 4) * stepsize; if (fe->lnb_drift >= maxdrift) { fe->auto_count = 0; fe->lnb_drift = 0; wrapped = 1; } // perform inversion and +/- zigzag switch(fe->auto_count % 4) { case 0: fe->inversion = INVERSION_OFF; ready = 1; break; case 1: if (!autoinversion) break; fe->inversion = INVERSION_ON; ready = 1; break; case 2: if (fe->lnb_drift == 0) break; fe->inversion = INVERSION_OFF; fe->lnb_drift = -fe->lnb_drift; ready = 1; break; case 3: if (fe->lnb_drift == 0) break; if (!autoinversion) break; fe->inversion = INVERSION_ON; fe->lnb_drift = -fe->lnb_drift; ready = 1; break; } if (!ready) fe->auto_count++; } // perform frequency bending if enabled if (dvb_frequency_bending) dvb_bend_frequency(fe, 0); // 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; // reset frontend IRQ bits to clean error stats dvb_frontend_internal_ioctl (&fe->frontend, FE_RESET, NULL); // if we've hit where we started from, indicate a complete iteration has occurred fe->auto_count++; if ((fe->auto_count == fe->started_auto_count) || (fe->started_auto_count==0 && wrapped)) return 1; 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_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; int clean_setup_count = 0; fe_status_t s; 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); while (1) { up (&fe->sem); /* is locked when we enter the thread... */ timeout = wait_event_interruptible_timeout(fe->wait_queue,0 != dvb_frontend_is_exiting (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_SEARCHING) && (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_count = fe->auto_count; // fallthrough } } // don't actually do anything if we're in the LOSTLOCK state // and the frontend can recover automatically if ((fe->state & FESTATE_LOSTLOCK) && (fe->info->caps & FE_CAN_RECOVER)) { 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 if (fe->state & FESTATE_RETUNE) { fe->lnb_drift = 0; fe->inversion = INVERSION_OFF; fe->auto_count = 0; fe->started_auto_count = 0; clean_setup_count = 0; } // fast zigzag. if ((fe->state & FESTATE_SEARCHING_FAST) || (fe->state & FESTATE_RETUNE)) { delay = fe->min_delay; // OK, if we've run out of trials at the fast speed. Drop back to // slow for the _next_ attempt if (dvb_frontend_autotune(fe)) { fe->state = FESTATE_SEARCHING_SLOW; fe->started_auto_count = fe->auto_count; continue; } // enter clean setup state after the first tune if necessary. yeuch if ((!(fe->info->caps & FE_CAN_CLEAN_SETUP)) && (clean_setup_count == 0)) { fe->state = FESTATE_CLEAN_SETUP; } // if we've just retuned, enter the ZIGZAG_FAST state. This ensures // we cannot return from an FE_SET_FRONTEND before the retune occurs. if (fe->state & FESTATE_RETUNE) { fe->state = FESTATE_TUNING_FAST; } } // slow zigzag if (fe->state & FESTATE_SEARCHING_SLOW) { update_delay(&quality, &delay, fe->min_delay, s & FE_HAS_LOCK); dvb_frontend_autotune(fe); } // clean setup if (fe->state & FESTATE_CLEAN_SETUP) { if ((clean_setup_count < 10) && (!(s & FE_HAS_LOCK))) { dvb_frontend_internal_ioctl(&fe->frontend, FE_RESET, NULL); } else { // return to tuning state fe->state = FESTATE_TUNING_FAST; } clean_setup_count++; } }; if (dvb_shutdown_timeout) dvb_frontend_internal_ioctl (&fe->frontend, FE_SLEEP, NULL); up (&fe->sem); fe->thread_pid = 0; mb(); wake_up_interruptible (&fe->wait_queue); 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 */ wake_up_interruptible(&fe->wait_queue); /* 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();#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)){ /* bug in linux 2.4.x: kernel_thread() fails when the process calling * open() is run in the debugger (fixed in kernel 2.5). I hope this * workaround does not have any ugly side effects... */ int pt = current->ptrace; current->ptrace = 0;#endif ret = kernel_thread (dvb_frontend_thread, fe, 0);#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)) current->ptrace = pt;}#endif 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; int err = 0; int delay_ms; 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_IDLE; break; case FE_SET_FRONTEND: fe->state = FESTATE_RETUNE; memcpy (&fe->parameters, parg, sizeof (struct dvb_frontend_parameters)); delay_ms = dvb_frontend_internal_ioctl(&fe->frontend, FE_GETMINDELAY, &fe->parameters); if (delay_ms >= 0) fe->min_delay = (delay_ms * HZ) / 1000; else { switch(fe->info->type) { case FE_QPSK: fe->min_delay = HZ/20; // default mindelay of 50ms break; case FE_QAM: fe->min_delay = HZ/20; // default mindelay of 50ms break; case FE_OFDM: fe->min_delay = HZ/10; // default mindelay of 100ms break; } } 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: dvb_frontend_internal_ioctl (&fe->frontend, cmd, parg); }; up (&fe->sem); // 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; tmp->caps |= FE_CAN_INVERSION_AUTO; }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -