|
SASC
DVBSoftCAM
|
00001 /* 00002 DVBLoopback 00003 Copyright Alan Nisota 2006 00004 00005 This file is part of DVBLoopback. 00006 00007 DVBLoopback is free software; you can redistribute it and/or modify 00008 it under the terms of the GNU General Public License as published by 00009 the Free Software Foundation; either version 2 of the License, or 00010 (at your option) any later version. 00011 00012 DVBLoopback is distributed in the hope that it will be useful, 00013 but WITHOUT ANY WARRANTY; without even the implied warranty of 00014 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00015 GNU General Public License for more details. 00016 00017 You should have received a copy of the GNU General Public License 00018 along with DVBLoopback; if not, write to the Free Software 00019 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 00020 */ 00021 #include <stdlib.h> 00022 #include <stdio.h> 00023 #include <fcntl.h> 00024 #include <pthread.h> 00025 #include <errno.h> 00026 #include <sys/mman.h> 00027 #include <sys/poll.h> 00028 #include <sys/ioctl.h> 00029 #include <sys/stat.h> 00030 #include <signal.h> 00031 #include <string.h> 00032 #include <getopt.h> 00033 #include <unistd.h> 00034 #include <sched.h> 00035 #include <netinet/in.h> 00036 00037 #include "process_req.h" 00038 00039 #define DBG_NAME dnames[pc->type] 00040 #define PLUGIN_ID (2*(pc->type-3)) 00041 00042 #define DVB_DEVICE_FRONTEND 3 00043 #define DVB_DEVICE_DEMUX 4 00044 #define DVB_DEVICE_DVR 5 00045 #define DVB_DEVICE_CA 6 00046 00047 #define MEMSIZE 100000 00048 00049 int find_free(struct parser_cmds *pc) 00050 { 00051 int i; 00052 for(i=0; i < DVBLB_MAXFD; i++) 00053 if(pc->realfd_ll[i].kernfd == 0) 00054 return i; 00055 return -1; 00056 } 00057 00058 struct poll_ll *find_pos(struct parser_cmds *pc, void *filp) 00059 { 00060 struct list_head *ptr; 00061 struct poll_ll *entry; 00062 list_for_each(ptr, &pc->used_list) { 00063 entry = list_entry(ptr, struct poll_ll); 00064 if (entry->kernfd == filp) 00065 return entry; 00066 } 00067 return NULL; 00068 } 00069 00070 // The poll_handler routine is used to trap a SIGPOLL 00071 // which is sent to restart the poll-loop if something changes 00072 void poll_handler(int num) {} 00073 void *poll_loop(void * parm) 00074 { 00075 struct parser_cmds *pc = (struct parser_cmds *)parm; 00076 int count; 00077 struct pollfd ufd[DVBLB_MAXFD+1]; 00078 00079 struct list_head *ptr; 00080 struct poll_ll *entry; 00081 00082 struct dvblb_pollmsg msg; 00083 00084 pthread_mutex_lock(&pc->poll_mutex); 00085 while(1) { 00086 int ret; 00087 pthread_cond_wait(&pc->poll_cond, &pc->poll_mutex); 00088 do { 00089 ret = 1; 00090 count = 0; 00091 list_for_each(ptr, &pc->used_list) { 00092 entry = list_entry(ptr, struct poll_ll); 00093 if(entry->poll) { 00094 ufd[count].fd = entry->fd; 00095 ufd[count].events = POLLIN; 00096 ufd[count].revents = 0; 00097 entry->pfd = &ufd[count]; 00098 count++; 00099 } 00100 } 00101 if (count > 0) { 00102 pthread_mutex_unlock(&pc->poll_mutex); 00103 ret = poll(ufd, count, -1); 00104 pthread_mutex_lock(&pc->poll_mutex); 00105 } 00106 } while(ret <= 0); 00107 msg.count = 0; 00108 list_for_each(ptr, &pc->used_list) { 00109 entry = list_entry(ptr, struct poll_ll); 00110 if(entry->pfd && entry->kernfd && entry->poll && entry->pfd->revents) { 00111 msg.file[msg.count++] = entry->kernfd; 00112 entry->pfd = NULL; 00113 entry->poll = 0; 00114 } 00115 } 00116 if (msg.count) { 00117 ioctl(pc->virtfd, DVBLB_CMD_ASYNC, &msg); 00118 } 00119 } 00120 return NULL; 00121 } 00122 00123 static cmdret_t do_cmd(struct list_head *list, struct parser_cmds *pc, 00124 struct poll_ll *fdptr, int *ret, 00125 unsigned long int cmd, unsigned char *data) 00126 { 00127 cmdret_t result = CMD_NOCHANGE; 00128 struct list_head *ptr; 00129 struct cmd_list *entry; 00130 list_for_each(ptr, list) { 00131 entry = list_entry(ptr, struct cmd_list); 00132 if(entry->cmd) 00133 entry->cmd(pc, fdptr, &result, ret, cmd, data); 00134 if(result & CMD_STOP) 00135 break; 00136 } 00137 return result; 00138 } 00139 00140 void get_thread_priority(char *str) 00141 { 00142 struct sched_param param; 00143 int priority; 00144 int policy; 00145 int ret; 00146 sleep(1); 00147 /* scheduling parameters of target thread */ 00148 ret = pthread_getschedparam (pthread_self(), &policy, ¶m); 00149 /* sched_priority contains the priority of the thread */ 00150 priority = param.sched_priority; 00151 sprintf(str, "The thread scheduling parameters indicate:\n" 00152 "policy = %d\npriority = %d\n", policy, param.sched_priority); 00153 } 00154 00155 //We can't allow blocking reads, since they could continue to stall even after 00156 //The requesting app is terminated. So we must emulate a blocking read by 00157 //alwaysw opening with 'O_NONBLOCK', and doing a poll/read pair to fill the 00158 //buffer 00159 static int read_block(struct parser_cmds *pc, int fd, unsigned char *buf, 00160 int numbytes) { 00161 int bytes = 0, ret; 00162 struct pollfd ufd[2]; 00163 ufd[0].fd = fd; 00164 ufd[0].events = POLLIN | POLLPRI; 00165 ufd[1].fd = pc->virtfd; 00166 ufd[1].events = POLLIN | POLLPRI; 00167 //printf("Start read on dvr t:%lu\n", pthread_self()); 00168 //wrPtr must always be an integer number of packets! 00169 while( bytes < numbytes) { 00170 dprintf1("Starting loop %d of %d\n", bytes, numbytes); 00171 //poll dvr fd and dvblb fd 00172 ufd[0].revents = 0; 00173 ufd[1].revents = 0; 00174 if(poll(&ufd[0], 2, -1) < 0 || ufd[1].revents) { 00175 //We should abort 00176 dprintf0("Aborting block read!\n"); 00177 if(! errno) 00178 errno = EFAULT; 00179 return -1; 00180 } 00181 ret = read(fd, buf+bytes, numbytes-bytes); 00182 if (ret <= 0) { 00183 break; 00184 } 00185 bytes += ret; 00186 } 00187 if(bytes) 00188 return bytes; 00189 else 00190 return ret; 00191 } 00192 00193 void *forward_data(void *parm) 00194 { 00195 struct parser_cmds *pc = (struct parser_cmds *)parm; 00196 char realdev[256]; 00197 char virtdev[256]; 00198 char str[256]; 00199 char *buf; 00200 void *file; 00201 int pos; 00202 00203 struct poll_ll *fdptr; 00204 00205 int size, ret; 00206 cmdret_t result; 00207 unsigned char ioctldata[1024], *start, *ioctldatastart; 00208 unsigned long int cmd; 00209 struct pollfd poll_fds; 00210 size_t memsize = MEMSIZE; 00211 00212 int offset = sizeof(unsigned long int) + sizeof (void *) - sizeof(int); 00213 if (offset < 0) { 00214 fprintf(stderr, "int is larger than long_int! that can't be right.\n"); 00215 exit(-1); 00216 } 00217 00218 if(pc->type == DVB_DEVICE_DVR) { 00219 memsize = pc->common->buffersize; 00220 } else if(pc->type == DVB_DEVICE_DEMUX) { 00221 memsize = pc->common->buffersize >> 3; 00222 } 00223 00224 start = ioctldata + offset; 00225 ioctldatastart = ioctldata + offset + sizeof(int); 00226 00227 sprintf(realdev, "/dev/dvb/adapter%d/%s0", pc->common->real_adapt, 00228 dnames[pc->type]); 00229 sprintf(virtdev, "/dev/dvb/adapter%d/%s1", pc->common->virt_adapt, 00230 dnames[pc->type]); 00231 00232 pc->virtfd = open(virtdev, O_RDWR); 00233 if(pc->virtfd < 0) { 00234 dprintf0("Could not open %s. Error was: %d\n", virtdev, errno); 00235 perror("Open failed\n"); 00236 exit(-1); 00237 } 00238 poll_fds.fd = pc->virtfd; 00239 00240 pc->mmap=(unsigned char *)mmap(0, memsize, PROT_READ|PROT_WRITE, 00241 MAP_SHARED, pc->virtfd, 0); 00242 buf = (char *)malloc(memsize); 00243 00244 if (! pc->mmap || ! buf) { 00245 fprintf(stderr, "Failed to execute mmap!\n"); 00246 exit(-1); 00247 } 00248 pthread_mutex_init(&pc->poll_mutex, NULL); 00249 pthread_cond_init(&pc->poll_cond, NULL); 00250 INIT_LIST_HEAD(&pc->used_list); 00251 bzero(&pc->realfd_ll, sizeof(pc->realfd_ll)); 00252 pthread_create(&pc->pollthread, &default_attr, poll_loop, pc); 00253 00254 if(pc->type == DVB_DEVICE_DVR) { 00255 struct sched_param param; 00256 param.sched_priority = sched_get_priority_max(SCHED_FIFO); 00257 pthread_setschedparam(pthread_self(), SCHED_FIFO, ¶m); 00258 } 00259 get_thread_priority(str); 00260 dprintf0("Starting thread on %s\n%s", virtdev, str); 00261 00262 //inform master thread that we're done 00263 pthread_mutex_lock(&pc->common->cond_lock); 00264 pc->common->cond_count--; 00265 pthread_cond_signal(&pc->common->cond); 00266 pthread_mutex_unlock(&pc->common->cond_lock); 00267 00268 //main loop 00269 while(1) { 00270 int poll_signal = 0; 00271 poll_fds.events = POLLIN; 00272 poll_fds.revents = 0; 00273 do { 00274 ret = poll(&poll_fds, 1, -1); 00275 if(ret < 0) 00276 perror("Poll failed"); 00277 } while (!(poll_fds.revents & POLLIN)); 00278 size=read(pc->virtfd, ioctldata, 1024); 00279 if(size < (int)(sizeof(long int)+ sizeof(void *))) { 00280 dprintf0("Didn't read enough data\n"); 00281 exit(-1); 00282 } 00283 cmd = *((unsigned long int *)ioctldata); 00284 file = *(void **)(ioctldata + sizeof(cmd)); 00285 if (cmd < DVBLB_MAX_CMDS) { 00286 struct dvblb_custommsg *ci; 00287 struct pollfd ufd; 00288 ci = (struct dvblb_custommsg *)ioctldatastart; 00289 dprintf3("Got custom command: %d\n", ci->type); 00290 switch(ci->type) { 00291 case DVBLB_OPEN: 00292 pos = find_free(pc); 00293 if (pos < 0) { 00294 dprintf0("Too Many files open!\n"); 00295 exit(-1); 00296 ret = -1; 00297 break; 00298 } 00299 fdptr = &pc->realfd_ll[pos]; 00300 fdptr->flags = ci->u.mode; 00301 result = do_cmd(&pc->pre_open, pc, fdptr, &ret, cmd, ioctldatastart); 00302 if(!(result & CMD_SKIPCALL)) 00303 fdptr->fd = open(realdev, fdptr->flags | O_NONBLOCK); 00304 if(!(result & CMD_SKIPPOST)) 00305 do_cmd(&pc->post_open, pc, fdptr, &ret, cmd, ioctldatastart); 00306 if (fdptr->fd < 0) { 00307 ret = fdptr->fd; 00308 dprintf1("Open failed. fd: %d\n", fdptr->fd); 00309 break; 00310 } 00311 fdptr->kernfd = file; 00312 fdptr->pfd = NULL; 00313 fdptr->poll = 0; 00314 00315 pthread_mutex_lock(&pc->poll_mutex); 00316 list_add(&fdptr->list, &pc->used_list); 00317 pthread_mutex_unlock(&pc->poll_mutex); 00318 00319 ret = 0; 00320 dprintf1("Opened fd: %d=%d mode: %o\n", pos, fdptr->fd, fdptr->flags); 00321 break; 00322 case DVBLB_CLOSE: 00323 fdptr = find_pos(pc, file); 00324 if (fdptr == NULL) { 00325 ret = -1; 00326 break; 00327 } 00328 //need to kill any polls before closing thread 00329 pthread_mutex_lock(&pc->poll_mutex); 00330 list_del(&fdptr->list); 00331 pthread_mutex_unlock(&pc->poll_mutex); 00332 pthread_kill(pc->pollthread, SIGPOLL); 00333 00334 result = do_cmd(&pc->pre_close, pc, fdptr, &ret, cmd, ioctldatastart); 00335 if(!(result & CMD_SKIPCALL)) { 00336 ret = close(fdptr->fd); 00337 if (ret < 0) { 00338 perror("Close failed:"); 00339 } 00340 } 00341 if(!(result & CMD_SKIPPOST)) 00342 do_cmd(&pc->post_close, pc, fdptr, &ret, cmd, ioctldatastart); 00343 fdptr->kernfd = 0; 00344 ret = 0; 00345 dprintf1("Closed fd: %d ret: 0\n", fdptr->fd); 00346 break; 00347 case DVBLB_READ: 00348 fdptr = find_pos(pc, file); 00349 if (fdptr == NULL) { 00350 ret = -1; 00351 break; 00352 } 00353 if(ci->u.count > memsize) { 00354 dprintf2("Too many bytes: %zu > %zu\n", ci->u.count, memsize); 00355 ci->u.count = memsize; 00356 } 00357 { 00358 int orig_cnt = ci->u.count; 00359 result = do_cmd(&pc->pre_read, pc, fdptr, &ret, cmd, ioctldatastart); 00360 if(!(result & CMD_SKIPCALL)) { 00361 if(fdptr->flags & O_NONBLOCK) 00362 ret = read(fdptr->fd, pc->mmap, ci->u.count); 00363 else 00364 ret = read_block(pc, fdptr->fd, pc->mmap, ci->u.count); 00365 if (ret < 0) 00366 ret = -errno; 00367 } 00368 if(!(result & CMD_SKIPPOST)) 00369 do_cmd(&pc->post_read, pc, fdptr, &ret, cmd, ioctldatastart); 00370 dprintf3("Read %d bytes (requested %zu or %d)\n", 00371 ret, ci->u.count, orig_cnt); 00372 } 00373 ci->u.count = ret; 00374 break; 00375 case DVBLB_WRITE: 00376 ret = -1; 00377 break; 00378 case DVBLB_POLL: 00379 fdptr = find_pos(pc, file); 00380 if (fdptr == NULL) { 00381 ret = -1; 00382 break; 00383 } 00384 result = do_cmd(&pc->pre_poll, pc, fdptr, &ret, cmd, ioctldatastart); 00385 if(!(result & CMD_SKIPCALL)) { 00386 ufd.fd = fdptr->fd; 00387 ufd.events = POLLIN | POLLPRI; 00388 ret = poll(&ufd, 1, 0); 00389 if(ret > 0 && !(ufd.revents & POLLIN)) 00390 ret = 0; 00391 //Only start the poll thread if there isn't data on the real dev 00392 //if (ret == 0) 00393 // poll_signal = 1; 00394 ci->u.mode = ufd.revents; 00395 } 00396 if(!(result & CMD_SKIPPOST)) 00397 do_cmd(&pc->post_poll, pc, fdptr, &ret, cmd, ioctldatastart); 00398 if (ret == 0) { 00399 poll_signal = 1; 00400 fdptr->poll = 1; 00401 } 00402 dprintf3("Poll mode:%o ret:%d - sig: %d\n", 00403 ci->u.mode, ret, poll_signal); 00404 break; 00405 } 00406 } else { 00407 dprintf2("Got command %lu (size: %d)\n", cmd & 0xff, size); 00408 fdptr = find_pos(pc, file); 00409 if (fdptr == NULL) { 00410 ret = -1; 00411 } else { 00412 result = do_cmd(&pc->pre_ioctl, pc, fdptr, &ret, cmd, ioctldatastart); 00413 if(!(result & CMD_SKIPCALL)) { 00414 if(_IOC_SIZE(cmd)) { 00415 ret = ioctl(fdptr->fd, cmd, ioctldatastart); 00416 } else { 00417 ret = ioctl(fdptr->fd, cmd, *(int *)ioctldatastart); 00418 } 00419 if(ret < 0) 00420 ret = -errno; 00421 } 00422 dprintf2("ioctl on (%d) returned: %d\n", fdptr->fd, ret); 00423 if(!(result & CMD_SKIPPOST)) 00424 do_cmd(&pc->post_ioctl, pc, fdptr, &ret, cmd, ioctldatastart); 00425 } 00426 } 00427 *(int *)start = ret; 00428 pthread_mutex_lock(&pc->poll_mutex); 00429 // Need to protect ioctl call in addition to the cond 00430 ioctl(pc->virtfd, cmd, start); 00431 if(poll_signal) { 00432 pthread_kill(pc->pollthread, SIGPOLL); // restart poll if already polling 00433 pthread_cond_signal(&pc->poll_cond); //otherwise start polling 00434 } 00435 pthread_mutex_unlock(&pc->poll_mutex); 00436 } 00437 } 00438 00439 static struct parser_cmds * init_device(struct common_data *common, int type) 00440 { 00441 struct parser_cmds *pc; 00442 pc = (struct parser_cmds *)malloc(sizeof(struct parser_cmds)); 00443 if(! pc) 00444 return NULL; 00445 bzero(pc, sizeof(struct parser_cmds)); 00446 common->cond_count++; //this doesn't need to be protected (no threads yet) 00447 pc->common = common; 00448 pc->type = type; 00449 00450 INIT_LIST_HEAD(&pc->pre_open); 00451 INIT_LIST_HEAD(&pc->post_open); 00452 00453 INIT_LIST_HEAD(&pc->pre_close); 00454 INIT_LIST_HEAD(&pc->post_close); 00455 00456 INIT_LIST_HEAD(&pc->pre_read); 00457 INIT_LIST_HEAD(&pc->post_read); 00458 00459 INIT_LIST_HEAD(&pc->pre_poll); 00460 INIT_LIST_HEAD(&pc->post_poll); 00461 00462 INIT_LIST_HEAD(&pc->pre_ioctl); 00463 INIT_LIST_HEAD(&pc->post_ioctl); 00464 return pc; 00465 } 00466 00467 void launch_processors(struct parser_adpt *pc_all) 00468 { 00469 //pthread_attr_t attr; 00470 signal(SIGPOLL, poll_handler); 00471 //pthread_attr_init(&attr); 00472 //pthread_attr_setscope( &attr, PTHREAD_SCOPE_SYSTEM ); 00473 //pthread_attr_setinheritsched(&attr, PTHREAD_EXPLICIT_SCHED); 00474 //pthread_attr_setschedpolicy( &attr, SCHED_FIFO ); 00475 if(pc_all->frontend) { 00476 pthread_create(&pc_all->frontend->thread, &default_attr, forward_data, 00477 pc_all->frontend); 00478 } 00479 if(pc_all->demux) { 00480 pthread_create(&pc_all->demux->thread, &default_attr, forward_data, 00481 pc_all->demux); 00482 } 00483 if(pc_all->dvr) { 00484 pthread_create(&pc_all->dvr->thread, &default_attr, forward_data, 00485 pc_all->dvr); 00486 } 00487 if(pc_all->ca) { 00488 pthread_create(&pc_all->ca->thread, &default_attr, forward_data, 00489 pc_all->ca); 00490 } 00491 } 00492 00493 static void kill_parser(struct parser_cmds *pc) 00494 { 00495 if(pc->pollthread) { 00496 pthread_kill(pc->pollthread, SIGTERM); 00497 pthread_join(pc->pollthread, NULL); 00498 } 00499 if(pc->thread) { 00500 pthread_kill(pc->thread, SIGTERM); 00501 pthread_join(pc->thread, NULL); 00502 } 00503 } 00504 void shutdown_parser(struct parser_adpt *pc_all) 00505 { 00506 if(pc_all->ca) 00507 kill_parser(pc_all->ca); 00508 if(pc_all->dvr) 00509 kill_parser(pc_all->dvr); 00510 if(pc_all->demux) 00511 kill_parser(pc_all->demux); 00512 if(pc_all->frontend) 00513 kill_parser(pc_all->frontend); 00514 } 00515 00516 void init_parser(struct parser_adpt *pc_all, struct common_data *common) 00517 { 00518 char realdev[255], virtdev[255]; 00519 struct stat st; 00520 00521 int types[] = {DVB_DEVICE_FRONTEND, DVB_DEVICE_DEMUX, DVB_DEVICE_DVR, -1}; 00522 struct parser_cmds **ptr; 00523 int i; 00524 00525 bzero(pc_all, sizeof(struct parser_adpt)); 00526 for (i = 0; types[i] != -1; i++) { 00527 sprintf(realdev, "/dev/dvb/adapter%d/%s0", common->real_adapt, 00528 dnames[types[i]]); 00529 sprintf(virtdev, "/dev/dvb/adapter%d/%s0", common->virt_adapt, 00530 dnames[types[i]]); 00531 if (stat(realdev, &st) != 0 || stat(virtdev, &st) != 0) { 00532 continue; 00533 } 00534 ptr = (&pc_all->frontend) + i;// * sizeof(struct parser_cmds *); 00535 *ptr = init_device(common, types[i]); 00536 } 00537 } 00538