/* Simplified 'hack' so that CCcam can work with up to 8 DVB adapters on a PC Linux
*
* Compile as follows:
* gcc -fbuiltin -fomit-frame-pointer -fPIC -shared -o ca.so ca.c -ldl
*
* then run CCcam with a shell script like:
*
* #!/bin/sh
* LD_PRELOAD=./ca.so ; export LD_PRELOAD
* /var/emu/CCcam.x86 -dv -t
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*/
#define DEBUG
#if defined(__GNUC__) && !defined(__STRICT_ANSI__)
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define MAX_DVB_ADAPTERS 8
#define MAX_DEMUXERS 64
/* BSDI has this functionality, but not define ) */
#if defined(RTLD_NEXT)
#define REAL_LIBC RTLD_NEXT
#else
#define REAL_LIBC ((void *) -1L)
#endif
static unsigned char sscw[MAX_DVB_ADAPTERS][16];
static int cafds[MAX_DVB_ADAPTERS] = { -1 };
int sendcw(int cardnum)
{
unsigned char buffer[18];
struct sockaddr_in saddr;
int len;
buffer[0]= cardnum & 0xff;
buffer[1]= ((cardnum >> & 0xFF);
memcpy(&buffer[2], sscw[cardnum], 16);
int ecmso = socket(PF_INET,SOCK_DGRAM,IPPROTO_UDP);
fcntl(ecmso,F_SETFL,O_NONBLOCK);
bzero(&saddr,sizeof(saddr));
saddr.sin_family = AF_INET;
saddr.sin_port = htons(9000);
saddr.sin_addr.s_addr = inet_addr("127.0.0.1");
len = connect(ecmso,(struct sockaddr *) &saddr,sizeof(saddr));
if (len<0)
{
printf("ca.so: Cannot connect UDP socket\n");
close(ecmso);
return 0;
}
if ( send(ecmso,buffer, 18, 0) == -1 )
{
printf("ca.so: Sendcw Error sending cw\n");
}
close(ecmso);
return 1;
}
static int cactl (int card, int request, void *argp)
{
ca_descr_t *ca = argp;
ca_caps_t *cp = argp;
ca_pid_t *cpd = argp;
switch (request)
{
case CA_GET_CAP:
cp->slot_num = MAX_DVB_ADAPTERS;
cp->slot_type = CA_CI|CA_CI_LINK;
cp->descr_num = 1;
cp->descr_type = CA_ECD|CA_NDS|CA_DSS;
return 0;
case CA_SET_DESCR:
{
char filename[25];
sprintf(filename,"/tmp/cw%d",card);
int caf = open(filename, O_WRONLY|O_CREAT,S_IROTH|S_IRUSR);
#ifdef DEBUG
printf("Card: %d Parity: %d, Index: %d, CW: %02hhx%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx\n",
card, ca->parity, ca->index, ca->cw[0], ca->cw[1], ca->cw[2], ca->cw[3], ca->cw[4], ca->cw[5], ca->cw[6], ca->cw[7]);
#endif
if (!ca->parity)
memcpy(&sscw[card][0], &(ca->cw[0]), ;
else
memcpy(&sscw[card][8], &(ca->cw[0]), ;
write (caf, &sscw[card][0], 16);
close (caf);
sendcw(card);
}
break;
}
return 0;
}
int
ioctl (int fd, int request, void *a)
{
int i, j;
static int (*func) (int, int, void *) = NULL;
if (!func)
func = (int (*) (int, int, void *)) dlsym (REAL_LIBC, "ioctl");
for (i=0;i {
if (fd == cafds)
{
return cactl (i, request, a);
}
}
return (*func) (fd, request, a);
}
int open (const char *pathname, int flags, ...)
{
static int sInited = 0;
if (!sInited)
{
memset(cafds, 0xff, sizeof(cafds));
sInited = 1;
}
static int (*func) (const char *, int, mode_t) = NULL;
va_list args;
mode_t mode;
char buffer[255];
int i, j;
if (!func)
func = (int (*) (const char *, int, mode_t)) dlsym (REAL_LIBC, "open");
va_start (args, flags);
mode = va_arg (args, mode_t);
va_end (args);
if (strlen(pathname) > 40)
exit(0);
for (i=0;i {
char name[256];
sprintf(name, "/dev/dvb/adapter0/ca%d", i);
if (!strcmp (pathname, name))
{
#ifdef DEBUG
printf ("hijacking open %s\n", name);
#endif
cafds = (*func) ("/dev/zero", flags, mode);
return (cafds);
}
sprintf(name, "/dev/dvb/adapter0/demux%d", i);
if (!strcmp(pathname, name))
{
//#ifdef DEBUG
// printf ("******** hijacking open %s\n", name);
//#endif
sprintf(name, "/dev/dvb/adapter%d/demux0", i);
int fd = (*func) (name, flags, mode);
return fd;
}
}
return (*func) (pathname, flags, mode);
}
int close (int fd)
{
int i, j;
static int (*func) (int) = NULL;
if (!func)
func = (int (*) (int)) dlsym (REAL_LIBC, "close");
for (i=0;i {
if (fd == cafds)
{
#ifdef DEBUG
printf ("closing ca%d\n", i);
#endif
cafds = -1;
}
}
return (*func) (fd);
}
char *fgets(char *s, int size, FILE *stream)
{
static char * (*func) (char *, int, FILE *) = NULL;
if (!func)
func = (char * (*) (char *, int, FILE *)) dlsym (REAL_LIBC, "fgets");
char *outS = (*func) (s, size, stream);
if (outS)
{
if (strstr(outS, "vendor_id : ") == outS)
{
/*
strstr("cache size\t: 2048 KB\n", "STB04xxx") = NULL
strstr("cache size\t: 2048 KB\n", "relook400") = NULL
strstr("cache size\t: 2048 KB\n", "relook100s") = NULL
strstr("cache size\t: 2048 KB\n", "STBx25xx") = NULL
strstr("cache size\t: 2048 KB\n", "MIPS 4KEc") = NULL
strstr("cache size\t: 2048 KB\n", "Brcm7401") = NULL
strstr("cache size\t: 2048 KB\n", "Brcm4380") = NULL
strstr("cache size\t: 2048 KB\n", "tgs100") = NULL
*/
#ifdef DEBUG
printf ("old: '%s'\n", outS);
#endif
strcpy(outS, "vendor_id : Brcm4380");
#ifdef DEBUG
printf ("new: '%s'\n", outS);
#endif
}
}
return outS;
}
#endif