|
SASC
DVBSoftCAM
|
00001 /* 00002 * dvbloopback.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 * 00025 * This driver creates a virtual dvb adaper which can forward all I/O to 00026 * userspace or to another DVB card. Thus, it is possible to clone an 00027 * existing DVB card (why would you do that?), or to pre-process all data 00028 * in userspace before sending it on. It could also be used, in theory to 00029 * send arbitrary data (hand-crafted stream) to a DVB app. In addition, a 00030 * mixed mode is allowed. Each device can be set independantly, and in 00031 * fact each type of I/O can be set independantly (i.e. read, write, and 00032 * ioctl). The allowed modes are: forward to userspace, forward to 00033 * alternate dvb adapter, forward to alternate dvb adapter and send to 00034 * userspace (for monitor only). 00035 * The driver creates two devices of each type <dev>0 is the new virtual 00036 * device, and <dev>1 is the interface to userspace. 00037 * 00038 * This code is based off the video-loopback driver 00039 * http://www.lavrsen.dk/twiki/bin/view/Motion/VideoFourLinuxLoopbackDevice 00040 * 00041 */ 00042 00043 00044 #define DVBLOOPBACK_VERSION "0.0.1" 00045 00046 /* Include files common to 2.4 and 2.6 versions */ 00047 #include <linux/version.h> /* >= 2.6.14 LINUX_VERSION_CODE */ 00048 #include <linux/errno.h> 00049 #include <linux/kernel.h> 00050 #include <linux/module.h> 00051 #include <linux/pagemap.h> 00052 #include <linux/dvb/ca.h> 00053 #include <linux/dvb/frontend.h> 00054 #include <linux/dvb/version.h> 00055 #include <linux/vmalloc.h> 00056 #include <linux/cdev.h> 00057 #include <linux/platform_device.h> 00058 00059 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,32) 00060 #include <linux/sched.h> 00061 #endif 00062 00063 #include "dvbdev.h" 00064 #include "dvbdevwrap.h" 00065 #include "dvblb_internal.h" 00066 00067 #define N_BUFFS 2 /* Number of buffers used for pipes */ 00068 00069 #define info(format, arg...) printk(KERN_INFO __FILE__ ": " format "\n" "", ## arg) 00070 00071 #define dprintk if (dvblb_debug) printk 00072 #define dprintk2 if (dvblb_debug > 1) printk 00073 #define dprintk3 if (dvblb_debug > 2) printk 00074 00075 static int dvblb_debug = 0; 00076 static int num_adapters = 1; 00077 module_param(dvblb_debug, int, S_IRUGO | S_IWUSR); 00078 module_param(num_adapters, int, S_IRUGO); 00079 00080 static struct dvblb *dvblb_global; 00081 00082 static void *rvmalloc(unsigned long size) 00083 { 00084 void *mem; 00085 unsigned long adr; 00086 00087 size = PAGE_ALIGN(size); 00088 mem = vmalloc_32(size); 00089 if (!mem) 00090 return NULL; 00091 memset(mem, 0, size); /* Clear the ram out, no junk to the user */ 00092 adr = (unsigned long) mem; 00093 while (size > 0) { 00094 SetPageReserved(vmalloc_to_page((void *)adr)); 00095 adr += PAGE_SIZE; 00096 size -= PAGE_SIZE; 00097 } 00098 00099 return mem; 00100 } 00101 00102 static void rvfree(void *mem, unsigned long size) 00103 { 00104 unsigned long adr; 00105 00106 if (!mem) 00107 return; 00108 00109 adr = (unsigned long) mem; 00110 while ((long) size > 0) { 00111 ClearPageReserved(vmalloc_to_page((void *)adr)); 00112 adr += PAGE_SIZE; 00113 size -= PAGE_SIZE; 00114 } 00115 vfree(mem); 00116 } 00117 00118 /* This is a copy of dvb_usercopy. We need to do this because it isn't exported 00119 by dvbdev 00120 */ 00121 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,38) 00122 static int dvblb_usercopy(struct file *file, 00123 unsigned int cmd, unsigned long arg, 00124 int (*func)(struct file *file, 00125 unsigned int cmd, void *arg)) 00126 #else 00127 static int dvblb_usercopy(struct inode *inode, struct file *file, 00128 unsigned int cmd, unsigned long arg, 00129 int (*func)(struct inode *inode, struct file *file, 00130 unsigned int cmd, void *arg)) 00131 #endif 00132 { 00133 char sbuf[128]; 00134 void *mbuf = NULL; 00135 void *parg = NULL; 00136 int err = -EINVAL; 00137 #if DVB_API_VERSION >=5 00138 struct dtv_properties *tvps = NULL; 00139 struct dtv_property *tvp = NULL; 00140 #endif 00141 00142 /* Copy arguments into temp kernel buffer */ 00143 switch (_IOC_DIR(cmd)) { 00144 case _IOC_NONE: 00145 /* 00146 * For this command, the pointer is actually an integer 00147 * argument. 00148 */ 00149 parg = (void *) arg; 00150 break; 00151 case _IOC_READ: /* some v4l ioctls are marked wrong ... */ 00152 case _IOC_WRITE: 00153 case (_IOC_WRITE | _IOC_READ): 00154 if (_IOC_SIZE(cmd) <= sizeof(sbuf)) { 00155 parg = sbuf; 00156 } else { 00157 /* too big to allocate from stack */ 00158 mbuf = kmalloc(_IOC_SIZE(cmd),GFP_KERNEL); 00159 if (NULL == mbuf) 00160 return -ENOMEM; 00161 parg = mbuf; 00162 } 00163 00164 err = -EFAULT; 00165 if (copy_from_user(parg, (void __user *)arg, _IOC_SIZE(cmd))) 00166 goto out; 00167 #if DVB_API_VERSION >=5 00168 if ((cmd == FE_SET_PROPERTY) || (cmd == FE_GET_PROPERTY)) { 00169 tvps = (struct dtv_properties __user *)arg; 00170 tvp = (struct dtv_property *) kmalloc(tvps->num * 00171 sizeof(struct dtv_property), GFP_KERNEL); 00172 if (!tvp){ 00173 err = -ENOMEM; 00174 goto out; 00175 } 00176 if (copy_from_user(tvp, tvps->props, 00177 (tvps->num) * sizeof(struct dtv_property))) { 00178 err = -EFAULT; 00179 goto out; 00180 } 00181 tvps = (struct dtv_properties __user *)parg; 00182 tvps->props = tvp; 00183 tvp = NULL; 00184 } 00185 #endif 00186 break; 00187 } 00188 00189 /* call driver */ 00190 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,38) 00191 if ((err = func(file, cmd, parg)) == -ENOIOCTLCMD) 00192 #else 00193 if ((err = func(inode, file, cmd, parg)) == -ENOIOCTLCMD) 00194 #endif 00195 err = -EINVAL; 00196 00197 if (err < 0) 00198 goto out; 00199 00200 /* Copy results into user buffer */ 00201 switch (_IOC_DIR(cmd)) 00202 { 00203 case _IOC_READ: 00204 case (_IOC_WRITE | _IOC_READ): 00205 #if DVB_API_VERSION >=5 00206 if ((cmd == FE_GET_PROPERTY) || (cmd == FE_SET_PROPERTY)) 00207 { 00208 tvps = (struct dtv_properties __user *)arg; 00209 tvp = tvps->props; 00210 tvps = (struct dtv_properties __user *)parg; 00211 if (copy_to_user(tvp, tvps->props, tvps->num * 00212 sizeof(struct dtv_property))) { 00213 err = -EFAULT; 00214 goto out; 00215 } 00216 tvps->props = tvp; 00217 } 00218 #endif 00219 if (copy_to_user((void __user *)arg, parg, _IOC_SIZE(cmd))) 00220 err = -EFAULT; 00221 break; 00222 } 00223 00224 out: 00225 kfree(mbuf); 00226 return err; 00227 } 00228 00229 static int get_new_filemap(struct dvblb_devinfo *lbdev, int id) { 00230 int i; 00231 for(i = 0; i < DVBLB_MAXFD; i++) 00232 { 00233 if(lbdev->filemap[i] == NULL) { 00234 if(id) 00235 lbdev->filemap[i] = lbdev->user_dev; 00236 else 00237 lbdev->filemap[i] = lbdev->lb_dev; 00238 return i; 00239 } 00240 } 00241 return -1; 00242 } 00243 00244 static int find_filemap(struct dvblb_devinfo *lbdev, struct dvb_device **fm) { 00245 int i; 00246 for(i = 0; i < DVBLB_MAXFD; i++) 00247 if(&lbdev->filemap[i] == fm) 00248 return i; 00249 return -1; 00250 } 00251 00252 int inuse_filemap(struct dvblb_devinfo *lbdev) { 00253 int i, count = 0; 00254 for(i = 0; i < DVBLB_MAXFD; i++) 00255 if(lbdev->filemap[i] != NULL) 00256 count++; 00257 return count; 00258 } 00259 00260 static int dvblb_fake_ioctl(struct dvblb_devinfo *lbdev, struct dvb_device **f, 00261 unsigned long int cmd, void *arg) 00262 { 00263 int ret = 0; 00264 #if DVB_API_VERSION >=5 00265 struct dtv_properties *tvps = NULL; 00266 long unsigned int _ioctllen; 00267 #endif 00268 dprintk2("dvblb_fake_ioctl (%d) : %lu\n", lbdev->parent->adapter.num, 00269 0xFF & cmd); 00270 if (mutex_lock_interruptible(&lbdev->lock_fake_ioctl)) 00271 return -ERESTARTSYS; 00272 if (mutex_lock_interruptible(&lbdev->lock_ioctl)) { 00273 mutex_unlock(&lbdev->lock_fake_ioctl); 00274 return -ERESTARTSYS; 00275 } 00276 //printk("Sleep up on cmd: %u\n", cmd); 00277 lbdev->ioctlcmd = cmd; 00278 lbdev->ioctl_already_read = 0; 00279 if (cmd < DVBLB_MAX_CMDS) { 00280 // Read data command 00281 lbdev->ioctllen = sizeof(struct dvblb_custommsg); 00282 } else { 00283 // Regular ioctl 00284 lbdev->ioctllen = _IOC_SIZE(cmd); 00285 } 00286 00287 lbdev->ioctlfd = f; 00288 lbdev->ioctldata = arg; 00289 //kill_proc(lbdev->pid, SIGIO, 1); 00290 00291 mutex_unlock(&lbdev->lock_ioctl); 00292 wake_up_interruptible(&lbdev->wait_virt_poll); 00293 while(1) { 00294 ret = wait_event_interruptible_timeout(lbdev->wait_ioctl, 00295 lbdev->ioctlcmd == ULONG_MAX, HZ); 00296 dprintk2("fake-ioctl wait (%lu) returned: %d/%lu\n", cmd, 00297 ret, lbdev->ioctlcmd); 00298 if(ret >= 0 && lbdev->ioctlcmd == ULONG_MAX) 00299 break; 00300 if(cmd == DVBLB_CMD_CLOSE) { 00301 dprintk("Received a signal." 00302 " Resending DVBLB_CLOSE message\n"); 00303 wait_event_timeout(lbdev->wait_ioctl, 00304 lbdev->ioctlcmd == ULONG_MAX, HZ); 00305 break; 00306 } 00307 if(ret < 0 || lbdev->filemap[0] == NULL) { 00308 /* userspace driver has closed it would be nice if we 00309 could do something about it here */ 00310 printk("dvblb_fake_ioctl interrupted: %lu\n", 00311 lbdev->ioctlcmd); 00312 mutex_unlock(&lbdev->lock_fake_ioctl); 00313 return -1; 00314 } 00315 dprintk("dvbloopback: timeout waiting for userspace\n"); 00316 } 00317 00318 if (mutex_lock_interruptible(&lbdev->lock_ioctl)) { 00319 mutex_unlock(&lbdev->lock_fake_ioctl); 00320 return -ERESTARTSYS; 00321 } 00322 //printk("Woke up on cmd: %u\n", cmd); 00323 if (lbdev->ioctlcmd != ULONG_MAX) { 00324 mutex_unlock(&lbdev->lock_ioctl); 00325 mutex_unlock(&lbdev->lock_fake_ioctl); 00326 printk("dvblb_fake_ioctl failed: %lu\n",lbdev->ioctlcmd); 00327 return -1; 00328 } 00329 00330 if (cmd < DVBLB_MAX_CMDS || ! (cmd & IOC_IN)){ 00331 #if DVB_API_VERSION >=5 00332 if ((cmd == FE_GET_PROPERTY)) { 00333 tvps = (struct dtv_properties __user *)(lbdev->ioctlretdata + sizeof(int)); 00334 _ioctllen = lbdev->ioctllen + (tvps->num * sizeof(struct dtv_property)); 00335 memcpy(arg, lbdev->ioctlretdata + sizeof(int), _ioctllen); 00336 tvps = (struct dtv_properties __user *)arg; 00337 tvps->props = (struct dtv_property __user *)(arg + lbdev->ioctllen); 00338 } 00339 else 00340 #endif 00341 memcpy(arg, lbdev->ioctlretdata + sizeof(int), lbdev->ioctllen); 00342 } 00343 00344 ret = lbdev->ioctlretval; 00345 mutex_unlock(&lbdev->lock_ioctl); 00346 mutex_unlock(&lbdev->lock_fake_ioctl); 00347 return ret; 00348 } 00349 00350 static int dvblb_open(struct inode *inode, struct file *f) 00351 { 00352 struct dvb_device *dvbdev; 00353 struct dvblb_devinfo *lbdev; 00354 int ret, map; 00355 00356 dvbdev = (struct dvb_device *) f->private_data; 00357 if (dvbdev == NULL) { 00358 printk("Failed to open device\n"); 00359 return -EFAULT; 00360 } 00361 lbdev = (struct dvblb_devinfo *)dvbdev->priv; 00362 if (lbdev == NULL) { 00363 printk("Failed to find private data during open\n"); 00364 return -EFAULT; 00365 } 00366 dprintk("dvblb_open %d%s%d\n", lbdev->parent->adapter.num, 00367 dnames[dvbdev->type], dvbdev->id); 00368 00369 if(dvbdev->id == 0) { 00370 /* This is the looped device */ 00371 struct dvblb_custommsg ci; 00372 00373 /*must update private_data so we can map fds properly */ 00374 if (mutex_lock_interruptible(&lbdev->lock_ioctl)) 00375 return -ERESTARTSYS; 00376 map = get_new_filemap(lbdev, 0); 00377 if (map < 0) { 00378 printk("dvblb_open %s: Failed to set filemap\n", 00379 dnames[dvbdev->type]); 00380 mutex_unlock(&lbdev->lock_ioctl); 00381 return -EBUSY; 00382 } 00383 try_module_get(THIS_MODULE); 00384 lbdev->dbgfilemap[map] = f; 00385 f->private_data = &lbdev->filemap[map]; 00386 lbdev->poll_waiting = 0; 00387 mutex_unlock(&lbdev->lock_ioctl); 00388 dprintk("dvblb_open %s: fd: %d\n", dnames[dvbdev->type], map); 00389 if (lbdev->forward_dev) { 00390 ret = dvblb_forward_open(lbdev, inode, f); 00391 if(ret < 0) { 00392 module_put(THIS_MODULE); 00393 lbdev->filemap[map] = NULL; 00394 } 00395 return ret; 00396 } 00397 00398 if (lbdev->pid == -1) { 00399 module_put(THIS_MODULE); 00400 lbdev->filemap[map] = NULL; 00401 return -EFAULT; 00402 } 00403 ci.type = DVBLB_OPEN; 00404 ci.u.mode = f->f_flags; 00405 ret = dvblb_fake_ioctl(lbdev, &lbdev->filemap[map], 00406 DVBLB_CMD_OPEN, &ci); 00407 if(ret < 0) { 00408 module_put(THIS_MODULE); 00409 lbdev->filemap[map] = NULL; 00410 } 00411 00412 return ret; 00413 } 00414 /* This is the userspace control device */ 00415 if(lbdev->forward_dev) 00416 return -EFAULT; 00417 ret = dvb_generic_open(inode, f); 00418 if (ret >= 0) { 00419 lbdev->pid = current->pid; 00420 lbdev->ioctlcmd = ULONG_MAX; 00421 lbdev->ioctllen = 0; 00422 mutex_lock(&lbdev->lock_ioctl); 00423 memset(lbdev->filemap, 0, sizeof(lbdev->filemap)); 00424 map = get_new_filemap(lbdev, 1); 00425 if (map < 0) { 00426 printk("dvblb_open %s: Failed to set filemap\n", 00427 dnames[dvbdev->type]); 00428 mutex_unlock(&lbdev->lock_ioctl); 00429 return -EBUSY; 00430 } 00431 try_module_get(THIS_MODULE); 00432 f->private_data = &lbdev->filemap[map]; 00433 lbdev->dbgfilemap[map] = f; 00434 lbdev->poll_waiting = 0; 00435 mutex_unlock(&lbdev->lock_ioctl); 00436 dprintk("dvblb_open %s: fd: %d\n", dnames[dvbdev->type], map); 00437 } 00438 return ret; 00439 } 00440 00441 static int dvblb_release(struct inode *inode, struct file *f) 00442 { 00443 struct dvb_device *dvbdev, **filemap; 00444 struct dvblb_devinfo *lbdev; 00445 int ret; 00446 00447 filemap = (struct dvb_device **) f->private_data; 00448 if(filemap == NULL) { 00449 printk("Failed to locate device\n"); 00450 return -EFAULT; 00451 } 00452 dvbdev = *filemap; 00453 if (dvbdev == NULL) { 00454 printk("Failed to locate device\n"); 00455 return -EFAULT; 00456 } 00457 lbdev = (struct dvblb_devinfo *)dvbdev->priv; 00458 if (lbdev == NULL) { 00459 printk("Failed to find private data during close\n"); 00460 return -EFAULT; 00461 } 00462 dprintk("dvblb_release %d%s%d fd:%d\n", lbdev->parent->adapter.num, 00463 dnames[dvbdev->type], 00464 dvbdev->id, find_filemap(lbdev, filemap)); 00465 00466 if(dvbdev->id == 0) { 00467 /* This is the looped device */ 00468 struct dvblb_custommsg ci; 00469 00470 if (lbdev->forward_dev) { 00471 ret = dvblb_forward_release(lbdev, f); 00472 *filemap = NULL; 00473 goto out; 00474 } 00475 00476 if (lbdev->pid == -1) { 00477 ret = -EFAULT; 00478 goto out; 00479 } 00480 ci.type = DVBLB_CLOSE; 00481 ret = dvblb_fake_ioctl(lbdev, filemap, DVBLB_CMD_CLOSE, &ci); 00482 if (mutex_lock_interruptible(&lbdev->lock_ioctl)) { 00483 ret = -ERESTARTSYS; 00484 goto out; 00485 } 00486 lbdev->poll_waiting = 0; 00487 *filemap = NULL; 00488 mutex_unlock(&lbdev->lock_ioctl); 00489 goto out; 00490 } 00491 /* This is the userspace control device */ 00492 *filemap = NULL; 00493 f->private_data = dvbdev; 00494 ret = dvb_generic_release(inode, f); 00495 if (ret < 0) { 00496 goto out; 00497 } 00498 lbdev->pid = -1; 00499 if (mutex_lock_interruptible(&lbdev->lock_buffer)) { 00500 ret = -ERESTARTSYS; 00501 goto out; 00502 } 00503 if (lbdev->buffer) { 00504 rvfree(lbdev->buffer, lbdev->buflen*N_BUFFS); 00505 lbdev->buffer = NULL; 00506 } 00507 mutex_unlock(&lbdev->lock_buffer); 00508 ret = 0; 00509 goto out; 00510 00511 out: 00512 module_put(THIS_MODULE); 00513 return ret; 00514 } 00515 00516 static ssize_t dvblb_write(struct file *f, const char *buf, 00517 size_t count, loff_t *offset) 00518 { 00519 struct dvb_device *dvbdev, **filemap; 00520 struct dvblb_devinfo *lbdev; 00521 00522 filemap = (struct dvb_device **) f->private_data; 00523 if(filemap == NULL) { 00524 printk("Failed to locate device\n"); 00525 return -EFAULT; 00526 } 00527 dvbdev = *filemap; 00528 if (dvbdev == NULL) { 00529 printk("Failed to locate device\n"); 00530 return -EFAULT; 00531 } 00532 lbdev = (struct dvblb_devinfo *)dvbdev->priv; 00533 if (lbdev == NULL) { 00534 printk("Failed to find private data during close\n"); 00535 return -EFAULT; 00536 } 00537 dprintk3("dvblb_write %d%s%d fd:%d\n", lbdev->parent->adapter.num, 00538 dnames[dvbdev->type], 00539 dvbdev->id, find_filemap(lbdev, filemap)); 00540 00541 if (lbdev->forward_dev) 00542 return dvblb_forward_write(lbdev, f, buf, count, offset); 00543 00544 printk("Write not supported on loopback device\n"); 00545 return -EFAULT; 00546 } 00547 00548 static ssize_t dvblb_read (struct file *f, char * buf, size_t count, loff_t *offset) 00549 { 00550 struct dvb_device *dvbdev, **filemap; 00551 struct dvblb_devinfo *lbdev; 00552 #if DVB_API_VERSION >=5 00553 struct dtv_properties *tvps = NULL; 00554 #endif 00555 unsigned long int _count = 0; 00556 00557 filemap = (struct dvb_device **) f->private_data; 00558 if(filemap == NULL) { 00559 printk("Failed to locate device\n"); 00560 return -EFAULT; 00561 } 00562 dvbdev = *filemap; 00563 if (dvbdev == NULL) { 00564 printk("Failed to find device\n"); 00565 return -EFAULT; 00566 } 00567 lbdev = (struct dvblb_devinfo *)dvbdev->priv; 00568 if (lbdev == NULL) { 00569 printk("Failed to find private data during read\n"); 00570 return -EFAULT; 00571 } 00572 dprintk3("dvblb_read %d%s%d fd:%d\n", lbdev->parent->adapter.num, 00573 dnames[dvbdev->type], 00574 dvbdev->id, find_filemap(lbdev, filemap)); 00575 if(dvbdev->id == 0) { 00576 /* This is the looped device */ 00577 struct dvblb_custommsg ci; 00578 00579 if (lbdev->forward_dev) 00580 return dvblb_forward_read(lbdev, f, buf, count, offset); 00581 00582 ci.type = DVBLB_READ; 00583 ci.u.count = count; 00584 if (lbdev->pid == -1) 00585 return -EFAULT; 00586 if (mutex_lock_interruptible(&lbdev->lock_buffer)) 00587 return -ERESTARTSYS; 00588 if(dvblb_fake_ioctl(lbdev, filemap, DVBLB_CMD_READ, &ci) < 0 || 00589 ! lbdev->buffer) { 00590 mutex_unlock(&lbdev->lock_buffer); 00591 return 0; 00592 } 00593 if (ci.u.count > lbdev->buflen) 00594 ci.u.count = lbdev->buflen; 00595 if (copy_to_user(buf, lbdev->buffer, ci.u.count)) { 00596 mutex_unlock(&lbdev->lock_buffer); 00597 return -EFAULT; 00598 } 00599 mutex_unlock(&lbdev->lock_buffer); 00600 dprintk3("Read %ld bytes\n", (long)ci.u.count); 00601 return ci.u.count; 00602 } else { 00603 /* This is the userspace control device */ 00604 /* We pass ioctls to the userspace driver this way */ 00605 unsigned long int cmd, base_size, size; 00606 base_size = sizeof(cmd) + sizeof(lbdev->ioctlfd); 00607 if (mutex_lock_interruptible(&lbdev->lock_ioctl)) 00608 return -ERESTARTSYS; 00609 00610 cmd = lbdev->ioctlcmd; 00611 size = (lbdev->ioctllen > sizeof(int)) ? lbdev->ioctllen : 00612 sizeof(int); 00613 #if DVB_API_VERSION >=5 00614 if ((cmd == FE_GET_PROPERTY) || (cmd == FE_SET_PROPERTY)){ 00615 tvps = (struct dtv_properties __user *)(lbdev->ioctldata); 00616 _count = size + base_size + (tvps->num * sizeof(struct dtv_property)); 00617 } 00618 else 00619 #endif 00620 _count = base_size + size; 00621 00622 if (count < _count || lbdev->ioctlcmd == ULONG_MAX || 00623 lbdev->ioctl_already_read) { 00624 mutex_unlock(&lbdev->lock_ioctl); 00625 return -EFAULT; 00626 } 00627 if (cmd == ULONG_MAX) 00628 count = base_size; 00629 else 00630 count = _count; 00631 00632 if (copy_to_user(buf, &cmd, sizeof(cmd))) { 00633 mutex_unlock(&lbdev->lock_ioctl); 00634 return -EFAULT; 00635 } 00636 00637 if (copy_to_user(buf + sizeof(cmd), &lbdev->ioctlfd, 00638 sizeof(lbdev->ioctlfd))) { 00639 mutex_unlock(&lbdev->lock_ioctl); 00640 return -EFAULT; 00641 } 00642 00643 if (lbdev->ioctllen == 0) { 00644 if (copy_to_user(buf + base_size, &lbdev->ioctldata, 00645 size)) { 00646 mutex_unlock(&lbdev->lock_ioctl); 00647 return -EFAULT; 00648 } 00649 00650 } else { 00651 #if DVB_API_VERSION >=5 00652 if ((cmd == FE_GET_PROPERTY) || (cmd == FE_SET_PROPERTY)) { 00653 if (copy_to_user(buf + base_size + size, tvps->props, 00654 tvps->num * sizeof(struct dtv_property))) { 00655 mutex_unlock(&lbdev->lock_ioctl); 00656 return -EFAULT; 00657 } 00658 tvps->props = (struct dtv_property __user *)(buf + base_size + size); 00659 } 00660 #endif 00661 if (copy_to_user(buf + base_size, lbdev->ioctldata, 00662 size)) { 00663 mutex_unlock(&lbdev->lock_ioctl); 00664 return -EFAULT; 00665 } 00666 } 00667 lbdev->ioctl_already_read = 1; 00668 mutex_unlock(&lbdev->lock_ioctl); 00669 return count; 00670 } 00671 } 00672 00673 /* The following routine gets called by dvblb_usercopy (used to be 00674 dvb_generic_ioctl) which is called by dvblb_ioctl for device-0. It is 00675 used to forward ioctl commands back to the userspace application 00676 */ 00677 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,38) 00678 static int dvblb_looped_ioctl(struct file *f, 00679 unsigned int cmd, void *parg) 00680 #else 00681 static int dvblb_looped_ioctl(struct inode *inode, struct file *f, 00682 unsigned int cmd, void *parg) 00683 #endif 00684 { 00685 int ret; 00686 struct dvb_device *dvbdev, **filemap; 00687 struct dvblb_devinfo *lbdev; 00688 00689 filemap = (struct dvb_device **) f->private_data; 00690 if(filemap == NULL) { 00691 printk("Failed to locate device\n"); 00692 return -EFAULT; 00693 } 00694 dvbdev = *filemap; 00695 if (dvbdev == NULL) { 00696 printk("Failed to locate device\n"); 00697 return -EFAULT; 00698 } 00699 lbdev = (struct dvblb_devinfo *)dvbdev->priv; 00700 if (lbdev == NULL) { 00701 printk("Failed to find private data during ioctl\n"); 00702 return -EFAULT; 00703 } 00704 dprintk("dvblb_ioctl %d%s%d fd:%d\n", lbdev->parent->adapter.num, 00705 dnames[dvbdev->type], 00706 dvbdev->id, find_filemap(lbdev, filemap)); 00707 ret = dvblb_fake_ioctl(lbdev, filemap, cmd, parg); 00708 return ret; 00709 } 00710 00711 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,38) 00712 static long dvblb_ioctl(struct file *f, 00713 unsigned int cmd, unsigned long arg) 00714 #else 00715 static int dvblb_ioctl(struct inode *inode, struct file *f, 00716 unsigned int cmd, unsigned long arg) 00717 #endif 00718 { 00719 void * parg = (void *)arg; 00720 struct dvb_device *dvbdev, **filemap; 00721 struct dvblb_devinfo *lbdev; 00722 #if DVB_API_VERSION >=5 00723 struct dtv_properties *tvps; 00724 #endif 00725 int size; 00726 00727 filemap = (struct dvb_device **) f->private_data; 00728 if(filemap == NULL) { 00729 printk("Failed to locate device\n"); 00730 return -EFAULT; 00731 } 00732 dvbdev = *filemap; 00733 if (dvbdev == NULL) { 00734 printk("Failed to locate device\n"); 00735 return -EFAULT; 00736 } 00737 lbdev = (struct dvblb_devinfo *)dvbdev->priv; 00738 if (lbdev == NULL) { 00739 printk("Failed to find private data during ioctl\n"); 00740 return -EFAULT; 00741 } 00742 if(dvbdev->id == 0) { 00743 /* This is the looped device */ 00744 if (lbdev->forward_dev) 00745 return dvblb_forward_ioctl(lbdev, f, cmd, arg); 00746 00747 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,38) 00748 return dvblb_usercopy (f, cmd, arg, 00749 dvbdev->kernel_ioctl); 00750 #else 00751 return dvblb_usercopy (inode, f, cmd, arg, 00752 dvbdev->kernel_ioctl); 00753 #endif 00754 } 00755 /* This is the userspace control device */ 00756 dprintk2("dvblb_ioctl %d%s%d fd:%d cmd:%x\n",lbdev->parent->adapter.num, 00757 dnames[dvbdev->type], 00758 dvbdev->id, find_filemap(lbdev, filemap), cmd); 00759 if (cmd == DVBLB_CMD_ASYNC) { 00760 /* async command return */ 00761 int pos, i; 00762 struct dvblb_pollmsg pollmsg; 00763 if (copy_from_user(&pollmsg, parg, 00764 sizeof(struct dvblb_pollmsg))) { 00765 printk("Failed to read pollmsg from ioctl\n"); 00766 return -EFAULT; 00767 } 00768 if (mutex_lock_interruptible(&lbdev->lock_ioctl)) 00769 return -ERESTARTSYS; 00770 if (pollmsg.count == 0) { 00771 /* Send wakeup to all waiting polls */ 00772 /* 00773 printk("Waking all fds on %s\n", dnames[dvbdev->type]); 00774 */ 00775 lbdev->poll_waiting = 0; 00776 for (i = 0; i < DVBLB_MAXFD; i++) 00777 if(lbdev->filemap[i] != 0) 00778 wake_up_interruptible( 00779 &lbdev->wait_poll[i]); 00780 } 00781 for (i = 0; i < pollmsg.count; i++) { 00782 pos = find_filemap(lbdev, pollmsg.file[i]); 00783 if (pos >= 0) { 00784 /* 00785 printk("Sending wakeup command to %p, pos:%d\n", 00786 lbdev->filemap[pos], pos); 00787 */ 00788 lbdev->poll_waiting &= ~(1<<pos); 00789 wake_up_interruptible(&lbdev->wait_poll[pos]); 00790 } 00791 } 00792 mutex_unlock(&lbdev->lock_ioctl); 00793 return 0; 00794 } 00795 if (mutex_lock_interruptible(&lbdev->lock_ioctl)) 00796 return -ERESTARTSYS; 00797 if (cmd != lbdev->ioctlcmd) { 00798 // Incorrect response 00799 printk("dvbloopback: Got wrong response (%u != %lu)\n", cmd, 00800 lbdev->ioctlcmd); 00801 mutex_unlock(&lbdev->lock_ioctl); 00802 return 0; 00803 } 00804 if (cmd < DVBLB_MAX_CMDS) 00805 size = sizeof(int) + sizeof(struct dvblb_custommsg); 00806 else if (cmd & IOC_IN) 00807 size = sizeof(int); 00808 else 00809 size = sizeof(int) + _IOC_SIZE(cmd); 00810 00811 if (copy_from_user(lbdev->ioctlretdata, parg, size)) { 00812 mutex_unlock(&lbdev->lock_ioctl); 00813 return -EFAULT; 00814 } 00815 #if DVB_API_VERSION >=5 00816 if (cmd == FE_GET_PROPERTY) 00817 { 00818 tvps = (struct dtv_properties __user *)(lbdev->ioctlretdata + sizeof(int)); 00819 if (copy_from_user(lbdev->ioctlretdata + size, tvps->props, 00820 tvps->num * sizeof(struct dtv_property))) 00821 { 00822 mutex_unlock(&lbdev->lock_ioctl); 00823 return -EFAULT; 00824 } 00825 tvps = (struct dtv_properties __user *)(lbdev->ioctlretdata + sizeof(int)); 00826 tvps->props = (struct dtv_property __user *)(lbdev->ioctlretdata + size); 00827 dprintk("%s() copy_from_user: cmd %u\n", __func__, tvps->props[0].cmd); 00828 } 00829 #endif 00830 00831 lbdev->ioctlretval = *(int *)lbdev->ioctlretdata; 00832 lbdev->ioctlcmd = ULONG_MAX; 00833 mutex_unlock(&lbdev->lock_ioctl); 00834 wake_up(&lbdev->wait_ioctl); 00835 return 0; 00836 } 00837 00838 static int dvblb_mmap(struct file *f, struct vm_area_struct *vma) 00839 { 00840 struct dvb_device *dvbdev, **filemap; 00841 struct dvblb_devinfo *lbdev; 00842 unsigned long start = (unsigned long)vma->vm_start; 00843 long size = vma->vm_end - vma->vm_start; 00844 unsigned long page, pos; 00845 00846 filemap = (struct dvb_device **) f->private_data; 00847 if(filemap == NULL) { 00848 printk("Failed to locate device\n"); 00849 return -EFAULT; 00850 } 00851 dvbdev = *filemap; 00852 if (dvbdev == NULL) { 00853 printk("Failed to locate device\n"); 00854 return -EFAULT; 00855 } 00856 lbdev = (struct dvblb_devinfo *)dvbdev->priv; 00857 if (lbdev == NULL) { 00858 printk("Failed to find private data during mmap\n"); 00859 return -EFAULT; 00860 } 00861 dprintk("dvblb_mmap %d%s%d fd:%d\n", lbdev->parent->adapter.num, 00862 dnames[dvbdev->type], 00863 dvbdev->id, find_filemap(lbdev, filemap)); 00864 if(dvbdev->id == 0) { 00865 /* This is the looped device */ 00866 if (lbdev->forward_dev) 00867 return dvblb_forward_mmap(lbdev, f, vma); 00868 00869 return -EINVAL; 00870 } 00871 /* This is the userspace control device */ 00872 if (!size) 00873 return -EINVAL; 00874 if (mutex_lock_interruptible(&lbdev->lock_buffer)) 00875 return -ERESTARTSYS; 00876 if (lbdev->buffer) 00877 rvfree(lbdev->buffer, lbdev->buflen*N_BUFFS); 00878 lbdev->buflen=size; 00879 lbdev->buffer=rvmalloc(lbdev->buflen*N_BUFFS); 00880 00881 if (lbdev->buffer == NULL) { 00882 mutex_unlock(&lbdev->lock_buffer); 00883 return -EINVAL; 00884 } 00885 00886 if (size > (((N_BUFFS * lbdev->buflen) + PAGE_SIZE - 1) & ~(PAGE_SIZE - 1))) { 00887 mutex_unlock(&lbdev->lock_buffer); 00888 return -EINVAL; 00889 } 00890 00891 pos = (unsigned long)lbdev->buffer; 00892 while (size > 0) { 00893 page = vmalloc_to_pfn((void *)pos); 00894 if (remap_pfn_range(vma, start, page, PAGE_SIZE, 00895 PAGE_SHARED)) { 00896 mutex_unlock(&lbdev->lock_buffer); 00897 return -EAGAIN; 00898 } 00899 start += PAGE_SIZE; 00900 pos += PAGE_SIZE; 00901 size -= PAGE_SIZE; 00902 } 00903 mutex_unlock(&lbdev->lock_buffer); 00904 00905 return 0; 00906 } 00907 00908 static unsigned int dvblb_poll(struct file *f, struct poll_table_struct *wait) 00909 { 00910 struct dvb_device *dvbdev, **filemap; 00911 struct dvblb_devinfo *lbdev; 00912 00913 filemap = (struct dvb_device **) f->private_data; 00914 if(filemap == NULL) { 00915 printk("Failed to locate device\n"); 00916 return -EFAULT; 00917 } 00918 dvbdev = *filemap; 00919 if (dvbdev == NULL) { 00920 printk("Failed to locate device\n"); 00921 return -EFAULT; 00922 } 00923 lbdev = (struct dvblb_devinfo *)dvbdev->priv; 00924 if (lbdev == NULL) { 00925 printk("Failed to find private data during poll\n"); 00926 return -EFAULT; 00927 } 00928 dprintk3("dvblb_poll %d%s%d: fd:%d\n", lbdev->parent->adapter.num, 00929 dnames[dvbdev->type], 00930 dvbdev->id, find_filemap(lbdev, filemap)); 00931 if(dvbdev->id == 0) { 00932 /* This is the looped device */ 00933 struct dvblb_custommsg ci; 00934 int ret; 00935 int do_poll = 1; 00936 int pos; 00937 00938 if (lbdev->forward_dev) 00939 return dvblb_forward_poll(lbdev, f, wait); 00940 00941 if (lbdev->pid == -1) { 00942 printk("no pid found!\n"); 00943 return -EFAULT; 00944 } 00945 pos = find_filemap(lbdev, filemap); 00946 if (pos == -1) { 00947 printk("dvblb_poll %s: Didn't find filemap!\n", 00948 dnames[dvbdev->type]); 00949 return -EFAULT; 00950 } 00951 poll_wait(f, &lbdev->wait_poll[pos], wait); 00952 00953 if (mutex_lock_interruptible(&lbdev->lock_ioctl)) 00954 return -ERESTARTSYS; 00955 if(lbdev->poll_waiting & (1 << pos)) 00956 do_poll = 0; 00957 else /* need to set it before the fake_ioctl to prevent race */ 00958 lbdev->poll_waiting |= (1 << pos); 00959 mutex_unlock(&lbdev->lock_ioctl); 00960 00961 if(do_poll) { 00962 ci.type = DVBLB_POLL; 00963 ci.u.mode = (wait == NULL) ? 0 : 1; 00964 ret = dvblb_fake_ioctl(lbdev, filemap, DVBLB_CMD_POLL, 00965 &ci); 00966 if(ret != 0) { 00967 if (mutex_lock_interruptible(&lbdev->lock_ioctl)) 00968 return -ERESTARTSYS; 00969 lbdev->poll_waiting &= ~(1 << pos); 00970 mutex_unlock(&lbdev->lock_ioctl); 00971 if(ret < 0) 00972 return ret; 00973 } 00974 if (ci.u.mode & POLLIN) 00975 ci.u.mode |= POLLRDNORM; 00976 } else { 00977 ci.u.mode = 0; 00978 /* 00979 printk("skipping poll on %p (%d)\n", f, pos); 00980 */ 00981 } 00982 dprintk3("dvblb_poll %d%s%d: fd:%d returned: %d\n", 00983 lbdev->parent->adapter.num, 00984 dnames[dvbdev->type], dvbdev->id, pos, ci.u.mode); 00985 return(ci.u.mode); 00986 } 00987 00988 poll_wait(f, &lbdev->wait_virt_poll, wait); 00989 if (mutex_lock_interruptible(&lbdev->lock_ioctl)) 00990 return -ERESTARTSYS; 00991 if (lbdev->ioctlcmd != ULONG_MAX && ! lbdev->ioctl_already_read) { 00992 mutex_unlock(&lbdev->lock_ioctl); 00993 return (POLLIN | POLLPRI | POLLRDNORM); 00994 } 00995 mutex_unlock(&lbdev->lock_ioctl); 00996 return 0; 00997 } 00998 00999 static struct file_operations dvbdev_looped_fops = { 01000 .owner = THIS_MODULE, 01001 .open = dvblb_open, 01002 .release = dvblb_release, 01003 .read = dvblb_read, 01004 .write = dvblb_write, 01005 .poll = dvblb_poll, 01006 .mmap = dvblb_mmap, 01007 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,38) 01008 .unlocked_ioctl = dvblb_ioctl, 01009 #else 01010 .ioctl = dvblb_ioctl, 01011 #endif 01012 }; 01013 01014 static struct dvb_device dvbdev_looped = { 01015 .priv = NULL, 01016 .users = DVBLB_MAXFD, 01017 .readers = 1, 01018 .writers = 1, 01019 .fops = &dvbdev_looped_fops, 01020 .kernel_ioctl = dvblb_looped_ioctl, 01021 }; 01022 01023 static struct file_operations dvbdev_userspace_fops = { 01024 .owner = THIS_MODULE, 01025 .open = dvblb_open, 01026 .release = dvblb_release, 01027 .read = dvblb_read, 01028 .write = dvblb_write, 01029 .poll = dvblb_poll, 01030 .mmap = dvblb_mmap, 01031 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,38) 01032 .unlocked_ioctl = dvblb_ioctl, 01033 #else 01034 .ioctl = dvblb_ioctl, 01035 #endif 01036 }; 01037 01038 static struct dvb_device dvbdev_userspace = { 01039 .priv = NULL, 01040 .users = 1, 01041 .readers = 1, 01042 .writers = 1, 01043 .fops = &dvbdev_userspace_fops, 01044 .kernel_ioctl = dvblb_looped_ioctl, 01045 }; 01046 01047 static int create_lb_dev(struct dvblb *dvblb, int dev_idx, int type) 01048 { 01049 int ret; 01050 struct dvblb_devinfo *lbdev = &dvblb->devinfo[dev_idx]; 01051 01052 // create loopback device (will be frontend0) 01053 ret = dvb_register_device(&dvblb->adapter, &lbdev->lb_dev, 01054 &dvbdev_looped, lbdev, type); 01055 if (ret != 0) { 01056 info("error registering device adapter%d", 01057 dvblb->adapter.num); 01058 return ret; 01059 } 01060 // create userspace device (will be frontend1) 01061 ret = dvb_register_device(&dvblb->adapter, &lbdev->user_dev, 01062 &dvbdev_userspace, lbdev, type); 01063 if (ret != 0) { 01064 info("error registering device adapter%d", 01065 dvblb->adapter.num); 01066 dvb_unregister_device(lbdev->lb_dev); 01067 return ret; 01068 } 01069 // initialize all data 01070 //lbdev->ioctldata=kmalloc(1024, GFP_KERNEL); 01071 //if(lbdev->ioctldata == NULL) 01072 //{ 01073 // dvb_unregister_device(lbdev->lb_dev); 01074 // dvb_unregister_device(lbdev->user_dev); 01075 // return -ENOMEM; 01076 //} 01077 lbdev->parent = dvblb; 01078 lbdev->ioctlretdata=kmalloc(5*1024, GFP_KERNEL); 01079 lbdev->pid = -1; 01080 lbdev->buffer = NULL; 01081 lbdev->buflen = 0; 01082 lbdev->ioctlcmd = ULONG_MAX; 01083 lbdev->ioctllen = 0; 01084 lbdev->ioctl_already_read = 1; 01085 lbdev->forward_dev = NULL; 01086 memset(lbdev->filemap, 0, sizeof(lbdev->filemap)); 01087 memset(lbdev->forwardmap, 0, sizeof(lbdev->forwardmap)); 01088 01089 lbdev->poll_waiting = 0; 01090 dvblb_init_procfs_device(dvblb, lbdev); 01091 01092 { 01093 int i; 01094 for(i = 0; i < DVBLB_MAXFD; i++) 01095 init_waitqueue_head(&lbdev->wait_poll[i]); 01096 } 01097 init_waitqueue_head(&lbdev->wait_virt_poll); 01098 init_waitqueue_head(&lbdev->wait_ioctl); 01099 mutex_init(&lbdev->lock_fake_ioctl); 01100 mutex_init(&lbdev->lock_ioctl); 01101 mutex_init(&lbdev->lock_buffer); 01102 dvblb->init |= (1 << dev_idx); 01103 return 0; 01104 } 01105 01106 static int destroy_lb_dev(struct dvblb *dvblb, int dev_idx) 01107 { 01108 if (0 == (dvblb->init & (1 << dev_idx))) 01109 return 0; 01110 dvb_unregister_device(dvblb->devinfo[dev_idx].lb_dev); 01111 dvb_unregister_device(dvblb->devinfo[dev_idx].user_dev); 01112 if (dvblb->devinfo[dev_idx].buffer) 01113 rvfree(dvblb->devinfo[dev_idx].buffer, 01114 dvblb->devinfo[dev_idx].buflen*N_BUFFS); 01115 //kfree(lbdev->ioctldata); 01116 kfree(dvblb->devinfo[dev_idx].ioctlretdata); 01117 dvblb_remove_procfs(dvblb->devinfo[dev_idx].procfile, dvblb->procdir); 01118 dvblb->init &= ~(1 << dev_idx); 01119 return 0; 01120 } 01121 01122 static int destroy_lb_adapter(struct dvblb *dvblb) 01123 { 01124 destroy_lb_dev(dvblb, DVBLB_FRONTEND); 01125 destroy_lb_dev(dvblb, DVBLB_DEMUX); 01126 destroy_lb_dev(dvblb, DVBLB_DVR); 01127 destroy_lb_dev(dvblb, DVBLB_VIDEO); 01128 destroy_lb_dev(dvblb, DVBLB_AUDIO); 01129 destroy_lb_dev(dvblb, DVBLB_OSD); 01130 01131 dvblb_remove_procfs_adapter(dvblb); 01132 dvb_unregister_adapter(&dvblb->adapter); 01133 dvblb->init &= ~DVBLB_STATUS_ADAPTER; 01134 01135 return 0; 01136 } 01137 /**************************************************************************** 01138 * init stuff 01139 ****************************************************************************/ 01140 01141 01142 MODULE_AUTHOR("Alan Nisota"); 01143 MODULE_DESCRIPTION("DVB loopback device."); 01144 MODULE_LICENSE("GPL"); 01145 MODULE_VERSION( DVBLOOPBACK_VERSION ); 01146 01147 static struct platform_device *dvblb_basedev; 01148 01149 static int __init dvblb_init(void) 01150 { 01151 int i,ret, failed; 01152 i=0; 01153 failed=0; 01154 01155 dvblb_init_procfs(); 01156 01157 info("frontend loopback driver v"DVBLOOPBACK_VERSION); 01158 if (num_adapters < 1 || num_adapters > DVBLB_MAX_ADAPTERS) { 01159 printk("dvbloopback: param num_adapters=%d. Must be between" 01160 " 1 and %d\n", num_adapters, DVBLB_MAX_ADAPTERS); 01161 return -EFAULT; 01162 } 01163 printk("dvbloopback: registering %d adapters\n", num_adapters); 01164 01165 dvblb_global = kmalloc(sizeof(struct dvblb) * num_adapters, GFP_KERNEL); 01166 if (dvblb_global == NULL) 01167 return -ENOMEM; 01168 for(i=0; i < num_adapters; i++) 01169 dvblb_global[i].init = 0; 01170 01171 dvblb_basedev = platform_device_alloc("dvbloopback", -1); 01172 if (!dvblb_basedev) { 01173 kfree(dvblb_global); 01174 return -ENOMEM; 01175 } 01176 ret = platform_device_add(dvblb_basedev); 01177 if (ret) { 01178 platform_device_put(dvblb_basedev); 01179 kfree(dvblb_global); 01180 return ret; 01181 } 01182 for(i=0; i < num_adapters; i++) { 01183 struct dvblb *this_adptr = &dvblb_global[i]; 01184 // register new adapter (happens in main driver) 01185 if (wrap_dvb_reg_adapter(&this_adptr->adapter, 01186 "DVB-LOOPBACK", NULL) < 0) { 01187 failed = 1; 01188 break; 01189 } 01190 this_adptr->init |= DVBLB_STATUS_ADAPTER; 01191 01192 // NOTE: we use the next line to fetch the start-node for the 01193 // the adapter linked-list. However it relies on us grabbing it 01194 // before another device is added (i.e. this adapter must be the 01195 // last on the list. 01196 if (0 == i) { 01197 this_adptr->adapter_ll = 01198 this_adptr->adapter.list_head.next; 01199 } else { 01200 this_adptr->adapter_ll = dvblb_global[0].adapter_ll; 01201 } 01202 this_adptr->link = -1; 01203 dvblb_init_procfs_adapter(this_adptr); 01204 01205 ret = create_lb_dev(this_adptr, DVBLB_FRONTEND, 01206 DVB_DEVICE_FRONTEND); 01207 if (ret != 0) { 01208 info("Failed to add loopback for adapter"); 01209 failed = 1; 01210 break; 01211 } 01212 01213 ret = create_lb_dev(this_adptr, DVBLB_DEMUX, 01214 DVB_DEVICE_DEMUX); 01215 if (ret != 0) { 01216 info("Failed to add loopback for adapter"); 01217 failed = 1; 01218 break; 01219 } 01220 01221 ret = create_lb_dev(this_adptr, DVBLB_DVR, 01222 DVB_DEVICE_DVR); 01223 if (ret != 0) { 01224 info("Failed to add loopback for adapter"); 01225 failed = 1; 01226 break; 01227 } 01228 01229 ret = create_lb_dev(this_adptr, DVBLB_VIDEO, 01230 DVB_DEVICE_VIDEO); 01231 if (ret != 0) { 01232 info("Failed to add loopback for adapter"); 01233 failed = 1; 01234 break; 01235 } 01236 01237 ret = create_lb_dev(this_adptr, DVBLB_AUDIO, 01238 DVB_DEVICE_AUDIO); 01239 if (ret != 0) { 01240 info("Failed to add loopback for adapter"); 01241 failed = 1; 01242 break; 01243 } 01244 01245 ret = create_lb_dev(this_adptr, DVBLB_OSD, 01246 DVB_DEVICE_OSD); 01247 if (ret != 0) { 01248 info("Failed to add loopback for adapter"); 01249 failed = 1; 01250 break; 01251 } 01252 } 01253 01254 if (failed) { 01255 for(i = 0; i < num_adapters; i++) { 01256 if(0 == dvblb_global[i].init) 01257 break; 01258 destroy_lb_adapter(&dvblb_global[i]); 01259 } 01260 platform_device_unregister(dvblb_basedev); 01261 kfree(dvblb_global); 01262 return -EFAULT; 01263 } 01264 return 0; 01265 } 01266 01267 static void __exit cleanup_dvblb_module(void) 01268 { 01269 int i; 01270 info("Unregistering ca loopback devices"); 01271 for(i = 0; i < num_adapters; i++) { 01272 if(0 == dvblb_global[i].init) 01273 break; 01274 destroy_lb_adapter(&dvblb_global[i]); 01275 } 01276 platform_device_unregister(dvblb_basedev); 01277 kfree(dvblb_global); 01278 dvblb_uninit_procfs(); 01279 } 01280 01281 module_init(dvblb_init); 01282 module_exit(cleanup_dvblb_module);