📄 av7110.c
字号:
len = 2 * 1024; iwdebi(av7110, DEBINOSWAP, TX_LEN, len, 2); iwdebi(av7110, DEBINOSWAP, IRQ_STATE_EXT, len, 2); memcpy(av7110->debi_virt, av7110->bmpbuf+av7110->bmpp, len); av7110->bmpp += len; av7110->bmplen -= len; saa7146_wait_for_debi_done(av7110->dev); saa7146_write(av7110->dev, IER, saa7146_read(av7110->dev, IER) | MASK_19); if (len < 5) len = 5; /* we want a real DEBI DMA */ iwdebi(av7110, DEBISWAB, DPRAM_BASE+txbuf, 0, (len + 3) & ~3); spin_unlock(&av7110->debilock); return; case DATA_CI_GET: case DATA_COMMON_INTERFACE: case DATA_FSECTION: case DATA_IPMPE: case DATA_PIPING: if (!len || len > 4 * 1024) { iwdebi(av7110, DEBINOSWAP, RX_BUFF, 0, 2); break; } /* fall through */ case DATA_TS_RECORD: case DATA_PES_RECORD: saa7146_wait_for_debi_done(av7110->dev); saa7146_write(av7110->dev, IER, saa7146_read(av7110->dev, IER) | MASK_19); irdebi(av7110, DEBISWAB, DPRAM_BASE+rxbuf, 0, len); spin_unlock(&av7110->debilock); return; case DATA_DEBUG_MESSAGE: saa7146_wait_for_debi_done(av7110->dev); if (!len || len > 0xff) { iwdebi(av7110, DEBINOSWAP, RX_BUFF, 0, 2); break; } saa7146_write(av7110->dev, IER, saa7146_read(av7110->dev, IER) | MASK_19); irdebi(av7110, DEBISWAB, Reserved, 0, len); spin_unlock(&av7110->debilock); return; case DATA_IRCOMMAND: IR_handle(av7110, swahw32(irdebi(av7110, DEBINOSWAP, Reserved, 0, 4))); iwdebi(av7110, DEBINOSWAP, RX_BUFF, 0, 2); break; default: printk("gpioirq unknown type=%d len=%d\n", av7110->debitype, av7110->debilen); break; } ARM_ClearMailBox(av7110); av7110->debitype = -1; spin_unlock(&av7110->debilock);}#ifdef CONFIG_DVB_AV7110_OSDstatic int dvb_osd_ioctl(struct inode *inode, struct file *file, unsigned int cmd, void *parg){ struct dvb_device *dvbdev = (struct dvb_device *) file->private_data; struct av7110 *av7110 = (struct av7110 *) dvbdev->priv; DEB_EE(("av7110: %p\n", av7110)); if (cmd == OSD_SEND_CMD) return av7110_osd_cmd(av7110, (osd_cmd_t *) parg); return -EINVAL;}static struct file_operations dvb_osd_fops = { .owner = THIS_MODULE, .ioctl = dvb_generic_ioctl, .open = dvb_generic_open, .release = dvb_generic_release,};static struct dvb_device dvbdev_osd = { .priv = 0, .users = 1, .writers = 1, .fops = &dvb_osd_fops, .kernel_ioctl = dvb_osd_ioctl,};#endif /* CONFIG_DVB_AV7110_OSD */static inline int SetPIDs(struct av7110 *av7110, u16 vpid, u16 apid, u16 ttpid, u16 subpid, u16 pcrpid){ DEB_EE(("av7110: %p\n", av7110)); if (vpid == 0x1fff || apid == 0x1fff || ttpid == 0x1fff || subpid == 0x1fff || pcrpid == 0x1fff) { vpid = apid = ttpid = subpid = pcrpid = 0; av7110->pids[DMX_PES_VIDEO] = 0; av7110->pids[DMX_PES_AUDIO] = 0; av7110->pids[DMX_PES_TELETEXT] = 0; av7110->pids[DMX_PES_PCR] = 0; } return av7110_fw_cmd(av7110, COMTYPE_PIDFILTER, MultiPID, 5, pcrpid, vpid, apid, ttpid, subpid);}void ChangePIDs(struct av7110 *av7110, u16 vpid, u16 apid, u16 ttpid, u16 subpid, u16 pcrpid){ DEB_EE(("av7110: %p\n", av7110)); if (down_interruptible(&av7110->pid_mutex)) return; if (!(vpid & 0x8000)) av7110->pids[DMX_PES_VIDEO] = vpid; if (!(apid & 0x8000)) av7110->pids[DMX_PES_AUDIO] = apid; if (!(ttpid & 0x8000)) av7110->pids[DMX_PES_TELETEXT] = ttpid; if (!(pcrpid & 0x8000)) av7110->pids[DMX_PES_PCR] = pcrpid; av7110->pids[DMX_PES_SUBTITLE] = 0; if (av7110->fe_synced) { pcrpid = av7110->pids[DMX_PES_PCR]; SetPIDs(av7110, vpid, apid, ttpid, subpid, pcrpid); } up(&av7110->pid_mutex);}/****************************************************************************** * hardware filter functions ******************************************************************************/static int StartHWFilter(struct dvb_demux_filter *dvbdmxfilter){ struct dvb_demux_feed *dvbdmxfeed = dvbdmxfilter->feed; struct av7110 *av7110 = (struct av7110 *) dvbdmxfeed->demux->priv; u16 buf[20]; int ret, i; u16 handle;// u16 mode=0x0320; u16 mode=0xb96a; DEB_EE(("av7110: %p\n", av7110)); if (dvbdmxfilter->type == DMX_TYPE_SEC) { if (hw_sections) { buf[4] = (dvbdmxfilter->filter.filter_value[0] << 8) | dvbdmxfilter->maskandmode[0]; for (i = 3; i < 18; i++) buf[i + 4 - 2] = (dvbdmxfilter->filter.filter_value[i] << 8) | dvbdmxfilter->maskandmode[i]; mode = 4; } } else if ((dvbdmxfeed->ts_type & TS_PACKET) && !(dvbdmxfeed->ts_type & TS_PAYLOAD_ONLY)) { av7110_p2t_init(&av7110->p2t_filter[dvbdmxfilter->index], dvbdmxfeed); } buf[0] = (COMTYPE_PID_FILTER << 8) + AddPIDFilter; buf[1] = 16; buf[2] = dvbdmxfeed->pid; buf[3] = mode; ret = av7110_fw_request(av7110, buf, 20, &handle, 1); if (ret < 0) { printk("StartHWFilter error\n"); return ret; } av7110->handle2filter[handle] = dvbdmxfilter; dvbdmxfilter->hw_handle = handle; return ret;}static int StopHWFilter(struct dvb_demux_filter *dvbdmxfilter){ struct av7110 *av7110 = (struct av7110 *) dvbdmxfilter->feed->demux->priv; u16 buf[3]; u16 answ[2]; int ret; u16 handle; DEB_EE(("av7110: %p\n", av7110)); handle = dvbdmxfilter->hw_handle; if (handle > 32) { DEB_S(("dvb: StopHWFilter tried to stop invalid filter %d.\n", handle)); DEB_S(("dvb: filter type = %d\n", dvbdmxfilter->type)); return 0; } av7110->handle2filter[handle] = NULL; buf[0] = (COMTYPE_PID_FILTER << 8) + DelPIDFilter; buf[1] = 1; buf[2] = handle; ret = av7110_fw_request(av7110, buf, 3, answ, 2); if (ret) printk("StopHWFilter error\n"); if (answ[1] != handle) { DEB_S(("dvb: filter %d shutdown error :%d\n", handle, answ[1])); ret = -1; } return ret;}static void dvb_feed_start_pid(struct dvb_demux_feed *dvbdmxfeed){ struct dvb_demux *dvbdmx = dvbdmxfeed->demux; struct av7110 *av7110 = (struct av7110 *) dvbdmx->priv; u16 *pid = dvbdmx->pids, npids[5]; int i; DEB_EE(("av7110: %p\n", av7110)); npids[0] = npids[1] = npids[2] = npids[3] = npids[4] = 0xffff; i = dvbdmxfeed->pes_type; npids[i] = (pid[i]&0x8000) ? 0 : pid[i]; if ((i == 2) && npids[i] && (dvbdmxfeed->ts_type & TS_PACKET)) { npids[i] = 0; ChangePIDs(av7110, npids[1], npids[0], npids[2], npids[3], npids[4]); StartHWFilter(dvbdmxfeed->filter); return; } if (dvbdmxfeed->pes_type <= 2 || dvbdmxfeed->pes_type == 4) ChangePIDs(av7110, npids[1], npids[0], npids[2], npids[3], npids[4]); if (dvbdmxfeed->pes_type < 2 && npids[0]) if (av7110->fe_synced) av7110_fw_cmd(av7110, COMTYPE_PIDFILTER, Scan, 0); if ((dvbdmxfeed->ts_type & TS_PACKET)) { if (dvbdmxfeed->pes_type == 0 && !(dvbdmx->pids[0] & 0x8000)) av7110_av_start_record(av7110, RP_AUDIO, dvbdmxfeed); if (dvbdmxfeed->pes_type == 1 && !(dvbdmx->pids[1] & 0x8000)) av7110_av_start_record(av7110, RP_VIDEO, dvbdmxfeed); }}static void dvb_feed_stop_pid(struct dvb_demux_feed *dvbdmxfeed){ struct dvb_demux *dvbdmx = dvbdmxfeed->demux; struct av7110 *av7110 = (struct av7110 *) dvbdmx->priv; u16 *pid = dvbdmx->pids, npids[5]; int i; DEB_EE(("av7110: %p\n", av7110)); if (dvbdmxfeed->pes_type <= 1) { av7110_av_stop(av7110, dvbdmxfeed->pes_type ? RP_VIDEO : RP_AUDIO); if (!av7110->rec_mode) dvbdmx->recording = 0; if (!av7110->playing) dvbdmx->playing = 0; } npids[0] = npids[1] = npids[2] = npids[3] = npids[4] = 0xffff; i = dvbdmxfeed->pes_type; switch (i) { case 2: //teletext if (dvbdmxfeed->ts_type & TS_PACKET) StopHWFilter(dvbdmxfeed->filter); npids[2] = 0; break; case 0: case 1: case 4: if (!pids_off) return; npids[i] = (pid[i]&0x8000) ? 0 : pid[i]; break; } ChangePIDs(av7110, npids[1], npids[0], npids[2], npids[3], npids[4]);}static int av7110_start_feed(struct dvb_demux_feed *feed){ struct dvb_demux *demux = feed->demux; struct av7110 *av7110 = (struct av7110 *) demux->priv; DEB_EE(("av7110: %p\n", av7110)); if (!demux->dmx.frontend) return -EINVAL; if (feed->pid > 0x1fff) return -EINVAL; if (feed->type == DMX_TYPE_TS) { if ((feed->ts_type & TS_DECODER) && (feed->pes_type < DMX_TS_PES_OTHER)) { switch (demux->dmx.frontend->source) { case DMX_MEMORY_FE: if (feed->ts_type & TS_DECODER) if (feed->pes_type < 2 && !(demux->pids[0] & 0x8000) && !(demux->pids[1] & 0x8000)) { dvb_ringbuffer_flush_spinlock_wakeup(&av7110->avout); dvb_ringbuffer_flush_spinlock_wakeup(&av7110->aout); av7110_av_start_play(av7110,RP_AV); demux->playing = 1; } break; default: dvb_feed_start_pid(feed); break; } } else if ((feed->ts_type & TS_PACKET) && (demux->dmx.frontend->source != DMX_MEMORY_FE)) { StartHWFilter(feed->filter); } } if (feed->type == DMX_TYPE_SEC) { int i; for (i = 0; i < demux->filternum; i++) { if (demux->filter[i].state != DMX_STATE_READY) continue; if (demux->filter[i].type != DMX_TYPE_SEC) continue; if (demux->filter[i].filter.parent != &feed->feed.sec) continue; demux->filter[i].state = DMX_STATE_GO; if (demux->dmx.frontend->source != DMX_MEMORY_FE) StartHWFilter(&demux->filter[i]); } } return 0;}static int av7110_stop_feed(struct dvb_demux_feed *feed){ struct dvb_demux *demux = feed->demux; struct av7110 *av7110 = (struct av7110 *) demux->priv; DEB_EE(("av7110: %p\n", av7110)); if (feed->type == DMX_TYPE_TS) { if (feed->ts_type & TS_DECODER) { if (feed->pes_type >= DMX_TS_PES_OTHER || !demux->pesfilter[feed->pes_type]) return -EINVAL; demux->pids[feed->pes_type] |= 0x8000; demux->pesfilter[feed->pes_type] = 0; } if (feed->ts_type & TS_DECODER && feed->pes_type < DMX_TS_PES_OTHER) { dvb_feed_stop_pid(feed); } else if ((feed->ts_type & TS_PACKET) && (demux->dmx.frontend->source != DMX_MEMORY_FE)) StopHWFilter(feed->filter); } if (feed->type == DMX_TYPE_SEC) { int i; for (i=0; i<demux->filternum; i++) if (demux->filter[i].state == DMX_STATE_GO && demux->filter[i].filter.parent == &feed->feed.sec) { demux->filter[i].state = DMX_STATE_READY; if (demux->dmx.frontend->source != DMX_MEMORY_FE) StopHWFilter(&demux->filter[i]); } } return 0;}static void restart_feeds(struct av7110 *av7110){ struct dvb_demux *dvbdmx = &av7110->demux; struct dvb_demux_feed *feed; int mode; int i; DEB_EE(("av7110: %p\n", av7110)); mode = av7110->playing; av7110->playing = 0; av7110->rec_mode = 0; for (i = 0; i < dvbdmx->filternum; i++) { feed = &dvbdmx->feed[i]; if (feed->state == DMX_STATE_GO) av7110_start_feed(feed); } if (mode) av7110_av_start_play(av7110, mode);}static int dvb_get_stc(struct dmx_demux *demux, unsigned int num, uint64_t *stc, unsigned int *base){ int ret; u16 fwstc[4]; u16 tag = ((COMTYPE_REQUEST << 8) + ReqSTC); struct dvb_demux *dvbdemux; struct av7110 *av7110; /* pointer casting paranoia... */ if (!demux) BUG(); dvbdemux = (struct dvb_demux *) demux->priv; if (!dvbdemux) BUG(); av7110 = (struct av7110 *) dvbdemux->priv; DEB_EE(("av7110: %p\n", av7110)); if (num != 0) return -EINVAL; ret = av7110_fw_request(av7110, &tag, 0, fwstc, 4); if (ret) { printk(KERN_ERR "%s: av7110_fw_request error\n", __FUNCTION__); return -EIO; } DEB_EE(("av7110: fwstc = %04hx %04hx %04hx %04hx\n", fwstc[0], fwstc[1], fwstc[2], fwstc[3])); *stc = (((uint64_t) ((fwstc[3] & 0x8000) >> 15)) << 32) | (((uint64_t) fwstc[1]) << 16) | ((uint64_t) fwstc[0]); *base = 1; DEB_EE(("av7110: stc = %lu\n", (unsigned long)*stc)); return 0;}/****************************************************************************** * SEC device file operations ******************************************************************************/static int av7110_diseqc_ioctl(struct dvb_frontend *fe, unsigned int cmd, void *arg){ struct av7110 *av7110 = fe->before_after_data; DEB_EE(("av7110: %p\n", av7110)); switch (cmd) { case FE_SET_TONE: switch ((fe_sec_tone_mode_t) arg) { case SEC_TONE_ON: Set22K(av7110, 1); break; case SEC_TONE_OFF: Set22K(av7110, 0); break; default: return -EINVAL; }; break; case FE_DISEQC_SEND_MASTER_CMD: { struct dvb_diseqc_master_cmd *cmd = arg; av7110_diseqc_send(av7110, cmd->msg_len, cmd->msg, -1); break; } case FE_DISEQC_SEND_BURST: av7110_diseqc_send(av7110, 0, NULL, (unsigned long) arg); break; default: return -EOPNOTSUPP; }; return 0;}static void av7110_before_after_tune(fe_status_t s, void *data){ struct av7110 *av7110 = data; DEB_EE(("av7110: %p\n", av7110)); av7110->fe_synced = (s & FE_HAS_LOCK) ? 1 : 0; if (av7110->playing) return; if (down_interruptible(&av7110->pid_mutex)) return; if (av7110->fe_synced) { SetPIDs(av7110, av7110->pids[DMX_PES_VIDEO], av7110->pids[DMX_PES_AUDIO], av7110->pids[DMX_PES_TELETEXT], 0, av7110->pids[DMX_PES_PCR]); av7110_fw_cmd(av7110, COMTYPE_PIDFILTER, Scan, 0); } else { SetPIDs(av7110, 0, 0, 0, 0, 0); av7110_fw_cmd(av7110, COMTYPE_PIDFILTER, FlushTSQueue, 0); } up(&av7110->pid_mutex);}static int av7110_register(struct av7110 *av7110){ int ret, i; struct dvb_demux *dvbdemux = &av7110->demux; DEB_EE(("av7110: %p\n", av7110)); if (av7110->registered) return -1; av7110->registered = 1; dvb_add_frontend_notifier (av7110->dvb_adapter, av7110_before_after_tune, av7110); /** * init DiSEqC stuff */ dvb_add_frontend_ioctls (av7110->dvb_adapter, av7110_diseqc_ioctl, NULL, av7110); dvbdemux->priv = (void *) av7110; for (i = 0; i < 32; i++) av7110->handle2filter[i] = NULL; dvbdemux->filternum = 32; dvbdemux->feednum = 32; dvbdemux->start_feed = av7110_start_feed; dvbdemux->stop_feed = av7110_stop_feed; dvbdemux->write_to_decoder = av7110_write_to_decoder; dvbdemux->dmx.capabilities = (DMX_TS_FILTERING | DMX_SECTION_FILTERING | DMX_MEMORY_BASED_FILTERING); dvb_dmx_init(&av7110->demux); av7110->demux.dmx.get_stc = dvb_get_stc; av7110->dmxdev.filternum = 32; av7110->dmxdev.demux = &dvbdemux->dmx; av7110->dmxdev.capabilities = 0;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -