|
SASC-NG
DVBSoftCAM
|
00001 /* 00002 * dvblb_proc.c 00003 * 00004 * DVBLoopback Copyright Alan Nisota 2006 00005 * 00006 * Portions of this code also have copyright: 00007 * Video Loopback Copyright Jeroen Vreeken (pe1rxq@amsat.org), 2000 00008 * 00009 * Published under the GNU Public License. 00010 * DVBLoopback is free software; you can redistribute it and/or modify 00011 * it under the terms of the GNU General Public License as published by 00012 * the Free Software Foundation; either version 2 of the License, or 00013 * (at your option) any later version. 00014 * 00015 * DVBLoopback is distributed in the hope that it will be useful, 00016 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00017 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00018 * GNU General Public License for more details. 00019 * 00020 * You should have received a copy of the GNU General Public License 00021 * along with Foobar; if not, write to the Free Software 00022 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 00023 */ 00024 #include <linux/version.h> /* >= 2.6.14 LINUX_VERSION_CODE */ 00025 #include <linux/errno.h> 00026 #include <linux/kernel.h> 00027 #include <linux/module.h> 00028 00029 #include <linux/proc_fs.h> 00030 #include "dvblb_internal.h" 00031 00032 static struct proc_dir_entry *procdir; 00033 00034 static int dvblb_procfs_read(char *page, char **start, off_t off, int count, 00035 int *eof, void *data) 00036 { 00037 struct dvblb_devinfo *lbdev = (struct dvblb_devinfo *)data; 00038 int val; 00039 if (lbdev == NULL) 00040 return 0; 00041 val = (lbdev->forward_dev) ? 1 : 0; 00042 return sprintf(page, "%03d", val); 00043 } 00044 00045 static int dvblb_procfs_write(struct file *file, const char *buffer, 00046 unsigned long count, void *data) 00047 { 00048 char str[10]; 00049 int val, v1, v2, v3, fm; 00050 struct dvblb_devinfo *lbdev = (struct dvblb_devinfo *)data; 00051 if (lbdev == NULL) 00052 return count; 00053 if (lbdev->parent->link == -1) 00054 return count; 00055 if (count > 10) 00056 count = 10; 00057 if (copy_from_user(str, buffer, count)) { 00058 return -EFAULT; 00059 } 00060 val = simple_strtoul(str, NULL, 0); 00061 v1 = val /100; 00062 v2 = (val - v1*100) / 10; 00063 v3 = val - v1*100 - v2*10; 00064 if (v1 < 0 || v1 > 2) 00065 return -EFAULT; 00066 if((fm = inuse_filemap(lbdev))) { 00067 int type = lbdev->lb_dev->type; 00068 printk("dvbloopback: Can't change forward on adapter%d." 00069 " Device %s still has %d users!\n", 00070 lbdev->parent->adapter.num, dnames[type], fm); 00071 return count; 00072 } 00073 if (v3 == 1) { 00074 struct list_head *entry; 00075 list_for_each (entry, lbdev->parent->adapter_ll) { 00076 struct dvb_adapter *adap; 00077 adap = list_entry (entry, struct dvb_adapter, 00078 list_head); 00079 if (adap->num == lbdev->parent->link) { 00080 struct list_head *entry0; 00081 list_for_each (entry0, 00082 &adap->device_list) { 00083 struct dvb_device *dev; 00084 dev = list_entry (entry0, 00085 struct dvb_device, list_head); 00086 if (dev->type == lbdev->lb_dev->type) { 00087 lbdev->forward_dev = dev; 00088 return count; 00089 } 00090 } 00091 } 00092 } 00093 } else if (v3 == 0) { 00094 lbdev->forward_dev = NULL; 00095 } 00096 return count; 00097 } 00098 00099 static int dvblb_procfs_adapter_read(char *page, char **start, off_t off, 00100 int count, int *eof, void *data) 00101 { 00102 struct dvblb *dvblb = (struct dvblb *)data; 00103 if (dvblb == NULL) 00104 return 0; 00105 return sprintf(page, "%d", dvblb->link); 00106 } 00107 00108 static int dvblb_procfs_adapter_write(struct file *file, const char *buffer, 00109 unsigned long count, void *data) 00110 { 00111 char str[10]; 00112 int val, i, fm; 00113 struct dvblb *dvbdev = (struct dvblb *)data; 00114 if (dvbdev == NULL) 00115 return count; 00116 if (count > 10) 00117 count = 10; 00118 if (copy_from_user(str, buffer, count)) { 00119 return -EFAULT; 00120 } 00121 val = simple_strtol(str, NULL, 0); 00122 00123 if(val == -999) { 00124 /*This is a debug case. Try to force close all open fds 00125 This is known not to be very reliable, but better than 00126 nothing 00127 */ 00128 for(i = 0; i < DVBLB_NUM_DEVS; i++) { 00129 while((fm = inuse_filemap(&dvbdev->devinfo[i]))) { 00130 filp_close(dvbdev->devinfo[i].dbgfilemap[fm], 00131 NULL); 00132 dvbdev->devinfo[i].filemap[fm] = NULL; 00133 } 00134 } 00135 return count; 00136 } 00137 for(i = 0; i < DVBLB_NUM_DEVS; i++) { 00138 if(dvbdev->devinfo[i].forward_dev == NULL) 00139 continue; 00140 if((fm = inuse_filemap(&dvbdev->devinfo[i]))) { 00141 int type = dvbdev->devinfo[i].lb_dev->type; 00142 printk("dvbloopback: Can't change forward on adapter%d." 00143 " Device %s still has %d users!\n", 00144 dvbdev->adapter.num, dnames[type], fm); 00145 return count; 00146 } 00147 } 00148 for(i = 0; i < DVBLB_NUM_DEVS; i++) 00149 dvbdev->devinfo[i].forward_dev = NULL; 00150 dvbdev->link = val; 00151 return count; 00152 } 00153 00154 int dvblb_remove_procfs(struct proc_dir_entry *pdir, 00155 struct proc_dir_entry *parent) 00156 { 00157 char name[20]; 00158 memcpy(name, pdir->name, pdir->namelen); 00159 name[pdir->namelen] = '\0'; 00160 // printk("Removing proc: %s\n", name); 00161 remove_proc_entry(name, parent); 00162 return 0; 00163 } 00164 EXPORT_SYMBOL(dvblb_remove_procfs); 00165 00166 int dvblb_init_procfs_device(struct dvblb *dvblb, struct dvblb_devinfo *lbdev) 00167 { 00168 int type = lbdev->lb_dev->type; 00169 lbdev->procfile = create_proc_entry(dnames[type], 0644, dvblb->procdir); 00170 if (lbdev->procfile == NULL) 00171 return -ENOMEM; 00172 lbdev->procfile->data = lbdev; 00173 lbdev->procfile->read_proc = dvblb_procfs_read; 00174 lbdev->procfile->write_proc = dvblb_procfs_write; 00175 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,31) 00176 lbdev->procfile->owner = THIS_MODULE; 00177 #endif 00178 return 0; 00179 } 00180 EXPORT_SYMBOL(dvblb_init_procfs_device); 00181 00182 int dvblb_init_procfs_adapter(struct dvblb *dvblb) 00183 { 00184 char name[10]; 00185 sprintf(name, "adapter%d", dvblb->adapter.num); 00186 dvblb->procdir = proc_mkdir(name, procdir); 00187 if (dvblb->procdir == NULL) 00188 return -ENOMEM; 00189 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,31) 00190 dvblb->procdir->owner = THIS_MODULE; 00191 #endif 00192 dvblb->procfile = create_proc_entry("adapter", 0644, dvblb->procdir); 00193 if (dvblb->procfile == NULL) { 00194 dvblb_remove_procfs(dvblb->procdir, procdir); 00195 return -ENOMEM; 00196 } 00197 dvblb->procfile->data = dvblb; 00198 dvblb->procfile->read_proc = dvblb_procfs_adapter_read; 00199 dvblb->procfile->write_proc = dvblb_procfs_adapter_write; 00200 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,31) 00201 dvblb->procfile->owner = THIS_MODULE; 00202 #endif 00203 dvblb->init |= DVBLB_STATUS_PROC; 00204 00205 return 0; 00206 } 00207 EXPORT_SYMBOL(dvblb_init_procfs_adapter); 00208 00209 int dvblb_remove_procfs_adapter(struct dvblb *dvblb) 00210 { 00211 if(dvblb->init & DVBLB_STATUS_PROC) { 00212 dvblb_remove_procfs(dvblb->procfile, dvblb->procdir); 00213 dvblb_remove_procfs(dvblb->procdir, procdir); 00214 printk("removing dvblb proc adapter\n"); 00215 } 00216 dvblb->init &= ~DVBLB_STATUS_PROC; 00217 printk("dvblb init = %x\n", dvblb->init); 00218 return 0; 00219 } 00220 EXPORT_SYMBOL(dvblb_remove_procfs_adapter); 00221 00222 int dvblb_init_procfs(void) 00223 { 00224 procdir = proc_mkdir("dvbloopback", NULL); 00225 if (procdir == NULL) 00226 return -ENOMEM; 00227 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,31) 00228 procdir->owner = THIS_MODULE; 00229 #endif 00230 return 0; 00231 } 00232 EXPORT_SYMBOL(dvblb_init_procfs); 00233 00234 int dvblb_uninit_procfs(void) 00235 { 00236 dvblb_remove_procfs(procdir, NULL); 00237 return 0; 00238 } 00239 EXPORT_SYMBOL(dvblb_uninit_procfs); 00240