mirror of
https://github.com/DigitalDevices/dddvb.git
synced 2023-10-10 13:37:43 +02:00
Merge branch 'internal'
This commit is contained in:
commit
100aa25176
200
apps/modtest.c
200
apps/modtest.c
@ -866,7 +866,7 @@ int mci_set_output(int fd, uint8_t connector, uint8_t nchannels, uint8_t unit,
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
fprintf(stderr,"Setting DVBT Modulator output to %s, %d channels, power %f%s\n",
|
fprintf(stderr,"Setting DVB Modulator output to %s, %d channels, power %f%s\n",
|
||||||
con, nchannels, (double)power/100, un );
|
con, nchannels, (double)power/100, un );
|
||||||
|
|
||||||
return mci_cmd(fd,&msg_output);
|
return mci_cmd(fd,&msg_output);
|
||||||
@ -934,19 +934,32 @@ int mci_set_channels(int fd, uint32_t freq, uint8_t nchan, uint8_t standard,
|
|||||||
snprintf(stand, 24, "MOD_STANDARD_DVBT_5");
|
snprintf(stand, 24, "MOD_STANDARD_DVBT_5");
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case MOD_STANDARD_DVBC_8:
|
||||||
|
snprintf(stand, 24, "MOD_STANDARD_DVBC_8");
|
||||||
|
break;
|
||||||
|
|
||||||
|
case MOD_STANDARD_DVBC_7:
|
||||||
|
snprintf(stand, 24, "MOD_STANDARD_DVBC_7");
|
||||||
|
break;
|
||||||
|
|
||||||
|
case MOD_STANDARD_DVBC_6:
|
||||||
|
snprintf(stand, 24, "MOD_STANDARD_DVBC_6");
|
||||||
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
fprintf(stderr,"unknown standard in channels setup\n");
|
fprintf(stderr,"unknown standard in channels setup\n");
|
||||||
return -1;
|
return -1;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
}
|
}
|
||||||
fprintf(stderr,"Setting DVBT Modulator channels to %d HZ, %d channels, %s\n",
|
fprintf(stderr,"Setting DVB Modulator channels to %d HZ, %d channels, %s\n",
|
||||||
freq, nchan, stand);
|
freq, nchan, stand);
|
||||||
|
|
||||||
return mci_cmd(fd,&msg_channels);
|
return mci_cmd(fd,&msg_channels);
|
||||||
}
|
}
|
||||||
|
|
||||||
int mci_set_channels_simple(int adapt, uint32_t freq, uint8_t nchan)
|
int mci_set_channels_simple(int adapt, enum fe_delivery_system delsys,
|
||||||
|
uint32_t freq, uint8_t nchan)
|
||||||
{
|
{
|
||||||
|
|
||||||
char fn[128];
|
char fn[128];
|
||||||
@ -958,8 +971,18 @@ int mci_set_channels_simple(int adapt, uint32_t freq, uint8_t nchan)
|
|||||||
fprintf(stderr, "Could not open %s\n", fn);
|
fprintf(stderr, "Could not open %s\n", fn);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
switch(delsys){
|
||||||
|
case SYS_DVBC_ANNEX_A:
|
||||||
|
re = mci_set_channels(fd, freq, nchan, MOD_STANDARD_DVBC_8, 0, 0);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case SYS_DVBT:
|
||||||
re = mci_set_channels(fd, freq, nchan, MOD_STANDARD_DVBT_8, 0, 0);
|
re = mci_set_channels(fd, freq, nchan, MOD_STANDARD_DVBT_8, 0, 0);
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
re = -1;
|
||||||
|
}
|
||||||
close(fd);
|
close(fd);
|
||||||
return re;
|
return re;
|
||||||
}
|
}
|
||||||
@ -971,15 +994,11 @@ int mci_set_stream( int fd, uint8_t stream, uint8_t channel, uint8_t standard,
|
|||||||
uint8_t puncture_rate, uint8_t constellation,
|
uint8_t puncture_rate, uint8_t constellation,
|
||||||
uint16_t cell_identifier)
|
uint16_t cell_identifier)
|
||||||
{
|
{
|
||||||
struct mci_command msg_stream = {
|
struct mci_command msg_stream;
|
||||||
.mod_command = MOD_SETUP_STREAM,
|
|
||||||
.mod_channel = 0,
|
|
||||||
.mod_stream = 0,
|
|
||||||
.mod_setup_stream = {
|
|
||||||
.standard = MOD_STANDARD_DVBC_8,
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
|
memset(&msg_stream,0,sizeof(msg_stream));
|
||||||
|
|
||||||
|
msg_stream.mod_command = MOD_SETUP_STREAM;
|
||||||
msg_stream.mod_channel = channel;
|
msg_stream.mod_channel = channel;
|
||||||
msg_stream.mod_stream = stream;
|
msg_stream.mod_stream = stream;
|
||||||
msg_stream.mod_setup_stream.standard = standard;
|
msg_stream.mod_setup_stream.standard = standard;
|
||||||
@ -990,125 +1009,63 @@ int mci_set_stream( int fd, uint8_t stream, uint8_t channel, uint8_t standard,
|
|||||||
msg_stream.mod_setup_stream.qam.modulation = modulation;
|
msg_stream.mod_setup_stream.qam.modulation = modulation;
|
||||||
if (rolloff)
|
if (rolloff)
|
||||||
msg_stream.mod_setup_stream.qam.rolloff = rolloff;
|
msg_stream.mod_setup_stream.qam.rolloff = rolloff;
|
||||||
|
if (fft_size)
|
||||||
msg_stream.mod_setup_stream.ofdm.fft_size = fft_size;
|
msg_stream.mod_setup_stream.ofdm.fft_size = fft_size;
|
||||||
|
if (guard_interval)
|
||||||
msg_stream.mod_setup_stream.ofdm.guard_interval = guard_interval;
|
msg_stream.mod_setup_stream.ofdm.guard_interval = guard_interval;
|
||||||
|
if (puncture_rate)
|
||||||
msg_stream.mod_setup_stream.ofdm.puncture_rate = puncture_rate;
|
msg_stream.mod_setup_stream.ofdm.puncture_rate = puncture_rate;
|
||||||
|
if (constellation)
|
||||||
msg_stream.mod_setup_stream.ofdm.constellation = constellation;
|
msg_stream.mod_setup_stream.ofdm.constellation = constellation;
|
||||||
if (cell_identifier)
|
if (cell_identifier)
|
||||||
msg_stream.mod_setup_stream.ofdm.cell_identifier = cell_identifier;
|
msg_stream.mod_setup_stream.ofdm.cell_identifier = cell_identifier;
|
||||||
|
|
||||||
fprintf(stderr,"Setting DVBT Stream %d to channel %d\n",stream, channel);
|
fprintf(stderr,"Setting DVB Stream %d to channel %d\n",stream, channel);
|
||||||
|
|
||||||
return mci_cmd(fd,&msg_stream);
|
return mci_cmd(fd,&msg_stream);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void set_dvbt_mods(int adapt, int chans, uint32_t start_freq, write_data *wd)
|
void set_dvb_mods(int adapt, int chans, uint32_t start_freq,
|
||||||
|
enum fe_delivery_system delsys, write_data *wd)
|
||||||
{
|
{
|
||||||
if ((mci_set_output_simple(adapt, chans) < 0)||
|
if ((mci_set_output_simple(adapt, chans) < 0)||
|
||||||
(mci_set_channels_simple(adapt, start_freq, chans)< 0))
|
(mci_set_channels_simple(adapt, delsys, start_freq, chans)< 0))
|
||||||
{
|
{
|
||||||
fprintf(stderr,"Error setting up DVBT Modulator\n");
|
fprintf(stderr,"Error setting up DVB Modulator\n");
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
wd->chans = chans;
|
wd->chans = chans;
|
||||||
wd->fd_out = (int *)malloc(chans*sizeof(int));
|
wd->fd_out = (int *)malloc(chans*sizeof(int));
|
||||||
memset(wd->fd_out,0,chans*sizeof(int));
|
memset(wd->fd_out,0,chans*sizeof(int));
|
||||||
|
|
||||||
for (int i = 0; i < chans; i++){
|
|
||||||
char *device;
|
|
||||||
int fd;
|
|
||||||
|
|
||||||
wd->tp[i].tpid = 1; // all the same transport stream id
|
|
||||||
wd->tp[i].delsys = SYS_DVBT;
|
|
||||||
wd->tp[i].freq = start_freq+8000000*i;
|
|
||||||
wd->tp[i].qam = 2;
|
|
||||||
wd->tp[i].symbolrate = 0;
|
|
||||||
wd->tp[i].bandwidth = 0;
|
|
||||||
wd->tp[i].guard = 0;
|
|
||||||
wd->tp[i].code_rate = 4;
|
|
||||||
wd->tp[i].trans_mode = MOD_STANDARD_DVBT_8;
|
|
||||||
|
|
||||||
device = malloc(sizeof(char)*40);
|
|
||||||
snprintf(device,35,"/dev/dvb/adapter%d/mod%d",adapt,i);
|
|
||||||
fd = open(device, O_RDWR);
|
|
||||||
if( fd < 0 )
|
|
||||||
{
|
|
||||||
fprintf(stderr,"Error opening %s : %s\n",device,strerror(errno));
|
|
||||||
free(device);
|
|
||||||
exit(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
mci_set_stream( fd, i, i, MOD_STANDARD_DVBT_8, 4, 0, 0, 0, 1, 0, 4, 2, 0);
|
|
||||||
close(fd);
|
|
||||||
free(device);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
||||||
|
|
||||||
//++++++++++++++++++++++++++++++++DVBC MOD++++++++++++++++++++++++++++++++
|
|
||||||
|
|
||||||
static int set_property(int fd, uint32_t cmd, uint32_t data)
|
|
||||||
{
|
|
||||||
struct dtv_property p;
|
|
||||||
struct dtv_properties c;
|
|
||||||
int ret;
|
|
||||||
|
|
||||||
p.cmd = cmd;
|
|
||||||
c.num = 1;
|
|
||||||
c.props = &p;
|
|
||||||
p.u.data = data;
|
|
||||||
ret = ioctl(fd, FE_SET_PROPERTY, &c);
|
|
||||||
if (ret < 0) {
|
|
||||||
fprintf(stderr, "FE_SET_PROPERTY returned %d\n", errno);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int set_input_bitrate(int fd, uint64_t data)
|
|
||||||
{
|
|
||||||
struct dtv_property p;
|
|
||||||
struct dtv_properties c;
|
|
||||||
int ret;
|
|
||||||
|
|
||||||
p.cmd = MODULATOR_INPUT_BITRATE;
|
|
||||||
c.num = 1;
|
|
||||||
c.props = &p;
|
|
||||||
p.u.data64 = data;
|
|
||||||
ret = ioctl(fd, FE_SET_PROPERTY, &c);
|
|
||||||
if (ret < 0) {
|
|
||||||
fprintf(stderr, "FE_SET_PROPERTY returned %d\n", errno);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
void set_dvbc_mods(int adapt, int chans, uint32_t start_freq, write_data *wd)
|
|
||||||
{
|
|
||||||
uint32_t freq = start_freq;
|
|
||||||
uint8_t qam = QAM_256;
|
|
||||||
uint32_t sym = 6900000;
|
|
||||||
|
|
||||||
wd->chans = chans;
|
|
||||||
wd->fd_out = (int *)malloc(chans*sizeof(int));
|
|
||||||
memset(wd->fd_out,0,chans*sizeof(int));
|
|
||||||
|
|
||||||
for (int i = 0; i < chans; i++){
|
for (int i = 0; i < chans; i++){
|
||||||
char *device;
|
char *device;
|
||||||
int fd;
|
int fd;
|
||||||
|
|
||||||
wd->tp[i].tpid = i;
|
wd->tp[i].tpid = i;
|
||||||
wd->tp[i].delsys = SYS_DVBC_ANNEX_A;
|
wd->tp[i].delsys = delsys;
|
||||||
wd->tp[i].freq = freq;
|
wd->tp[i].freq = start_freq+8000000*i;
|
||||||
wd->tp[i].qam = qam;
|
|
||||||
wd->tp[i].symbolrate = sym;
|
switch(delsys){
|
||||||
|
case SYS_DVBT:
|
||||||
|
wd->tp[i].qam = 2;
|
||||||
|
wd->tp[i].symbolrate = 0;
|
||||||
|
wd->tp[i].bandwidth = 0;
|
||||||
|
wd->tp[i].guard = 0;
|
||||||
|
wd->tp[i].code_rate = 4;
|
||||||
|
wd->tp[i].trans_mode = MOD_STANDARD_DVBT_8;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case SYS_DVBC_ANNEX_A:
|
||||||
|
wd->tp[i].qam = MOD_QAM_DVBC_256;
|
||||||
|
wd->tp[i].symbolrate = 6900000;
|
||||||
wd->tp[i].bandwidth = 0;
|
wd->tp[i].bandwidth = 0;
|
||||||
wd->tp[i].guard = 0;
|
wd->tp[i].guard = 0;
|
||||||
wd->tp[i].code_rate = 0;
|
wd->tp[i].code_rate = 0;
|
||||||
wd->tp[i].trans_mode = 0;
|
wd->tp[i].trans_mode = 0;
|
||||||
|
break;
|
||||||
|
}
|
||||||
device = malloc(sizeof(char)*40);
|
device = malloc(sizeof(char)*40);
|
||||||
snprintf(device,35,"/dev/dvb/adapter%d/mod%d",adapt,i);
|
snprintf(device,35,"/dev/dvb/adapter%d/mod%d",adapt,i);
|
||||||
fd = open(device, O_RDWR);
|
fd = open(device, O_RDWR);
|
||||||
@ -1118,26 +1075,29 @@ void set_dvbc_mods(int adapt, int chans, uint32_t start_freq, write_data *wd)
|
|||||||
free(device);
|
free(device);
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
if (set_property(fd, MODULATOR_FREQUENCY, freq) < 0){
|
|
||||||
fprintf(stderr,"setting freq %d failed\n",freq);
|
|
||||||
exit(1);
|
|
||||||
}
|
|
||||||
if (set_property(fd, MODULATOR_MODULATION, qam) < 0){
|
|
||||||
fprintf(stderr,"setting qam %d failed\n",qam);
|
|
||||||
exit(1);
|
|
||||||
}
|
|
||||||
if (set_property(fd, MODULATOR_SYMBOL_RATE, sym) < 0){
|
|
||||||
fprintf(stderr,"setting sym %d failed\n",sym);
|
|
||||||
exit(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (set_input_bitrate(fd, (DEFAULT_BIT_RATE_C << 32)) < 0){
|
int re= 0;
|
||||||
fprintf(stderr,"setting bitrate %d failed\n",
|
uint8_t stream_format = 4; //format is ransport stream
|
||||||
(int)DEFAULT_BIT_RATE_C);
|
uint8_t fft_size = wd->tp[i].trans_mode;
|
||||||
exit(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
freq += 8000000;
|
switch(delsys){
|
||||||
|
case SYS_DVBC_ANNEX_A:
|
||||||
|
re = mci_set_stream( fd, i, i, MOD_STANDARD_DVBC_8,
|
||||||
|
stream_format, wd->tp[i].symbolrate,
|
||||||
|
wd->tp[i].qam, 0, 0, 0, 0, 0, 0);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case SYS_DVBT:
|
||||||
|
re = mci_set_stream( fd, i, i, MOD_STANDARD_DVBT_8,
|
||||||
|
stream_format, 0, 0,
|
||||||
|
0, fft_size, wd->tp[i].guard,
|
||||||
|
wd->tp[i].code_rate, wd->tp[i].qam,
|
||||||
|
0);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
re = -1;
|
||||||
|
}
|
||||||
|
if (re < 0) fprintf(stderr,"ERROR setting stream\n");
|
||||||
close(fd);
|
close(fd);
|
||||||
free(device);
|
free(device);
|
||||||
}
|
}
|
||||||
@ -1296,9 +1256,9 @@ int main(int argc, char **argv)
|
|||||||
chans = ddevices.ndevs[adapt];
|
chans = ddevices.ndevs[adapt];
|
||||||
|
|
||||||
if (dvbt){
|
if (dvbt){
|
||||||
set_dvbt_mods(adapt, chans, start_freq, &wd);
|
set_dvb_mods(adapt, chans, start_freq, SYS_DVBT, &wd);
|
||||||
} else {
|
} else {
|
||||||
set_dvbc_mods(adapt, chans, start_freq, &wd);
|
set_dvb_mods(adapt, chans, start_freq, SYS_DVBC_ANNEX_A, &wd);
|
||||||
}
|
}
|
||||||
|
|
||||||
fprintf(stderr,"Reading from %s\n", filename);
|
fprintf(stderr,"Reading from %s\n", filename);
|
||||||
|
@ -237,6 +237,8 @@ static int slot_reset_xo2(struct dvb_ca_en50221 *ca, int slot)
|
|||||||
{
|
{
|
||||||
struct ddb_ci *ci = ca->data;
|
struct ddb_ci *ci = ca->data;
|
||||||
|
|
||||||
|
write_creg(ci, 0x00, 0x01);
|
||||||
|
msleep(300);
|
||||||
write_creg(ci, 0x01, 0x01);
|
write_creg(ci, 0x01, 0x01);
|
||||||
write_creg(ci, 0x04, 0x04);
|
write_creg(ci, 0x04, 0x04);
|
||||||
msleep(300);
|
msleep(300);
|
||||||
|
@ -6,7 +6,7 @@
|
|||||||
config DVB_MMAP
|
config DVB_MMAP
|
||||||
bool "Enable DVB memory-mapped API (EXPERIMENTAL)"
|
bool "Enable DVB memory-mapped API (EXPERIMENTAL)"
|
||||||
depends on DVB_CORE
|
depends on DVB_CORE
|
||||||
depends on VIDEO_V4L2=y || VIDEO_V4L2=DVB_CORE
|
depends on VIDEO_DEV=y || VIDEO_DEV=DVB_CORE
|
||||||
select VIDEOBUF2_VMALLOC
|
select VIDEOBUF2_VMALLOC
|
||||||
help
|
help
|
||||||
This option enables DVB experimental memory-mapped API, which
|
This option enables DVB experimental memory-mapped API, which
|
||||||
|
@ -4,7 +4,7 @@
|
|||||||
|
|
||||||
dvb-net-$(CONFIG_DVB_NET) := dvb_net.o
|
dvb-net-$(CONFIG_DVB_NET) := dvb_net.o
|
||||||
|
|
||||||
dvb-core-objs := dvbdev.o dmxdev.o dvb_demux.o dvb_filter.o \
|
dvb-core-objs := dvbdev.o dmxdev.o dvb_demux.o \
|
||||||
dvb_ca_en50221.o dvb_frontend.o \
|
dvb_ca_en50221.o dvb_frontend.o \
|
||||||
$(dvb-net-y) dvb_ringbuffer.o dvb_math.o
|
$(dvb-net-y) dvb_ringbuffer.o dvb_math.o
|
||||||
|
|
||||||
|
@ -158,6 +158,12 @@ struct dvb_ca_private {
|
|||||||
|
|
||||||
/* mutex serializing ioctls */
|
/* mutex serializing ioctls */
|
||||||
struct mutex ioctl_mutex;
|
struct mutex ioctl_mutex;
|
||||||
|
|
||||||
|
/* A mutex used when a device is disconnected */
|
||||||
|
struct mutex remove_mutex;
|
||||||
|
|
||||||
|
/* Whether the device is disconnected */
|
||||||
|
int exit;
|
||||||
};
|
};
|
||||||
|
|
||||||
static void dvb_ca_private_free(struct dvb_ca_private *ca)
|
static void dvb_ca_private_free(struct dvb_ca_private *ca)
|
||||||
@ -194,7 +200,7 @@ static void dvb_ca_en50221_thread_wakeup(struct dvb_ca_private *ca);
|
|||||||
static int dvb_ca_en50221_read_data(struct dvb_ca_private *ca, int slot,
|
static int dvb_ca_en50221_read_data(struct dvb_ca_private *ca, int slot,
|
||||||
u8 *ebuf, int ecount);
|
u8 *ebuf, int ecount);
|
||||||
static int dvb_ca_en50221_write_data(struct dvb_ca_private *ca, int slot,
|
static int dvb_ca_en50221_write_data(struct dvb_ca_private *ca, int slot,
|
||||||
u8 *ebuf, int ecount, u8 flags);
|
u8 *ebuf, int ecount, int size_write_flag);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* findstr - Safely find needle in haystack.
|
* findstr - Safely find needle in haystack.
|
||||||
@ -785,18 +791,19 @@ exit:
|
|||||||
* @buf: The data in this buffer is treated as a complete link-level packet to
|
* @buf: The data in this buffer is treated as a complete link-level packet to
|
||||||
* be written.
|
* be written.
|
||||||
* @bytes_write: Size of ebuf.
|
* @bytes_write: Size of ebuf.
|
||||||
|
* @size_write_flag: A flag on Command Register which says whether the link size
|
||||||
|
* information will be writen or not.
|
||||||
*
|
*
|
||||||
* return: Number of bytes written, or < 0 on error.
|
* return: Number of bytes written, or < 0 on error.
|
||||||
*/
|
*/
|
||||||
static int dvb_ca_en50221_write_data(struct dvb_ca_private *ca, int slot,
|
static int dvb_ca_en50221_write_data(struct dvb_ca_private *ca, int slot,
|
||||||
u8 *buf, int bytes_write, u8 flags)
|
u8 *buf, int bytes_write, int size_write_flag)
|
||||||
{
|
{
|
||||||
struct dvb_ca_slot *sl = &ca->slot_info[slot];
|
struct dvb_ca_slot *sl = &ca->slot_info[slot];
|
||||||
int status;
|
int status;
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
dprintk("%s\n", __func__);
|
dprintk("%s\n", __func__);
|
||||||
flags=0;
|
|
||||||
/* sanity check */
|
/* sanity check */
|
||||||
if (bytes_write > sl->link_buf_size)
|
if (bytes_write > sl->link_buf_size)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
@ -824,7 +831,7 @@ static int dvb_ca_en50221_write_data(struct dvb_ca_private *ca, int slot,
|
|||||||
|
|
||||||
/* OK, set HC bit */
|
/* OK, set HC bit */
|
||||||
status = ca->pub->write_cam_control(ca->pub, slot, CTRLIF_COMMAND,
|
status = ca->pub->write_cam_control(ca->pub, slot, CTRLIF_COMMAND,
|
||||||
IRQEN | CMDREG_HC | flags);
|
IRQEN | CMDREG_HC | size_write_flag);
|
||||||
if (status)
|
if (status)
|
||||||
goto exit;
|
goto exit;
|
||||||
|
|
||||||
@ -894,7 +901,7 @@ static int dvb_ca_en50221_write_data(struct dvb_ca_private *ca, int slot,
|
|||||||
buf[0], (buf[1] & 0x80) == 0, bytes_write);
|
buf[0], (buf[1] & 0x80) == 0, bytes_write);
|
||||||
|
|
||||||
exit:
|
exit:
|
||||||
ca->pub->write_cam_control(ca->pub, slot, CTRLIF_COMMAND, IRQEN | flags);
|
ca->pub->write_cam_control(ca->pub, slot, CTRLIF_COMMAND, IRQEN);
|
||||||
|
|
||||||
exitnowrite:
|
exitnowrite:
|
||||||
return status;
|
return status;
|
||||||
@ -1412,6 +1419,7 @@ static int dvb_ca_en50221_io_do_ioctl(struct file *file,
|
|||||||
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 14, 18))
|
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 14, 18))
|
||||||
slot = array_index_nospec(slot, ca->slot_count);
|
slot = array_index_nospec(slot, ca->slot_count);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
info->type = CA_CI_LINK;
|
info->type = CA_CI_LINK;
|
||||||
info->flags = 0;
|
info->flags = 0;
|
||||||
sl = &ca->slot_info[slot];
|
sl = &ca->slot_info[slot];
|
||||||
@ -1490,6 +1498,7 @@ static ssize_t dvb_ca_en50221_io_write(struct file *file,
|
|||||||
return -EFAULT;
|
return -EFAULT;
|
||||||
buf += 2;
|
buf += 2;
|
||||||
count -= 2;
|
count -= 2;
|
||||||
|
|
||||||
if (slot >= ca->slot_count)
|
if (slot >= ca->slot_count)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 14, 18))
|
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 14, 18))
|
||||||
@ -1734,12 +1743,22 @@ static int dvb_ca_en50221_io_open(struct inode *inode, struct file *file)
|
|||||||
|
|
||||||
dprintk("%s\n", __func__);
|
dprintk("%s\n", __func__);
|
||||||
|
|
||||||
if (!try_module_get(ca->pub->owner))
|
mutex_lock(&ca->remove_mutex);
|
||||||
|
|
||||||
|
if (ca->exit) {
|
||||||
|
mutex_unlock(&ca->remove_mutex);
|
||||||
|
return -ENODEV;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!try_module_get(ca->pub->owner)) {
|
||||||
|
mutex_unlock(&ca->remove_mutex);
|
||||||
return -EIO;
|
return -EIO;
|
||||||
|
}
|
||||||
|
|
||||||
err = dvb_generic_open(inode, file);
|
err = dvb_generic_open(inode, file);
|
||||||
if (err < 0) {
|
if (err < 0) {
|
||||||
module_put(ca->pub->owner);
|
module_put(ca->pub->owner);
|
||||||
|
mutex_unlock(&ca->remove_mutex);
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1764,6 +1783,7 @@ static int dvb_ca_en50221_io_open(struct inode *inode, struct file *file)
|
|||||||
|
|
||||||
dvb_ca_private_get(ca);
|
dvb_ca_private_get(ca);
|
||||||
|
|
||||||
|
mutex_unlock(&ca->remove_mutex);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1783,6 +1803,8 @@ static int dvb_ca_en50221_io_release(struct inode *inode, struct file *file)
|
|||||||
|
|
||||||
dprintk("%s\n", __func__);
|
dprintk("%s\n", __func__);
|
||||||
|
|
||||||
|
mutex_lock(&ca->remove_mutex);
|
||||||
|
|
||||||
/* mark the CA device as closed */
|
/* mark the CA device as closed */
|
||||||
ca->open = 0;
|
ca->open = 0;
|
||||||
dvb_ca_en50221_thread_update_delay(ca);
|
dvb_ca_en50221_thread_update_delay(ca);
|
||||||
@ -1793,6 +1815,13 @@ static int dvb_ca_en50221_io_release(struct inode *inode, struct file *file)
|
|||||||
|
|
||||||
dvb_ca_private_put(ca);
|
dvb_ca_private_put(ca);
|
||||||
|
|
||||||
|
if (dvbdev->users == 1 && ca->exit == 1) {
|
||||||
|
mutex_unlock(&ca->remove_mutex);
|
||||||
|
wake_up(&dvbdev->wait_queue);
|
||||||
|
} else {
|
||||||
|
mutex_unlock(&ca->remove_mutex);
|
||||||
|
}
|
||||||
|
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1920,6 +1949,7 @@ int dvb_ca_en50221_init(struct dvb_adapter *dvb_adapter,
|
|||||||
}
|
}
|
||||||
|
|
||||||
mutex_init(&ca->ioctl_mutex);
|
mutex_init(&ca->ioctl_mutex);
|
||||||
|
mutex_init(&ca->remove_mutex);
|
||||||
|
|
||||||
if (signal_pending(current)) {
|
if (signal_pending(current)) {
|
||||||
ret = -EINTR;
|
ret = -EINTR;
|
||||||
@ -1962,6 +1992,14 @@ void dvb_ca_en50221_release(struct dvb_ca_en50221 *pubca)
|
|||||||
|
|
||||||
dprintk("%s\n", __func__);
|
dprintk("%s\n", __func__);
|
||||||
|
|
||||||
|
mutex_lock(&ca->remove_mutex);
|
||||||
|
ca->exit = 1;
|
||||||
|
mutex_unlock(&ca->remove_mutex);
|
||||||
|
|
||||||
|
if (ca->dvbdev->users < 1)
|
||||||
|
wait_event(ca->dvbdev->wait_queue,
|
||||||
|
ca->dvbdev->users == 1);
|
||||||
|
|
||||||
/* shutdown the thread if there was one */
|
/* shutdown the thread if there was one */
|
||||||
kthread_stop(ca->thread);
|
kthread_stop(ca->thread);
|
||||||
|
|
||||||
|
@ -128,12 +128,12 @@ static inline int dvb_dmx_swfilter_payload(struct dvb_demux_feed *feed,
|
|||||||
|
|
||||||
cc = buf[3] & 0x0f;
|
cc = buf[3] & 0x0f;
|
||||||
ccok = ((feed->cc + 1) & 0x0f) == cc;
|
ccok = ((feed->cc + 1) & 0x0f) == cc;
|
||||||
feed->cc = cc;
|
|
||||||
if (!ccok) {
|
if (!ccok) {
|
||||||
set_buf_flags(feed, DMX_BUFFER_FLAG_DISCONTINUITY_DETECTED);
|
set_buf_flags(feed, DMX_BUFFER_FLAG_DISCONTINUITY_DETECTED);
|
||||||
dprintk_sect_loss("missed packet: %d instead of %d!\n",
|
dprintk_sect_loss("missed packet: %d instead of %d!\n",
|
||||||
cc, (feed->cc + 1) & 0x0f);
|
cc, (feed->cc + 1) & 0x0f);
|
||||||
}
|
}
|
||||||
|
feed->cc = cc;
|
||||||
|
|
||||||
if (buf[1] & 0x40) // PUSI ?
|
if (buf[1] & 0x40) // PUSI ?
|
||||||
feed->peslen = 0xfffa;
|
feed->peslen = 0xfffa;
|
||||||
@ -313,7 +313,6 @@ static int dvb_dmx_swfilter_section_packet(struct dvb_demux_feed *feed,
|
|||||||
|
|
||||||
cc = buf[3] & 0x0f;
|
cc = buf[3] & 0x0f;
|
||||||
ccok = ((feed->cc + 1) & 0x0f) == cc;
|
ccok = ((feed->cc + 1) & 0x0f) == cc;
|
||||||
feed->cc = cc;
|
|
||||||
|
|
||||||
if (buf[3] & 0x20) {
|
if (buf[3] & 0x20) {
|
||||||
/* adaption field present, check for discontinuity_indicator */
|
/* adaption field present, check for discontinuity_indicator */
|
||||||
@ -349,6 +348,7 @@ static int dvb_dmx_swfilter_section_packet(struct dvb_demux_feed *feed,
|
|||||||
feed->pusi_seen = false;
|
feed->pusi_seen = false;
|
||||||
dvb_dmx_swfilter_section_new(feed);
|
dvb_dmx_swfilter_section_new(feed);
|
||||||
}
|
}
|
||||||
|
feed->cc = cc;
|
||||||
|
|
||||||
if (buf[1] & 0x40) {
|
if (buf[1] & 0x40) {
|
||||||
/* PUSI=1 (is set), section boundary is here */
|
/* PUSI=1 (is set), section boundary is here */
|
||||||
|
@ -1,603 +0,0 @@
|
|||||||
#include <linux/kernel.h>
|
|
||||||
#include <linux/module.h>
|
|
||||||
#include <linux/string.h>
|
|
||||||
#include "dvb_filter.h"
|
|
||||||
|
|
||||||
#if 0
|
|
||||||
static unsigned int bitrates[3][16] =
|
|
||||||
{{0,32,64,96,128,160,192,224,256,288,320,352,384,416,448,0},
|
|
||||||
{0,32,48,56,64,80,96,112,128,160,192,224,256,320,384,0},
|
|
||||||
{0,32,40,48,56,64,80,96,112,128,160,192,224,256,320,0}};
|
|
||||||
#endif
|
|
||||||
|
|
||||||
static u32 freq[4] = {480, 441, 320, 0};
|
|
||||||
|
|
||||||
static unsigned int ac3_bitrates[32] =
|
|
||||||
{32,40,48,56,64,80,96,112,128,160,192,224,256,320,384,448,512,576,640,
|
|
||||||
0,0,0,0,0,0,0,0,0,0,0,0,0};
|
|
||||||
|
|
||||||
static u32 ac3_frames[3][32] =
|
|
||||||
{{64,80,96,112,128,160,192,224,256,320,384,448,512,640,768,896,1024,
|
|
||||||
1152,1280,0,0,0,0,0,0,0,0,0,0,0,0,0},
|
|
||||||
{69,87,104,121,139,174,208,243,278,348,417,487,557,696,835,975,1114,
|
|
||||||
1253,1393,0,0,0,0,0,0,0,0,0,0,0,0,0},
|
|
||||||
{96,120,144,168,192,240,288,336,384,480,576,672,768,960,1152,1344,
|
|
||||||
1536,1728,1920,0,0,0,0,0,0,0,0,0,0,0,0,0}};
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#if 0
|
|
||||||
static void setup_ts2pes(ipack *pa, ipack *pv, u16 *pida, u16 *pidv,
|
|
||||||
void (*pes_write)(u8 *buf, int count, void *data),
|
|
||||||
void *priv)
|
|
||||||
{
|
|
||||||
dvb_filter_ipack_init(pa, IPACKS, pes_write);
|
|
||||||
dvb_filter_ipack_init(pv, IPACKS, pes_write);
|
|
||||||
pa->pid = pida;
|
|
||||||
pv->pid = pidv;
|
|
||||||
pa->data = priv;
|
|
||||||
pv->data = priv;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if 0
|
|
||||||
static void ts_to_pes(ipack *p, u8 *buf) // don't need count (=188)
|
|
||||||
{
|
|
||||||
u8 off = 0;
|
|
||||||
|
|
||||||
if (!buf || !p ){
|
|
||||||
printk("NULL POINTER IDIOT\n");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (buf[1]&PAY_START) {
|
|
||||||
if (p->plength == MMAX_PLENGTH-6 && p->found>6){
|
|
||||||
p->plength = p->found-6;
|
|
||||||
p->found = 0;
|
|
||||||
send_ipack(p);
|
|
||||||
dvb_filter_ipack_reset(p);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (buf[3] & ADAPT_FIELD) { // adaptation field?
|
|
||||||
off = buf[4] + 1;
|
|
||||||
if (off+4 > 187) return;
|
|
||||||
}
|
|
||||||
dvb_filter_instant_repack(buf+4+off, TS_SIZE-4-off, p);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if 0
|
|
||||||
/* needs 5 byte input, returns picture coding type*/
|
|
||||||
static int read_picture_header(u8 *headr, struct mpg_picture *pic, int field, int pr)
|
|
||||||
{
|
|
||||||
u8 pct;
|
|
||||||
|
|
||||||
if (pr) printk( "Pic header: ");
|
|
||||||
pic->temporal_reference[field] = (( headr[0] << 2 ) |
|
|
||||||
(headr[1] & 0x03) )& 0x03ff;
|
|
||||||
if (pr) printk( " temp ref: 0x%04x", pic->temporal_reference[field]);
|
|
||||||
|
|
||||||
pct = ( headr[1] >> 2 ) & 0x07;
|
|
||||||
pic->picture_coding_type[field] = pct;
|
|
||||||
if (pr) {
|
|
||||||
switch(pct){
|
|
||||||
case I_FRAME:
|
|
||||||
printk( " I-FRAME");
|
|
||||||
break;
|
|
||||||
case B_FRAME:
|
|
||||||
printk( " B-FRAME");
|
|
||||||
break;
|
|
||||||
case P_FRAME:
|
|
||||||
printk( " P-FRAME");
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
pic->vinfo.vbv_delay = (( headr[1] >> 5 ) | ( headr[2] << 3) |
|
|
||||||
( (headr[3] & 0x1F) << 11) ) & 0xffff;
|
|
||||||
|
|
||||||
if (pr) printk( " vbv delay: 0x%04x", pic->vinfo.vbv_delay);
|
|
||||||
|
|
||||||
pic->picture_header_parameter = ( headr[3] & 0xe0 ) |
|
|
||||||
((headr[4] & 0x80) >> 3);
|
|
||||||
|
|
||||||
if ( pct == B_FRAME ){
|
|
||||||
pic->picture_header_parameter |= ( headr[4] >> 3 ) & 0x0f;
|
|
||||||
}
|
|
||||||
if (pr) printk( " pic head param: 0x%x",
|
|
||||||
pic->picture_header_parameter);
|
|
||||||
|
|
||||||
return pct;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if 0
|
|
||||||
/* needs 4 byte input */
|
|
||||||
static int read_gop_header(u8 *headr, struct mpg_picture *pic, int pr)
|
|
||||||
{
|
|
||||||
if (pr) printk("GOP header: ");
|
|
||||||
|
|
||||||
pic->time_code = (( headr[0] << 17 ) | ( headr[1] << 9) |
|
|
||||||
( headr[2] << 1 ) | (headr[3] &0x01)) & 0x1ffffff;
|
|
||||||
|
|
||||||
if (pr) printk(" time: %d:%d.%d ", (headr[0]>>2)& 0x1F,
|
|
||||||
((headr[0]<<4)& 0x30)| ((headr[1]>>4)& 0x0F),
|
|
||||||
((headr[1]<<3)& 0x38)| ((headr[2]>>5)& 0x0F));
|
|
||||||
|
|
||||||
if ( ( headr[3] & 0x40 ) != 0 ){
|
|
||||||
pic->closed_gop = 1;
|
|
||||||
} else {
|
|
||||||
pic->closed_gop = 0;
|
|
||||||
}
|
|
||||||
if (pr) printk("closed: %d", pic->closed_gop);
|
|
||||||
|
|
||||||
if ( ( headr[3] & 0x20 ) != 0 ){
|
|
||||||
pic->broken_link = 1;
|
|
||||||
} else {
|
|
||||||
pic->broken_link = 0;
|
|
||||||
}
|
|
||||||
if (pr) printk(" broken: %d\n", pic->broken_link);
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if 0
|
|
||||||
/* needs 8 byte input */
|
|
||||||
static int read_sequence_header(u8 *headr, struct dvb_video_info *vi, int pr)
|
|
||||||
{
|
|
||||||
int sw;
|
|
||||||
int form = -1;
|
|
||||||
|
|
||||||
if (pr) printk("Reading sequence header\n");
|
|
||||||
|
|
||||||
vi->horizontal_size = ((headr[1] &0xF0) >> 4) | (headr[0] << 4);
|
|
||||||
vi->vertical_size = ((headr[1] &0x0F) << 8) | (headr[2]);
|
|
||||||
|
|
||||||
sw = (int)((headr[3]&0xF0) >> 4) ;
|
|
||||||
|
|
||||||
switch( sw ){
|
|
||||||
case 1:
|
|
||||||
if (pr)
|
|
||||||
printk("Videostream: ASPECT: 1:1");
|
|
||||||
vi->aspect_ratio = 100;
|
|
||||||
break;
|
|
||||||
case 2:
|
|
||||||
if (pr)
|
|
||||||
printk("Videostream: ASPECT: 4:3");
|
|
||||||
vi->aspect_ratio = 133;
|
|
||||||
break;
|
|
||||||
case 3:
|
|
||||||
if (pr)
|
|
||||||
printk("Videostream: ASPECT: 16:9");
|
|
||||||
vi->aspect_ratio = 177;
|
|
||||||
break;
|
|
||||||
case 4:
|
|
||||||
if (pr)
|
|
||||||
printk("Videostream: ASPECT: 2.21:1");
|
|
||||||
vi->aspect_ratio = 221;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 5 ... 15:
|
|
||||||
if (pr)
|
|
||||||
printk("Videostream: ASPECT: reserved");
|
|
||||||
vi->aspect_ratio = 0;
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
vi->aspect_ratio = 0;
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (pr)
|
|
||||||
printk(" Size = %dx%d",vi->horizontal_size,vi->vertical_size);
|
|
||||||
|
|
||||||
sw = (int)(headr[3]&0x0F);
|
|
||||||
|
|
||||||
switch ( sw ) {
|
|
||||||
case 1:
|
|
||||||
if (pr)
|
|
||||||
printk(" FRate: 23.976 fps");
|
|
||||||
vi->framerate = 23976;
|
|
||||||
form = -1;
|
|
||||||
break;
|
|
||||||
case 2:
|
|
||||||
if (pr)
|
|
||||||
printk(" FRate: 24 fps");
|
|
||||||
vi->framerate = 24000;
|
|
||||||
form = -1;
|
|
||||||
break;
|
|
||||||
case 3:
|
|
||||||
if (pr)
|
|
||||||
printk(" FRate: 25 fps");
|
|
||||||
vi->framerate = 25000;
|
|
||||||
form = VIDEO_MODE_PAL;
|
|
||||||
break;
|
|
||||||
case 4:
|
|
||||||
if (pr)
|
|
||||||
printk(" FRate: 29.97 fps");
|
|
||||||
vi->framerate = 29970;
|
|
||||||
form = VIDEO_MODE_NTSC;
|
|
||||||
break;
|
|
||||||
case 5:
|
|
||||||
if (pr)
|
|
||||||
printk(" FRate: 30 fps");
|
|
||||||
vi->framerate = 30000;
|
|
||||||
form = VIDEO_MODE_NTSC;
|
|
||||||
break;
|
|
||||||
case 6:
|
|
||||||
if (pr)
|
|
||||||
printk(" FRate: 50 fps");
|
|
||||||
vi->framerate = 50000;
|
|
||||||
form = VIDEO_MODE_PAL;
|
|
||||||
break;
|
|
||||||
case 7:
|
|
||||||
if (pr)
|
|
||||||
printk(" FRate: 60 fps");
|
|
||||||
vi->framerate = 60000;
|
|
||||||
form = VIDEO_MODE_NTSC;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
vi->bit_rate = (headr[4] << 10) | (headr[5] << 2) | (headr[6] & 0x03);
|
|
||||||
|
|
||||||
vi->vbv_buffer_size
|
|
||||||
= (( headr[6] & 0xF8) >> 3 ) | (( headr[7] & 0x1F )<< 5);
|
|
||||||
|
|
||||||
if (pr){
|
|
||||||
printk(" BRate: %d Mbit/s",4*(vi->bit_rate)/10000);
|
|
||||||
printk(" vbvbuffer %d",16*1024*(vi->vbv_buffer_size));
|
|
||||||
printk("\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
vi->video_format = form;
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
||||||
#if 0
|
|
||||||
static int get_vinfo(u8 *mbuf, int count, struct dvb_video_info *vi, int pr)
|
|
||||||
{
|
|
||||||
u8 *headr;
|
|
||||||
int found = 0;
|
|
||||||
int c = 0;
|
|
||||||
|
|
||||||
while (found < 4 && c+4 < count){
|
|
||||||
u8 *b;
|
|
||||||
|
|
||||||
b = mbuf+c;
|
|
||||||
if ( b[0] == 0x00 && b[1] == 0x00 && b[2] == 0x01
|
|
||||||
&& b[3] == 0xb3) found = 4;
|
|
||||||
else {
|
|
||||||
c++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (! found) return -1;
|
|
||||||
c += 4;
|
|
||||||
if (c+12 >= count) return -1;
|
|
||||||
headr = mbuf+c;
|
|
||||||
if (read_sequence_header(headr, vi, pr) < 0) return -1;
|
|
||||||
vi->off = c-4;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
||||||
#if 0
|
|
||||||
static int get_ainfo(u8 *mbuf, int count, struct dvb_audio_info *ai, int pr)
|
|
||||||
{
|
|
||||||
u8 *headr;
|
|
||||||
int found = 0;
|
|
||||||
int c = 0;
|
|
||||||
int fr = 0;
|
|
||||||
|
|
||||||
while (found < 2 && c < count){
|
|
||||||
u8 b[2];
|
|
||||||
memcpy( b, mbuf+c, 2);
|
|
||||||
|
|
||||||
if ( b[0] == 0xff && (b[1] & 0xf8) == 0xf8)
|
|
||||||
found = 2;
|
|
||||||
else {
|
|
||||||
c++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!found) return -1;
|
|
||||||
|
|
||||||
if (c+3 >= count) return -1;
|
|
||||||
headr = mbuf+c;
|
|
||||||
|
|
||||||
ai->layer = (headr[1] & 0x06) >> 1;
|
|
||||||
|
|
||||||
if (pr)
|
|
||||||
printk("Audiostream: Layer: %d", 4-ai->layer);
|
|
||||||
|
|
||||||
|
|
||||||
ai->bit_rate = bitrates[(3-ai->layer)][(headr[2] >> 4 )]*1000;
|
|
||||||
|
|
||||||
if (pr){
|
|
||||||
if (ai->bit_rate == 0)
|
|
||||||
printk(" Bit rate: free");
|
|
||||||
else if (ai->bit_rate == 0xf)
|
|
||||||
printk(" BRate: reserved");
|
|
||||||
else
|
|
||||||
printk(" BRate: %d kb/s", ai->bit_rate/1000);
|
|
||||||
}
|
|
||||||
|
|
||||||
fr = (headr[2] & 0x0c ) >> 2;
|
|
||||||
ai->frequency = freq[fr]*100;
|
|
||||||
if (pr){
|
|
||||||
if (ai->frequency == 3)
|
|
||||||
printk(" Freq: reserved\n");
|
|
||||||
else
|
|
||||||
printk(" Freq: %d kHz\n",ai->frequency);
|
|
||||||
|
|
||||||
}
|
|
||||||
ai->off = c;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
||||||
int dvb_filter_get_ac3info(u8 *mbuf, int count, struct dvb_audio_info *ai, int pr)
|
|
||||||
{
|
|
||||||
u8 *headr;
|
|
||||||
int found = 0;
|
|
||||||
int c = 0;
|
|
||||||
u8 frame = 0;
|
|
||||||
int fr = 0;
|
|
||||||
|
|
||||||
while ( !found && c < count){
|
|
||||||
u8 *b = mbuf+c;
|
|
||||||
|
|
||||||
if ( b[0] == 0x0b && b[1] == 0x77 )
|
|
||||||
found = 1;
|
|
||||||
else {
|
|
||||||
c++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!found) return -1;
|
|
||||||
if (pr)
|
|
||||||
printk("Audiostream: AC3");
|
|
||||||
|
|
||||||
ai->off = c;
|
|
||||||
if (c+5 >= count) return -1;
|
|
||||||
|
|
||||||
ai->layer = 0; // 0 for AC3
|
|
||||||
headr = mbuf+c+2;
|
|
||||||
|
|
||||||
frame = (headr[2]&0x3f);
|
|
||||||
ai->bit_rate = ac3_bitrates[frame >> 1]*1000;
|
|
||||||
|
|
||||||
if (pr)
|
|
||||||
printk(" BRate: %d kb/s", (int) ai->bit_rate/1000);
|
|
||||||
|
|
||||||
ai->frequency = (headr[2] & 0xc0 ) >> 6;
|
|
||||||
fr = (headr[2] & 0xc0 ) >> 6;
|
|
||||||
ai->frequency = freq[fr]*100;
|
|
||||||
if (pr) printk (" Freq: %d Hz\n", (int) ai->frequency);
|
|
||||||
|
|
||||||
|
|
||||||
ai->framesize = ac3_frames[fr][frame >> 1];
|
|
||||||
if ((frame & 1) && (fr == 1)) ai->framesize++;
|
|
||||||
ai->framesize = ai->framesize << 1;
|
|
||||||
if (pr) printk (" Framesize %d\n",(int) ai->framesize);
|
|
||||||
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
EXPORT_SYMBOL(dvb_filter_get_ac3info);
|
|
||||||
|
|
||||||
|
|
||||||
#if 0
|
|
||||||
static u8 *skip_pes_header(u8 **bufp)
|
|
||||||
{
|
|
||||||
u8 *inbuf = *bufp;
|
|
||||||
u8 *buf = inbuf;
|
|
||||||
u8 *pts = NULL;
|
|
||||||
int skip = 0;
|
|
||||||
|
|
||||||
static const int mpeg1_skip_table[16] = {
|
|
||||||
1, 0xffff, 5, 10, 0xffff, 0xffff, 0xffff, 0xffff,
|
|
||||||
0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
if ((inbuf[6] & 0xc0) == 0x80){ /* mpeg2 */
|
|
||||||
if (buf[7] & PTS_ONLY)
|
|
||||||
pts = buf+9;
|
|
||||||
else pts = NULL;
|
|
||||||
buf = inbuf + 9 + inbuf[8];
|
|
||||||
} else { /* mpeg1 */
|
|
||||||
for (buf = inbuf + 6; *buf == 0xff; buf++)
|
|
||||||
if (buf == inbuf + 6 + 16) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if ((*buf & 0xc0) == 0x40)
|
|
||||||
buf += 2;
|
|
||||||
skip = mpeg1_skip_table [*buf >> 4];
|
|
||||||
if (skip == 5 || skip == 10) pts = buf;
|
|
||||||
else pts = NULL;
|
|
||||||
|
|
||||||
buf += mpeg1_skip_table [*buf >> 4];
|
|
||||||
}
|
|
||||||
|
|
||||||
*bufp = buf;
|
|
||||||
return pts;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if 0
|
|
||||||
static void initialize_quant_matrix( u32 *matrix )
|
|
||||||
{
|
|
||||||
int i;
|
|
||||||
|
|
||||||
matrix[0] = 0x08101013;
|
|
||||||
matrix[1] = 0x10131616;
|
|
||||||
matrix[2] = 0x16161616;
|
|
||||||
matrix[3] = 0x1a181a1b;
|
|
||||||
matrix[4] = 0x1b1b1a1a;
|
|
||||||
matrix[5] = 0x1a1a1b1b;
|
|
||||||
matrix[6] = 0x1b1d1d1d;
|
|
||||||
matrix[7] = 0x2222221d;
|
|
||||||
matrix[8] = 0x1d1d1b1b;
|
|
||||||
matrix[9] = 0x1d1d2020;
|
|
||||||
matrix[10] = 0x22222526;
|
|
||||||
matrix[11] = 0x25232322;
|
|
||||||
matrix[12] = 0x23262628;
|
|
||||||
matrix[13] = 0x28283030;
|
|
||||||
matrix[14] = 0x2e2e3838;
|
|
||||||
matrix[15] = 0x3a454553;
|
|
||||||
|
|
||||||
for ( i = 16 ; i < 32 ; i++ )
|
|
||||||
matrix[i] = 0x10101010;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if 0
|
|
||||||
static void initialize_mpg_picture(struct mpg_picture *pic)
|
|
||||||
{
|
|
||||||
int i;
|
|
||||||
|
|
||||||
/* set MPEG1 */
|
|
||||||
pic->mpeg1_flag = 1;
|
|
||||||
pic->profile_and_level = 0x4A ; /* MP@LL */
|
|
||||||
pic->progressive_sequence = 1;
|
|
||||||
pic->low_delay = 0;
|
|
||||||
|
|
||||||
pic->sequence_display_extension_flag = 0;
|
|
||||||
for ( i = 0 ; i < 4 ; i++ ){
|
|
||||||
pic->frame_centre_horizontal_offset[i] = 0;
|
|
||||||
pic->frame_centre_vertical_offset[i] = 0;
|
|
||||||
}
|
|
||||||
pic->last_frame_centre_horizontal_offset = 0;
|
|
||||||
pic->last_frame_centre_vertical_offset = 0;
|
|
||||||
|
|
||||||
pic->picture_display_extension_flag[0] = 0;
|
|
||||||
pic->picture_display_extension_flag[1] = 0;
|
|
||||||
pic->sequence_header_flag = 0;
|
|
||||||
pic->gop_flag = 0;
|
|
||||||
pic->sequence_end_flag = 0;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if 0
|
|
||||||
static void mpg_set_picture_parameter( int32_t field_type, struct mpg_picture *pic )
|
|
||||||
{
|
|
||||||
int16_t last_h_offset;
|
|
||||||
int16_t last_v_offset;
|
|
||||||
|
|
||||||
int16_t *p_h_offset;
|
|
||||||
int16_t *p_v_offset;
|
|
||||||
|
|
||||||
if ( pic->mpeg1_flag ){
|
|
||||||
pic->picture_structure[field_type] = VIDEO_FRAME_PICTURE;
|
|
||||||
pic->top_field_first = 0;
|
|
||||||
pic->repeat_first_field = 0;
|
|
||||||
pic->progressive_frame = 1;
|
|
||||||
pic->picture_coding_parameter = 0x000010;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Reset flag */
|
|
||||||
pic->picture_display_extension_flag[field_type] = 0;
|
|
||||||
|
|
||||||
last_h_offset = pic->last_frame_centre_horizontal_offset;
|
|
||||||
last_v_offset = pic->last_frame_centre_vertical_offset;
|
|
||||||
if ( field_type == FIRST_FIELD ){
|
|
||||||
p_h_offset = pic->frame_centre_horizontal_offset;
|
|
||||||
p_v_offset = pic->frame_centre_vertical_offset;
|
|
||||||
*p_h_offset = last_h_offset;
|
|
||||||
*(p_h_offset + 1) = last_h_offset;
|
|
||||||
*(p_h_offset + 2) = last_h_offset;
|
|
||||||
*p_v_offset = last_v_offset;
|
|
||||||
*(p_v_offset + 1) = last_v_offset;
|
|
||||||
*(p_v_offset + 2) = last_v_offset;
|
|
||||||
} else {
|
|
||||||
pic->frame_centre_horizontal_offset[3] = last_h_offset;
|
|
||||||
pic->frame_centre_vertical_offset[3] = last_v_offset;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if 0
|
|
||||||
static void init_mpg_picture( struct mpg_picture *pic, int chan, int32_t field_type)
|
|
||||||
{
|
|
||||||
pic->picture_header = 0;
|
|
||||||
pic->sequence_header_data
|
|
||||||
= ( INIT_HORIZONTAL_SIZE << 20 )
|
|
||||||
| ( INIT_VERTICAL_SIZE << 8 )
|
|
||||||
| ( INIT_ASPECT_RATIO << 4 )
|
|
||||||
| ( INIT_FRAME_RATE );
|
|
||||||
pic->mpeg1_flag = 0;
|
|
||||||
pic->vinfo.horizontal_size
|
|
||||||
= INIT_DISP_HORIZONTAL_SIZE;
|
|
||||||
pic->vinfo.vertical_size
|
|
||||||
= INIT_DISP_VERTICAL_SIZE;
|
|
||||||
pic->picture_display_extension_flag[field_type]
|
|
||||||
= 0;
|
|
||||||
pic->pts_flag[field_type] = 0;
|
|
||||||
|
|
||||||
pic->sequence_gop_header = 0;
|
|
||||||
pic->picture_header = 0;
|
|
||||||
pic->sequence_header_flag = 0;
|
|
||||||
pic->gop_flag = 0;
|
|
||||||
pic->sequence_end_flag = 0;
|
|
||||||
pic->sequence_display_extension_flag = 0;
|
|
||||||
pic->last_frame_centre_horizontal_offset = 0;
|
|
||||||
pic->last_frame_centre_vertical_offset = 0;
|
|
||||||
pic->channel = chan;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
void dvb_filter_pes2ts_init(struct dvb_filter_pes2ts *p2ts, unsigned short pid,
|
|
||||||
dvb_filter_pes2ts_cb_t *cb, void *priv)
|
|
||||||
{
|
|
||||||
unsigned char *buf=p2ts->buf;
|
|
||||||
|
|
||||||
buf[0]=0x47;
|
|
||||||
buf[1]=(pid>>8);
|
|
||||||
buf[2]=pid&0xff;
|
|
||||||
p2ts->cc=0;
|
|
||||||
p2ts->cb=cb;
|
|
||||||
p2ts->priv=priv;
|
|
||||||
}
|
|
||||||
EXPORT_SYMBOL(dvb_filter_pes2ts_init);
|
|
||||||
|
|
||||||
int dvb_filter_pes2ts(struct dvb_filter_pes2ts *p2ts, unsigned char *pes,
|
|
||||||
int len, int payload_start)
|
|
||||||
{
|
|
||||||
unsigned char *buf=p2ts->buf;
|
|
||||||
int ret=0, rest;
|
|
||||||
|
|
||||||
//len=6+((pes[4]<<8)|pes[5]);
|
|
||||||
|
|
||||||
if (payload_start)
|
|
||||||
buf[1]|=0x40;
|
|
||||||
else
|
|
||||||
buf[1]&=~0x40;
|
|
||||||
while (len>=184) {
|
|
||||||
buf[3]=0x10|((p2ts->cc++)&0x0f);
|
|
||||||
memcpy(buf+4, pes, 184);
|
|
||||||
if ((ret=p2ts->cb(p2ts->priv, buf)))
|
|
||||||
return ret;
|
|
||||||
len-=184; pes+=184;
|
|
||||||
buf[1]&=~0x40;
|
|
||||||
}
|
|
||||||
if (!len)
|
|
||||||
return 0;
|
|
||||||
buf[3]=0x30|((p2ts->cc++)&0x0f);
|
|
||||||
rest=183-len;
|
|
||||||
if (rest) {
|
|
||||||
buf[5]=0x00;
|
|
||||||
if (rest-1)
|
|
||||||
memset(buf+6, 0xff, rest-1);
|
|
||||||
}
|
|
||||||
buf[4]=rest;
|
|
||||||
memcpy(buf+5+rest, pes, len);
|
|
||||||
return p2ts->cb(p2ts->priv, buf);
|
|
||||||
}
|
|
||||||
EXPORT_SYMBOL(dvb_filter_pes2ts);
|
|
@ -299,14 +299,22 @@ static int dvb_frontend_get_event(struct dvb_frontend *fe,
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (events->eventw == events->eventr) {
|
if (events->eventw == events->eventr) {
|
||||||
int ret;
|
struct wait_queue_entry wait;
|
||||||
|
int ret = 0;
|
||||||
|
|
||||||
if (flags & O_NONBLOCK)
|
if (flags & O_NONBLOCK)
|
||||||
return -EWOULDBLOCK;
|
return -EWOULDBLOCK;
|
||||||
|
|
||||||
ret = wait_event_interruptible(events->wait_queue,
|
init_waitqueue_entry(&wait, current);
|
||||||
dvb_frontend_test_event(fepriv, events));
|
add_wait_queue(&events->wait_queue, &wait);
|
||||||
|
while (!dvb_frontend_test_event(fepriv, events)) {
|
||||||
|
wait_woken(&wait, TASK_INTERRUPTIBLE, 0);
|
||||||
|
if (signal_pending(current)) {
|
||||||
|
ret = -ERESTARTSYS;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
remove_wait_queue(&events->wait_queue, &wait);
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
@ -665,7 +665,7 @@ static void dvb_net_ule_check_crc(struct dvb_net_ule_handle *h,
|
|||||||
h->ts_remain > 2 ?
|
h->ts_remain > 2 ?
|
||||||
*(unsigned short *)h->from_where : 0);
|
*(unsigned short *)h->from_where : 0);
|
||||||
|
|
||||||
#ifdef DVB_ULE_DEBUG
|
#ifdef DVB_ULE_DEBUG
|
||||||
hexdump(iov[0].iov_base, iov[0].iov_len);
|
hexdump(iov[0].iov_base, iov[0].iov_len);
|
||||||
hexdump(iov[1].iov_base, iov[1].iov_len);
|
hexdump(iov[1].iov_base, iov[1].iov_len);
|
||||||
hexdump(iov[2].iov_base, iov[2].iov_len);
|
hexdump(iov[2].iov_base, iov[2].iov_len);
|
||||||
@ -1290,6 +1290,7 @@ static int dvb_net_set_mac (struct net_device *dev, void *p)
|
|||||||
#else
|
#else
|
||||||
eth_hw_addr_set(dev, addr->sa_data);
|
eth_hw_addr_set(dev, addr->sa_data);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if (netif_running(dev))
|
if (netif_running(dev))
|
||||||
schedule_work(&priv->restart_net_feed_wq);
|
schedule_work(&priv->restart_net_feed_wq);
|
||||||
|
|
||||||
@ -1589,15 +1590,43 @@ static long dvb_net_ioctl(struct file *file,
|
|||||||
return dvb_usercopy(file, cmd, arg, dvb_net_do_ioctl);
|
return dvb_usercopy(file, cmd, arg, dvb_net_do_ioctl);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int locked_dvb_net_open(struct inode *inode, struct file *file)
|
||||||
|
{
|
||||||
|
struct dvb_device *dvbdev = file->private_data;
|
||||||
|
struct dvb_net *dvbnet = dvbdev->priv;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
if (mutex_lock_interruptible(&dvbnet->remove_mutex))
|
||||||
|
return -ERESTARTSYS;
|
||||||
|
|
||||||
|
if (dvbnet->exit) {
|
||||||
|
mutex_unlock(&dvbnet->remove_mutex);
|
||||||
|
return -ENODEV;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = dvb_generic_open(inode, file);
|
||||||
|
|
||||||
|
mutex_unlock(&dvbnet->remove_mutex);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
static int dvb_net_close(struct inode *inode, struct file *file)
|
static int dvb_net_close(struct inode *inode, struct file *file)
|
||||||
{
|
{
|
||||||
struct dvb_device *dvbdev = file->private_data;
|
struct dvb_device *dvbdev = file->private_data;
|
||||||
struct dvb_net *dvbnet = dvbdev->priv;
|
struct dvb_net *dvbnet = dvbdev->priv;
|
||||||
|
|
||||||
|
mutex_lock(&dvbnet->remove_mutex);
|
||||||
|
|
||||||
dvb_generic_release(inode, file);
|
dvb_generic_release(inode, file);
|
||||||
|
|
||||||
if(dvbdev->users == 1 && dvbnet->exit == 1)
|
if (dvbdev->users == 1 && dvbnet->exit == 1) {
|
||||||
|
mutex_unlock(&dvbnet->remove_mutex);
|
||||||
wake_up(&dvbdev->wait_queue);
|
wake_up(&dvbdev->wait_queue);
|
||||||
|
} else {
|
||||||
|
mutex_unlock(&dvbnet->remove_mutex);
|
||||||
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1605,7 +1634,7 @@ static int dvb_net_close(struct inode *inode, struct file *file)
|
|||||||
static const struct file_operations dvb_net_fops = {
|
static const struct file_operations dvb_net_fops = {
|
||||||
.owner = THIS_MODULE,
|
.owner = THIS_MODULE,
|
||||||
.unlocked_ioctl = dvb_net_ioctl,
|
.unlocked_ioctl = dvb_net_ioctl,
|
||||||
.open = dvb_generic_open,
|
.open = locked_dvb_net_open,
|
||||||
.release = dvb_net_close,
|
.release = dvb_net_close,
|
||||||
.llseek = noop_llseek,
|
.llseek = noop_llseek,
|
||||||
};
|
};
|
||||||
@ -1624,10 +1653,13 @@ void dvb_net_release (struct dvb_net *dvbnet)
|
|||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
|
mutex_lock(&dvbnet->remove_mutex);
|
||||||
dvbnet->exit = 1;
|
dvbnet->exit = 1;
|
||||||
|
mutex_unlock(&dvbnet->remove_mutex);
|
||||||
|
|
||||||
if (dvbnet->dvbdev->users < 1)
|
if (dvbnet->dvbdev->users < 1)
|
||||||
wait_event(dvbnet->dvbdev->wait_queue,
|
wait_event(dvbnet->dvbdev->wait_queue,
|
||||||
dvbnet->dvbdev->users==1);
|
dvbnet->dvbdev->users == 1);
|
||||||
|
|
||||||
dvb_unregister_device(dvbnet->dvbdev);
|
dvb_unregister_device(dvbnet->dvbdev);
|
||||||
|
|
||||||
@ -1646,6 +1678,7 @@ int dvb_net_init (struct dvb_adapter *adap, struct dvb_net *dvbnet,
|
|||||||
int i;
|
int i;
|
||||||
|
|
||||||
mutex_init(&dvbnet->ioctl_mutex);
|
mutex_init(&dvbnet->ioctl_mutex);
|
||||||
|
mutex_init(&dvbnet->remove_mutex);
|
||||||
dvbnet->demux = dmx;
|
dvbnet->demux = dmx;
|
||||||
|
|
||||||
for (i=0; i<DVB_NET_DEVICES_MAX; i++)
|
for (i=0; i<DVB_NET_DEVICES_MAX; i++)
|
||||||
|
@ -30,6 +30,7 @@
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
static DEFINE_MUTEX(dvbdev_mutex);
|
static DEFINE_MUTEX(dvbdev_mutex);
|
||||||
|
static LIST_HEAD(dvbdevfops_list);
|
||||||
static int dvbdev_debug;
|
static int dvbdev_debug;
|
||||||
|
|
||||||
module_param(dvbdev_debug, int, 0644);
|
module_param(dvbdev_debug, int, 0644);
|
||||||
@ -85,7 +86,7 @@ static const u8 minor_type[] = {
|
|||||||
#define nums2minor(num, type, id) \
|
#define nums2minor(num, type, id) \
|
||||||
(((num) << 6) | ((id) << 4) | minor_type[type])
|
(((num) << 6) | ((id) << 4) | minor_type[type])
|
||||||
|
|
||||||
#define MAX_DVB_MINORS (DVB_MAX_ADAPTERS*64)
|
#define MAX_DVB_MINORS (DVB_MAX_ADAPTERS * 64)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
static struct class *dvb_class;
|
static struct class *dvb_class;
|
||||||
@ -122,9 +123,7 @@ fail:
|
|||||||
return -ENODEV;
|
return -ENODEV;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static const struct file_operations dvb_device_fops = {
|
||||||
static const struct file_operations dvb_device_fops =
|
|
||||||
{
|
|
||||||
.owner = THIS_MODULE,
|
.owner = THIS_MODULE,
|
||||||
.open = dvb_device_open,
|
.open = dvb_device_open,
|
||||||
.llseek = noop_llseek,
|
.llseek = noop_llseek,
|
||||||
@ -157,7 +156,6 @@ int dvb_generic_open(struct inode *inode, struct file *file)
|
|||||||
}
|
}
|
||||||
EXPORT_SYMBOL(dvb_generic_open);
|
EXPORT_SYMBOL(dvb_generic_open);
|
||||||
|
|
||||||
|
|
||||||
int dvb_generic_release(struct inode *inode, struct file *file)
|
int dvb_generic_release(struct inode *inode, struct file *file)
|
||||||
{
|
{
|
||||||
struct dvb_device *dvbdev = file->private_data;
|
struct dvb_device *dvbdev = file->private_data;
|
||||||
@ -165,11 +163,10 @@ int dvb_generic_release(struct inode *inode, struct file *file)
|
|||||||
if (!dvbdev)
|
if (!dvbdev)
|
||||||
return -ENODEV;
|
return -ENODEV;
|
||||||
|
|
||||||
if ((file->f_flags & O_ACCMODE) == O_RDONLY) {
|
if ((file->f_flags & O_ACCMODE) == O_RDONLY)
|
||||||
dvbdev->readers++;
|
dvbdev->readers++;
|
||||||
} else {
|
else
|
||||||
dvbdev->writers++;
|
dvbdev->writers++;
|
||||||
}
|
|
||||||
|
|
||||||
dvbdev->users++;
|
dvbdev->users++;
|
||||||
|
|
||||||
@ -179,7 +176,6 @@ int dvb_generic_release(struct inode *inode, struct file *file)
|
|||||||
}
|
}
|
||||||
EXPORT_SYMBOL(dvb_generic_release);
|
EXPORT_SYMBOL(dvb_generic_release);
|
||||||
|
|
||||||
|
|
||||||
long dvb_generic_ioctl(struct file *file,
|
long dvb_generic_ioctl(struct file *file,
|
||||||
unsigned int cmd, unsigned long arg)
|
unsigned int cmd, unsigned long arg)
|
||||||
{
|
{
|
||||||
@ -195,13 +191,13 @@ long dvb_generic_ioctl(struct file *file,
|
|||||||
}
|
}
|
||||||
EXPORT_SYMBOL(dvb_generic_ioctl);
|
EXPORT_SYMBOL(dvb_generic_ioctl);
|
||||||
|
|
||||||
|
static int dvbdev_get_free_id(struct dvb_adapter *adap, int type)
|
||||||
static int dvbdev_get_free_id (struct dvb_adapter *adap, int type)
|
|
||||||
{
|
{
|
||||||
u32 id = 0;
|
u32 id = 0;
|
||||||
|
|
||||||
while (id < DVB_MAX_IDS) {
|
while (id < DVB_MAX_IDS) {
|
||||||
struct dvb_device *dev;
|
struct dvb_device *dev;
|
||||||
|
|
||||||
list_for_each_entry(dev, &adap->device_list, list_head)
|
list_for_each_entry(dev, &adap->device_list, list_head)
|
||||||
if (dev->type == type && dev->id == id)
|
if (dev->type == type && dev->id == id)
|
||||||
goto skip;
|
goto skip;
|
||||||
@ -397,7 +393,7 @@ static int dvb_create_media_entity(struct dvb_device *dvbdev,
|
|||||||
|
|
||||||
static int dvb_register_media_device(struct dvb_device *dvbdev,
|
static int dvb_register_media_device(struct dvb_device *dvbdev,
|
||||||
int type, int minor,
|
int type, int minor,
|
||||||
unsigned demux_sink_pads)
|
unsigned int demux_sink_pads)
|
||||||
{
|
{
|
||||||
#if defined(CONFIG_MEDIA_CONTROLLER_DVB)
|
#if defined(CONFIG_MEDIA_CONTROLLER_DVB)
|
||||||
struct media_link *link;
|
struct media_link *link;
|
||||||
@ -464,14 +460,16 @@ int dvb_register_device(struct dvb_adapter *adap, struct dvb_device **pdvbdev,
|
|||||||
enum dvb_device_type type, int demux_sink_pads)
|
enum dvb_device_type type, int demux_sink_pads)
|
||||||
{
|
{
|
||||||
struct dvb_device *dvbdev;
|
struct dvb_device *dvbdev;
|
||||||
struct file_operations *dvbdevfops;
|
struct file_operations *dvbdevfops = NULL;
|
||||||
|
struct dvbdevfops_node *node = NULL, *new_node = NULL;
|
||||||
struct device *clsdev;
|
struct device *clsdev;
|
||||||
int minor;
|
int minor;
|
||||||
int id, ret;
|
int id, ret;
|
||||||
|
|
||||||
mutex_lock(&dvbdev_register_lock);
|
mutex_lock(&dvbdev_register_lock);
|
||||||
|
|
||||||
if ((id = dvbdev_get_free_id (adap, type)) < 0){
|
id = dvbdev_get_free_id(adap, type);
|
||||||
|
if (id < 0) {
|
||||||
mutex_unlock(&dvbdev_register_lock);
|
mutex_unlock(&dvbdev_register_lock);
|
||||||
*pdvbdev = NULL;
|
*pdvbdev = NULL;
|
||||||
pr_err("%s: couldn't find free device id\n", __func__);
|
pr_err("%s: couldn't find free device id\n", __func__);
|
||||||
@ -479,20 +477,46 @@ int dvb_register_device(struct dvb_adapter *adap, struct dvb_device **pdvbdev,
|
|||||||
}
|
}
|
||||||
|
|
||||||
*pdvbdev = dvbdev = kzalloc(sizeof(*dvbdev), GFP_KERNEL);
|
*pdvbdev = dvbdev = kzalloc(sizeof(*dvbdev), GFP_KERNEL);
|
||||||
|
if (!dvbdev) {
|
||||||
if (!dvbdev){
|
|
||||||
mutex_unlock(&dvbdev_register_lock);
|
mutex_unlock(&dvbdev_register_lock);
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
}
|
}
|
||||||
|
|
||||||
dvbdevfops = kmemdup(template->fops, sizeof(*dvbdevfops), GFP_KERNEL);
|
/*
|
||||||
|
* When a device of the same type is probe()d more than once,
|
||||||
|
* the first allocated fops are used. This prevents memory leaks
|
||||||
|
* that can occur when the same device is probe()d repeatedly.
|
||||||
|
*/
|
||||||
|
list_for_each_entry(node, &dvbdevfops_list, list_head) {
|
||||||
|
if (node->fops->owner == adap->module &&
|
||||||
|
node->type == type && node->template == template) {
|
||||||
|
dvbdevfops = node->fops;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (!dvbdevfops){
|
if (!dvbdevfops) {
|
||||||
kfree (dvbdev);
|
dvbdevfops = kmemdup(template->fops, sizeof(*dvbdevfops), GFP_KERNEL);
|
||||||
|
if (!dvbdevfops) {
|
||||||
|
kfree(dvbdev);
|
||||||
mutex_unlock(&dvbdev_register_lock);
|
mutex_unlock(&dvbdev_register_lock);
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
new_node = kzalloc(sizeof(*new_node), GFP_KERNEL);
|
||||||
|
if (!new_node) {
|
||||||
|
kfree(dvbdevfops);
|
||||||
|
kfree(dvbdev);
|
||||||
|
mutex_unlock(&dvbdev_register_lock);
|
||||||
|
return -ENOMEM;
|
||||||
|
}
|
||||||
|
|
||||||
|
new_node->fops = dvbdevfops;
|
||||||
|
new_node->type = type;
|
||||||
|
new_node->template = template;
|
||||||
|
list_add_tail(&new_node->list_head, &dvbdevfops_list);
|
||||||
|
}
|
||||||
|
|
||||||
memcpy(dvbdev, template, sizeof(struct dvb_device));
|
memcpy(dvbdev, template, sizeof(struct dvb_device));
|
||||||
kref_init(&dvbdev->ref);
|
kref_init(&dvbdev->ref);
|
||||||
dvbdev->type = type;
|
dvbdev->type = type;
|
||||||
@ -500,21 +524,21 @@ int dvb_register_device(struct dvb_adapter *adap, struct dvb_device **pdvbdev,
|
|||||||
dvbdev->adapter = adap;
|
dvbdev->adapter = adap;
|
||||||
dvbdev->priv = priv;
|
dvbdev->priv = priv;
|
||||||
dvbdev->fops = dvbdevfops;
|
dvbdev->fops = dvbdevfops;
|
||||||
init_waitqueue_head (&dvbdev->wait_queue);
|
init_waitqueue_head(&dvbdev->wait_queue);
|
||||||
|
|
||||||
dvbdevfops->owner = adap->module;
|
dvbdevfops->owner = adap->module;
|
||||||
|
list_add_tail(&dvbdev->list_head, &adap->device_list);
|
||||||
list_add_tail (&dvbdev->list_head, &adap->device_list);
|
|
||||||
|
|
||||||
down_write(&minor_rwsem);
|
down_write(&minor_rwsem);
|
||||||
#ifdef CONFIG_DVB_DYNAMIC_MINORS
|
#ifdef CONFIG_DVB_DYNAMIC_MINORS
|
||||||
for (minor = 0; minor < MAX_DVB_MINORS; minor++)
|
for (minor = 0; minor < MAX_DVB_MINORS; minor++)
|
||||||
if (dvb_minors[minor] == NULL)
|
if (!dvb_minors[minor])
|
||||||
break;
|
break;
|
||||||
|
|
||||||
if (minor == MAX_DVB_MINORS) {
|
if (minor == MAX_DVB_MINORS) {
|
||||||
list_del (&dvbdev->list_head);
|
if (new_node) {
|
||||||
|
list_del(&new_node->list_head);
|
||||||
kfree(dvbdevfops);
|
kfree(dvbdevfops);
|
||||||
|
kfree(new_node);
|
||||||
|
}
|
||||||
|
list_del(&dvbdev->list_head);
|
||||||
kfree(dvbdev);
|
kfree(dvbdev);
|
||||||
up_write(&minor_rwsem);
|
up_write(&minor_rwsem);
|
||||||
mutex_unlock(&dvbdev_register_lock);
|
mutex_unlock(&dvbdev_register_lock);
|
||||||
@ -523,46 +547,51 @@ int dvb_register_device(struct dvb_adapter *adap, struct dvb_device **pdvbdev,
|
|||||||
#else
|
#else
|
||||||
minor = nums2minor(adap->num, type, id);
|
minor = nums2minor(adap->num, type, id);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
dvbdev->minor = minor;
|
dvbdev->minor = minor;
|
||||||
dvb_minors[minor] = dvb_device_get(dvbdev);
|
dvb_minors[minor] = dvb_device_get(dvbdev);
|
||||||
up_write(&minor_rwsem);
|
up_write(&minor_rwsem);
|
||||||
|
|
||||||
ret = dvb_register_media_device(dvbdev, type, minor, demux_sink_pads);
|
ret = dvb_register_media_device(dvbdev, type, minor, demux_sink_pads);
|
||||||
if (ret) {
|
if (ret) {
|
||||||
pr_err("%s: dvb_register_media_device failed to create the mediagraph\n",
|
pr_err("%s: dvb_register_media_device failed to create the mediagraph\n",
|
||||||
__func__);
|
__func__);
|
||||||
|
if (new_node) {
|
||||||
dvb_media_device_free(dvbdev);
|
list_del(&new_node->list_head);
|
||||||
list_del (&dvbdev->list_head);
|
|
||||||
kfree(dvbdevfops);
|
kfree(dvbdevfops);
|
||||||
|
kfree(new_node);
|
||||||
|
}
|
||||||
|
dvb_media_device_free(dvbdev);
|
||||||
|
list_del(&dvbdev->list_head);
|
||||||
kfree(dvbdev);
|
kfree(dvbdev);
|
||||||
mutex_unlock(&dvbdev_register_lock);
|
mutex_unlock(&dvbdev_register_lock);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
mutex_unlock(&dvbdev_register_lock);
|
|
||||||
|
|
||||||
clsdev = device_create(dvb_class, adap->device,
|
clsdev = device_create(dvb_class, adap->device,
|
||||||
MKDEV(DVB_MAJOR, minor),
|
MKDEV(DVB_MAJOR, minor),
|
||||||
dvbdev, "dvb%d.%s%d", adap->num, dnames[type], id);
|
dvbdev, "dvb%d.%s%d", adap->num, dnames[type], id);
|
||||||
if (IS_ERR(clsdev)) {
|
if (IS_ERR(clsdev)) {
|
||||||
pr_err("%s: failed to create device dvb%d.%s%d (%ld)\n",
|
pr_err("%s: failed to create device dvb%d.%s%d (%ld)\n",
|
||||||
__func__, adap->num, dnames[type], id, PTR_ERR(clsdev));
|
__func__, adap->num, dnames[type], id, PTR_ERR(clsdev));
|
||||||
dvb_media_device_free(dvbdev);
|
if (new_node) {
|
||||||
list_del (&dvbdev->list_head);
|
list_del(&new_node->list_head);
|
||||||
kfree(dvbdevfops);
|
kfree(dvbdevfops);
|
||||||
|
kfree(new_node);
|
||||||
|
}
|
||||||
|
dvb_media_device_free(dvbdev);
|
||||||
|
list_del(&dvbdev->list_head);
|
||||||
kfree(dvbdev);
|
kfree(dvbdev);
|
||||||
|
mutex_unlock(&dvbdev_register_lock);
|
||||||
return PTR_ERR(clsdev);
|
return PTR_ERR(clsdev);
|
||||||
}
|
}
|
||||||
|
|
||||||
dprintk("DVB: register adapter%d/%s%d @ minor: %i (0x%02x)\n",
|
dprintk("DVB: register adapter%d/%s%d @ minor: %i (0x%02x)\n",
|
||||||
adap->num, dnames[type], id, minor, minor);
|
adap->num, dnames[type], id, minor, minor);
|
||||||
|
|
||||||
|
mutex_unlock(&dvbdev_register_lock);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL(dvb_register_device);
|
EXPORT_SYMBOL(dvb_register_device);
|
||||||
|
|
||||||
|
|
||||||
void dvb_remove_device(struct dvb_device *dvbdev)
|
void dvb_remove_device(struct dvb_device *dvbdev)
|
||||||
{
|
{
|
||||||
if (!dvbdev)
|
if (!dvbdev)
|
||||||
@ -577,20 +606,17 @@ void dvb_remove_device(struct dvb_device *dvbdev)
|
|||||||
|
|
||||||
device_destroy(dvb_class, MKDEV(DVB_MAJOR, dvbdev->minor));
|
device_destroy(dvb_class, MKDEV(DVB_MAJOR, dvbdev->minor));
|
||||||
|
|
||||||
list_del (&dvbdev->list_head);
|
list_del(&dvbdev->list_head);
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL(dvb_remove_device);
|
EXPORT_SYMBOL(dvb_remove_device);
|
||||||
|
|
||||||
|
|
||||||
static void dvb_free_device(struct kref *ref)
|
static void dvb_free_device(struct kref *ref)
|
||||||
{
|
{
|
||||||
struct dvb_device *dvbdev = container_of(ref, struct dvb_device, ref);
|
struct dvb_device *dvbdev = container_of(ref, struct dvb_device, ref);
|
||||||
|
|
||||||
kfree (dvbdev->fops);
|
kfree(dvbdev);
|
||||||
kfree (dvbdev);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
struct dvb_device *dvb_device_get(struct dvb_device *dvbdev)
|
struct dvb_device *dvb_device_get(struct dvb_device *dvbdev)
|
||||||
{
|
{
|
||||||
kref_get(&dvbdev->ref);
|
kref_get(&dvbdev->ref);
|
||||||
@ -598,14 +624,12 @@ struct dvb_device *dvb_device_get(struct dvb_device *dvbdev)
|
|||||||
}
|
}
|
||||||
EXPORT_SYMBOL(dvb_device_get);
|
EXPORT_SYMBOL(dvb_device_get);
|
||||||
|
|
||||||
|
|
||||||
void dvb_device_put(struct dvb_device *dvbdev)
|
void dvb_device_put(struct dvb_device *dvbdev)
|
||||||
{
|
{
|
||||||
if (dvbdev)
|
if (dvbdev)
|
||||||
kref_put(&dvbdev->ref, dvb_free_device);
|
kref_put(&dvbdev->ref, dvb_free_device);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void dvb_unregister_device(struct dvb_device *dvbdev)
|
void dvb_unregister_device(struct dvb_device *dvbdev)
|
||||||
{
|
{
|
||||||
dvb_remove_device(dvbdev);
|
dvb_remove_device(dvbdev);
|
||||||
@ -613,7 +637,6 @@ void dvb_unregister_device(struct dvb_device *dvbdev)
|
|||||||
}
|
}
|
||||||
EXPORT_SYMBOL(dvb_unregister_device);
|
EXPORT_SYMBOL(dvb_unregister_device);
|
||||||
|
|
||||||
|
|
||||||
#ifdef CONFIG_MEDIA_CONTROLLER_DVB
|
#ifdef CONFIG_MEDIA_CONTROLLER_DVB
|
||||||
|
|
||||||
static int dvb_create_io_intf_links(struct dvb_adapter *adap,
|
static int dvb_create_io_intf_links(struct dvb_adapter *adap,
|
||||||
@ -646,9 +669,9 @@ int dvb_create_media_graph(struct dvb_adapter *adap,
|
|||||||
struct media_entity *demux = NULL, *ca = NULL;
|
struct media_entity *demux = NULL, *ca = NULL;
|
||||||
struct media_link *link;
|
struct media_link *link;
|
||||||
struct media_interface *intf;
|
struct media_interface *intf;
|
||||||
unsigned demux_pad = 0;
|
unsigned int demux_pad = 0;
|
||||||
unsigned dvr_pad = 0;
|
unsigned int dvr_pad = 0;
|
||||||
unsigned ntuner = 0, ndemod = 0;
|
unsigned int ntuner = 0, ndemod = 0;
|
||||||
int ret, pad_source, pad_sink;
|
int ret, pad_source, pad_sink;
|
||||||
static const char *connector_name = "Television";
|
static const char *connector_name = "Television";
|
||||||
|
|
||||||
@ -719,7 +742,7 @@ int dvb_create_media_graph(struct dvb_adapter *adap,
|
|||||||
false);
|
false);
|
||||||
} else {
|
} else {
|
||||||
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5,2,0))
|
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5,2,0))
|
||||||
pad_sink = media_get_pad_index(tuner, true,
|
pad_sink = media_get_pad_index(tuner, MEDIA_PAD_FL_SINK,
|
||||||
PAD_SIGNAL_ANALOG);
|
PAD_SIGNAL_ANALOG);
|
||||||
if (pad_sink < 0)
|
if (pad_sink < 0)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
@ -741,7 +764,7 @@ int dvb_create_media_graph(struct dvb_adapter *adap,
|
|||||||
if (ntuner && ndemod) {
|
if (ntuner && ndemod) {
|
||||||
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5,2,0))
|
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5,2,0))
|
||||||
/* NOTE: first found tuner source pad presumed correct */
|
/* NOTE: first found tuner source pad presumed correct */
|
||||||
pad_source = media_get_pad_index(tuner, false,
|
pad_source = media_get_pad_index(tuner, MEDIA_PAD_FL_SOURCE,
|
||||||
PAD_SIGNAL_ANALOG);
|
PAD_SIGNAL_ANALOG);
|
||||||
if (pad_source < 0)
|
if (pad_source < 0)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
@ -850,8 +873,10 @@ EXPORT_SYMBOL_GPL(dvb_create_media_graph);
|
|||||||
static int dvbdev_check_free_adapter_num(int num)
|
static int dvbdev_check_free_adapter_num(int num)
|
||||||
{
|
{
|
||||||
struct list_head *entry;
|
struct list_head *entry;
|
||||||
|
|
||||||
list_for_each(entry, &dvb_adapter_list) {
|
list_for_each(entry, &dvb_adapter_list) {
|
||||||
struct dvb_adapter *adap;
|
struct dvb_adapter *adap;
|
||||||
|
|
||||||
adap = list_entry(entry, struct dvb_adapter, list_head);
|
adap = list_entry(entry, struct dvb_adapter, list_head);
|
||||||
if (adap->num == num)
|
if (adap->num == num)
|
||||||
return 0;
|
return 0;
|
||||||
@ -859,7 +884,7 @@ static int dvbdev_check_free_adapter_num(int num)
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int dvbdev_get_free_adapter_num (void)
|
static int dvbdev_get_free_adapter_num(void)
|
||||||
{
|
{
|
||||||
int num = 0;
|
int num = 0;
|
||||||
|
|
||||||
@ -872,7 +897,6 @@ static int dvbdev_get_free_adapter_num (void)
|
|||||||
return -ENFILE;
|
return -ENFILE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
int dvb_register_adapter(struct dvb_adapter *adap, const char *name,
|
int dvb_register_adapter(struct dvb_adapter *adap, const char *name,
|
||||||
struct module *module, struct device *device,
|
struct module *module, struct device *device,
|
||||||
short *adapter_nums)
|
short *adapter_nums)
|
||||||
@ -899,8 +923,8 @@ int dvb_register_adapter(struct dvb_adapter *adap, const char *name,
|
|||||||
return -ENFILE;
|
return -ENFILE;
|
||||||
}
|
}
|
||||||
|
|
||||||
memset (adap, 0, sizeof(struct dvb_adapter));
|
memset(adap, 0, sizeof(struct dvb_adapter));
|
||||||
INIT_LIST_HEAD (&adap->device_list);
|
INIT_LIST_HEAD(&adap->device_list);
|
||||||
|
|
||||||
pr_info("DVB: registering new adapter (%s)\n", name);
|
pr_info("DVB: registering new adapter (%s)\n", name);
|
||||||
|
|
||||||
@ -910,13 +934,13 @@ int dvb_register_adapter(struct dvb_adapter *adap, const char *name,
|
|||||||
adap->device = device;
|
adap->device = device;
|
||||||
adap->mfe_shared = 0;
|
adap->mfe_shared = 0;
|
||||||
adap->mfe_dvbdev = NULL;
|
adap->mfe_dvbdev = NULL;
|
||||||
mutex_init (&adap->mfe_lock);
|
mutex_init(&adap->mfe_lock);
|
||||||
|
|
||||||
#ifdef CONFIG_MEDIA_CONTROLLER_DVB
|
#ifdef CONFIG_MEDIA_CONTROLLER_DVB
|
||||||
mutex_init(&adap->mdev_lock);
|
mutex_init(&adap->mdev_lock);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
list_add_tail (&adap->list_head, &dvb_adapter_list);
|
list_add_tail(&adap->list_head, &dvb_adapter_list);
|
||||||
|
|
||||||
mutex_unlock(&dvbdev_register_lock);
|
mutex_unlock(&dvbdev_register_lock);
|
||||||
|
|
||||||
@ -924,21 +948,22 @@ int dvb_register_adapter(struct dvb_adapter *adap, const char *name,
|
|||||||
}
|
}
|
||||||
EXPORT_SYMBOL(dvb_register_adapter);
|
EXPORT_SYMBOL(dvb_register_adapter);
|
||||||
|
|
||||||
|
|
||||||
int dvb_unregister_adapter(struct dvb_adapter *adap)
|
int dvb_unregister_adapter(struct dvb_adapter *adap)
|
||||||
{
|
{
|
||||||
mutex_lock(&dvbdev_register_lock);
|
mutex_lock(&dvbdev_register_lock);
|
||||||
list_del (&adap->list_head);
|
list_del(&adap->list_head);
|
||||||
mutex_unlock(&dvbdev_register_lock);
|
mutex_unlock(&dvbdev_register_lock);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL(dvb_unregister_adapter);
|
EXPORT_SYMBOL(dvb_unregister_adapter);
|
||||||
|
|
||||||
/* if the miracle happens and "generic_usercopy()" is included into
|
/*
|
||||||
the kernel, then this can vanish. please don't make the mistake and
|
* if the miracle happens and "generic_usercopy()" is included into
|
||||||
define this as video_usercopy(). this will introduce a dependency
|
* the kernel, then this can vanish. please don't make the mistake and
|
||||||
to the v4l "videodev.o" module, which is unnecessary for some
|
* define this as video_usercopy(). this will introduce a dependency
|
||||||
cards (ie. the budget dvb-cards don't need the v4l module...) */
|
* to the v4l "videodev.o" module, which is unnecessary for some
|
||||||
|
* cards (ie. the budget dvb-cards don't need the v4l module...)
|
||||||
|
*/
|
||||||
int dvb_usercopy(struct file *file,
|
int dvb_usercopy(struct file *file,
|
||||||
unsigned int cmd, unsigned long arg,
|
unsigned int cmd, unsigned long arg,
|
||||||
int (*func)(struct file *file,
|
int (*func)(struct file *file,
|
||||||
@ -956,7 +981,7 @@ int dvb_usercopy(struct file *file,
|
|||||||
* For this command, the pointer is actually an integer
|
* For this command, the pointer is actually an integer
|
||||||
* argument.
|
* argument.
|
||||||
*/
|
*/
|
||||||
parg = (void *) arg;
|
parg = (void *)arg;
|
||||||
break;
|
break;
|
||||||
case _IOC_READ: /* some v4l ioctls are marked wrong ... */
|
case _IOC_READ: /* some v4l ioctls are marked wrong ... */
|
||||||
case _IOC_WRITE:
|
case _IOC_WRITE:
|
||||||
@ -966,7 +991,7 @@ int dvb_usercopy(struct file *file,
|
|||||||
} else {
|
} else {
|
||||||
/* too big to allocate from stack */
|
/* too big to allocate from stack */
|
||||||
mbuf = kmalloc(_IOC_SIZE(cmd), GFP_KERNEL);
|
mbuf = kmalloc(_IOC_SIZE(cmd), GFP_KERNEL);
|
||||||
if (NULL == mbuf)
|
if (!mbuf)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
parg = mbuf;
|
parg = mbuf;
|
||||||
}
|
}
|
||||||
@ -978,15 +1003,15 @@ int dvb_usercopy(struct file *file,
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* call driver */
|
/* call driver */
|
||||||
if ((err = func(file, cmd, parg)) == -ENOIOCTLCMD)
|
err = func(file, cmd, parg);
|
||||||
|
if (err == -ENOIOCTLCMD)
|
||||||
err = -ENOTTY;
|
err = -ENOTTY;
|
||||||
|
|
||||||
if (err < 0)
|
if (err < 0)
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
/* Copy results into user buffer */
|
/* Copy results into user buffer */
|
||||||
switch (_IOC_DIR(cmd))
|
switch (_IOC_DIR(cmd)) {
|
||||||
{
|
|
||||||
case _IOC_READ:
|
case _IOC_READ:
|
||||||
case (_IOC_WRITE | _IOC_READ):
|
case (_IOC_WRITE | _IOC_READ):
|
||||||
if (copy_to_user((void __user *)arg, parg, _IOC_SIZE(cmd)))
|
if (copy_to_user((void __user *)arg, parg, _IOC_SIZE(cmd)))
|
||||||
@ -998,7 +1023,6 @@ out:
|
|||||||
kfree(mbuf);
|
kfree(mbuf);
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL(dvb_usercopy);
|
|
||||||
|
|
||||||
#if IS_ENABLED(CONFIG_I2C)
|
#if IS_ENABLED(CONFIG_I2C)
|
||||||
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5,5,0))
|
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5,5,0))
|
||||||
@ -1083,13 +1107,15 @@ static int __init init_dvbdev(void)
|
|||||||
int retval;
|
int retval;
|
||||||
dev_t dev = MKDEV(DVB_MAJOR, 0);
|
dev_t dev = MKDEV(DVB_MAJOR, 0);
|
||||||
|
|
||||||
if ((retval = register_chrdev_region(dev, MAX_DVB_MINORS, "DVB")) != 0) {
|
retval = register_chrdev_region(dev, MAX_DVB_MINORS, "DVB");
|
||||||
|
if (retval != 0) {
|
||||||
pr_err("dvb-core: unable to get major %d\n", DVB_MAJOR);
|
pr_err("dvb-core: unable to get major %d\n", DVB_MAJOR);
|
||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
cdev_init(&dvb_device_cdev, &dvb_device_fops);
|
cdev_init(&dvb_device_cdev, &dvb_device_fops);
|
||||||
if ((retval = cdev_add(&dvb_device_cdev, dev, MAX_DVB_MINORS)) != 0) {
|
retval = cdev_add(&dvb_device_cdev, dev, MAX_DVB_MINORS);
|
||||||
|
if (retval != 0) {
|
||||||
pr_err("dvb-core: unable register character device\n");
|
pr_err("dvb-core: unable register character device\n");
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
@ -1113,12 +1139,19 @@ error:
|
|||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static void __exit exit_dvbdev(void)
|
static void __exit exit_dvbdev(void)
|
||||||
{
|
{
|
||||||
|
struct dvbdevfops_node *node, *next;
|
||||||
|
|
||||||
class_destroy(dvb_class);
|
class_destroy(dvb_class);
|
||||||
cdev_del(&dvb_device_cdev);
|
cdev_del(&dvb_device_cdev);
|
||||||
unregister_chrdev_region(MKDEV(DVB_MAJOR, 0), MAX_DVB_MINORS);
|
unregister_chrdev_region(MKDEV(DVB_MAJOR, 0), MAX_DVB_MINORS);
|
||||||
|
|
||||||
|
list_for_each_entry_safe(node, next, &dvbdevfops_list, list_head) {
|
||||||
|
list_del(&node->list_head);
|
||||||
|
kfree(node->fops);
|
||||||
|
kfree(node);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
subsys_initcall(init_dvbdev);
|
subsys_initcall(init_dvbdev);
|
||||||
|
@ -1643,7 +1643,7 @@ static int clear_slave(struct dvb_frontend *fe)
|
|||||||
|
|
||||||
get_field(RXEND, &done);
|
get_field(RXEND, &done);
|
||||||
get_reg(DISRXBYTES, &n);
|
get_reg(DISRXBYTES, &n);
|
||||||
printk("clear: done = %u, %u fifo bytes\n", done, n);
|
//printk("clear: done = %u, %u fifo bytes\n", done, n);
|
||||||
|
|
||||||
for (get_reg(DISRXBYTES, &n); n; n--)
|
for (get_reg(DISRXBYTES, &n); n; n--)
|
||||||
get_reg(DISRXFIFO, &d);
|
get_reg(DISRXFIFO, &d);
|
||||||
@ -1699,7 +1699,7 @@ static int recv_slave_reply(struct dvb_frontend *fe,
|
|||||||
msleep(10);
|
msleep(10);
|
||||||
}
|
}
|
||||||
get_reg(DISRXBYTES, &val);
|
get_reg(DISRXBYTES, &val);
|
||||||
printk("done = %u, %u fifo bytes, i=%u\n", done, val, i);
|
//printk("done = %u, %u fifo bytes, i=%u\n", done, val, i);
|
||||||
if (i == to && !val)
|
if (i == to && !val)
|
||||||
return -EIO;
|
return -EIO;
|
||||||
if (done && !val)
|
if (done && !val)
|
||||||
|
@ -302,6 +302,7 @@ enum fe_spectral_inversion {
|
|||||||
* @FEC_7_15: Forward Error Correction Code 7/15
|
* @FEC_7_15: Forward Error Correction Code 7/15
|
||||||
* @FEC_29_45: Forward Error Correction Code 29/45
|
* @FEC_29_45: Forward Error Correction Code 29/45
|
||||||
* @FEC_31_45: Forward Error Correction Code 31/45
|
* @FEC_31_45: Forward Error Correction Code 31/45
|
||||||
|
*
|
||||||
* Please note that not all FEC types are supported by a given standard.
|
* Please note that not all FEC types are supported by a given standard.
|
||||||
*/
|
*/
|
||||||
enum fe_code_rate {
|
enum fe_code_rate {
|
||||||
|
@ -10,6 +10,6 @@
|
|||||||
#define _DVBVERSION_H_
|
#define _DVBVERSION_H_
|
||||||
|
|
||||||
#define DVB_API_VERSION 5
|
#define DVB_API_VERSION 5
|
||||||
#define DVB_API_VERSION_MINOR 11
|
#define DVB_API_VERSION_MINOR 12
|
||||||
|
|
||||||
#endif /*_DVBVERSION_H_*/
|
#endif /*_DVBVERSION_H_*/
|
||||||
|
@ -1,246 +0,0 @@
|
|||||||
/*
|
|
||||||
* dvb_filter.h
|
|
||||||
*
|
|
||||||
* Copyright (C) 2003 Convergence GmbH
|
|
||||||
*
|
|
||||||
* This program is free software; you can redistribute it and/or
|
|
||||||
* modify it under the terms of the GNU Lesser General Public License
|
|
||||||
* as published by the Free Software Foundation; either version 2.1
|
|
||||||
* of the License, or (at your option) any later version.
|
|
||||||
*
|
|
||||||
* This program 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 General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU Lesser General Public License
|
|
||||||
* along with this program; if not, write to the Free Software
|
|
||||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef _DVB_FILTER_H_
|
|
||||||
#define _DVB_FILTER_H_
|
|
||||||
|
|
||||||
#include <linux/slab.h>
|
|
||||||
|
|
||||||
#include "demux.h"
|
|
||||||
|
|
||||||
typedef int (dvb_filter_pes2ts_cb_t) (void *, unsigned char *);
|
|
||||||
|
|
||||||
struct dvb_filter_pes2ts {
|
|
||||||
unsigned char buf[188];
|
|
||||||
unsigned char cc;
|
|
||||||
dvb_filter_pes2ts_cb_t *cb;
|
|
||||||
void *priv;
|
|
||||||
};
|
|
||||||
|
|
||||||
void dvb_filter_pes2ts_init(struct dvb_filter_pes2ts *p2ts, unsigned short pid,
|
|
||||||
dvb_filter_pes2ts_cb_t *cb, void *priv);
|
|
||||||
|
|
||||||
int dvb_filter_pes2ts(struct dvb_filter_pes2ts *p2ts, unsigned char *pes,
|
|
||||||
int len, int payload_start);
|
|
||||||
|
|
||||||
|
|
||||||
#define PROG_STREAM_MAP 0xBC
|
|
||||||
#define PRIVATE_STREAM1 0xBD
|
|
||||||
#define PADDING_STREAM 0xBE
|
|
||||||
#define PRIVATE_STREAM2 0xBF
|
|
||||||
#define AUDIO_STREAM_S 0xC0
|
|
||||||
#define AUDIO_STREAM_E 0xDF
|
|
||||||
#define VIDEO_STREAM_S 0xE0
|
|
||||||
#define VIDEO_STREAM_E 0xEF
|
|
||||||
#define ECM_STREAM 0xF0
|
|
||||||
#define EMM_STREAM 0xF1
|
|
||||||
#define DSM_CC_STREAM 0xF2
|
|
||||||
#define ISO13522_STREAM 0xF3
|
|
||||||
#define PROG_STREAM_DIR 0xFF
|
|
||||||
|
|
||||||
#define DVB_PICTURE_START 0x00
|
|
||||||
#define DVB_USER_START 0xb2
|
|
||||||
#define DVB_SEQUENCE_HEADER 0xb3
|
|
||||||
#define DVB_SEQUENCE_ERROR 0xb4
|
|
||||||
#define DVB_EXTENSION_START 0xb5
|
|
||||||
#define DVB_SEQUENCE_END 0xb7
|
|
||||||
#define DVB_GOP_START 0xb8
|
|
||||||
#define DVB_EXCEPT_SLICE 0xb0
|
|
||||||
|
|
||||||
#define SEQUENCE_EXTENSION 0x01
|
|
||||||
#define SEQUENCE_DISPLAY_EXTENSION 0x02
|
|
||||||
#define PICTURE_CODING_EXTENSION 0x08
|
|
||||||
#define QUANT_MATRIX_EXTENSION 0x03
|
|
||||||
#define PICTURE_DISPLAY_EXTENSION 0x07
|
|
||||||
|
|
||||||
#define I_FRAME 0x01
|
|
||||||
#define B_FRAME 0x02
|
|
||||||
#define P_FRAME 0x03
|
|
||||||
|
|
||||||
/* Initialize sequence_data */
|
|
||||||
#define INIT_HORIZONTAL_SIZE 720
|
|
||||||
#define INIT_VERTICAL_SIZE 576
|
|
||||||
#define INIT_ASPECT_RATIO 0x02
|
|
||||||
#define INIT_FRAME_RATE 0x03
|
|
||||||
#define INIT_DISP_HORIZONTAL_SIZE 540
|
|
||||||
#define INIT_DISP_VERTICAL_SIZE 576
|
|
||||||
|
|
||||||
|
|
||||||
//flags2
|
|
||||||
#define PTS_DTS_FLAGS 0xC0
|
|
||||||
#define ESCR_FLAG 0x20
|
|
||||||
#define ES_RATE_FLAG 0x10
|
|
||||||
#define DSM_TRICK_FLAG 0x08
|
|
||||||
#define ADD_CPY_FLAG 0x04
|
|
||||||
#define PES_CRC_FLAG 0x02
|
|
||||||
#define PES_EXT_FLAG 0x01
|
|
||||||
|
|
||||||
//pts_dts flags
|
|
||||||
#define PTS_ONLY 0x80
|
|
||||||
#define PTS_DTS 0xC0
|
|
||||||
|
|
||||||
#define TS_SIZE 188
|
|
||||||
#define TRANS_ERROR 0x80
|
|
||||||
#define PAY_START 0x40
|
|
||||||
#define TRANS_PRIO 0x20
|
|
||||||
#define PID_MASK_HI 0x1F
|
|
||||||
//flags
|
|
||||||
#define TRANS_SCRMBL1 0x80
|
|
||||||
#define TRANS_SCRMBL2 0x40
|
|
||||||
#define ADAPT_FIELD 0x20
|
|
||||||
#define PAYLOAD 0x10
|
|
||||||
#define COUNT_MASK 0x0F
|
|
||||||
|
|
||||||
// adaptation flags
|
|
||||||
#define DISCON_IND 0x80
|
|
||||||
#define RAND_ACC_IND 0x40
|
|
||||||
#define ES_PRI_IND 0x20
|
|
||||||
#define PCR_FLAG 0x10
|
|
||||||
#define OPCR_FLAG 0x08
|
|
||||||
#define SPLICE_FLAG 0x04
|
|
||||||
#define TRANS_PRIV 0x02
|
|
||||||
#define ADAP_EXT_FLAG 0x01
|
|
||||||
|
|
||||||
// adaptation extension flags
|
|
||||||
#define LTW_FLAG 0x80
|
|
||||||
#define PIECE_RATE 0x40
|
|
||||||
#define SEAM_SPLICE 0x20
|
|
||||||
|
|
||||||
|
|
||||||
#define MAX_PLENGTH 0xFFFF
|
|
||||||
#define MMAX_PLENGTH (256*MAX_PLENGTH)
|
|
||||||
|
|
||||||
#ifndef IPACKS
|
|
||||||
#define IPACKS 2048
|
|
||||||
#endif
|
|
||||||
|
|
||||||
struct ipack {
|
|
||||||
int size;
|
|
||||||
int found;
|
|
||||||
u8 *buf;
|
|
||||||
u8 cid;
|
|
||||||
u32 plength;
|
|
||||||
u8 plen[2];
|
|
||||||
u8 flag1;
|
|
||||||
u8 flag2;
|
|
||||||
u8 hlength;
|
|
||||||
u8 pts[5];
|
|
||||||
u16 *pid;
|
|
||||||
int mpeg;
|
|
||||||
u8 check;
|
|
||||||
int which;
|
|
||||||
int done;
|
|
||||||
void *data;
|
|
||||||
void (*func)(u8 *buf, int size, void *priv);
|
|
||||||
int count;
|
|
||||||
int repack_subids;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct dvb_video_info {
|
|
||||||
u32 horizontal_size;
|
|
||||||
u32 vertical_size;
|
|
||||||
u32 aspect_ratio;
|
|
||||||
u32 framerate;
|
|
||||||
u32 video_format;
|
|
||||||
u32 bit_rate;
|
|
||||||
u32 comp_bit_rate;
|
|
||||||
u32 vbv_buffer_size;
|
|
||||||
s16 vbv_delay;
|
|
||||||
u32 CSPF;
|
|
||||||
u32 off;
|
|
||||||
};
|
|
||||||
|
|
||||||
#define OFF_SIZE 4
|
|
||||||
#define FIRST_FIELD 0
|
|
||||||
#define SECOND_FIELD 1
|
|
||||||
#define VIDEO_FRAME_PICTURE 0x03
|
|
||||||
|
|
||||||
struct mpg_picture {
|
|
||||||
int channel;
|
|
||||||
struct dvb_video_info vinfo;
|
|
||||||
u32 *sequence_gop_header;
|
|
||||||
u32 *picture_header;
|
|
||||||
s32 time_code;
|
|
||||||
int low_delay;
|
|
||||||
int closed_gop;
|
|
||||||
int broken_link;
|
|
||||||
int sequence_header_flag;
|
|
||||||
int gop_flag;
|
|
||||||
int sequence_end_flag;
|
|
||||||
|
|
||||||
u8 profile_and_level;
|
|
||||||
s32 picture_coding_parameter;
|
|
||||||
u32 matrix[32];
|
|
||||||
s8 matrix_change_flag;
|
|
||||||
|
|
||||||
u8 picture_header_parameter;
|
|
||||||
/* bit 0 - 2: bwd f code
|
|
||||||
bit 3 : fpb vector
|
|
||||||
bit 4 - 6: fwd f code
|
|
||||||
bit 7 : fpf vector */
|
|
||||||
|
|
||||||
int mpeg1_flag;
|
|
||||||
int progressive_sequence;
|
|
||||||
int sequence_display_extension_flag;
|
|
||||||
u32 sequence_header_data;
|
|
||||||
s16 last_frame_centre_horizontal_offset;
|
|
||||||
s16 last_frame_centre_vertical_offset;
|
|
||||||
|
|
||||||
u32 pts[2]; /* [0] 1st field, [1] 2nd field */
|
|
||||||
int top_field_first;
|
|
||||||
int repeat_first_field;
|
|
||||||
int progressive_frame;
|
|
||||||
int bank;
|
|
||||||
int forward_bank;
|
|
||||||
int backward_bank;
|
|
||||||
int compress;
|
|
||||||
s16 frame_centre_horizontal_offset[OFF_SIZE];
|
|
||||||
/* [0-2] 1st field, [3] 2nd field */
|
|
||||||
s16 frame_centre_vertical_offset[OFF_SIZE];
|
|
||||||
/* [0-2] 1st field, [3] 2nd field */
|
|
||||||
s16 temporal_reference[2];
|
|
||||||
/* [0] 1st field, [1] 2nd field */
|
|
||||||
|
|
||||||
s8 picture_coding_type[2];
|
|
||||||
/* [0] 1st field, [1] 2nd field */
|
|
||||||
s8 picture_structure[2];
|
|
||||||
/* [0] 1st field, [1] 2nd field */
|
|
||||||
s8 picture_display_extension_flag[2];
|
|
||||||
/* [0] 1st field, [1] 2nd field */
|
|
||||||
/* picture_display_extenion() 0:no 1:exit*/
|
|
||||||
s8 pts_flag[2];
|
|
||||||
/* [0] 1st field, [1] 2nd field */
|
|
||||||
};
|
|
||||||
|
|
||||||
struct dvb_audio_info {
|
|
||||||
int layer;
|
|
||||||
u32 bit_rate;
|
|
||||||
u32 frequency;
|
|
||||||
u32 mode;
|
|
||||||
u32 mode_extension ;
|
|
||||||
u32 emphasis;
|
|
||||||
u32 framesize;
|
|
||||||
u32 off;
|
|
||||||
};
|
|
||||||
|
|
||||||
int dvb_filter_get_ac3info(u8 *mbuf, int count, struct dvb_audio_info *ai, int pr);
|
|
||||||
|
|
||||||
|
|
||||||
#endif
|
|
@ -19,13 +19,11 @@
|
|||||||
#define _DVB_NET_H_
|
#define _DVB_NET_H_
|
||||||
|
|
||||||
#include <linux/module.h>
|
#include <linux/module.h>
|
||||||
#include <linux/netdevice.h>
|
|
||||||
#include <linux/inetdevice.h>
|
|
||||||
#include <linux/etherdevice.h>
|
|
||||||
#include <linux/skbuff.h>
|
|
||||||
|
|
||||||
#include <media/dvbdev.h>
|
#include <media/dvbdev.h>
|
||||||
|
|
||||||
|
struct net_device;
|
||||||
|
|
||||||
#define DVB_NET_DEVICES_MAX 10
|
#define DVB_NET_DEVICES_MAX 10
|
||||||
|
|
||||||
#ifdef CONFIG_DVB_NET
|
#ifdef CONFIG_DVB_NET
|
||||||
@ -41,6 +39,9 @@
|
|||||||
* @exit: flag to indicate when the device is being removed.
|
* @exit: flag to indicate when the device is being removed.
|
||||||
* @demux: pointer to &struct dmx_demux.
|
* @demux: pointer to &struct dmx_demux.
|
||||||
* @ioctl_mutex: protect access to this struct.
|
* @ioctl_mutex: protect access to this struct.
|
||||||
|
* @remove_mutex: mutex that avoids a race condition between a callback
|
||||||
|
* called when the hardware is disconnected and the
|
||||||
|
* file_operations of dvb_net.
|
||||||
*
|
*
|
||||||
* Currently, the core supports up to %DVB_NET_DEVICES_MAX (10) network
|
* Currently, the core supports up to %DVB_NET_DEVICES_MAX (10) network
|
||||||
* devices.
|
* devices.
|
||||||
@ -53,6 +54,7 @@ struct dvb_net {
|
|||||||
unsigned int exit:1;
|
unsigned int exit:1;
|
||||||
struct dmx_demux *demux;
|
struct dmx_demux *demux;
|
||||||
struct mutex ioctl_mutex;
|
struct mutex ioctl_mutex;
|
||||||
|
struct mutex remove_mutex;
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -139,7 +139,7 @@ struct dvb_adapter {
|
|||||||
* struct dvb_device - represents a DVB device node
|
* struct dvb_device - represents a DVB device node
|
||||||
*
|
*
|
||||||
* @list_head: List head with all DVB devices
|
* @list_head: List head with all DVB devices
|
||||||
* @ref: reference counter
|
* @ref: reference count for this device
|
||||||
* @fops: pointer to struct file_operations
|
* @fops: pointer to struct file_operations
|
||||||
* @adapter: pointer to the adapter that holds this device node
|
* @adapter: pointer to the adapter that holds this device node
|
||||||
* @type: type of the device, as defined by &enum dvb_device_type.
|
* @type: type of the device, as defined by &enum dvb_device_type.
|
||||||
@ -202,6 +202,21 @@ struct dvb_device {
|
|||||||
void *priv;
|
void *priv;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* struct dvbdevfops_node - fops nodes registered in dvbdevfops_list
|
||||||
|
*
|
||||||
|
* @fops: Dynamically allocated fops for ->owner registration
|
||||||
|
* @type: type of dvb_device
|
||||||
|
* @template: dvb_device used for registration
|
||||||
|
* @list_head: list_head for dvbdevfops_list
|
||||||
|
*/
|
||||||
|
struct dvbdevfops_node {
|
||||||
|
struct file_operations *fops;
|
||||||
|
enum dvb_device_type type;
|
||||||
|
const struct dvb_device *template;
|
||||||
|
struct list_head list_head;
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* dvb_device_get - Increase dvb_device reference
|
* dvb_device_get - Increase dvb_device reference
|
||||||
*
|
*
|
||||||
@ -260,10 +275,10 @@ int dvb_register_device(struct dvb_adapter *adap,
|
|||||||
/**
|
/**
|
||||||
* dvb_remove_device - Remove a registered DVB device
|
* dvb_remove_device - Remove a registered DVB device
|
||||||
*
|
*
|
||||||
|
* @dvbdev: pointer to struct dvb_device
|
||||||
|
*
|
||||||
* This does not free memory. dvb_free_device() will do that when
|
* This does not free memory. dvb_free_device() will do that when
|
||||||
* reference counter is empty
|
* reference counter is empty
|
||||||
*
|
|
||||||
* @dvbdev: pointer to struct dvb_device
|
|
||||||
*/
|
*/
|
||||||
void dvb_remove_device(struct dvb_device *dvbdev);
|
void dvb_remove_device(struct dvb_device *dvbdev);
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user