📄 dvb_frontend.c
字号:
// if the frontend has just been set, wait until the first tune has finished. // This ensures the app doesn't start reading data too quickly, perhaps from the // previous lock, which is REALLY CONFUSING TO DEBUG! if ((cmd == FE_SET_FRONTEND) && (err == 0)) { // note: cannot use wait_event_interruptible_* here as that // causes the thread not to wake until AFTER the call here returns. This is useless // because the whole point is to have the thread wake first, and perform at least one tune wake_up_interruptible(&fe->wait_queue); while(fe->state & FESTATE_RETUNE) { dvb_delay(10); } } return err;}static unsigned int dvb_frontend_poll (struct file *file, struct poll_table_struct *wait){ struct dvb_device *dvbdev = file->private_data; struct dvb_frontend_data *fe = dvbdev->priv; dprintk ("%s\n", __FUNCTION__); poll_wait (file, &fe->events.wait_queue, wait); if (fe->events.eventw != fe->events.eventr) return (POLLIN | POLLRDNORM | POLLPRI); return 0;}static int dvb_frontend_open (struct inode *inode, struct file *file){ struct dvb_device *dvbdev = file->private_data; struct dvb_frontend_data *fe = dvbdev->priv; int ret; dprintk ("%s\n", __FUNCTION__); if ((ret = dvb_generic_open (inode, file)) < 0) return ret; if ((file->f_flags & O_ACCMODE) != O_RDONLY) { ret = dvb_frontend_start (fe); if (ret) dvb_generic_release (inode, file); /* empty event queue */ fe->events.eventr = fe->events.eventw = 0; } return ret;}static int dvb_frontend_release (struct inode *inode, struct file *file){ struct dvb_device *dvbdev = file->private_data; struct dvb_frontend_data *fe = dvbdev->priv; dprintk ("%s\n", __FUNCTION__); if ((file->f_flags & O_ACCMODE) != O_RDONLY) fe->release_jiffies = jiffies; return dvb_generic_release (inode, file);}intdvb_add_frontend_ioctls (struct dvb_adapter *adapter, int (*before_ioctl) (struct dvb_frontend *frontend, unsigned int cmd, void *arg), int (*after_ioctl) (struct dvb_frontend *frontend, unsigned int cmd, void *arg), void *before_after_data){ struct dvb_frontend_ioctl_data *ioctl; struct list_head *entry; dprintk ("%s\n", __FUNCTION__); if (down_interruptible (&frontend_mutex)) return -ERESTARTSYS; ioctl = kmalloc (sizeof(struct dvb_frontend_ioctl_data), GFP_KERNEL); if (!ioctl) { up (&frontend_mutex); return -ENOMEM; } ioctl->adapter = adapter; ioctl->before_ioctl = before_ioctl; ioctl->after_ioctl = after_ioctl; ioctl->before_after_data = before_after_data; list_add_tail (&ioctl->list_head, &frontend_ioctl_list); list_for_each (entry, &frontend_list) { struct dvb_frontend_data *fe; fe = list_entry (entry, struct dvb_frontend_data, list_head); if (fe->frontend.i2c->adapter == adapter && fe->frontend.before_ioctl == NULL && fe->frontend.after_ioctl == NULL) { fe->frontend.before_ioctl = before_ioctl; fe->frontend.after_ioctl = after_ioctl; fe->frontend.before_after_data = before_after_data; } } up (&frontend_mutex); return 0;}voiddvb_remove_frontend_ioctls (struct dvb_adapter *adapter, int (*before_ioctl) (struct dvb_frontend *frontend, unsigned int cmd, void *arg), int (*after_ioctl) (struct dvb_frontend *frontend, unsigned int cmd, void *arg)){ struct list_head *entry, *n; dprintk ("%s\n", __FUNCTION__); down (&frontend_mutex); list_for_each (entry, &frontend_list) { struct dvb_frontend_data *fe; fe = list_entry (entry, struct dvb_frontend_data, list_head); if (fe->frontend.i2c->adapter == adapter && fe->frontend.before_ioctl == before_ioctl && fe->frontend.after_ioctl == after_ioctl) { fe->frontend.before_ioctl = NULL; fe->frontend.after_ioctl = NULL; } } list_for_each_safe (entry, n, &frontend_ioctl_list) { struct dvb_frontend_ioctl_data *ioctl; ioctl = list_entry (entry, struct dvb_frontend_ioctl_data, list_head); if (ioctl->adapter == adapter && ioctl->before_ioctl == before_ioctl && ioctl->after_ioctl == after_ioctl) { list_del (&ioctl->list_head); kfree (ioctl); break; } } up (&frontend_mutex);}intdvb_add_frontend_notifier (struct dvb_adapter *adapter, void (*callback) (fe_status_t s, void *data), void *data){ struct dvb_frontend_notifier_data *notifier; struct list_head *entry; dprintk ("%s\n", __FUNCTION__); if (down_interruptible (&frontend_mutex)) return -ERESTARTSYS; notifier = kmalloc (sizeof(struct dvb_frontend_notifier_data), GFP_KERNEL); if (!notifier) { up (&frontend_mutex); return -ENOMEM; } notifier->adapter = adapter; notifier->callback = callback; notifier->data = data; list_add_tail (¬ifier->list_head, &frontend_notifier_list); list_for_each (entry, &frontend_list) { struct dvb_frontend_data *fe; fe = list_entry (entry, struct dvb_frontend_data, list_head); if (fe->frontend.i2c->adapter == adapter && fe->frontend.notifier_callback == NULL) { fe->frontend.notifier_callback = callback; fe->frontend.notifier_data = data; } } up (&frontend_mutex); return 0;}voiddvb_remove_frontend_notifier (struct dvb_adapter *adapter, void (*callback) (fe_status_t s, void *data)){ struct list_head *entry, *n; dprintk ("%s\n", __FUNCTION__); down (&frontend_mutex); list_for_each (entry, &frontend_list) { struct dvb_frontend_data *fe; fe = list_entry (entry, struct dvb_frontend_data, list_head); if (fe->frontend.i2c->adapter == adapter && fe->frontend.notifier_callback == callback) { fe->frontend.notifier_callback = NULL; } } list_for_each_safe (entry, n, &frontend_notifier_list) { struct dvb_frontend_notifier_data *notifier; notifier = list_entry (entry, struct dvb_frontend_notifier_data, list_head); if (notifier->adapter == adapter && notifier->callback == callback) { list_del (¬ifier->list_head); kfree (notifier); break; } } up (&frontend_mutex);}static struct file_operations dvb_frontend_fops = { .owner = THIS_MODULE, .ioctl = dvb_generic_ioctl, .poll = dvb_frontend_poll, .open = dvb_frontend_open, .release = dvb_frontend_release};intdvb_register_frontend (int (*ioctl) (struct dvb_frontend *frontend, unsigned int cmd, void *arg), struct dvb_i2c_bus *i2c, void *data, struct dvb_frontend_info *info){ struct list_head *entry; struct dvb_frontend_data *fe; static const struct dvb_device dvbdev_template = { .users = ~0, .writers = 1, .readers = (~0)-1, .fops = &dvb_frontend_fops, .kernel_ioctl = dvb_frontend_ioctl }; dprintk ("%s\n", __FUNCTION__); if (down_interruptible (&frontend_mutex)) return -ERESTARTSYS; if (!(fe = kmalloc (sizeof (struct dvb_frontend_data), GFP_KERNEL))) { up (&frontend_mutex); return -ENOMEM; } memset (fe, 0, sizeof (struct dvb_frontend_data)); init_MUTEX (&fe->sem); init_waitqueue_head (&fe->wait_queue); init_waitqueue_head (&fe->events.wait_queue); init_MUTEX (&fe->events.sem); fe->events.eventw = fe->events.eventr = 0; fe->events.overflow = 0; fe->frontend.ioctl = ioctl; fe->frontend.i2c = i2c; fe->frontend.data = data; fe->info = info; list_for_each (entry, &frontend_ioctl_list) { struct dvb_frontend_ioctl_data *ioctl; ioctl = list_entry (entry, struct dvb_frontend_ioctl_data, list_head); if (ioctl->adapter == i2c->adapter) { fe->frontend.before_ioctl = ioctl->before_ioctl; fe->frontend.after_ioctl = ioctl->after_ioctl; fe->frontend.before_after_data = ioctl->before_after_data; break; } } list_for_each (entry, &frontend_notifier_list) { struct dvb_frontend_notifier_data *notifier; notifier = list_entry (entry, struct dvb_frontend_notifier_data, list_head); if (notifier->adapter == i2c->adapter) { fe->frontend.notifier_callback = notifier->callback; fe->frontend.notifier_data = notifier->data; break; } } list_add_tail (&fe->list_head, &frontend_list); printk ("DVB: registering frontend %i:%i (%s)...\n", fe->frontend.i2c->adapter->num, fe->frontend.i2c->id, fe->info->name); dvb_register_device (i2c->adapter, &fe->dvbdev, &dvbdev_template, fe, DVB_DEVICE_FRONTEND); up (&frontend_mutex); return 0;}int dvb_unregister_frontend (int (*ioctl) (struct dvb_frontend *frontend, unsigned int cmd, void *arg), struct dvb_i2c_bus *i2c){ struct list_head *entry, *n; dprintk ("%s\n", __FUNCTION__); down (&frontend_mutex); list_for_each_safe (entry, n, &frontend_list) { struct dvb_frontend_data *fe; fe = list_entry (entry, struct dvb_frontend_data, list_head); if (fe->frontend.ioctl == ioctl && fe->frontend.i2c == i2c) { dvb_unregister_device (fe->dvbdev); list_del (entry); up (&frontend_mutex); dvb_frontend_stop (fe); kfree (fe); return 0; } } up (&frontend_mutex); return -EINVAL;}MODULE_PARM(dvb_frontend_debug,"i");MODULE_PARM(dvb_shutdown_timeout,"i");MODULE_PARM(dvb_frequency_bending,"i");MODULE_PARM_DESC(dvb_frontend_debug, "enable verbose debug messages");MODULE_PARM_DESC(dvb_shutdown_timeout, "wait <shutdown_timeout> seconds after close() before suspending hardware");MODULE_PARM_DESC(dvb_frequency_bending, "0: disable frequency bending, 1: enable (default)");
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -