diff --git a/apps/modtest.c b/apps/modtest.c index de04850..bec55b5 100644 --- a/apps/modtest.c +++ b/apps/modtest.c @@ -866,7 +866,7 @@ int mci_set_output(int fd, uint8_t connector, uint8_t nchannels, uint8_t unit, 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 ); 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"); 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: fprintf(stderr,"unknown standard in channels setup\n"); return -1; 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); 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]; @@ -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); 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); + break; - re = mci_set_channels(fd, freq, nchan, MOD_STANDARD_DVBT_8, 0, 0); + default: + re = -1; + } close(fd); 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, uint16_t cell_identifier) { - struct mci_command msg_stream = { - .mod_command = MOD_SETUP_STREAM, - .mod_channel = 0, - .mod_stream = 0, - .mod_setup_stream = { - .standard = MOD_STANDARD_DVBC_8, - }, - }; - + struct mci_command msg_stream; + + memset(&msg_stream,0,sizeof(msg_stream)); + + msg_stream.mod_command = MOD_SETUP_STREAM; msg_stream.mod_channel = channel; msg_stream.mod_stream = stream; msg_stream.mod_setup_stream.standard = standard; @@ -990,25 +1009,30 @@ int mci_set_stream( int fd, uint8_t stream, uint8_t channel, uint8_t standard, msg_stream.mod_setup_stream.qam.modulation = modulation; if (rolloff) msg_stream.mod_setup_stream.qam.rolloff = rolloff; - msg_stream.mod_setup_stream.ofdm.fft_size = fft_size; - msg_stream.mod_setup_stream.ofdm.guard_interval = guard_interval; - msg_stream.mod_setup_stream.ofdm.puncture_rate = puncture_rate; - msg_stream.mod_setup_stream.ofdm.constellation = constellation; + if (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; + if (puncture_rate) + msg_stream.mod_setup_stream.ofdm.puncture_rate = puncture_rate; + if (constellation) + msg_stream.mod_setup_stream.ofdm.constellation = constellation; if (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); } -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)|| - (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); } wd->chans = chans; @@ -1019,16 +1043,29 @@ void set_dvbt_mods(int adapt, int chans, uint32_t start_freq, write_data *wd) char *device; int fd; - wd->tp[i].tpid = 1; // all the same transport stream id - wd->tp[i].delsys = SYS_DVBT; + wd->tp[i].tpid = i; + wd->tp[i].delsys = delsys; 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; + 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].guard = 0; + wd->tp[i].code_rate = 0; + wd->tp[i].trans_mode = 0; + break; + } device = malloc(sizeof(char)*40); snprintf(device,35,"/dev/dvb/adapter%d/mod%d",adapt,i); fd = open(device, O_RDWR); @@ -1038,106 +1075,29 @@ void set_dvbt_mods(int adapt, int chans, uint32_t start_freq, write_data *wd) free(device); exit(1); } + + int re= 0; + uint8_t stream_format = 4; //format is ransport stream + uint8_t fft_size = wd->tp[i].trans_mode; - 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++){ - char *device; - int fd; - - wd->tp[i].tpid = i; - wd->tp[i].delsys = SYS_DVBC_ANNEX_A; - wd->tp[i].freq = freq; - wd->tp[i].qam = qam; - wd->tp[i].symbolrate = sym; - wd->tp[i].bandwidth = 0; - wd->tp[i].guard = 0; - wd->tp[i].code_rate = 0; - wd->tp[i].trans_mode = 0; - - 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); + 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 (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){ - fprintf(stderr,"setting bitrate %d failed\n", - (int)DEFAULT_BIT_RATE_C); - exit(1); - } - - freq += 8000000; + if (re < 0) fprintf(stderr,"ERROR setting stream\n"); close(fd); free(device); } @@ -1296,9 +1256,9 @@ int main(int argc, char **argv) chans = ddevices.ndevs[adapt]; if (dvbt){ - set_dvbt_mods(adapt, chans, start_freq, &wd); + set_dvb_mods(adapt, chans, start_freq, SYS_DVBT, &wd); } 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); diff --git a/ddbridge/ddbridge-ci.c b/ddbridge/ddbridge-ci.c index d7a36aa..33f419b 100644 --- a/ddbridge/ddbridge-ci.c +++ b/ddbridge/ddbridge-ci.c @@ -237,6 +237,8 @@ static int slot_reset_xo2(struct dvb_ca_en50221 *ca, int slot) { struct ddb_ci *ci = ca->data; + write_creg(ci, 0x00, 0x01); + msleep(300); write_creg(ci, 0x01, 0x01); write_creg(ci, 0x04, 0x04); msleep(300); diff --git a/dvb-core/Kconfig b/dvb-core/Kconfig index 6ffac61..8b3f2d5 100644 --- a/dvb-core/Kconfig +++ b/dvb-core/Kconfig @@ -6,7 +6,7 @@ config DVB_MMAP bool "Enable DVB memory-mapped API (EXPERIMENTAL)" 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 help This option enables DVB experimental memory-mapped API, which diff --git a/dvb-core/Makefile b/dvb-core/Makefile index c9ff666..3894b5f 100644 --- a/dvb-core/Makefile +++ b/dvb-core/Makefile @@ -6,8 +6,8 @@ dvb-net-$(CONFIG_DVB_NET) := dvb_net.o dvb-vb2-$(CONFIG_DVB_MMAP) := dvb_vb2.o -dvb-core-objs := dvbdev.o dmxdev.o dvb_demux.o \ - dvb_ca_en50221.o dvb_frontend.o \ +dvb-core-objs := dvbdev.o dmxdev.o dvb_demux.o \ + dvb_ca_en50221.o dvb_frontend.o \ $(dvb-net-y) dvb_ringbuffer.o $(dvb-vb2-y) dvb_math.o obj-$(CONFIG_DVB_CORE) += dvb-core.o diff --git a/dvb-core/Makefile.kernel b/dvb-core/Makefile.kernel index 0814bc9..535070e 100644 --- a/dvb-core/Makefile.kernel +++ b/dvb-core/Makefile.kernel @@ -4,7 +4,7 @@ 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-net-y) dvb_ringbuffer.o dvb_math.o diff --git a/dvb-core/dvb_ca_en50221.c b/dvb-core/dvb_ca_en50221.c index 208c9ef..3187394 100644 --- a/dvb-core/dvb_ca_en50221.c +++ b/dvb-core/dvb_ca_en50221.c @@ -158,6 +158,12 @@ struct dvb_ca_private { /* mutex serializing ioctls */ 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) @@ -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, u8 *ebuf, int ecount); 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. @@ -785,18 +791,19 @@ exit: * @buf: The data in this buffer is treated as a complete link-level packet to * be written. * @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. */ 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]; int status; int i; dprintk("%s\n", __func__); - flags=0; /* sanity check */ if (bytes_write > sl->link_buf_size) return -EINVAL; @@ -824,7 +831,7 @@ static int dvb_ca_en50221_write_data(struct dvb_ca_private *ca, int slot, /* OK, set HC bit */ status = ca->pub->write_cam_control(ca->pub, slot, CTRLIF_COMMAND, - IRQEN | CMDREG_HC | flags); + IRQEN | CMDREG_HC | size_write_flag); if (status) 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); 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: 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)) slot = array_index_nospec(slot, ca->slot_count); #endif + info->type = CA_CI_LINK; info->flags = 0; sl = &ca->slot_info[slot]; @@ -1490,6 +1498,7 @@ static ssize_t dvb_ca_en50221_io_write(struct file *file, return -EFAULT; buf += 2; count -= 2; + if (slot >= ca->slot_count) return -EINVAL; #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__); - 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; + } err = dvb_generic_open(inode, file); if (err < 0) { module_put(ca->pub->owner); + mutex_unlock(&ca->remove_mutex); return err; } @@ -1764,6 +1783,7 @@ static int dvb_ca_en50221_io_open(struct inode *inode, struct file *file) dvb_ca_private_get(ca); + mutex_unlock(&ca->remove_mutex); return 0; } @@ -1783,6 +1803,8 @@ static int dvb_ca_en50221_io_release(struct inode *inode, struct file *file) dprintk("%s\n", __func__); + mutex_lock(&ca->remove_mutex); + /* mark the CA device as closed */ ca->open = 0; 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); + 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; } @@ -1920,6 +1949,7 @@ int dvb_ca_en50221_init(struct dvb_adapter *dvb_adapter, } mutex_init(&ca->ioctl_mutex); + mutex_init(&ca->remove_mutex); if (signal_pending(current)) { ret = -EINTR; @@ -1962,6 +1992,14 @@ void dvb_ca_en50221_release(struct dvb_ca_en50221 *pubca) 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 */ kthread_stop(ca->thread); diff --git a/dvb-core/dvb_demux.c b/dvb-core/dvb_demux.c index dd29a59..50f9dad 100644 --- a/dvb-core/dvb_demux.c +++ b/dvb-core/dvb_demux.c @@ -128,12 +128,12 @@ static inline int dvb_dmx_swfilter_payload(struct dvb_demux_feed *feed, cc = buf[3] & 0x0f; ccok = ((feed->cc + 1) & 0x0f) == cc; - feed->cc = cc; if (!ccok) { set_buf_flags(feed, DMX_BUFFER_FLAG_DISCONTINUITY_DETECTED); dprintk_sect_loss("missed packet: %d instead of %d!\n", cc, (feed->cc + 1) & 0x0f); } + feed->cc = cc; if (buf[1] & 0x40) // PUSI ? feed->peslen = 0xfffa; @@ -313,7 +313,6 @@ static int dvb_dmx_swfilter_section_packet(struct dvb_demux_feed *feed, cc = buf[3] & 0x0f; ccok = ((feed->cc + 1) & 0x0f) == cc; - feed->cc = cc; if (buf[3] & 0x20) { /* 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; dvb_dmx_swfilter_section_new(feed); } + feed->cc = cc; if (buf[1] & 0x40) { /* PUSI=1 (is set), section boundary is here */ diff --git a/dvb-core/dvb_filter.c b/dvb-core/dvb_filter.c deleted file mode 100644 index 772003f..0000000 --- a/dvb-core/dvb_filter.c +++ /dev/null @@ -1,603 +0,0 @@ -#include -#include -#include -#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); diff --git a/dvb-core/dvb_frontend.c b/dvb-core/dvb_frontend.c index 0c462c5..6a1caca 100644 --- a/dvb-core/dvb_frontend.c +++ b/dvb-core/dvb_frontend.c @@ -299,14 +299,22 @@ static int dvb_frontend_get_event(struct dvb_frontend *fe, } if (events->eventw == events->eventr) { - int ret; + struct wait_queue_entry wait; + int ret = 0; if (flags & O_NONBLOCK) return -EWOULDBLOCK; - ret = wait_event_interruptible(events->wait_queue, - dvb_frontend_test_event(fepriv, events)); - + init_waitqueue_entry(&wait, current); + 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) return ret; } diff --git a/dvb-core/dvb_net.c b/dvb-core/dvb_net.c index 0dd739e..4d013cc 100644 --- a/dvb-core/dvb_net.c +++ b/dvb-core/dvb_net.c @@ -665,7 +665,7 @@ static void dvb_net_ule_check_crc(struct dvb_net_ule_handle *h, h->ts_remain > 2 ? *(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[1].iov_base, iov[1].iov_len); hexdump(iov[2].iov_base, iov[2].iov_len); @@ -995,8 +995,8 @@ static void dvb_net_sec(struct net_device *dev, } static int dvb_net_sec_callback(const u8 *buffer1, size_t buffer1_len, - const u8 *buffer2, size_t buffer2_len, - struct dmx_section_filter *filter, u32 *buffer_flags) + const u8 *buffer2, size_t buffer2_len, + struct dmx_section_filter *filter, u32 *buffer_flags) { struct net_device *dev = filter->priv; @@ -1290,6 +1290,7 @@ static int dvb_net_set_mac (struct net_device *dev, void *p) #else eth_hw_addr_set(dev, addr->sa_data); #endif + if (netif_running(dev)) 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); } +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) { struct dvb_device *dvbdev = file->private_data; struct dvb_net *dvbnet = dvbdev->priv; + mutex_lock(&dvbnet->remove_mutex); + 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); + } else { + mutex_unlock(&dvbnet->remove_mutex); + } + 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 = { .owner = THIS_MODULE, .unlocked_ioctl = dvb_net_ioctl, - .open = dvb_generic_open, + .open = locked_dvb_net_open, .release = dvb_net_close, .llseek = noop_llseek, }; @@ -1624,10 +1653,13 @@ void dvb_net_release (struct dvb_net *dvbnet) { int i; + mutex_lock(&dvbnet->remove_mutex); dvbnet->exit = 1; + mutex_unlock(&dvbnet->remove_mutex); + if (dvbnet->dvbdev->users < 1) wait_event(dvbnet->dvbdev->wait_queue, - dvbnet->dvbdev->users==1); + dvbnet->dvbdev->users == 1); dvb_unregister_device(dvbnet->dvbdev); @@ -1646,6 +1678,7 @@ int dvb_net_init (struct dvb_adapter *adap, struct dvb_net *dvbnet, int i; mutex_init(&dvbnet->ioctl_mutex); + mutex_init(&dvbnet->remove_mutex); dvbnet->demux = dmx; for (i=0; iprivate_data; @@ -165,11 +163,10 @@ int dvb_generic_release(struct inode *inode, struct file *file) if (!dvbdev) return -ENODEV; - if ((file->f_flags & O_ACCMODE) == O_RDONLY) { + if ((file->f_flags & O_ACCMODE) == O_RDONLY) dvbdev->readers++; - } else { + else dvbdev->writers++; - } dvbdev->users++; @@ -179,7 +176,6 @@ int dvb_generic_release(struct inode *inode, struct file *file) } EXPORT_SYMBOL(dvb_generic_release); - long dvb_generic_ioctl(struct file *file, unsigned int cmd, unsigned long arg) { @@ -195,13 +191,13 @@ long dvb_generic_ioctl(struct file *file, } 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; while (id < DVB_MAX_IDS) { struct dvb_device *dev; + list_for_each_entry(dev, &adap->device_list, list_head) if (dev->type == type && dev->id == id) goto skip; @@ -255,7 +251,7 @@ static void dvb_media_device_free(struct dvb_device *dvbdev) #if defined(CONFIG_MEDIA_CONTROLLER_DVB) static int dvb_create_tsout_entity(struct dvb_device *dvbdev, - const char *name, int npads) + const char *name, int npads) { int i; @@ -397,7 +393,7 @@ static int dvb_create_media_entity(struct dvb_device *dvbdev, static int dvb_register_media_device(struct dvb_device *dvbdev, int type, int minor, - unsigned demux_sink_pads) + unsigned int demux_sink_pads) { #if defined(CONFIG_MEDIA_CONTROLLER_DVB) 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) { struct dvb_device *dvbdev; - struct file_operations *dvbdevfops; + struct file_operations *dvbdevfops = NULL; + struct dvbdevfops_node *node = NULL, *new_node = NULL; struct device *clsdev; int minor; int id, ret; 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); *pdvbdev = NULL; pr_err("%s: couldn't find free device id\n", __func__); @@ -479,18 +477,44 @@ int dvb_register_device(struct dvb_adapter *adap, struct dvb_device **pdvbdev, } *pdvbdev = dvbdev = kzalloc(sizeof(*dvbdev), GFP_KERNEL); - - if (!dvbdev){ + if (!dvbdev) { mutex_unlock(&dvbdev_register_lock); 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){ - kfree (dvbdev); - mutex_unlock(&dvbdev_register_lock); - return -ENOMEM; + if (!dvbdevfops) { + dvbdevfops = kmemdup(template->fops, sizeof(*dvbdevfops), GFP_KERNEL); + if (!dvbdevfops) { + kfree(dvbdev); + mutex_unlock(&dvbdev_register_lock); + 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)); @@ -500,21 +524,21 @@ int dvb_register_device(struct dvb_adapter *adap, struct dvb_device **pdvbdev, dvbdev->adapter = adap; dvbdev->priv = priv; dvbdev->fops = dvbdevfops; - init_waitqueue_head (&dvbdev->wait_queue); - + init_waitqueue_head(&dvbdev->wait_queue); 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); #ifdef CONFIG_DVB_DYNAMIC_MINORS for (minor = 0; minor < MAX_DVB_MINORS; minor++) - if (dvb_minors[minor] == NULL) + if (!dvb_minors[minor]) break; - if (minor == MAX_DVB_MINORS) { - list_del (&dvbdev->list_head); - kfree(dvbdevfops); + if (new_node) { + list_del(&new_node->list_head); + kfree(dvbdevfops); + kfree(new_node); + } + list_del(&dvbdev->list_head); kfree(dvbdev); up_write(&minor_rwsem); mutex_unlock(&dvbdev_register_lock); @@ -523,46 +547,51 @@ int dvb_register_device(struct dvb_adapter *adap, struct dvb_device **pdvbdev, #else minor = nums2minor(adap->num, type, id); #endif - dvbdev->minor = minor; dvb_minors[minor] = dvb_device_get(dvbdev); up_write(&minor_rwsem); - ret = dvb_register_media_device(dvbdev, type, minor, demux_sink_pads); if (ret) { pr_err("%s: dvb_register_media_device failed to create the mediagraph\n", - __func__); - + __func__); + if (new_node) { + list_del(&new_node->list_head); + kfree(dvbdevfops); + kfree(new_node); + } dvb_media_device_free(dvbdev); - list_del (&dvbdev->list_head); - kfree(dvbdevfops); + list_del(&dvbdev->list_head); kfree(dvbdev); mutex_unlock(&dvbdev_register_lock); return ret; } - mutex_unlock(&dvbdev_register_lock); - clsdev = device_create(dvb_class, adap->device, MKDEV(DVB_MAJOR, minor), dvbdev, "dvb%d.%s%d", adap->num, dnames[type], id); if (IS_ERR(clsdev)) { pr_err("%s: failed to create device dvb%d.%s%d (%ld)\n", __func__, adap->num, dnames[type], id, PTR_ERR(clsdev)); + if (new_node) { + list_del(&new_node->list_head); + kfree(dvbdevfops); + kfree(new_node); + } dvb_media_device_free(dvbdev); - list_del (&dvbdev->list_head); - kfree(dvbdevfops); + list_del(&dvbdev->list_head); kfree(dvbdev); + mutex_unlock(&dvbdev_register_lock); return PTR_ERR(clsdev); } + dprintk("DVB: register adapter%d/%s%d @ minor: %i (0x%02x)\n", adap->num, dnames[type], id, minor, minor); + mutex_unlock(&dvbdev_register_lock); return 0; } EXPORT_SYMBOL(dvb_register_device); - void dvb_remove_device(struct dvb_device *dvbdev) { if (!dvbdev) @@ -577,20 +606,17 @@ void dvb_remove_device(struct dvb_device *dvbdev) device_destroy(dvb_class, MKDEV(DVB_MAJOR, dvbdev->minor)); - list_del (&dvbdev->list_head); + list_del(&dvbdev->list_head); } EXPORT_SYMBOL(dvb_remove_device); - static void dvb_free_device(struct kref *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) { kref_get(&dvbdev->ref); @@ -598,14 +624,12 @@ struct dvb_device *dvb_device_get(struct dvb_device *dvbdev) } EXPORT_SYMBOL(dvb_device_get); - void dvb_device_put(struct dvb_device *dvbdev) { if (dvbdev) kref_put(&dvbdev->ref, dvb_free_device); } - void dvb_unregister_device(struct dvb_device *dvbdev) { dvb_remove_device(dvbdev); @@ -613,7 +637,6 @@ void dvb_unregister_device(struct dvb_device *dvbdev) } EXPORT_SYMBOL(dvb_unregister_device); - #ifdef CONFIG_MEDIA_CONTROLLER_DVB 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_link *link; struct media_interface *intf; - unsigned demux_pad = 0; - unsigned dvr_pad = 0; - unsigned ntuner = 0, ndemod = 0; + unsigned int demux_pad = 0; + unsigned int dvr_pad = 0; + unsigned int ntuner = 0, ndemod = 0; int ret, pad_source, pad_sink; static const char *connector_name = "Television"; @@ -719,7 +742,7 @@ int dvb_create_media_graph(struct dvb_adapter *adap, false); } else { #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); if (pad_sink < 0) return -EINVAL; @@ -741,7 +764,7 @@ int dvb_create_media_graph(struct dvb_adapter *adap, if (ntuner && ndemod) { #if (LINUX_VERSION_CODE >= KERNEL_VERSION(5,2,0)) /* 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); if (pad_source < 0) return -EINVAL; @@ -781,18 +804,18 @@ int dvb_create_media_graph(struct dvb_adapter *adap, media_device_for_each_entity(entity, mdev) { if (entity->function == MEDIA_ENT_F_IO_DTV) { if (!strncmp(entity->name, DVR_TSOUT, - strlen(DVR_TSOUT))) { + strlen(DVR_TSOUT))) { ret = media_create_pad_link(demux, - ++dvr_pad, - entity, 0, 0); + ++dvr_pad, + entity, 0, 0); if (ret) return ret; } if (!strncmp(entity->name, DEMUX_TSOUT, - strlen(DEMUX_TSOUT))) { + strlen(DEMUX_TSOUT))) { ret = media_create_pad_link(demux, - ++demux_pad, - entity, 0, 0); + ++demux_pad, + entity, 0, 0); if (ret) return ret; } @@ -850,8 +873,10 @@ EXPORT_SYMBOL_GPL(dvb_create_media_graph); static int dvbdev_check_free_adapter_num(int num) { struct list_head *entry; + list_for_each(entry, &dvb_adapter_list) { struct dvb_adapter *adap; + adap = list_entry(entry, struct dvb_adapter, list_head); if (adap->num == num) return 0; @@ -859,7 +884,7 @@ static int dvbdev_check_free_adapter_num(int num) return 1; } -static int dvbdev_get_free_adapter_num (void) +static int dvbdev_get_free_adapter_num(void) { int num = 0; @@ -872,7 +897,6 @@ static int dvbdev_get_free_adapter_num (void) return -ENFILE; } - int dvb_register_adapter(struct dvb_adapter *adap, const char *name, struct module *module, struct device *device, short *adapter_nums) @@ -899,8 +923,8 @@ int dvb_register_adapter(struct dvb_adapter *adap, const char *name, return -ENFILE; } - memset (adap, 0, sizeof(struct dvb_adapter)); - INIT_LIST_HEAD (&adap->device_list); + memset(adap, 0, sizeof(struct dvb_adapter)); + INIT_LIST_HEAD(&adap->device_list); 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->mfe_shared = 0; adap->mfe_dvbdev = NULL; - mutex_init (&adap->mfe_lock); + mutex_init(&adap->mfe_lock); #ifdef CONFIG_MEDIA_CONTROLLER_DVB mutex_init(&adap->mdev_lock); #endif - list_add_tail (&adap->list_head, &dvb_adapter_list); + list_add_tail(&adap->list_head, &dvb_adapter_list); mutex_unlock(&dvbdev_register_lock); @@ -924,25 +948,26 @@ int dvb_register_adapter(struct dvb_adapter *adap, const char *name, } EXPORT_SYMBOL(dvb_register_adapter); - int dvb_unregister_adapter(struct dvb_adapter *adap) { mutex_lock(&dvbdev_register_lock); - list_del (&adap->list_head); + list_del(&adap->list_head); mutex_unlock(&dvbdev_register_lock); return 0; } 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 - define this as video_usercopy(). this will introduce a dependency - to the v4l "videodev.o" module, which is unnecessary for some - cards (ie. the budget dvb-cards don't need the v4l module...) */ +/* + * if the miracle happens and "generic_usercopy()" is included into + * the kernel, then this can vanish. please don't make the mistake and + * define this as video_usercopy(). this will introduce a dependency + * 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, - unsigned int cmd, unsigned long arg, - int (*func)(struct file *file, - unsigned int cmd, void *arg)) + unsigned int cmd, unsigned long arg, + int (*func)(struct file *file, + unsigned int cmd, void *arg)) { char sbuf[128]; void *mbuf = NULL; @@ -956,7 +981,7 @@ int dvb_usercopy(struct file *file, * For this command, the pointer is actually an integer * argument. */ - parg = (void *) arg; + parg = (void *)arg; break; case _IOC_READ: /* some v4l ioctls are marked wrong ... */ case _IOC_WRITE: @@ -966,7 +991,7 @@ int dvb_usercopy(struct file *file, } else { /* too big to allocate from stack */ mbuf = kmalloc(_IOC_SIZE(cmd), GFP_KERNEL); - if (NULL == mbuf) + if (!mbuf) return -ENOMEM; parg = mbuf; } @@ -978,15 +1003,15 @@ int dvb_usercopy(struct file *file, } /* call driver */ - if ((err = func(file, cmd, parg)) == -ENOIOCTLCMD) + err = func(file, cmd, parg); + if (err == -ENOIOCTLCMD) err = -ENOTTY; if (err < 0) goto out; /* Copy results into user buffer */ - switch (_IOC_DIR(cmd)) - { + switch (_IOC_DIR(cmd)) { case _IOC_READ: case (_IOC_WRITE | _IOC_READ): if (copy_to_user((void __user *)arg, parg, _IOC_SIZE(cmd))) @@ -998,7 +1023,6 @@ out: kfree(mbuf); return err; } -EXPORT_SYMBOL(dvb_usercopy); #if IS_ENABLED(CONFIG_I2C) #if (LINUX_VERSION_CODE >= KERNEL_VERSION(5,5,0)) @@ -1083,13 +1107,15 @@ static int __init init_dvbdev(void) int retval; 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); return retval; } 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"); goto error; } @@ -1113,12 +1139,19 @@ error: return retval; } - static void __exit exit_dvbdev(void) { + struct dvbdevfops_node *node, *next; + class_destroy(dvb_class); cdev_del(&dvb_device_cdev); 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); diff --git a/frontends/stv0910.c b/frontends/stv0910.c index 431028d..00cf2f2 100644 --- a/frontends/stv0910.c +++ b/frontends/stv0910.c @@ -1643,7 +1643,7 @@ static int clear_slave(struct dvb_frontend *fe) get_field(RXEND, &done); 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--) get_reg(DISRXFIFO, &d); @@ -1699,7 +1699,7 @@ static int recv_slave_reply(struct dvb_frontend *fe, msleep(10); } 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) return -EIO; if (done && !val) diff --git a/include/linux/dvb/frontend.h b/include/linux/dvb/frontend.h index 9ddfe4b..c135ef3 100644 --- a/include/linux/dvb/frontend.h +++ b/include/linux/dvb/frontend.h @@ -302,6 +302,7 @@ enum fe_spectral_inversion { * @FEC_7_15: Forward Error Correction Code 7/15 * @FEC_29_45: Forward Error Correction Code 29/45 * @FEC_31_45: Forward Error Correction Code 31/45 + * * Please note that not all FEC types are supported by a given standard. */ enum fe_code_rate { @@ -597,7 +598,7 @@ enum fe_interleaving { #define DTV_STAT_TOTAL_BLOCK_COUNT 69 /* Physical layer scrambling */ -#define DTV_SCRAMBLING_SEQUENCE_INDEX 70 +#define DTV_SCRAMBLING_SEQUENCE_INDEX 70 #define DTV_INPUT 71 #define DTV_MAX_COMMAND DTV_INPUT diff --git a/include/linux/dvb/version.h b/include/linux/dvb/version.h index 1a8cd03..20bc874 100644 --- a/include/linux/dvb/version.h +++ b/include/linux/dvb/version.h @@ -10,6 +10,6 @@ #define _DVBVERSION_H_ #define DVB_API_VERSION 5 -#define DVB_API_VERSION_MINOR 11 +#define DVB_API_VERSION_MINOR 12 #endif /*_DVBVERSION_H_*/ diff --git a/include/linux/media/dvb_filter.h b/include/linux/media/dvb_filter.h deleted file mode 100644 index 375e3be..0000000 --- a/include/linux/media/dvb_filter.h +++ /dev/null @@ -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 - -#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 diff --git a/include/linux/media/dvb_net.h b/include/linux/media/dvb_net.h index 5e31d37..4a921ea 100644 --- a/include/linux/media/dvb_net.h +++ b/include/linux/media/dvb_net.h @@ -19,13 +19,11 @@ #define _DVB_NET_H_ #include -#include -#include -#include -#include #include +struct net_device; + #define DVB_NET_DEVICES_MAX 10 #ifdef CONFIG_DVB_NET @@ -41,6 +39,9 @@ * @exit: flag to indicate when the device is being removed. * @demux: pointer to &struct dmx_demux. * @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 * devices. @@ -53,6 +54,7 @@ struct dvb_net { unsigned int exit:1; struct dmx_demux *demux; struct mutex ioctl_mutex; + struct mutex remove_mutex; }; /** diff --git a/include/linux/media/dvbdev.h b/include/linux/media/dvbdev.h index 5765792..91fcab8 100644 --- a/include/linux/media/dvbdev.h +++ b/include/linux/media/dvbdev.h @@ -139,7 +139,7 @@ struct dvb_adapter { * struct dvb_device - represents a DVB device node * * @list_head: List head with all DVB devices - * @ref: reference counter + * @ref: reference count for this device * @fops: pointer to struct file_operations * @adapter: pointer to the adapter that holds this device node * @type: type of the device, as defined by &enum dvb_device_type. @@ -202,6 +202,21 @@ struct dvb_device { 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 * @@ -260,10 +275,10 @@ int dvb_register_device(struct dvb_adapter *adap, /** * 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 * reference counter is empty - * - * @dvbdev: pointer to struct dvb_device */ void dvb_remove_device(struct dvb_device *dvbdev);