Merge master.kernel.org:/pub/scm/linux/kernel/git/mchehab/v4l-dvb

This commit is contained in:
Linus Torvalds 2006-01-09 13:03:58 -08:00
commit f17578decc
203 changed files with 10715 additions and 5153 deletions

View File

@ -150,7 +150,8 @@ Getting the card going
The frontend module sp887x.o, requires an external firmware. The frontend module sp887x.o, requires an external firmware.
Please use the command "get_dvb_firmware sp887x" to download Please use the command "get_dvb_firmware sp887x" to download
it. Then copy it to /usr/lib/hotplug/firmware. it. Then copy it to /usr/lib/hotplug/firmware or /lib/firmware/
(depending on configuration of firmware hotplug).
Receiving DVB-T in Australia Receiving DVB-T in Australia

View File

@ -23,7 +23,7 @@ use IO::Handle;
@components = ( "sp8870", "sp887x", "tda10045", "tda10046", "av7110", "dec2000t", @components = ( "sp8870", "sp887x", "tda10045", "tda10046", "av7110", "dec2000t",
"dec2540t", "dec3000s", "vp7041", "dibusb", "nxt2002", "nxt2004", "dec2540t", "dec3000s", "vp7041", "dibusb", "nxt2002", "nxt2004",
"or51211", "or51132_qam", "or51132_vsb"); "or51211", "or51132_qam", "or51132_vsb", "bluebird");
# Check args # Check args
syntax() if (scalar(@ARGV) != 1); syntax() if (scalar(@ARGV) != 1);
@ -34,7 +34,11 @@ for ($i=0; $i < scalar(@components); $i++) {
if ($cid eq $components[$i]) { if ($cid eq $components[$i]) {
$outfile = eval($cid); $outfile = eval($cid);
die $@ if $@; die $@ if $@;
print STDERR "Firmware $outfile extracted successfully. Now copy it to either /lib/firmware or /usr/lib/hotplug/firmware/ (depending on your hotplug version).\n"; print STDERR <<EOF;
Firmware $outfile extracted successfully.
Now copy it to either /usr/lib/hotplug/firmware or /lib/firmware
(depending on configuration of firmware hotplug).
EOF
exit(0); exit(0);
} }
} }
@ -308,6 +312,19 @@ sub or51132_vsb {
$fwfile; $fwfile;
} }
sub bluebird {
my $url = "http://www.linuxtv.org/download/dvb/firmware/dvb-usb-bluebird-01.fw";
my $outfile = "dvb-usb-bluebird-01.fw";
my $hash = "658397cb9eba9101af9031302671f49d";
checkstandard();
wgetfile($outfile, $url);
verify($outfile,$hash);
$outfile;
}
# --------------------------------------------------------------- # ---------------------------------------------------------------
# Utilities # Utilities

View File

@ -41,4 +41,5 @@ Hotplug Firmware Loading for 2.6 kernels
For 2.6 kernels the firmware is loaded at the point that the driver module is For 2.6 kernels the firmware is loaded at the point that the driver module is
loaded. See linux/Documentation/dvb/firmware.txt for more information. loaded. See linux/Documentation/dvb/firmware.txt for more information.
Copy the three files downloaded above into the /usr/lib/hotplug/firmware directory. Copy the three files downloaded above into the /usr/lib/hotplug/firmware or
/lib/firmware directory (depending on configuration of firmware hotplug).

View File

@ -141,3 +141,4 @@
140 -> Osprey 440 [0070:ff07] 140 -> Osprey 440 [0070:ff07]
141 -> Asound Skyeye PCTV 141 -> Asound Skyeye PCTV
142 -> Sabrent TV-FM (bttv version) 142 -> Sabrent TV-FM (bttv version)
143 -> Hauppauge ImpactVCB (bt878) [0070:13eb]

View File

@ -16,7 +16,7 @@
15 -> DViCO FusionHDTV DVB-T1 [18ac:db00] 15 -> DViCO FusionHDTV DVB-T1 [18ac:db00]
16 -> KWorld LTV883RF 16 -> KWorld LTV883RF
17 -> DViCO FusionHDTV 3 Gold-Q [18ac:d810] 17 -> DViCO FusionHDTV 3 Gold-Q [18ac:d810]
18 -> Hauppauge Nova-T DVB-T [0070:9002] 18 -> Hauppauge Nova-T DVB-T [0070:9002,0070:9001]
19 -> Conexant DVB-T reference design [14f1:0187] 19 -> Conexant DVB-T reference design [14f1:0187]
20 -> Provideo PV259 [1540:2580] 20 -> Provideo PV259 [1540:2580]
21 -> DViCO FusionHDTV DVB-T Plus [18ac:db10] 21 -> DViCO FusionHDTV DVB-T Plus [18ac:db10]
@ -35,3 +35,11 @@
34 -> ATI HDTV Wonder [1002:a101] 34 -> ATI HDTV Wonder [1002:a101]
35 -> WinFast DTV1000-T [107d:665f] 35 -> WinFast DTV1000-T [107d:665f]
36 -> AVerTV 303 (M126) [1461:000a] 36 -> AVerTV 303 (M126) [1461:000a]
37 -> Hauppauge Nova-S-Plus DVB-S [0070:9201,0070:9202]
38 -> Hauppauge Nova-SE2 DVB-S [0070:9200]
39 -> KWorld DVB-S 100 [17de:08b2]
40 -> Hauppauge WinTV-HVR1100 DVB-T/Hybrid [0070:9400,0070:9402]
41 -> Hauppauge WinTV-HVR1100 DVB-T/Hybrid (Low Profile) [0070:9800,0070:9802]
42 -> digitalnow DNTV Live! DVB-T Pro [1822:0025]
43 -> KWorld/VStream XPert DVB-T with cx22702 [17de:08a1]
44 -> DViCO FusionHDTV DVB-T Dual Digital [18ac:db50]

View File

@ -56,7 +56,7 @@
55 -> LifeView FlyDVB-T DUO [5168:0502,5168:0306] 55 -> LifeView FlyDVB-T DUO [5168:0502,5168:0306]
56 -> Avermedia AVerTV 307 [1461:a70a] 56 -> Avermedia AVerTV 307 [1461:a70a]
57 -> Avermedia AVerTV GO 007 FM [1461:f31f] 57 -> Avermedia AVerTV GO 007 FM [1461:f31f]
58 -> ADS Tech Instant TV (saa7135) [1421:0350,1421:0370,1421:1370] 58 -> ADS Tech Instant TV (saa7135) [1421:0350,1421:0351,1421:0370,1421:1370]
59 -> Kworld/Tevion V-Stream Xpert TV PVR7134 59 -> Kworld/Tevion V-Stream Xpert TV PVR7134
60 -> Typhoon DVB-T Duo Digital/Analog Cardbus [4e42:0502] 60 -> Typhoon DVB-T Duo Digital/Analog Cardbus [4e42:0502]
61 -> Philips TOUGH DVB-T reference design [1131:2004] 61 -> Philips TOUGH DVB-T reference design [1131:2004]
@ -81,4 +81,5 @@
80 -> ASUS Digimatrix TV [1043:0210] 80 -> ASUS Digimatrix TV [1043:0210]
81 -> Philips Tiger reference design [1131:2018] 81 -> Philips Tiger reference design [1131:2018]
82 -> MSI TV@Anywhere plus [1462:6231] 82 -> MSI TV@Anywhere plus [1462:6231]
83 -> Terratec Cinergy 250 PCI TV [153b:1160]
84 -> LifeView FlyDVB Trio [5168:0319]

View File

@ -40,7 +40,7 @@ tuner=38 - Philips PAL/SECAM multi (FM1216ME MK3)
tuner=39 - LG NTSC (newer TAPC series) tuner=39 - LG NTSC (newer TAPC series)
tuner=40 - HITACHI V7-J180AT tuner=40 - HITACHI V7-J180AT
tuner=41 - Philips PAL_MK (FI1216 MK) tuner=41 - Philips PAL_MK (FI1216 MK)
tuner=42 - Philips 1236D ATSC/NTSC daul in tuner=42 - Philips 1236D ATSC/NTSC dual in
tuner=43 - Philips NTSC MK3 (FM1236MK3 or FM1236/F) tuner=43 - Philips NTSC MK3 (FM1236MK3 or FM1236/F)
tuner=44 - Philips 4 in 1 (ATI TV Wonder Pro/Conexant) tuner=44 - Philips 4 in 1 (ATI TV Wonder Pro/Conexant)
tuner=45 - Microtune 4049 FM5 tuner=45 - Microtune 4049 FM5
@ -50,7 +50,7 @@ tuner=48 - Tenna TNF 8831 BGFF)
tuner=49 - Microtune 4042 FI5 ATSC/NTSC dual in tuner=49 - Microtune 4042 FI5 ATSC/NTSC dual in
tuner=50 - TCL 2002N tuner=50 - TCL 2002N
tuner=51 - Philips PAL/SECAM_D (FM 1256 I-H3) tuner=51 - Philips PAL/SECAM_D (FM 1256 I-H3)
tuner=52 - Thomson DDT 7610 (ATSC/NTSC) tuner=52 - Thomson DTT 7610 (ATSC/NTSC)
tuner=53 - Philips FQ1286 tuner=53 - Philips FQ1286
tuner=54 - tda8290+75 tuner=54 - tda8290+75
tuner=55 - TCL 2002MB tuner=55 - TCL 2002MB
@ -58,7 +58,7 @@ tuner=56 - Philips PAL/SECAM multi (FQ1216AME MK4)
tuner=57 - Philips FQ1236A MK4 tuner=57 - Philips FQ1236A MK4
tuner=58 - Ymec TVision TVF-8531MF/8831MF/8731MF tuner=58 - Ymec TVision TVF-8531MF/8831MF/8731MF
tuner=59 - Ymec TVision TVF-5533MF tuner=59 - Ymec TVision TVF-5533MF
tuner=60 - Thomson DDT 7611 (ATSC/NTSC) tuner=60 - Thomson DTT 761X (ATSC/NTSC)
tuner=61 - Tena TNF9533-D/IF/TNF9533-B/DF tuner=61 - Tena TNF9533-D/IF/TNF9533-B/DF
tuner=62 - Philips TEA5767HN FM Radio tuner=62 - Philips TEA5767HN FM Radio
tuner=63 - Philips FMD1216ME MK3 Hybrid Tuner tuner=63 - Philips FMD1216ME MK3 Hybrid Tuner

View File

@ -253,7 +253,10 @@ static int fops_open(struct inode *inode, struct file *file)
if( fh->type == V4L2_BUF_TYPE_VBI_CAPTURE) { if( fh->type == V4L2_BUF_TYPE_VBI_CAPTURE) {
DEB_S(("initializing vbi...\n")); DEB_S(("initializing vbi...\n"));
if (dev->ext_vv_data->capabilities & V4L2_CAP_VBI_CAPTURE)
result = saa7146_vbi_uops.open(dev,file); result = saa7146_vbi_uops.open(dev,file);
if (dev->ext_vv_data->vbi_fops.open)
dev->ext_vv_data->vbi_fops.open(inode, file);
} else { } else {
DEB_S(("initializing video...\n")); DEB_S(("initializing video...\n"));
result = saa7146_video_uops.open(dev,file); result = saa7146_video_uops.open(dev,file);
@ -289,7 +292,10 @@ static int fops_release(struct inode *inode, struct file *file)
return -ERESTARTSYS; return -ERESTARTSYS;
if( fh->type == V4L2_BUF_TYPE_VBI_CAPTURE) { if( fh->type == V4L2_BUF_TYPE_VBI_CAPTURE) {
if (dev->ext_vv_data->capabilities & V4L2_CAP_VBI_CAPTURE)
saa7146_vbi_uops.release(dev,file); saa7146_vbi_uops.release(dev,file);
if (dev->ext_vv_data->vbi_fops.release)
dev->ext_vv_data->vbi_fops.release(inode, file);
} else { } else {
saa7146_video_uops.release(dev,file); saa7146_video_uops.release(dev,file);
} }
@ -332,6 +338,7 @@ static int fops_mmap(struct file *file, struct vm_area_struct * vma)
BUG(); BUG();
return 0; return 0;
} }
return videobuf_mmap_mapper(q,vma); return videobuf_mmap_mapper(q,vma);
} }
@ -381,7 +388,10 @@ static ssize_t fops_read(struct file *file, char __user *data, size_t count, lof
} }
case V4L2_BUF_TYPE_VBI_CAPTURE: { case V4L2_BUF_TYPE_VBI_CAPTURE: {
// DEB_EE(("V4L2_BUF_TYPE_VBI_CAPTURE: file:%p, data:%p, count:%lu\n", file, data, (unsigned long)count)); // DEB_EE(("V4L2_BUF_TYPE_VBI_CAPTURE: file:%p, data:%p, count:%lu\n", file, data, (unsigned long)count));
if (fh->dev->ext_vv_data->capabilities & V4L2_CAP_VBI_CAPTURE)
return saa7146_vbi_uops.read(file,data,count,ppos); return saa7146_vbi_uops.read(file,data,count,ppos);
else
return -EINVAL;
} }
break; break;
default: default:
@ -390,12 +400,31 @@ static ssize_t fops_read(struct file *file, char __user *data, size_t count, lof
} }
} }
static ssize_t fops_write(struct file *file, const char __user *data, size_t count, loff_t *ppos)
{
struct saa7146_fh *fh = file->private_data;
switch (fh->type) {
case V4L2_BUF_TYPE_VIDEO_CAPTURE:
return -EINVAL;
case V4L2_BUF_TYPE_VBI_CAPTURE:
if (fh->dev->ext_vv_data->vbi_fops.write)
return fh->dev->ext_vv_data->vbi_fops.write(file, data, count, ppos);
else
return -EINVAL;
default:
BUG();
return -EINVAL;
}
}
static struct file_operations video_fops = static struct file_operations video_fops =
{ {
.owner = THIS_MODULE, .owner = THIS_MODULE,
.open = fops_open, .open = fops_open,
.release = fops_release, .release = fops_release,
.read = fops_read, .read = fops_read,
.write = fops_write,
.poll = fops_poll, .poll = fops_poll,
.mmap = fops_mmap, .mmap = fops_mmap,
.ioctl = fops_ioctl, .ioctl = fops_ioctl,
@ -467,6 +496,7 @@ int saa7146_vv_init(struct saa7146_dev* dev, struct saa7146_ext_vv *ext_vv)
memset(vv->d_clipping.cpu_addr, 0x0, SAA7146_CLIPPING_MEM); memset(vv->d_clipping.cpu_addr, 0x0, SAA7146_CLIPPING_MEM);
saa7146_video_uops.init(dev,vv); saa7146_video_uops.init(dev,vv);
if (dev->ext_vv_data->capabilities & V4L2_CAP_VBI_CAPTURE)
saa7146_vbi_uops.init(dev,vv); saa7146_vbi_uops.init(dev,vv);
dev->vv_data = vv; dev->vv_data = vv;

View File

@ -562,19 +562,26 @@ static void saa7146_set_position(struct saa7146_dev *dev, int w_x, int w_y, int
int b_depth = vv->ov_fmt->depth; int b_depth = vv->ov_fmt->depth;
int b_bpl = vv->ov_fb.fmt.bytesperline; int b_bpl = vv->ov_fb.fmt.bytesperline;
u32 base = (u32)vv->ov_fb.base; /* The unsigned long cast is to remove a 64-bit compile warning since
it looks like a 64-bit address is cast to a 32-bit value, even
though the base pointer is really a 32-bit physical address that
goes into a 32-bit DMA register.
FIXME: might not work on some 64-bit platforms, but see the FIXME
in struct v4l2_framebuffer (videodev2.h) for that.
*/
u32 base = (u32)(unsigned long)vv->ov_fb.base;
struct saa7146_video_dma vdma1; struct saa7146_video_dma vdma1;
/* calculate memory offsets for picture, look if we shall top-down-flip */ /* calculate memory offsets for picture, look if we shall top-down-flip */
vdma1.pitch = 2*b_bpl; vdma1.pitch = 2*b_bpl;
if ( 0 == vv->vflip ) { if ( 0 == vv->vflip ) {
vdma1.base_even = (u32)base + (w_y * (vdma1.pitch/2)) + (w_x * (b_depth / 8)); vdma1.base_even = base + (w_y * (vdma1.pitch/2)) + (w_x * (b_depth / 8));
vdma1.base_odd = vdma1.base_even + (vdma1.pitch / 2); vdma1.base_odd = vdma1.base_even + (vdma1.pitch / 2);
vdma1.prot_addr = vdma1.base_even + (w_height * (vdma1.pitch / 2)); vdma1.prot_addr = vdma1.base_even + (w_height * (vdma1.pitch / 2));
} }
else { else {
vdma1.base_even = (u32)base + ((w_y+w_height) * (vdma1.pitch/2)) + (w_x * (b_depth / 8)); vdma1.base_even = base + ((w_y+w_height) * (vdma1.pitch/2)) + (w_x * (b_depth / 8));
vdma1.base_odd = vdma1.base_even - (vdma1.pitch / 2); vdma1.base_odd = vdma1.base_even - (vdma1.pitch / 2);
vdma1.prot_addr = vdma1.base_odd - (w_height * (vdma1.pitch / 2)); vdma1.prot_addr = vdma1.base_odd - (w_height * (vdma1.pitch / 2));
} }

View File

@ -1114,10 +1114,6 @@ int saa7146_video_do_ioctl(struct inode *inode, struct file *file, unsigned int
return 0; return 0;
} }
case VIDIOC_OVERLAY: case VIDIOC_OVERLAY:
{ {
int on = *(int *)arg; int on = *(int *)arg;
int err = 0; int err = 0;
@ -1359,7 +1355,6 @@ static void buffer_queue(struct videobuf_queue *q, struct videobuf_buffer *vb)
saa7146_buffer_queue(fh->dev,&vv->video_q,buf); saa7146_buffer_queue(fh->dev,&vv->video_q,buf);
} }
static void buffer_release(struct videobuf_queue *q, struct videobuf_buffer *vb) static void buffer_release(struct videobuf_queue *q, struct videobuf_buffer *vb)
{ {
struct file *file = q->priv_data; struct file *file = q->priv_data;

View File

@ -485,12 +485,16 @@ static struct stv0297_config alps_tdee4_stv0297_config = {
/* try to figure out the frontend, each card/box can have on of the following list */ /* try to figure out the frontend, each card/box can have on of the following list */
int flexcop_frontend_init(struct flexcop_device *fc) int flexcop_frontend_init(struct flexcop_device *fc)
{ {
struct dvb_frontend_ops *ops;
/* try the sky v2.6 (stv0299/Samsung tbmu24112(sl1935)) */ /* try the sky v2.6 (stv0299/Samsung tbmu24112(sl1935)) */
if ((fc->fe = stv0299_attach(&samsung_tbmu24112_config, &fc->i2c_adap)) != NULL) { if ((fc->fe = stv0299_attach(&samsung_tbmu24112_config, &fc->i2c_adap)) != NULL) {
fc->fe->ops->set_voltage = flexcop_set_voltage; ops = fc->fe->ops;
fc->fe_sleep = fc->fe->ops->sleep; ops->set_voltage = flexcop_set_voltage;
fc->fe->ops->sleep = flexcop_sleep;
fc->fe_sleep = ops->sleep;
ops->sleep = flexcop_sleep;
fc->dev_type = FC_SKY; fc->dev_type = FC_SKY;
info("found the stv0299 at i2c address: 0x%02x",samsung_tbmu24112_config.demod_address); info("found the stv0299 at i2c address: 0x%02x",samsung_tbmu24112_config.demod_address);
@ -522,13 +526,15 @@ int flexcop_frontend_init(struct flexcop_device *fc)
} else } else
/* try the sky v2.3 (vp310/Samsung tbdu18132(tsa5059)) */ /* try the sky v2.3 (vp310/Samsung tbdu18132(tsa5059)) */
if ((fc->fe = vp310_attach(&skystar23_samsung_tbdu18132_config, &fc->i2c_adap)) != NULL) { if ((fc->fe = vp310_attach(&skystar23_samsung_tbdu18132_config, &fc->i2c_adap)) != NULL) {
fc->fe->ops->diseqc_send_master_cmd = flexcop_diseqc_send_master_cmd; ops = fc->fe->ops;
fc->fe->ops->diseqc_send_burst = flexcop_diseqc_send_burst;
fc->fe->ops->set_tone = flexcop_set_tone;
fc->fe->ops->set_voltage = flexcop_set_voltage;
fc->fe_sleep = fc->fe->ops->sleep; ops->diseqc_send_master_cmd = flexcop_diseqc_send_master_cmd;
fc->fe->ops->sleep = flexcop_sleep; ops->diseqc_send_burst = flexcop_diseqc_send_burst;
ops->set_tone = flexcop_set_tone;
ops->set_voltage = flexcop_set_voltage;
fc->fe_sleep = ops->sleep;
ops->sleep = flexcop_sleep;
fc->dev_type = FC_SKY_OLD; fc->dev_type = FC_SKY_OLD;
info("found the vp310 (aka mt312) at i2c address: 0x%02x",skystar23_samsung_tbdu18132_config.demod_address); info("found the vp310 (aka mt312) at i2c address: 0x%02x",skystar23_samsung_tbdu18132_config.demod_address);
@ -540,8 +546,9 @@ int flexcop_frontend_init(struct flexcop_device *fc)
} else { } else {
if (dvb_register_frontend(&fc->dvb_adapter, fc->fe)) { if (dvb_register_frontend(&fc->dvb_adapter, fc->fe)) {
err("frontend registration failed!"); err("frontend registration failed!");
if (fc->fe->ops->release != NULL) ops = fc->fe->ops;
fc->fe->ops->release(fc->fe); if (ops->release != NULL)
ops->release(fc->fe);
fc->fe = NULL; fc->fe = NULL;
return -EINVAL; return -EINVAL;
} }

View File

@ -39,11 +39,13 @@ extern const char *flexcop_device_names[];
/* FlexCop IBI Registers */ /* FlexCop IBI Registers */
#if defined(__LITTLE_ENDIAN) #if defined(__LITTLE_ENDIAN)
#include "flexcop_ibi_value_le.h" #include "flexcop_ibi_value_le.h"
#elif defined(__BIG_ENDIAN) #else
#if defined(__BIG_ENDIAN)
#include "flexcop_ibi_value_be.h" #include "flexcop_ibi_value_be.h"
#else #else
#error no endian defined #error no endian defined
#endif #endif
#endif
#define fc_data_Tag_ID_DVB 0x3e #define fc_data_Tag_ID_DVB 0x3e
#define fc_data_Tag_ID_ATSC 0x3f #define fc_data_Tag_ID_ATSC 0x3f

View File

@ -1341,10 +1341,15 @@ static int dst_read_snr(struct dvb_frontend *fe, u16 *snr)
return 0; return 0;
} }
static int dst_set_frontend(struct dvb_frontend *fe, struct dvb_frontend_parameters *p) static int dst_set_frontend(struct dvb_frontend* fe,
struct dvb_frontend_parameters* p,
unsigned int mode_flags,
int *delay,
fe_status_t *status)
{ {
struct dst_state *state = fe->demodulator_priv; struct dst_state *state = fe->demodulator_priv;
if (p != NULL) {
dst_set_freq(state, p->frequency); dst_set_freq(state, p->frequency);
dprintk(verbose, DST_DEBUG, 1, "Set Frequency=[%d]", p->frequency); dprintk(verbose, DST_DEBUG, 1, "Set Frequency=[%d]", p->frequency);
@ -1364,7 +1369,12 @@ static int dst_set_frontend(struct dvb_frontend *fe, struct dvb_frontend_paramet
dst_set_modulation(state, p->u.qam.modulation); dst_set_modulation(state, p->u.qam.modulation);
} }
dst_write_tuna(fe); dst_write_tuna(fe);
}
if (!(mode_flags & FE_TUNE_MODE_ONESHOT))
dst_read_status(fe, status);
*delay = HZ/10;
return 0; return 0;
} }
@ -1445,7 +1455,7 @@ static struct dvb_frontend_ops dst_dvbt_ops = {
.release = dst_release, .release = dst_release,
.init = dst_init, .init = dst_init,
.set_frontend = dst_set_frontend, .tune = dst_set_frontend,
.get_frontend = dst_get_frontend, .get_frontend = dst_get_frontend,
.read_status = dst_read_status, .read_status = dst_read_status,
.read_signal_strength = dst_read_signal_strength, .read_signal_strength = dst_read_signal_strength,
@ -1469,7 +1479,7 @@ static struct dvb_frontend_ops dst_dvbs_ops = {
.release = dst_release, .release = dst_release,
.init = dst_init, .init = dst_init,
.set_frontend = dst_set_frontend, .tune = dst_set_frontend,
.get_frontend = dst_get_frontend, .get_frontend = dst_get_frontend,
.read_status = dst_read_status, .read_status = dst_read_status,
.read_signal_strength = dst_read_signal_strength, .read_signal_strength = dst_read_signal_strength,
@ -1496,7 +1506,7 @@ static struct dvb_frontend_ops dst_dvbc_ops = {
.release = dst_release, .release = dst_release,
.init = dst_init, .init = dst_init,
.set_frontend = dst_set_frontend, .tune = dst_set_frontend,
.get_frontend = dst_get_frontend, .get_frontend = dst_get_frontend,
.read_status = dst_read_status, .read_status = dst_read_status,
.read_signal_strength = dst_read_signal_strength, .read_signal_strength = dst_read_signal_strength,

View File

@ -283,16 +283,17 @@ static int handle_dst_tag(struct dst_state *state, struct ca_msg *p_ca_message,
hw_buffer->msg[4] = 0x03; hw_buffer->msg[4] = 0x03;
hw_buffer->msg[5] = length & 0xff; hw_buffer->msg[5] = length & 0xff;
hw_buffer->msg[6] = 0x00; hw_buffer->msg[6] = 0x00;
/* /*
* Need to compute length for EN50221 section 8.3.2, for the time being * Need to compute length for EN50221 section 8.3.2, for the time being
* assuming 8.3.2 is not applicable * assuming 8.3.2 is not applicable
*/ */
memcpy(&hw_buffer->msg[7], &p_ca_message->msg[4], length); memcpy(&hw_buffer->msg[7], &p_ca_message->msg[4], length);
} }
return 0; return 0;
} }
static int write_to_8820(struct dst_state *state, struct ca_msg *hw_buffer, u8 length, u8 reply) static int write_to_8820(struct dst_state *state, struct ca_msg *hw_buffer, u8 length, u8 reply)
{ {
if ((dst_put_ci(state, hw_buffer->msg, length, hw_buffer->msg, reply)) < 0) { if ((dst_put_ci(state, hw_buffer->msg, length, hw_buffer->msg, reply)) < 0) {

View File

@ -600,7 +600,6 @@ static void frontend_init(struct dvb_bt8xx_card *card, u32 type)
struct dst_state* state = NULL; struct dst_state* state = NULL;
switch(type) { switch(type) {
#ifdef BTTV_BOARD_DVICO_DVBT_LITE
case BTTV_BOARD_DVICO_DVBT_LITE: case BTTV_BOARD_DVICO_DVBT_LITE:
card->fe = mt352_attach(&thomson_dtt7579_config, card->i2c_adapter); card->fe = mt352_attach(&thomson_dtt7579_config, card->i2c_adapter);
if (card->fe != NULL) { if (card->fe != NULL) {
@ -608,22 +607,15 @@ static void frontend_init(struct dvb_bt8xx_card *card, u32 type)
card->fe->ops->info.frequency_max = 862000000; card->fe->ops->info.frequency_max = 862000000;
} }
break; break;
#endif
#ifdef BTTV_BOARD_DVICO_FUSIONHDTV_5_LITE
case BTTV_BOARD_DVICO_FUSIONHDTV_5_LITE: case BTTV_BOARD_DVICO_FUSIONHDTV_5_LITE:
lgdt330x_reset(card); lgdt330x_reset(card);
card->fe = lgdt330x_attach(&tdvs_tua6034_config, card->i2c_adapter); card->fe = lgdt330x_attach(&tdvs_tua6034_config, card->i2c_adapter);
if (card->fe != NULL) if (card->fe != NULL)
dprintk ("dvb_bt8xx: lgdt330x detected\n"); dprintk ("dvb_bt8xx: lgdt330x detected\n");
break; break;
#endif
#ifdef BTTV_BOARD_TWINHAN_VP3021
case BTTV_BOARD_TWINHAN_VP3021:
#else
case BTTV_BOARD_NEBULA_DIGITV: case BTTV_BOARD_NEBULA_DIGITV:
#endif
/* /*
* It is possible to determine the correct frontend using the I2C bus (see the Nebula SDK); * It is possible to determine the correct frontend using the I2C bus (see the Nebula SDK);
* this would be a cleaner solution than trying each frontend in turn. * this would be a cleaner solution than trying each frontend in turn.
@ -812,9 +804,7 @@ static int dvb_bt8xx_probe(struct device *dev)
card->irq_err_ignore = 0; card->irq_err_ignore = 0;
break; break;
#ifdef BTTV_BOARD_DVICO_DVBT_LITE
case BTTV_BOARD_DVICO_DVBT_LITE: case BTTV_BOARD_DVICO_DVBT_LITE:
#endif
card->gpio_mode = 0x0400C060; card->gpio_mode = 0x0400C060;
card->op_sync_orin = 0; card->op_sync_orin = 0;
card->irq_err_ignore = 0; card->irq_err_ignore = 0;
@ -823,19 +813,13 @@ static int dvb_bt8xx_probe(struct device *dev)
* DA_APP(parallel) */ * DA_APP(parallel) */
break; break;
#ifdef BTTV_BOARD_DVICO_FUSIONHDTV_5_LITE
case BTTV_BOARD_DVICO_FUSIONHDTV_5_LITE: case BTTV_BOARD_DVICO_FUSIONHDTV_5_LITE:
#endif
card->gpio_mode = 0x0400c060; card->gpio_mode = 0x0400c060;
card->op_sync_orin = BT878_RISC_SYNC_MASK; card->op_sync_orin = BT878_RISC_SYNC_MASK;
card->irq_err_ignore = BT878_AFBUS | BT878_AFDSR; card->irq_err_ignore = BT878_AFBUS | BT878_AFDSR;
break; break;
#ifdef BTTV_BOARD_TWINHAN_VP3021
case BTTV_BOARD_TWINHAN_VP3021:
#else
case BTTV_BOARD_NEBULA_DIGITV: case BTTV_BOARD_NEBULA_DIGITV:
#endif
case BTTV_BOARD_AVDVBT_761: case BTTV_BOARD_AVDVBT_761:
card->gpio_mode = (1 << 26) | (1 << 14) | (1 << 5); card->gpio_mode = (1 << 26) | (1 << 14) | (1 << 5);
card->op_sync_orin = 0; card->op_sync_orin = 0;

View File

@ -131,6 +131,8 @@ struct cinergyt2 {
wait_queue_head_t poll_wq; wait_queue_head_t poll_wq;
int pending_fe_events; int pending_fe_events;
int disconnect_pending;
atomic_t inuse;
void *streambuf; void *streambuf;
dma_addr_t streambuf_dmahandle; dma_addr_t streambuf_dmahandle;
@ -343,7 +345,7 @@ static int cinergyt2_start_feed(struct dvb_demux_feed *dvbdmxfeed)
struct dvb_demux *demux = dvbdmxfeed->demux; struct dvb_demux *demux = dvbdmxfeed->demux;
struct cinergyt2 *cinergyt2 = demux->priv; struct cinergyt2 *cinergyt2 = demux->priv;
if (down_interruptible(&cinergyt2->sem)) if (cinergyt2->disconnect_pending || down_interruptible(&cinergyt2->sem))
return -ERESTARTSYS; return -ERESTARTSYS;
if (cinergyt2->streaming == 0) if (cinergyt2->streaming == 0)
@ -359,7 +361,7 @@ static int cinergyt2_stop_feed(struct dvb_demux_feed *dvbdmxfeed)
struct dvb_demux *demux = dvbdmxfeed->demux; struct dvb_demux *demux = dvbdmxfeed->demux;
struct cinergyt2 *cinergyt2 = demux->priv; struct cinergyt2 *cinergyt2 = demux->priv;
if (down_interruptible(&cinergyt2->sem)) if (cinergyt2->disconnect_pending || down_interruptible(&cinergyt2->sem))
return -ERESTARTSYS; return -ERESTARTSYS;
if (--cinergyt2->streaming == 0) if (--cinergyt2->streaming == 0)
@ -479,23 +481,37 @@ static int cinergyt2_open (struct inode *inode, struct file *file)
{ {
struct dvb_device *dvbdev = file->private_data; struct dvb_device *dvbdev = file->private_data;
struct cinergyt2 *cinergyt2 = dvbdev->priv; struct cinergyt2 *cinergyt2 = dvbdev->priv;
int err; int err = -ERESTARTSYS;
if ((err = dvb_generic_open(inode, file))) if (cinergyt2->disconnect_pending || down_interruptible(&cinergyt2->sem))
return err;
if (down_interruptible(&cinergyt2->sem))
return -ERESTARTSYS; return -ERESTARTSYS;
if ((err = dvb_generic_open(inode, file))) {
up(&cinergyt2->sem);
return err;
}
if ((file->f_flags & O_ACCMODE) != O_RDONLY) { if ((file->f_flags & O_ACCMODE) != O_RDONLY) {
cinergyt2_sleep(cinergyt2, 0); cinergyt2_sleep(cinergyt2, 0);
schedule_delayed_work(&cinergyt2->query_work, HZ/2); schedule_delayed_work(&cinergyt2->query_work, HZ/2);
} }
atomic_inc(&cinergyt2->inuse);
up(&cinergyt2->sem); up(&cinergyt2->sem);
return 0; return 0;
} }
static void cinergyt2_unregister(struct cinergyt2 *cinergyt2)
{
dvb_unregister_device(cinergyt2->fedev);
dvb_unregister_adapter(&cinergyt2->adapter);
cinergyt2_free_stream_urbs(cinergyt2);
kfree(cinergyt2);
}
static int cinergyt2_release (struct inode *inode, struct file *file) static int cinergyt2_release (struct inode *inode, struct file *file)
{ {
struct dvb_device *dvbdev = file->private_data; struct dvb_device *dvbdev = file->private_data;
@ -504,7 +520,7 @@ static int cinergyt2_release (struct inode *inode, struct file *file)
if (down_interruptible(&cinergyt2->sem)) if (down_interruptible(&cinergyt2->sem))
return -ERESTARTSYS; return -ERESTARTSYS;
if ((file->f_flags & O_ACCMODE) != O_RDONLY) { if (!cinergyt2->disconnect_pending && (file->f_flags & O_ACCMODE) != O_RDONLY) {
cancel_delayed_work(&cinergyt2->query_work); cancel_delayed_work(&cinergyt2->query_work);
flush_scheduled_work(); flush_scheduled_work();
cinergyt2_sleep(cinergyt2, 1); cinergyt2_sleep(cinergyt2, 1);
@ -512,6 +528,11 @@ static int cinergyt2_release (struct inode *inode, struct file *file)
up(&cinergyt2->sem); up(&cinergyt2->sem);
if (atomic_dec_and_test(&cinergyt2->inuse) && cinergyt2->disconnect_pending) {
warn("delayed unregister in release");
cinergyt2_unregister(cinergyt2);
}
return dvb_generic_release(inode, file); return dvb_generic_release(inode, file);
} }
@ -519,7 +540,14 @@ static unsigned int cinergyt2_poll (struct file *file, struct poll_table_struct
{ {
struct dvb_device *dvbdev = file->private_data; struct dvb_device *dvbdev = file->private_data;
struct cinergyt2 *cinergyt2 = dvbdev->priv; struct cinergyt2 *cinergyt2 = dvbdev->priv;
if (cinergyt2->disconnect_pending || down_interruptible(&cinergyt2->sem))
return -ERESTARTSYS;
poll_wait(file, &cinergyt2->poll_wq, wait); poll_wait(file, &cinergyt2->poll_wq, wait);
up(&cinergyt2->sem);
return (POLLIN | POLLRDNORM | POLLPRI); return (POLLIN | POLLRDNORM | POLLPRI);
} }
@ -564,10 +592,15 @@ static int cinergyt2_ioctl (struct inode *inode, struct file *file,
(__u16 __user *) arg); (__u16 __user *) arg);
case FE_READ_UNCORRECTED_BLOCKS: case FE_READ_UNCORRECTED_BLOCKS:
/* UNC are already converted to host byte order... */ {
return put_user(stat->uncorrected_block_count, uint32_t unc_count;
(__u32 __user *) arg);
unc_count = stat->uncorrected_block_count;
stat->uncorrected_block_count = 0;
/* UNC are already converted to host byte order... */
return put_user(unc_count,(__u32 __user *) arg);
}
case FE_SET_FRONTEND: case FE_SET_FRONTEND:
{ {
struct dvbt_set_parameters_msg *param = &cinergyt2->param; struct dvbt_set_parameters_msg *param = &cinergyt2->param;
@ -580,7 +613,7 @@ static int cinergyt2_ioctl (struct inode *inode, struct file *file,
if (copy_from_user(&p, (void __user*) arg, sizeof(p))) if (copy_from_user(&p, (void __user*) arg, sizeof(p)))
return -EFAULT; return -EFAULT;
if (down_interruptible(&cinergyt2->sem)) if (cinergyt2->disconnect_pending || down_interruptible(&cinergyt2->sem))
return -ERESTARTSYS; return -ERESTARTSYS;
param->cmd = CINERGYT2_EP1_SET_TUNER_PARAMETERS; param->cmd = CINERGYT2_EP1_SET_TUNER_PARAMETERS;
@ -691,7 +724,7 @@ static void cinergyt2_query_rc (void *data)
struct cinergyt2_rc_event rc_events[12]; struct cinergyt2_rc_event rc_events[12];
int n, len, i; int n, len, i;
if (down_interruptible(&cinergyt2->sem)) if (cinergyt2->disconnect_pending || down_interruptible(&cinergyt2->sem))
return; return;
len = cinergyt2_command(cinergyt2, buf, sizeof(buf), len = cinergyt2_command(cinergyt2, buf, sizeof(buf),
@ -786,7 +819,6 @@ static int cinergyt2_register_rc(struct cinergyt2 *cinergyt2)
static void cinergyt2_unregister_rc(struct cinergyt2 *cinergyt2) static void cinergyt2_unregister_rc(struct cinergyt2 *cinergyt2)
{ {
cancel_delayed_work(&cinergyt2->rc_query_work); cancel_delayed_work(&cinergyt2->rc_query_work);
flush_scheduled_work();
input_unregister_device(cinergyt2->rc_input_dev); input_unregister_device(cinergyt2->rc_input_dev);
} }
@ -817,7 +849,7 @@ static void cinergyt2_query (void *data)
uint8_t lock_bits; uint8_t lock_bits;
uint32_t unc; uint32_t unc;
if (down_interruptible(&cinergyt2->sem)) if (cinergyt2->disconnect_pending || down_interruptible(&cinergyt2->sem))
return; return;
unc = s->uncorrected_block_count; unc = s->uncorrected_block_count;
@ -917,28 +949,25 @@ static void cinergyt2_disconnect (struct usb_interface *intf)
{ {
struct cinergyt2 *cinergyt2 = usb_get_intfdata (intf); struct cinergyt2 *cinergyt2 = usb_get_intfdata (intf);
if (down_interruptible(&cinergyt2->sem)) flush_scheduled_work();
return;
cinergyt2_unregister_rc(cinergyt2); cinergyt2_unregister_rc(cinergyt2);
cinergyt2->demux.dmx.close(&cinergyt2->demux.dmx); cancel_delayed_work(&cinergyt2->query_work);
dvb_net_release(&cinergyt2->dvbnet); wake_up_interruptible(&cinergyt2->poll_wq);
dvb_dmxdev_release(&cinergyt2->dmxdev);
dvb_dmx_release(&cinergyt2->demux);
dvb_unregister_device(cinergyt2->fedev);
dvb_unregister_adapter(&cinergyt2->adapter);
cinergyt2_free_stream_urbs(cinergyt2); cinergyt2->demux.dmx.close(&cinergyt2->demux.dmx);
up(&cinergyt2->sem); cinergyt2->disconnect_pending = 1;
kfree(cinergyt2);
if (!atomic_read(&cinergyt2->inuse))
cinergyt2_unregister(cinergyt2);
} }
static int cinergyt2_suspend (struct usb_interface *intf, pm_message_t state) static int cinergyt2_suspend (struct usb_interface *intf, pm_message_t state)
{ {
struct cinergyt2 *cinergyt2 = usb_get_intfdata (intf); struct cinergyt2 *cinergyt2 = usb_get_intfdata (intf);
if (down_interruptible(&cinergyt2->sem)) if (cinergyt2->disconnect_pending || down_interruptible(&cinergyt2->sem))
return -ERESTARTSYS; return -ERESTARTSYS;
if (state.event > PM_EVENT_ON) { if (state.event > PM_EVENT_ON) {
@ -961,7 +990,7 @@ static int cinergyt2_resume (struct usb_interface *intf)
struct cinergyt2 *cinergyt2 = usb_get_intfdata (intf); struct cinergyt2 *cinergyt2 = usb_get_intfdata (intf);
struct dvbt_set_parameters_msg *param = &cinergyt2->param; struct dvbt_set_parameters_msg *param = &cinergyt2->param;
if (down_interruptible(&cinergyt2->sem)) if (cinergyt2->disconnect_pending || down_interruptible(&cinergyt2->sem))
return -ERESTARTSYS; return -ERESTARTSYS;
if (!cinergyt2->sleeping) { if (!cinergyt2->sleeping) {
@ -1014,4 +1043,3 @@ module_exit (cinergyt2_exit);
MODULE_LICENSE("GPL"); MODULE_LICENSE("GPL");
MODULE_AUTHOR("Holger Waechtler, Daniel Mack"); MODULE_AUTHOR("Holger Waechtler, Daniel Mack");

View File

@ -1745,10 +1745,8 @@ void dvb_ca_en50221_release(struct dvb_ca_en50221 *pubca)
for (i = 0; i < ca->slot_count; i++) { for (i = 0; i < ca->slot_count; i++) {
dvb_ca_en50221_slot_shutdown(ca, i); dvb_ca_en50221_slot_shutdown(ca, i);
if (ca->slot_info[i].rx_buffer.data != NULL) {
vfree(ca->slot_info[i].rx_buffer.data); vfree(ca->slot_info[i].rx_buffer.data);
} }
}
kfree(ca->slot_info); kfree(ca->slot_info);
dvb_unregister_device(ca->dvbdev); dvb_unregister_device(ca->dvbdev);
kfree(ca); kfree(ca);

View File

@ -92,6 +92,7 @@ static DECLARE_MUTEX(frontend_mutex);
struct dvb_frontend_private { struct dvb_frontend_private {
/* thread/frontend values */
struct dvb_device *dvbdev; struct dvb_device *dvbdev;
struct dvb_frontend_parameters parameters; struct dvb_frontend_parameters parameters;
struct dvb_fe_events events; struct dvb_fe_events events;
@ -100,20 +101,25 @@ struct dvb_frontend_private {
wait_queue_head_t wait_queue; wait_queue_head_t wait_queue;
pid_t thread_pid; pid_t thread_pid;
unsigned long release_jiffies; unsigned long release_jiffies;
int state; unsigned int exit;
int bending; unsigned int wakeup;
int lnb_drift;
int inversion;
int auto_step;
int auto_sub_step;
int started_auto_step;
int min_delay;
int max_drift;
int step_size;
int exit;
int wakeup;
fe_status_t status; fe_status_t status;
fe_sec_tone_mode_t tone; unsigned long tune_mode_flags;
unsigned int delay;
/* swzigzag values */
unsigned int state;
unsigned int bending;
int lnb_drift;
unsigned int inversion;
unsigned int auto_step;
unsigned int auto_sub_step;
unsigned int started_auto_step;
unsigned int min_delay;
unsigned int max_drift;
unsigned int step_size;
int quality;
unsigned int check_wrapped;
}; };
@ -208,21 +214,21 @@ static void dvb_frontend_init(struct dvb_frontend *fe)
fe->ops->init(fe); fe->ops->init(fe);
} }
static void update_delay(int *quality, int *delay, int min_delay, int locked) static void dvb_frontend_swzigzag_update_delay(struct dvb_frontend_private *fepriv, int locked)
{ {
int q2; int q2;
dprintk ("%s\n", __FUNCTION__); dprintk ("%s\n", __FUNCTION__);
if (locked) if (locked)
(*quality) = (*quality * 220 + 36*256) / 256; (fepriv->quality) = (fepriv->quality * 220 + 36*256) / 256;
else else
(*quality) = (*quality * 220 + 0) / 256; (fepriv->quality) = (fepriv->quality * 220 + 0) / 256;
q2 = *quality - 128; q2 = fepriv->quality - 128;
q2 *= q2; q2 *= q2;
*delay = min_delay + q2 * HZ / (128*128); fepriv->delay = fepriv->min_delay + q2 * HZ / (128*128);
} }
/** /**
@ -232,7 +238,7 @@ static void update_delay(int *quality, int *delay, int min_delay, int locked)
* @param check_wrapped Checks if an iteration has completed. DO NOT SET ON THE FIRST ATTEMPT * @param check_wrapped Checks if an iteration has completed. DO NOT SET ON THE FIRST ATTEMPT
* @returns Number of complete iterations that have been performed. * @returns Number of complete iterations that have been performed.
*/ */
static int dvb_frontend_autotune(struct dvb_frontend *fe, int check_wrapped) static int dvb_frontend_swzigzag_autotune(struct dvb_frontend *fe, int check_wrapped)
{ {
int autoinversion; int autoinversion;
int ready = 0; int ready = 0;
@ -321,6 +327,129 @@ static int dvb_frontend_autotune(struct dvb_frontend *fe, int check_wrapped)
return 0; return 0;
} }
static void dvb_frontend_swzigzag(struct dvb_frontend *fe)
{
fe_status_t s;
struct dvb_frontend_private *fepriv = fe->frontend_priv;
/* if we've got no parameters, just keep idling */
if (fepriv->state & FESTATE_IDLE) {
fepriv->delay = 3*HZ;
fepriv->quality = 0;
return;
}
/* in SCAN mode, we just set the frontend when asked and leave it alone */
if (fepriv->tune_mode_flags & FE_TUNE_MODE_ONESHOT) {
if (fepriv->state & FESTATE_RETUNE) {
if (fe->ops->set_frontend)
fe->ops->set_frontend(fe, &fepriv->parameters);
fepriv->state = FESTATE_TUNED;
}
fepriv->delay = 3*HZ;
fepriv->quality = 0;
return;
}
/* get the frontend status */
if (fepriv->state & FESTATE_RETUNE) {
s = 0;
} else {
if (fe->ops->read_status)
fe->ops->read_status(fe, &s);
if (s != fepriv->status) {
dvb_frontend_add_event(fe, s);
fepriv->status = s;
}
}
/* if we're not tuned, and we have a lock, move to the TUNED state */
if ((fepriv->state & FESTATE_WAITFORLOCK) && (s & FE_HAS_LOCK)) {
dvb_frontend_swzigzag_update_delay(fepriv, s & FE_HAS_LOCK);
fepriv->state = FESTATE_TUNED;
/* if we're tuned, then we have determined the correct inversion */
if ((!(fe->ops->info.caps & FE_CAN_INVERSION_AUTO)) &&
(fepriv->parameters.inversion == INVERSION_AUTO)) {
fepriv->parameters.inversion = fepriv->inversion;
}
return;
}
/* if we are tuned already, check we're still locked */
if (fepriv->state & FESTATE_TUNED) {
dvb_frontend_swzigzag_update_delay(fepriv, s & FE_HAS_LOCK);
/* we're tuned, and the lock is still good... */
if (s & FE_HAS_LOCK) {
return;
} else { /* if we _WERE_ tuned, but now don't have a lock */
fepriv->state = FESTATE_ZIGZAG_FAST;
fepriv->started_auto_step = fepriv->auto_step;
fepriv->check_wrapped = 0;
}
}
/* don't actually do anything if we're in the LOSTLOCK state,
* the frontend is set to FE_CAN_RECOVER, and the max_drift is 0 */
if ((fepriv->state & FESTATE_LOSTLOCK) &&
(fe->ops->info.caps & FE_CAN_RECOVER) && (fepriv->max_drift == 0)) {
dvb_frontend_swzigzag_update_delay(fepriv, s & FE_HAS_LOCK);
return;
}
/* don't do anything if we're in the DISEQC state, since this
* might be someone with a motorized dish controlled by DISEQC.
* If its actually a re-tune, there will be a SET_FRONTEND soon enough. */
if (fepriv->state & FESTATE_DISEQC) {
dvb_frontend_swzigzag_update_delay(fepriv, s & FE_HAS_LOCK);
return;
}
/* if we're in the RETUNE state, set everything up for a brand
* new scan, keeping the current inversion setting, as the next
* tune is _very_ likely to require the same */
if (fepriv->state & FESTATE_RETUNE) {
fepriv->lnb_drift = 0;
fepriv->auto_step = 0;
fepriv->auto_sub_step = 0;
fepriv->started_auto_step = 0;
fepriv->check_wrapped = 0;
}
/* fast zigzag. */
if ((fepriv->state & FESTATE_SEARCHING_FAST) || (fepriv->state & FESTATE_RETUNE)) {
fepriv->delay = fepriv->min_delay;
/* peform a tune */
if (dvb_frontend_swzigzag_autotune(fe, fepriv->check_wrapped)) {
/* OK, if we've run out of trials at the fast speed.
* Drop back to slow for the _next_ attempt */
fepriv->state = FESTATE_SEARCHING_SLOW;
fepriv->started_auto_step = fepriv->auto_step;
return;
}
fepriv->check_wrapped = 1;
/* if we've just retuned, enter the ZIGZAG_FAST state.
* This ensures we cannot return from an
* FE_SET_FRONTEND ioctl before the first frontend tune
* occurs */
if (fepriv->state & FESTATE_RETUNE) {
fepriv->state = FESTATE_TUNING_FAST;
}
}
/* slow zigzag */
if (fepriv->state & FESTATE_SEARCHING_SLOW) {
dvb_frontend_swzigzag_update_delay(fepriv, s & FE_HAS_LOCK);
/* Note: don't bother checking for wrapping; we stay in this
* state until we get a lock */
dvb_frontend_swzigzag_autotune(fe, 0);
}
}
static int dvb_frontend_is_exiting(struct dvb_frontend *fe) static int dvb_frontend_is_exiting(struct dvb_frontend *fe)
{ {
struct dvb_frontend_private *fepriv = fe->frontend_priv; struct dvb_frontend_private *fepriv = fe->frontend_priv;
@ -355,18 +484,14 @@ static void dvb_frontend_wakeup(struct dvb_frontend *fe)
wake_up_interruptible(&fepriv->wait_queue); wake_up_interruptible(&fepriv->wait_queue);
} }
/*
* FIXME: use linux/kthread.h
*/
static int dvb_frontend_thread(void *data) static int dvb_frontend_thread(void *data)
{ {
struct dvb_frontend *fe = data; struct dvb_frontend *fe = data;
struct dvb_frontend_private *fepriv = fe->frontend_priv; struct dvb_frontend_private *fepriv = fe->frontend_priv;
unsigned long timeout; unsigned long timeout;
char name [15]; char name [15];
int quality = 0, delay = 3*HZ;
fe_status_t s; fe_status_t s;
int check_wrapped = 0; struct dvb_frontend_parameters *params;
dprintk("%s\n", __FUNCTION__); dprintk("%s\n", __FUNCTION__);
@ -377,6 +502,9 @@ static int dvb_frontend_thread(void *data)
sigfillset(&current->blocked); sigfillset(&current->blocked);
unlock_kernel(); unlock_kernel();
fepriv->check_wrapped = 0;
fepriv->quality = 0;
fepriv->delay = 3*HZ;
fepriv->status = 0; fepriv->status = 0;
dvb_frontend_init(fe); dvb_frontend_init(fe);
fepriv->wakeup = 0; fepriv->wakeup = 0;
@ -386,7 +514,7 @@ static int dvb_frontend_thread(void *data)
timeout = wait_event_interruptible_timeout(fepriv->wait_queue, timeout = wait_event_interruptible_timeout(fepriv->wait_queue,
dvb_frontend_should_wakeup(fe), dvb_frontend_should_wakeup(fe),
delay); fepriv->delay);
if (0 != dvb_frontend_is_exiting(fe)) { if (0 != dvb_frontend_is_exiting(fe)) {
/* got signal or quitting */ /* got signal or quitting */
break; break;
@ -397,108 +525,22 @@ static int dvb_frontend_thread(void *data)
if (down_interruptible(&fepriv->sem)) if (down_interruptible(&fepriv->sem))
break; break;
/* if we've got no parameters, just keep idling */ /* do an iteration of the tuning loop */
if (fepriv->state & FESTATE_IDLE) { if (fe->ops->tune) {
delay = 3*HZ; /* have we been asked to retune? */
quality = 0; params = NULL;
continue; if (fepriv->state & FESTATE_RETUNE) {
params = &fepriv->parameters;
fepriv->state = FESTATE_TUNED;
} }
/* get the frontend status */ fe->ops->tune(fe, params, fepriv->tune_mode_flags, &fepriv->delay, &s);
if (fepriv->state & FESTATE_RETUNE) {
s = 0;
} else {
if (fe->ops->read_status)
fe->ops->read_status(fe, &s);
if (s != fepriv->status) { if (s != fepriv->status) {
dvb_frontend_add_event(fe, s); dvb_frontend_add_event(fe, s);
fepriv->status = s; fepriv->status = s;
} }
} } else {
/* if we're not tuned, and we have a lock, move to the TUNED state */ dvb_frontend_swzigzag(fe);
if ((fepriv->state & FESTATE_WAITFORLOCK) && (s & FE_HAS_LOCK)) {
update_delay(&quality, &delay, fepriv->min_delay, s & FE_HAS_LOCK);
fepriv->state = FESTATE_TUNED;
/* if we're tuned, then we have determined the correct inversion */
if ((!(fe->ops->info.caps & FE_CAN_INVERSION_AUTO)) &&
(fepriv->parameters.inversion == INVERSION_AUTO)) {
fepriv->parameters.inversion = fepriv->inversion;
}
continue;
}
/* if we are tuned already, check we're still locked */
if (fepriv->state & FESTATE_TUNED) {
update_delay(&quality, &delay, fepriv->min_delay, s & FE_HAS_LOCK);
/* we're tuned, and the lock is still good... */
if (s & FE_HAS_LOCK)
continue;
else { /* if we _WERE_ tuned, but now don't have a lock */
fepriv->state = FESTATE_ZIGZAG_FAST;
fepriv->started_auto_step = fepriv->auto_step;
check_wrapped = 0;
}
}
/* don't actually do anything if we're in the LOSTLOCK state,
* the frontend is set to FE_CAN_RECOVER, and the max_drift is 0 */
if ((fepriv->state & FESTATE_LOSTLOCK) &&
(fe->ops->info.caps & FE_CAN_RECOVER) && (fepriv->max_drift == 0)) {
update_delay(&quality, &delay, fepriv->min_delay, s & FE_HAS_LOCK);
continue;
}
/* don't do anything if we're in the DISEQC state, since this
* might be someone with a motorized dish controlled by DISEQC.
* If its actually a re-tune, there will be a SET_FRONTEND soon enough. */
if (fepriv->state & FESTATE_DISEQC) {
update_delay(&quality, &delay, fepriv->min_delay, s & FE_HAS_LOCK);
continue;
}
/* if we're in the RETUNE state, set everything up for a brand
* new scan, keeping the current inversion setting, as the next
* tune is _very_ likely to require the same */
if (fepriv->state & FESTATE_RETUNE) {
fepriv->lnb_drift = 0;
fepriv->auto_step = 0;
fepriv->auto_sub_step = 0;
fepriv->started_auto_step = 0;
check_wrapped = 0;
}
/* fast zigzag. */
if ((fepriv->state & FESTATE_SEARCHING_FAST) || (fepriv->state & FESTATE_RETUNE)) {
delay = fepriv->min_delay;
/* peform a tune */
if (dvb_frontend_autotune(fe, check_wrapped)) {
/* OK, if we've run out of trials at the fast speed.
* Drop back to slow for the _next_ attempt */
fepriv->state = FESTATE_SEARCHING_SLOW;
fepriv->started_auto_step = fepriv->auto_step;
continue;
}
check_wrapped = 1;
/* if we've just retuned, enter the ZIGZAG_FAST state.
* This ensures we cannot return from an
* FE_SET_FRONTEND ioctl before the first frontend tune
* occurs */
if (fepriv->state & FESTATE_RETUNE) {
fepriv->state = FESTATE_TUNING_FAST;
}
}
/* slow zigzag */
if (fepriv->state & FESTATE_SEARCHING_SLOW) {
update_delay(&quality, &delay, fepriv->min_delay, s & FE_HAS_LOCK);
/* Note: don't bother checking for wrapping; we stay in this
* state until we get a lock */
dvb_frontend_autotune(fe, 0);
} }
} }
@ -733,7 +775,6 @@ static int dvb_frontend_ioctl(struct inode *inode, struct file *file,
err = fe->ops->set_tone(fe, (fe_sec_tone_mode_t) parg); err = fe->ops->set_tone(fe, (fe_sec_tone_mode_t) parg);
fepriv->state = FESTATE_DISEQC; fepriv->state = FESTATE_DISEQC;
fepriv->status = 0; fepriv->status = 0;
fepriv->tone = (fe_sec_tone_mode_t) parg;
} }
break; break;
@ -747,7 +788,7 @@ static int dvb_frontend_ioctl(struct inode *inode, struct file *file,
case FE_DISHNETWORK_SEND_LEGACY_CMD: case FE_DISHNETWORK_SEND_LEGACY_CMD:
if (fe->ops->dishnetwork_send_legacy_command) { if (fe->ops->dishnetwork_send_legacy_command) {
err = fe->ops->dishnetwork_send_legacy_command(fe, (unsigned int) parg); err = fe->ops->dishnetwork_send_legacy_command(fe, (unsigned long) parg);
fepriv->state = FESTATE_DISEQC; fepriv->state = FESTATE_DISEQC;
fepriv->status = 0; fepriv->status = 0;
} else if (fe->ops->set_voltage) { } else if (fe->ops->set_voltage) {
@ -767,13 +808,13 @@ static int dvb_frontend_ioctl(struct inode *inode, struct file *file,
* initialization, so parg is 8 bits and does not * initialization, so parg is 8 bits and does not
* include the initialization or start bit * include the initialization or start bit
*/ */
unsigned int cmd = ((unsigned int) parg) << 1; unsigned long cmd = ((unsigned long) parg) << 1;
struct timeval nexttime; struct timeval nexttime;
struct timeval tv[10]; struct timeval tv[10];
int i; int i;
u8 last = 1; u8 last = 1;
if (dvb_frontend_debug) if (dvb_frontend_debug)
printk("%s switch command: 0x%04x\n", __FUNCTION__, cmd); printk("%s switch command: 0x%04lx\n", __FUNCTION__, cmd);
do_gettimeofday(&nexttime); do_gettimeofday(&nexttime);
if (dvb_frontend_debug) if (dvb_frontend_debug)
memcpy(&tv[0], &nexttime, sizeof(struct timeval)); memcpy(&tv[0], &nexttime, sizeof(struct timeval));
@ -814,7 +855,7 @@ static int dvb_frontend_ioctl(struct inode *inode, struct file *file,
case FE_ENABLE_HIGH_LNB_VOLTAGE: case FE_ENABLE_HIGH_LNB_VOLTAGE:
if (fe->ops->enable_high_lnb_voltage) if (fe->ops->enable_high_lnb_voltage)
err = fe->ops->enable_high_lnb_voltage(fe, (int) parg); err = fe->ops->enable_high_lnb_voltage(fe, (long) parg);
break; break;
case FE_SET_FRONTEND: { case FE_SET_FRONTEND: {
@ -891,6 +932,10 @@ static int dvb_frontend_ioctl(struct inode *inode, struct file *file,
err = fe->ops->get_frontend(fe, (struct dvb_frontend_parameters*) parg); err = fe->ops->get_frontend(fe, (struct dvb_frontend_parameters*) parg);
} }
break; break;
case FE_SET_FRONTEND_TUNE_MODE:
fepriv->tune_mode_flags = (unsigned long) parg;
break;
}; };
up (&fepriv->sem); up (&fepriv->sem);
@ -932,6 +977,9 @@ static int dvb_frontend_open(struct inode *inode, struct file *file)
/* empty event queue */ /* empty event queue */
fepriv->events.eventr = fepriv->events.eventw = 0; fepriv->events.eventr = fepriv->events.eventw = 0;
/* normal tune mode when opened R/W */
fepriv->tune_mode_flags &= ~FE_TUNE_MODE_ONESHOT;
} }
return ret; return ret;
@ -990,7 +1038,6 @@ int dvb_register_frontend(struct dvb_adapter* dvb,
init_MUTEX (&fepriv->events.sem); init_MUTEX (&fepriv->events.sem);
fe->dvb = dvb; fe->dvb = dvb;
fepriv->inversion = INVERSION_OFF; fepriv->inversion = INVERSION_OFF;
fepriv->tone = SEC_TONE_OFF;
printk ("DVB: registering frontend %i (%s)...\n", printk ("DVB: registering frontend %i (%s)...\n",
fe->dvb->num, fe->dvb->num,

View File

@ -58,10 +58,19 @@ struct dvb_frontend_ops {
int (*init)(struct dvb_frontend* fe); int (*init)(struct dvb_frontend* fe);
int (*sleep)(struct dvb_frontend* fe); int (*sleep)(struct dvb_frontend* fe);
/* if this is set, it overrides the default swzigzag */
int (*tune)(struct dvb_frontend* fe,
struct dvb_frontend_parameters* params,
unsigned int mode_flags,
int *delay,
fe_status_t *status);
/* these two are only used for the swzigzag code */
int (*set_frontend)(struct dvb_frontend* fe, struct dvb_frontend_parameters* params); int (*set_frontend)(struct dvb_frontend* fe, struct dvb_frontend_parameters* params);
int (*get_frontend)(struct dvb_frontend* fe, struct dvb_frontend_parameters* params);
int (*get_tune_settings)(struct dvb_frontend* fe, struct dvb_frontend_tune_settings* settings); int (*get_tune_settings)(struct dvb_frontend* fe, struct dvb_frontend_tune_settings* settings);
int (*get_frontend)(struct dvb_frontend* fe, struct dvb_frontend_parameters* params);
int (*read_status)(struct dvb_frontend* fe, fe_status_t* status); int (*read_status)(struct dvb_frontend* fe, fe_status_t* status);
int (*read_ber)(struct dvb_frontend* fe, u32* ber); int (*read_ber)(struct dvb_frontend* fe, u32* ber);
int (*read_signal_strength)(struct dvb_frontend* fe, u16* strength); int (*read_signal_strength)(struct dvb_frontend* fe, u16* strength);
@ -74,8 +83,9 @@ struct dvb_frontend_ops {
int (*diseqc_send_burst)(struct dvb_frontend* fe, fe_sec_mini_cmd_t minicmd); int (*diseqc_send_burst)(struct dvb_frontend* fe, fe_sec_mini_cmd_t minicmd);
int (*set_tone)(struct dvb_frontend* fe, fe_sec_tone_mode_t tone); int (*set_tone)(struct dvb_frontend* fe, fe_sec_tone_mode_t tone);
int (*set_voltage)(struct dvb_frontend* fe, fe_sec_voltage_t voltage); int (*set_voltage)(struct dvb_frontend* fe, fe_sec_voltage_t voltage);
int (*enable_high_lnb_voltage)(struct dvb_frontend* fe, int arg); int (*enable_high_lnb_voltage)(struct dvb_frontend* fe, long arg);
int (*dishnetwork_send_legacy_command)(struct dvb_frontend* fe, unsigned int cmd); int (*dishnetwork_send_legacy_command)(struct dvb_frontend* fe, unsigned long cmd);
int (*i2c_gate_ctrl)(struct dvb_frontend* fe, int enable);
}; };
#define MAX_EVENT 8 #define MAX_EVENT 8

View File

@ -1222,7 +1222,7 @@ static int dvb_net_add_if(struct dvb_net *dvbnet, u16 pid, u8 feedtype)
return if_num; return if_num;
} }
static int dvb_net_remove_if(struct dvb_net *dvbnet, unsigned int num) static int dvb_net_remove_if(struct dvb_net *dvbnet, unsigned long num)
{ {
struct net_device *net = dvbnet->device[num]; struct net_device *net = dvbnet->device[num];
struct dvb_net_priv *priv; struct dvb_net_priv *priv;
@ -1296,9 +1296,9 @@ static int dvb_net_do_ioctl(struct inode *inode, struct file *file,
if (!capable(CAP_SYS_ADMIN)) if (!capable(CAP_SYS_ADMIN))
return -EPERM; return -EPERM;
if ((unsigned int) parg >= DVB_NET_DEVICES_MAX) if ((unsigned long) parg >= DVB_NET_DEVICES_MAX)
return -EINVAL; return -EINVAL;
ret = dvb_net_remove_if(dvbnet, (unsigned int) parg); ret = dvb_net_remove_if(dvbnet, (unsigned long) parg);
if (!ret) if (!ret)
module_put(dvbdev->adapter->module); module_put(dvbdev->adapter->module);
return ret; return ret;

View File

@ -37,16 +37,16 @@ config DVB_USB_DIBUSB_MB
DiBcom (<http://www.dibcom.fr>) equipped with a DiB3000M-B demodulator. DiBcom (<http://www.dibcom.fr>) equipped with a DiB3000M-B demodulator.
Devices supported by this driver: Devices supported by this driver:
TwinhanDTV USB-Ter (VP7041)
TwinhanDTV Magic Box (VP7041e)
KWorld/JetWay/ADSTech V-Stream XPERT DTV - DVB-T USB1.1 and USB2.0
Hama DVB-T USB1.1-Box
DiBcom USB1.1 reference devices (non-public)
Ultima Electronic/Artec T1 USB TVBOX
Compro Videomate DVB-U2000 - DVB-T USB
Grandtec DVB-T USB
Avermedia AverTV DVBT USB1.1
Artec T1 USB1.1 boxes Artec T1 USB1.1 boxes
Avermedia AverTV DVBT USB1.1
Compro Videomate DVB-U2000 - DVB-T USB
DiBcom USB1.1 reference devices (non-public)
Grandtec DVB-T USB
Hama DVB-T USB1.1-Box
KWorld/JetWay/ADSTech V-Stream XPERT DTV - DVB-T USB1.1 and USB2.0
TwinhanDTV Magic Box (VP7041e)
TwinhanDTV USB-Ter (VP7041)
Ultima Electronic/Artec T1 USB TVBOX
The VP7041 seems to be identical to "CTS Portable" (Chinese The VP7041 seems to be identical to "CTS Portable" (Chinese
Television System). Television System).
@ -54,6 +54,12 @@ config DVB_USB_DIBUSB_MB
Say Y if you own such a device and want to use it. You should build it as Say Y if you own such a device and want to use it. You should build it as
a module. a module.
config DVB_USB_DIBUSB_MB_FAULTY
bool "Support faulty USB IDs"
depends on DVB_USB_DIBUSB_MB
help
Support for faulty USB IDs due to an invalid EEPROM on some Artec devices.
config DVB_USB_DIBUSB_MC config DVB_USB_DIBUSB_MC
tristate "DiBcom USB DVB-T devices (based on the DiB3000M-C/P) (see help for device list)" tristate "DiBcom USB DVB-T devices (based on the DiB3000M-C/P) (see help for device list)"
depends on DVB_USB depends on DVB_USB
@ -63,8 +69,8 @@ config DVB_USB_DIBUSB_MC
DiBcom (<http://www.dibcom.fr>) equipped with a DiB3000M-C/P demodulator. DiBcom (<http://www.dibcom.fr>) equipped with a DiB3000M-C/P demodulator.
Devices supported by this driver: Devices supported by this driver:
DiBcom USB2.0 reference devices (non-public)
Artec T1 USB2.0 boxes Artec T1 USB2.0 boxes
DiBcom USB2.0 reference devices (non-public)
Say Y if you own such a device and want to use it. You should build it as Say Y if you own such a device and want to use it. You should build it as
a module. a module.

View File

@ -11,10 +11,11 @@
* design, so it can be reused for the "analogue-only" device (if it will * design, so it can be reused for the "analogue-only" device (if it will
* appear at all). * appear at all).
* *
* TODO: check if the cx25840-driver (from ivtv) can be used for the analogue * TODO: Use the cx25840-driver for the analogue part
* part
* *
* Copyright (C) 2005 Patrick Boettcher (patrick.boettcher@desy.de) * Copyright (C) 2005 Patrick Boettcher (patrick.boettcher@desy.de)
* Copyright (C) 2005 Michael Krufky (mkrufky@m1k.net)
* Copyright (C) 2006 Chris Pascoe (c.pascoe@itee.uq.edu.au)
* *
* This program is free software; you can redistribute it and/or modify it * This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free * under the terms of the GNU General Public License as published by the Free
@ -25,6 +26,9 @@
#include "cxusb.h" #include "cxusb.h"
#include "cx22702.h" #include "cx22702.h"
#include "lgdt330x.h"
#include "mt352.h"
#include "mt352_priv.h"
/* debug */ /* debug */
int dvb_usb_cxusb_debug; int dvb_usb_cxusb_debug;
@ -156,6 +160,99 @@ static int cxusb_streaming_ctrl(struct dvb_usb_device *d, int onoff)
return 0; return 0;
} }
static int cxusb_rc_query(struct dvb_usb_device *d, u32 *event, int *state)
{
struct dvb_usb_rc_key *keymap = d->props.rc_key_map;
u8 ircode[4];
int i;
cxusb_ctrl_msg(d, CMD_GET_IR_CODE, NULL, 0, ircode, 4);
*event = 0;
*state = REMOTE_NO_KEY_PRESSED;
for (i = 0; i < d->props.rc_key_map_size; i++) {
if (keymap[i].custom == ircode[2] &&
keymap[i].data == ircode[3]) {
*event = keymap[i].event;
*state = REMOTE_KEY_PRESSED;
return 0;
}
}
return 0;
}
struct dvb_usb_rc_key dvico_mce_rc_keys[] = {
{ 0xfe, 0x02, KEY_TV },
{ 0xfe, 0x0e, KEY_MP3 },
{ 0xfe, 0x1a, KEY_DVD },
{ 0xfe, 0x1e, KEY_FAVORITES },
{ 0xfe, 0x16, KEY_SETUP },
{ 0xfe, 0x46, KEY_POWER2 },
{ 0xfe, 0x0a, KEY_EPG },
{ 0xfe, 0x49, KEY_BACK },
{ 0xfe, 0x4d, KEY_MENU },
{ 0xfe, 0x51, KEY_UP },
{ 0xfe, 0x5b, KEY_LEFT },
{ 0xfe, 0x5f, KEY_RIGHT },
{ 0xfe, 0x53, KEY_DOWN },
{ 0xfe, 0x5e, KEY_OK },
{ 0xfe, 0x59, KEY_INFO },
{ 0xfe, 0x55, KEY_TAB },
{ 0xfe, 0x0f, KEY_PREVIOUSSONG },/* Replay */
{ 0xfe, 0x12, KEY_NEXTSONG }, /* Skip */
{ 0xfe, 0x42, KEY_ENTER }, /* Windows/Start */
{ 0xfe, 0x15, KEY_VOLUMEUP },
{ 0xfe, 0x05, KEY_VOLUMEDOWN },
{ 0xfe, 0x11, KEY_CHANNELUP },
{ 0xfe, 0x09, KEY_CHANNELDOWN },
{ 0xfe, 0x52, KEY_CAMERA },
{ 0xfe, 0x5a, KEY_TUNER }, /* Live */
{ 0xfe, 0x19, KEY_OPEN },
{ 0xfe, 0x0b, KEY_1 },
{ 0xfe, 0x17, KEY_2 },
{ 0xfe, 0x1b, KEY_3 },
{ 0xfe, 0x07, KEY_4 },
{ 0xfe, 0x50, KEY_5 },
{ 0xfe, 0x54, KEY_6 },
{ 0xfe, 0x48, KEY_7 },
{ 0xfe, 0x4c, KEY_8 },
{ 0xfe, 0x58, KEY_9 },
{ 0xfe, 0x13, KEY_ANGLE }, /* Aspect */
{ 0xfe, 0x03, KEY_0 },
{ 0xfe, 0x1f, KEY_ZOOM },
{ 0xfe, 0x43, KEY_REWIND },
{ 0xfe, 0x47, KEY_PLAYPAUSE },
{ 0xfe, 0x4f, KEY_FASTFORWARD },
{ 0xfe, 0x57, KEY_MUTE },
{ 0xfe, 0x0d, KEY_STOP },
{ 0xfe, 0x01, KEY_RECORD },
{ 0xfe, 0x4e, KEY_POWER },
};
static int cxusb_dee1601_demod_init(struct dvb_frontend* fe)
{
static u8 clock_config [] = { CLOCK_CTL, 0x38, 0x38 };
static u8 reset [] = { RESET, 0x80 };
static u8 adc_ctl_1_cfg [] = { ADC_CTL_1, 0x40 };
static u8 agc_cfg [] = { AGC_TARGET, 0x28, 0x20 };
static u8 gpp_ctl_cfg [] = { GPP_CTL, 0x33 };
static u8 capt_range_cfg[] = { CAPT_RANGE, 0x32 };
mt352_write(fe, clock_config, sizeof(clock_config));
udelay(200);
mt352_write(fe, reset, sizeof(reset));
mt352_write(fe, adc_ctl_1_cfg, sizeof(adc_ctl_1_cfg));
mt352_write(fe, agc_cfg, sizeof(agc_cfg));
mt352_write(fe, gpp_ctl_cfg, sizeof(gpp_ctl_cfg));
mt352_write(fe, capt_range_cfg, sizeof(capt_range_cfg));
return 0;
}
struct cx22702_config cxusb_cx22702_config = { struct cx22702_config cxusb_cx22702_config = {
.demod_address = 0x63, .demod_address = 0x63,
@ -165,8 +262,20 @@ struct cx22702_config cxusb_cx22702_config = {
.pll_set = dvb_usb_pll_set_i2c, .pll_set = dvb_usb_pll_set_i2c,
}; };
struct lgdt330x_config cxusb_lgdt330x_config = {
.demod_address = 0x0e,
.demod_chip = LGDT3303,
.pll_set = dvb_usb_pll_set_i2c,
};
struct mt352_config cxusb_dee1601_config = {
.demod_address = 0x0f,
.demod_init = cxusb_dee1601_demod_init,
.pll_set = dvb_usb_pll_set,
};
/* Callbacks for DVB USB */ /* Callbacks for DVB USB */
static int cxusb_tuner_attach(struct dvb_usb_device *d) static int cxusb_fmd1216me_tuner_attach(struct dvb_usb_device *d)
{ {
u8 bpll[4] = { 0x0b, 0xdc, 0x9c, 0xa0 }; u8 bpll[4] = { 0x0b, 0xdc, 0x9c, 0xa0 };
d->pll_addr = 0x61; d->pll_addr = 0x61;
@ -175,7 +284,25 @@ static int cxusb_tuner_attach(struct dvb_usb_device *d)
return 0; return 0;
} }
static int cxusb_frontend_attach(struct dvb_usb_device *d) static int cxusb_lgh064f_tuner_attach(struct dvb_usb_device *d)
{
u8 bpll[4] = { 0x00, 0x00, 0x18, 0x50 };
/* bpll[2] : unset bit 3, set bits 4&5
bpll[3] : 0x50 - digital, 0x20 - analog */
d->pll_addr = 0x61;
memcpy(d->pll_init, bpll, 4);
d->pll_desc = &dvb_pll_tdvs_tua6034;
return 0;
}
static int cxusb_dee1601_tuner_attach(struct dvb_usb_device *d)
{
d->pll_addr = 0x61;
d->pll_desc = &dvb_pll_thomson_dtt7579;
return 0;
}
static int cxusb_cx22702_frontend_attach(struct dvb_usb_device *d)
{ {
u8 b; u8 b;
if (usb_set_interface(d->udev,0,6) < 0) if (usb_set_interface(d->udev,0,6) < 0)
@ -189,22 +316,84 @@ static int cxusb_frontend_attach(struct dvb_usb_device *d)
return -EIO; return -EIO;
} }
static int cxusb_lgdt330x_frontend_attach(struct dvb_usb_device *d)
{
if (usb_set_interface(d->udev,0,7) < 0)
err("set interface failed");
cxusb_ctrl_msg(d,CMD_DIGITAL, NULL, 0, NULL, 0);
if ((d->fe = lgdt330x_attach(&cxusb_lgdt330x_config, &d->i2c_adap)) != NULL)
return 0;
return -EIO;
}
static int cxusb_dee1601_frontend_attach(struct dvb_usb_device *d)
{
if (usb_set_interface(d->udev,0,0) < 0)
err("set interface failed");
cxusb_ctrl_msg(d,CMD_DIGITAL, NULL, 0, NULL, 0);
if ((d->fe = mt352_attach(&cxusb_dee1601_config, &d->i2c_adap)) != NULL)
return 0;
return -EIO;
}
/*
* DViCO bluebird firmware needs the "warm" product ID to be patched into the
* firmware file before download.
*/
#define BLUEBIRD_01_ID_OFFSET 6638
static int bluebird_patch_dvico_firmware_download(struct usb_device *udev, const struct firmware *fw)
{
if (fw->size < BLUEBIRD_01_ID_OFFSET + 4)
return -EINVAL;
if (fw->data[BLUEBIRD_01_ID_OFFSET] == (USB_VID_DVICO & 0xff) &&
fw->data[BLUEBIRD_01_ID_OFFSET + 1] == USB_VID_DVICO >> 8) {
/* FIXME: are we allowed to change the fw-data ? */
fw->data[BLUEBIRD_01_ID_OFFSET + 2] = udev->descriptor.idProduct + 1;
fw->data[BLUEBIRD_01_ID_OFFSET + 3] = udev->descriptor.idProduct >> 8;
return usb_cypress_load_firmware(udev,fw,CYPRESS_FX2);
}
return -EINVAL;
}
/* DVB USB Driver stuff */ /* DVB USB Driver stuff */
static struct dvb_usb_properties cxusb_properties; static struct dvb_usb_properties cxusb_medion_properties;
static struct dvb_usb_properties cxusb_bluebird_lgh064f_properties;
static struct dvb_usb_properties cxusb_bluebird_dee1601_properties;
static int cxusb_probe(struct usb_interface *intf, static int cxusb_probe(struct usb_interface *intf,
const struct usb_device_id *id) const struct usb_device_id *id)
{ {
return dvb_usb_device_init(intf,&cxusb_properties,THIS_MODULE,NULL); if (dvb_usb_device_init(intf,&cxusb_medion_properties,THIS_MODULE,NULL) == 0 ||
dvb_usb_device_init(intf,&cxusb_bluebird_lgh064f_properties,THIS_MODULE,NULL) == 0 ||
dvb_usb_device_init(intf,&cxusb_bluebird_dee1601_properties,THIS_MODULE,NULL) == 0) {
return 0;
}
return -EINVAL;
} }
static struct usb_device_id cxusb_table [] = { static struct usb_device_id cxusb_table [] = {
{ USB_DEVICE(USB_VID_MEDION, USB_PID_MEDION_MD95700) }, { USB_DEVICE(USB_VID_MEDION, USB_PID_MEDION_MD95700) },
{ USB_DEVICE(USB_VID_DVICO, USB_PID_DVICO_BLUEBIRD_LG064F_COLD) },
{ USB_DEVICE(USB_VID_DVICO, USB_PID_DVICO_BLUEBIRD_LG064F_WARM) },
{ USB_DEVICE(USB_VID_DVICO, USB_PID_DVICO_BLUEBIRD_DEE1601_COLD) },
{ USB_DEVICE(USB_VID_DVICO, USB_PID_DVICO_BLUEBIRD_DEE1601_WARM) },
{} /* Terminating entry */ {} /* Terminating entry */
}; };
MODULE_DEVICE_TABLE (usb, cxusb_table); MODULE_DEVICE_TABLE (usb, cxusb_table);
static struct dvb_usb_properties cxusb_properties = { static struct dvb_usb_properties cxusb_medion_properties = {
.caps = DVB_USB_IS_AN_I2C_ADAPTER, .caps = DVB_USB_IS_AN_I2C_ADAPTER,
.usb_ctrl = CYPRESS_FX2, .usb_ctrl = CYPRESS_FX2,
@ -213,8 +402,8 @@ static struct dvb_usb_properties cxusb_properties = {
.streaming_ctrl = cxusb_streaming_ctrl, .streaming_ctrl = cxusb_streaming_ctrl,
.power_ctrl = cxusb_power_ctrl, .power_ctrl = cxusb_power_ctrl,
.frontend_attach = cxusb_frontend_attach, .frontend_attach = cxusb_cx22702_frontend_attach,
.tuner_attach = cxusb_tuner_attach, .tuner_attach = cxusb_fmd1216me_tuner_attach,
.i2c_algo = &cxusb_i2c_algo, .i2c_algo = &cxusb_i2c_algo,
@ -240,6 +429,91 @@ static struct dvb_usb_properties cxusb_properties = {
} }
}; };
static struct dvb_usb_properties cxusb_bluebird_lgh064f_properties = {
.caps = DVB_USB_IS_AN_I2C_ADAPTER,
.usb_ctrl = DEVICE_SPECIFIC,
.firmware = "dvb-usb-bluebird-01.fw",
.download_firmware = bluebird_patch_dvico_firmware_download,
/* use usb alt setting 0 for EP4 transfer (dvb-t),
use usb alt setting 7 for EP2 transfer (atsc) */
.size_of_priv = sizeof(struct cxusb_state),
.streaming_ctrl = cxusb_streaming_ctrl,
.power_ctrl = cxusb_power_ctrl,
.frontend_attach = cxusb_lgdt330x_frontend_attach,
.tuner_attach = cxusb_lgh064f_tuner_attach,
.i2c_algo = &cxusb_i2c_algo,
.generic_bulk_ctrl_endpoint = 0x01,
/* parameter for the MPEG2-data transfer */
.urb = {
.type = DVB_USB_BULK,
.count = 5,
.endpoint = 0x02,
.u = {
.bulk = {
.buffersize = 8192,
}
}
},
.num_device_descs = 1,
.devices = {
{ "DViCO FusionHDTV5 USB Gold",
{ &cxusb_table[1], NULL },
{ &cxusb_table[2], NULL },
},
}
};
static struct dvb_usb_properties cxusb_bluebird_dee1601_properties = {
.caps = DVB_USB_IS_AN_I2C_ADAPTER,
.usb_ctrl = DEVICE_SPECIFIC,
.firmware = "dvb-usb-bluebird-01.fw",
.download_firmware = bluebird_patch_dvico_firmware_download,
/* use usb alt setting 0 for EP4 transfer (dvb-t),
use usb alt setting 7 for EP2 transfer (atsc) */
.size_of_priv = sizeof(struct cxusb_state),
.streaming_ctrl = cxusb_streaming_ctrl,
.power_ctrl = cxusb_power_ctrl,
.frontend_attach = cxusb_dee1601_frontend_attach,
.tuner_attach = cxusb_dee1601_tuner_attach,
.i2c_algo = &cxusb_i2c_algo,
.rc_interval = 150,
.rc_key_map = dvico_mce_rc_keys,
.rc_key_map_size = ARRAY_SIZE(dvico_mce_rc_keys),
.rc_query = cxusb_rc_query,
.generic_bulk_ctrl_endpoint = 0x01,
/* parameter for the MPEG2-data transfer */
.urb = {
.type = DVB_USB_BULK,
.count = 5,
.endpoint = 0x04,
.u = {
.bulk = {
.buffersize = 8192,
}
}
},
.num_device_descs = 1,
.devices = {
{ "DViCO FusionHDTV DVB-T Dual USB",
{ &cxusb_table[3], NULL },
{ &cxusb_table[4], NULL },
},
}
};
static struct usb_driver cxusb_driver = { static struct usb_driver cxusb_driver = {
.name = "dvb_usb_cxusb", .name = "dvb_usb_cxusb",
.probe = cxusb_probe, .probe = cxusb_probe,

View File

@ -21,6 +21,8 @@ extern int dvb_usb_cxusb_debug;
#define CMD_STREAMING_ON 0x36 #define CMD_STREAMING_ON 0x36
#define CMD_STREAMING_OFF 0x37 #define CMD_STREAMING_OFF 0x37
#define CMD_GET_IR_CODE 0x47
#define CMD_ANALOG 0x50 #define CMD_ANALOG 0x50
#define CMD_DIGITAL 0x51 #define CMD_DIGITAL 0x51

View File

@ -65,11 +65,11 @@ static int dibusb_tuner_probe_and_attach(struct dvb_usb_device *d)
d->tuner_pass_ctrl(d->fe,0,msg[0].addr); d->tuner_pass_ctrl(d->fe,0,msg[0].addr);
if (b2[0] == 0xfe) { if (b2[0] == 0xfe) {
info("this device has the Thomson Cable onboard. Which is default."); info("This device has the Thomson Cable onboard. Which is default.");
dibusb_thomson_tuner_attach(d); dibusb_thomson_tuner_attach(d);
} else { } else {
u8 bpll[4] = { 0x0b, 0xf5, 0x85, 0xab }; u8 bpll[4] = { 0x0b, 0xf5, 0x85, 0xab };
info("this device has the Panasonic ENV77H11D5 onboard."); info("This device has the Panasonic ENV77H11D5 onboard.");
d->pll_addr = 0x60; d->pll_addr = 0x60;
memcpy(d->pll_init,bpll,4); memcpy(d->pll_init,bpll,4);
d->pll_desc = &dvb_pll_tda665x; d->pll_desc = &dvb_pll_tda665x;
@ -133,11 +133,18 @@ static struct usb_device_id dibusb_dib3000mb_table [] = {
/* 28 */ { USB_DEVICE(USB_VID_ULTIMA_ELECTRONIC, USB_PID_ULTIMA_TVBOX_USB2_COLD) }, /* 28 */ { USB_DEVICE(USB_VID_ULTIMA_ELECTRONIC, USB_PID_ULTIMA_TVBOX_USB2_COLD) },
/* 29 */ { USB_DEVICE(USB_VID_ULTIMA_ELECTRONIC, USB_PID_ULTIMA_TVBOX_USB2_WARM) }, /* 29 */ { USB_DEVICE(USB_VID_ULTIMA_ELECTRONIC, USB_PID_ULTIMA_TVBOX_USB2_WARM) },
// #define DVB_USB_DIBUSB_MB_FAULTY_USB_IDs /*
* XXX: As Artec just 'forgot' to program the EEPROM on some Artec T1 devices
* we don't catch these faulty IDs (namely 'Cypress FX1 USB controller') that
* have been left on the device. If you don't have such a device but an Artec
* device that's supposed to work with this driver but is not detected by it,
* free to enable CONFIG_DVB_USB_DIBUSB_MB_FAULTY via your kernel config.
*/
#ifdef DVB_USB_DIBUSB_MB_FAULTY_USB_IDs #ifdef CONFIG_DVB_USB_DIBUSB_MB_FAULTY
/* 30 */ { USB_DEVICE(USB_VID_ANCHOR, USB_PID_ULTIMA_TVBOX_ANCHOR_COLD) }, /* 30 */ { USB_DEVICE(USB_VID_ANCHOR, USB_PID_ULTIMA_TVBOX_ANCHOR_COLD) },
#endif #endif
{ } /* Terminating entry */ { } /* Terminating entry */
}; };
MODULE_DEVICE_TABLE (usb, dibusb_dib3000mb_table); MODULE_DEVICE_TABLE (usb, dibusb_dib3000mb_table);
@ -257,7 +264,7 @@ static struct dvb_usb_properties dibusb1_1_an2235_properties = {
} }
}, },
#ifdef DVB_USB_DIBUSB_MB_FAULTY_USB_IDs #ifdef CONFIG_DVB_USB_DIBUSB_MB_FAULTY
.num_device_descs = 2, .num_device_descs = 2,
#else #else
.num_device_descs = 1, .num_device_descs = 1,
@ -267,11 +274,12 @@ static struct dvb_usb_properties dibusb1_1_an2235_properties = {
{ &dibusb_dib3000mb_table[20], NULL }, { &dibusb_dib3000mb_table[20], NULL },
{ &dibusb_dib3000mb_table[21], NULL }, { &dibusb_dib3000mb_table[21], NULL },
}, },
#ifdef DVB_USB_DIBUSB_MB_FAULTY_USB_IDs #ifdef CONFIG_DVB_USB_DIBUSB_MB_FAULTY
{ "Artec T1 USB1.1 TVBOX with AN2235 (faulty USB IDs)", { "Artec T1 USB1.1 TVBOX with AN2235 (faulty USB IDs)",
{ &dibusb_dib3000mb_table[30], NULL }, { &dibusb_dib3000mb_table[30], NULL },
{ NULL }, { NULL },
}, },
{ NULL },
#endif #endif
} }
}; };
@ -323,6 +331,7 @@ static struct dvb_usb_properties dibusb2_0b_properties = {
{ &dibusb_dib3000mb_table[27], NULL }, { &dibusb_dib3000mb_table[27], NULL },
{ NULL } { NULL }
}, },
{ NULL },
} }
}; };
@ -369,6 +378,7 @@ static struct dvb_usb_properties artec_t1_usb2_properties = {
{ &dibusb_dib3000mb_table[28], NULL }, { &dibusb_dib3000mb_table[28], NULL },
{ &dibusb_dib3000mb_table[29], NULL }, { &dibusb_dib3000mb_table[29], NULL },
}, },
{ NULL },
} }
}; };

View File

@ -32,7 +32,7 @@ static int digitv_ctrl_msg(struct dvb_usb_device *d,
sndbuf[1] = vv; sndbuf[1] = vv;
sndbuf[2] = wo ? wlen : rlen; sndbuf[2] = wo ? wlen : rlen;
if (!wo) { if (wo) {
memcpy(&sndbuf[3],wbuf,wlen); memcpy(&sndbuf[3],wbuf,wlen);
dvb_usb_generic_write(d,sndbuf,7); dvb_usb_generic_write(d,sndbuf,7);
} else { } else {

View File

@ -151,7 +151,7 @@ static struct dvb_usb_properties dtt200u_properties = {
.cold_ids = { &dtt200u_usb_table[0], NULL }, .cold_ids = { &dtt200u_usb_table[0], NULL },
.warm_ids = { &dtt200u_usb_table[1], NULL }, .warm_ids = { &dtt200u_usb_table[1], NULL },
}, },
{ NULL }, { 0 },
} }
}; };
@ -160,7 +160,7 @@ static struct dvb_usb_properties wt220u_properties = {
.pid_filter_count = 15, .pid_filter_count = 15,
.usb_ctrl = CYPRESS_FX2, .usb_ctrl = CYPRESS_FX2,
.firmware = "dvb-usb-wt220u-01.fw", .firmware = "dvb-usb-wt220u-02.fw",
.power_ctrl = dtt200u_power_ctrl, .power_ctrl = dtt200u_power_ctrl,
.streaming_ctrl = dtt200u_streaming_ctrl, .streaming_ctrl = dtt200u_streaming_ctrl,
@ -192,7 +192,7 @@ static struct dvb_usb_properties wt220u_properties = {
.cold_ids = { &dtt200u_usb_table[2], NULL }, .cold_ids = { &dtt200u_usb_table[2], NULL },
.warm_ids = { &dtt200u_usb_table[3], NULL }, .warm_ids = { &dtt200u_usb_table[3], NULL },
}, },
{ NULL }, { 0 },
} }
}; };

View File

@ -13,6 +13,7 @@
#define _DVB_USB_DTT200U_H_ #define _DVB_USB_DTT200U_H_
#define DVB_USB_LOG_PREFIX "dtt200u" #define DVB_USB_LOG_PREFIX "dtt200u"
#include "dvb-usb.h" #include "dvb-usb.h"
extern int dvb_usb_dtt200u_debug; extern int dvb_usb_dtt200u_debug;

View File

@ -24,7 +24,7 @@ extern int dvb_usb_disable_rc_polling;
#define deb_mem(args...) dprintk(dvb_usb_debug,0x80,args) #define deb_mem(args...) dprintk(dvb_usb_debug,0x80,args)
/* commonly used methods */ /* commonly used methods */
extern int usb_cypress_load_firmware(struct usb_device *, const char *, int); extern int dvb_usb_download_firmware(struct usb_device *, struct dvb_usb_properties *);
extern int dvb_usb_urb_submit(struct dvb_usb_device *); extern int dvb_usb_urb_submit(struct dvb_usb_device *);
extern int dvb_usb_urb_kill(struct dvb_usb_device *); extern int dvb_usb_urb_kill(struct dvb_usb_device *);

View File

@ -9,7 +9,6 @@
*/ */
#include "dvb-usb-common.h" #include "dvb-usb-common.h"
#include <linux/firmware.h>
#include <linux/usb.h> #include <linux/usb.h>
struct usb_cypress_controller { struct usb_cypress_controller {
@ -19,6 +18,7 @@ struct usb_cypress_controller {
}; };
static struct usb_cypress_controller cypress[] = { static struct usb_cypress_controller cypress[] = {
{ .id = DEVICE_SPECIFIC, .name = "Device specific", .cpu_cs_register = 0 },
{ .id = CYPRESS_AN2135, .name = "Cypress AN2135", .cpu_cs_register = 0x7f92 }, { .id = CYPRESS_AN2135, .name = "Cypress AN2135", .cpu_cs_register = 0x7f92 },
{ .id = CYPRESS_AN2235, .name = "Cypress AN2235", .cpu_cs_register = 0x7f92 }, { .id = CYPRESS_AN2235, .name = "Cypress AN2235", .cpu_cs_register = 0x7f92 },
{ .id = CYPRESS_FX2, .name = "Cypress FX2", .cpu_cs_register = 0xe600 }, { .id = CYPRESS_FX2, .name = "Cypress FX2", .cpu_cs_register = 0xe600 },
@ -30,71 +30,117 @@ static struct usb_cypress_controller cypress[] = {
static int usb_cypress_writemem(struct usb_device *udev,u16 addr,u8 *data, u8 len) static int usb_cypress_writemem(struct usb_device *udev,u16 addr,u8 *data, u8 len)
{ {
return usb_control_msg(udev, usb_sndctrlpipe(udev,0), return usb_control_msg(udev, usb_sndctrlpipe(udev,0),
0xa0, USB_TYPE_VENDOR, addr, 0x00, data, len, 5*HZ); 0xa0, USB_TYPE_VENDOR, addr, 0x00, data, len, 5000);
} }
int usb_cypress_load_firmware(struct usb_device *udev, const char *filename, int type) int usb_cypress_load_firmware(struct usb_device *udev, const struct firmware *fw, int type)
{ {
const struct firmware *fw = NULL; struct hexline hx;
u16 addr;
u8 *b,*p;
int ret = 0,i;
if ((ret = request_firmware(&fw, filename, &udev->dev)) != 0) {
err("did not find the firmware file. (%s) "
"Please see linux/Documentation/dvb/ for more details on firmware-problems.",
filename);
return ret;
}
info("downloading firmware from file '%s' to the '%s'",filename,cypress[type].name);
p = kmalloc(fw->size,GFP_KERNEL);
if (p != NULL) {
u8 reset; u8 reset;
/* int ret,pos=0;
* you cannot use the fw->data as buffer for
* usb_control_msg, a new buffer has to be
* created
*/
memcpy(p,fw->data,fw->size);
/* stop the CPU */ /* stop the CPU */
reset = 1; reset = 1;
if ((ret = usb_cypress_writemem(udev,cypress[type].cpu_cs_register,&reset,1)) != 1) if ((ret = usb_cypress_writemem(udev,cypress[type].cpu_cs_register,&reset,1)) != 1)
err("could not stop the USB controller CPU."); err("could not stop the USB controller CPU.");
for(i = 0; p[i+3] == 0 && i < fw->size; ) {
b = (u8 *) &p[i];
addr = cpu_to_le16( *((u16 *) &b[1]) );
deb_fw("writing to address 0x%04x (buffer: 0x%02x%02x)\n",addr,b[1],b[2]); while ((ret = dvb_usb_get_hexline(fw,&hx,&pos)) > 0) {
deb_fw("writing to address 0x%04x (buffer: 0x%02x %02x)\n",hx.addr,hx.len,hx.chk);
ret = usb_cypress_writemem(udev,hx.addr,hx.data,hx.len);
ret = usb_cypress_writemem(udev,addr,&b[4],b[0]); if (ret != hx.len) {
if (ret != b[0]) {
err("error while transferring firmware " err("error while transferring firmware "
"(transferred size: %d, block size: %d)", "(transferred size: %d, block size: %d)",
ret,b[0]); ret,hx.len);
ret = -EINVAL; ret = -EINVAL;
break; break;
} }
i += 5 + b[0];
} }
/* length in ret */ if (ret < 0) {
if (ret > 0) err("firmware download failed at %d with %d",pos,ret);
ret = 0; return ret;
}
if (ret == 0) {
/* restart the CPU */ /* restart the CPU */
reset = 0; reset = 0;
if (ret || usb_cypress_writemem(udev,cypress[type].cpu_cs_register,&reset,1) != 1) { if (ret || usb_cypress_writemem(udev,cypress[type].cpu_cs_register,&reset,1) != 1) {
err("could not restart the USB controller CPU."); err("could not restart the USB controller CPU.");
ret = -EINVAL; ret = -EINVAL;
} }
} else
kfree(p); ret = -EIO;
} else {
ret = -ENOMEM;
}
release_firmware(fw);
return ret; return ret;
} }
EXPORT_SYMBOL(usb_cypress_load_firmware);
int dvb_usb_download_firmware(struct usb_device *udev, struct dvb_usb_properties *props)
{
int ret;
const struct firmware *fw = NULL;
if ((ret = request_firmware(&fw, props->firmware, &udev->dev)) != 0) {
err("did not find the firmware file. (%s) "
"Please see linux/Documentation/dvb/ for more details on firmware-problems. (%d)",
props->firmware,ret);
return ret;
}
info("downloading firmware from file '%s'",props->firmware);
switch (props->usb_ctrl) {
case CYPRESS_AN2135:
case CYPRESS_AN2235:
case CYPRESS_FX2:
ret = usb_cypress_load_firmware(udev, fw, props->usb_ctrl);
break;
case DEVICE_SPECIFIC:
if (props->download_firmware)
ret = props->download_firmware(udev,fw);
else {
err("BUG: driver didn't specified a download_firmware-callback, although it claims to have a DEVICE_SPECIFIC one.");
ret = -EINVAL;
}
break;
default:
ret = -EINVAL;
break;
}
release_firmware(fw);
return ret;
}
int dvb_usb_get_hexline(const struct firmware *fw, struct hexline *hx, int *pos)
{
u8 *b = (u8 *) &fw->data[*pos];
int data_offs = 4;
if (*pos >= fw->size)
return 0;
memset(hx,0,sizeof(struct hexline));
hx->len = b[0];
if ((*pos + hx->len + 4) >= fw->size)
return -EINVAL;
hx->addr = le16_to_cpu( *((u16 *) &b[1]) );
hx->type = b[3];
if (hx->type == 0x04) {
/* b[4] and b[5] are the Extended linear address record data field */
hx->addr |= (b[4] << 24) | (b[5] << 16);
/* hx->len -= 2;
data_offs += 2; */
}
memcpy(hx->data,&b[data_offs],hx->len);
hx->chk = b[hx->len + data_offs];
*pos += hx->len + 5;
return *pos;
}
EXPORT_SYMBOL(dvb_usb_get_hexline);

View File

@ -52,9 +52,8 @@ int dvb_usb_pll_init_i2c(struct dvb_frontend *fe)
struct i2c_msg msg = { .addr = d->pll_addr, .flags = 0, .buf = d->pll_init, .len = 4 }; struct i2c_msg msg = { .addr = d->pll_addr, .flags = 0, .buf = d->pll_init, .len = 4 };
int ret = 0; int ret = 0;
/* if there is nothing to initialize */ /* if pll_desc is not used */
if (d->pll_init[0] == 0x00 && d->pll_init[1] == 0x00 && if (d->pll_desc == NULL)
d->pll_init[2] == 0x00 && d->pll_init[3] == 0x00)
return 0; return 0;
if (d->tuner_pass_ctrl) if (d->tuner_pass_ctrl)
@ -80,6 +79,9 @@ int dvb_usb_pll_set(struct dvb_frontend *fe, struct dvb_frontend_parameters *fep
{ {
struct dvb_usb_device *d = fe->dvb->priv; struct dvb_usb_device *d = fe->dvb->priv;
if (d->pll_desc == NULL)
return 0;
deb_pll("pll addr: %x, freq: %d %p\n",d->pll_addr,fep->frequency,d->pll_desc); deb_pll("pll addr: %x, freq: %d %p\n",d->pll_addr,fep->frequency,d->pll_desc);
b[0] = d->pll_addr << 1; b[0] = d->pll_addr << 1;

View File

@ -86,11 +86,15 @@
#define USB_PID_WINTV_NOVA_T_USB2_COLD 0x9300 #define USB_PID_WINTV_NOVA_T_USB2_COLD 0x9300
#define USB_PID_WINTV_NOVA_T_USB2_WARM 0x9301 #define USB_PID_WINTV_NOVA_T_USB2_WARM 0x9301
#define USB_PID_NEBULA_DIGITV 0x0201 #define USB_PID_NEBULA_DIGITV 0x0201
#define USB_PID_DVICO_BLUEBIRD_LGZ201 0xdb00
#define USB_PID_DVICO_BLUEBIRD_TH7579 0xdb10
#define USB_PID_DVICO_BLUEBIRD_LGDT 0xd820 #define USB_PID_DVICO_BLUEBIRD_LGDT 0xd820
#define USB_PID_DVICO_BLUEBIRD_LGZ201_1 0xdb01 #define USB_PID_DVICO_BLUEBIRD_LG064F_COLD 0xd500
#define USB_PID_DVICO_BLUEBIRD_TH7579_2 0xdb11 #define USB_PID_DVICO_BLUEBIRD_LG064F_WARM 0xd501
#define USB_PID_DVICO_BLUEBIRD_LGZ201_COLD 0xdb00
#define USB_PID_DVICO_BLUEBIRD_LGZ201_WARM 0xdb01
#define USB_PID_DVICO_BLUEBIRD_TH7579_COLD 0xdb10
#define USB_PID_DVICO_BLUEBIRD_TH7579_WARM 0xdb11
#define USB_PID_DVICO_BLUEBIRD_DEE1601_COLD 0xdb50
#define USB_PID_DVICO_BLUEBIRD_DEE1601_WARM 0xdb51
#define USB_PID_MEDION_MD95700 0x0932 #define USB_PID_MEDION_MD95700 0x0932
#define USB_PID_KYE_DVB_T_COLD 0x701e #define USB_PID_KYE_DVB_T_COLD 0x701e
#define USB_PID_KYE_DVB_T_WARM 0x701f #define USB_PID_KYE_DVB_T_WARM 0x701f

View File

@ -138,6 +138,9 @@ int dvb_usb_device_init(struct usb_interface *intf, struct dvb_usb_properties
int ret = -ENOMEM,cold=0; int ret = -ENOMEM,cold=0;
if (du != NULL)
*du = NULL;
if ((desc = dvb_usb_find_device(udev,props,&cold)) == NULL) { if ((desc = dvb_usb_find_device(udev,props,&cold)) == NULL) {
deb_err("something went very wrong, device was not found in current device list - let's see what comes next.\n"); deb_err("something went very wrong, device was not found in current device list - let's see what comes next.\n");
return -ENODEV; return -ENODEV;
@ -145,8 +148,11 @@ int dvb_usb_device_init(struct usb_interface *intf, struct dvb_usb_properties
if (cold) { if (cold) {
info("found a '%s' in cold state, will try to load a firmware",desc->name); info("found a '%s' in cold state, will try to load a firmware",desc->name);
ret = usb_cypress_load_firmware(udev,props->firmware,props->usb_ctrl); ret = dvb_usb_download_firmware(udev,props);
} else { if (!props->no_reconnect)
return ret;
}
info("found a '%s' in warm state.",desc->name); info("found a '%s' in warm state.",desc->name);
d = kmalloc(sizeof(struct dvb_usb_device),GFP_KERNEL); d = kmalloc(sizeof(struct dvb_usb_device),GFP_KERNEL);
if (d == NULL) { if (d == NULL) {
@ -176,7 +182,6 @@ int dvb_usb_device_init(struct usb_interface *intf, struct dvb_usb_properties
*du = d; *du = d;
ret = dvb_usb_init(d); ret = dvb_usb_init(d);
}
if (ret == 0) if (ret == 0)
info("%s successfully initialized and connected.",desc->name); info("%s successfully initialized and connected.",desc->name);

View File

@ -10,8 +10,8 @@
#include <linux/config.h> #include <linux/config.h>
#include <linux/input.h> #include <linux/input.h>
#include <linux/module.h>
#include <linux/usb.h> #include <linux/usb.h>
#include <linux/firmware.h>
#include "dvb_frontend.h" #include "dvb_frontend.h"
#include "dvb_demux.h" #include "dvb_demux.h"
@ -94,7 +94,11 @@ struct dvb_usb_device;
* @usb_ctrl: which USB device-side controller is in use. Needed for firmware * @usb_ctrl: which USB device-side controller is in use. Needed for firmware
* download. * download.
* @firmware: name of the firmware file. * @firmware: name of the firmware file.
* * @download_firmware: called to download the firmware when the usb_ctrl is
* DEVICE_SPECIFIC.
* @no_reconnect: device doesn't do a reconnect after downloading the firmware,
so do the warm initialization right after it
* @size_of_priv: how many bytes shall be allocated for the private field * @size_of_priv: how many bytes shall be allocated for the private field
* of struct dvb_usb_device. * of struct dvb_usb_device.
* *
@ -142,11 +146,14 @@ struct dvb_usb_properties {
int caps; int caps;
int pid_filter_count; int pid_filter_count;
#define CYPRESS_AN2135 0 #define DEVICE_SPECIFIC 0
#define CYPRESS_AN2235 1 #define CYPRESS_AN2135 1
#define CYPRESS_FX2 2 #define CYPRESS_AN2235 2
#define CYPRESS_FX2 3
int usb_ctrl; int usb_ctrl;
const char *firmware; const char firmware[FIRMWARE_NAME_MAX];
int (*download_firmware) (struct usb_device *, const struct firmware *);
int no_reconnect;
int size_of_priv; int size_of_priv;
@ -326,5 +333,15 @@ extern int dvb_usb_pll_init_i2c(struct dvb_frontend *);
extern int dvb_usb_pll_set(struct dvb_frontend *, struct dvb_frontend_parameters *, u8[]); extern int dvb_usb_pll_set(struct dvb_frontend *, struct dvb_frontend_parameters *, u8[]);
extern int dvb_usb_pll_set_i2c(struct dvb_frontend *, struct dvb_frontend_parameters *); extern int dvb_usb_pll_set_i2c(struct dvb_frontend *, struct dvb_frontend_parameters *);
/* commonly used firmware download types and function */
struct hexline {
u8 len;
u32 addr;
u8 type;
u8 data[255];
u8 chk;
};
extern int dvb_usb_get_hexline(const struct firmware *, struct hexline *, int *);
extern int usb_cypress_load_firmware(struct usb_device *udev, const struct firmware *fw, int type);
#endif #endif

View File

@ -129,10 +129,6 @@ static int nova_t_read_mac_address (struct dvb_usb_device *d, u8 mac[6])
dibusb_read_eeprom_byte(d,i, &b); dibusb_read_eeprom_byte(d,i, &b);
mac[5 - (i - 136)] = b; mac[5 - (i - 136)] = b;
/* deb_ee("%02x ",b);
if ((i+1) % 16 == 0)
deb_ee("\n");*/
} }
return 0; return 0;
@ -198,6 +194,7 @@ static struct dvb_usb_properties nova_t_properties = {
{ &nova_t_table[0], NULL }, { &nova_t_table[0], NULL },
{ &nova_t_table[1], NULL }, { &nova_t_table[1], NULL },
}, },
{ NULL },
} }
}; };

View File

@ -37,7 +37,7 @@ extern int dvb_usb_vp702x_debug;
* len X1 X2 X3 X4 * len X1 X2 X3 X4
* additional in buffer: * additional in buffer:
* 0 1 2 * 0 1 2
* N/A 0 0 b[1] == b[2] == 0 -> success otherwise not */ * N/A 0 0 b[1] == b[2] == 0 -> success, failure otherwise */
#define SET_LNB_POWER 0x09 #define SET_LNB_POWER 0x09
/* additional out buffer: /* additional out buffer:
@ -45,7 +45,7 @@ extern int dvb_usb_vp702x_debug;
* 0x00 0xff 1 = on, 0 = off * 0x00 0xff 1 = on, 0 = off
* additional in buffer: * additional in buffer:
* 0 1 2 * 0 1 2
* N/A 0 0 b[1] == b[2] == 0 -> success otherwise not */ * N/A 0 0 b[1] == b[2] == 0 -> success failure otherwise */
#define GET_MAC_ADDRESS 0x0A #define GET_MAC_ADDRESS 0x0A
/* #define GET_MAC_ADDRESS 0x0B */ /* #define GET_MAC_ADDRESS 0x0B */
@ -64,7 +64,6 @@ extern int dvb_usb_vp702x_debug;
* freq0 freq1 divstep srate0 srate1 srate2 flag chksum * freq0 freq1 divstep srate0 srate1 srate2 flag chksum
*/ */
/* one direction requests */ /* one direction requests */
#define READ_REMOTE_REQ 0xB4 #define READ_REMOTE_REQ 0xB4
/* IN i: 0; v: 0; b[0] == request, b[1] == key */ /* IN i: 0; v: 0; b[0] == request, b[1] == key */

View File

@ -247,7 +247,7 @@ static struct dvb_usb_properties vp7045_properties = {
.cold_ids = { &vp7045_usb_table[2], NULL }, .cold_ids = { &vp7045_usb_table[2], NULL },
.warm_ids = { &vp7045_usb_table[3], NULL }, .warm_ids = { &vp7045_usb_table[3], NULL },
}, },
{ NULL }, { 0 },
} }
}; };

View File

@ -16,6 +16,12 @@ config DVB_CX24110
help help
A DVB-S tuner module. Say Y when you want to support this frontend. A DVB-S tuner module. Say Y when you want to support this frontend.
config DVB_CX24123
tristate "Conexant CX24123 based"
depends on DVB_CORE
help
A DVB-S tuner module. Say Y when you want to support this frontend.
config DVB_TDA8083 config DVB_TDA8083
tristate "Philips TDA8083 based" tristate "Philips TDA8083 based"
depends on DVB_CORE depends on DVB_CORE
@ -58,7 +64,8 @@ config DVB_SP8870
This driver needs external firmware. Please use the command This driver needs external firmware. Please use the command
"<kerneldir>/Documentation/dvb/get_dvb_firmware sp8870" to "<kerneldir>/Documentation/dvb/get_dvb_firmware sp8870" to
download/extract it, and then copy it to /usr/lib/hotplug/firmware. download/extract it, and then copy it to /usr/lib/hotplug/firmware
or /lib/firmware (depending on configuration of firmware hotplug).
config DVB_SP887X config DVB_SP887X
tristate "Spase sp887x based" tristate "Spase sp887x based"
@ -69,7 +76,8 @@ config DVB_SP887X
This driver needs external firmware. Please use the command This driver needs external firmware. Please use the command
"<kerneldir>/Documentation/dvb/get_dvb_firmware sp887x" to "<kerneldir>/Documentation/dvb/get_dvb_firmware sp887x" to
download/extract it, and then copy it to /usr/lib/hotplug/firmware. download/extract it, and then copy it to /usr/lib/hotplug/firmware
or /lib/firmware (depending on configuration of firmware hotplug).
config DVB_CX22700 config DVB_CX22700
tristate "Conexant CX22700 based" tristate "Conexant CX22700 based"
@ -99,7 +107,8 @@ config DVB_TDA1004X
This driver needs external firmware. Please use the commands This driver needs external firmware. Please use the commands
"<kerneldir>/Documentation/dvb/get_dvb_firmware tda10045", "<kerneldir>/Documentation/dvb/get_dvb_firmware tda10045",
"<kerneldir>/Documentation/dvb/get_dvb_firmware tda10046" to "<kerneldir>/Documentation/dvb/get_dvb_firmware tda10046" to
download/extract them, and then copy them to /usr/lib/hotplug/firmware. download/extract them, and then copy them to /usr/lib/hotplug/firmware
or /lib/firmware (depending on configuration of firmware hotplug).
config DVB_NXT6000 config DVB_NXT6000
tristate "NxtWave Communications NXT6000 based" tristate "NxtWave Communications NXT6000 based"
@ -164,6 +173,11 @@ config DVB_NXT2002
help help
An ATSC 8VSB tuner module. Say Y when you want to support this frontend. An ATSC 8VSB tuner module. Say Y when you want to support this frontend.
This driver needs external firmware. Please use the command
"<kerneldir>/Documentation/dvb/get_dvb_firmware nxt2002" to
download/extract it, and then copy it to /usr/lib/hotplug/firmware
or /lib/firmware (depending on configuration of firmware hotplug).
config DVB_NXT200X config DVB_NXT200X
tristate "Nextwave NXT2002/NXT2004 based" tristate "Nextwave NXT2002/NXT2004 based"
depends on DVB_CORE depends on DVB_CORE
@ -172,6 +186,12 @@ config DVB_NXT200X
An ATSC 8VSB and QAM64/256 tuner module. Say Y when you want An ATSC 8VSB and QAM64/256 tuner module. Say Y when you want
to support this frontend. to support this frontend.
This driver needs external firmware. Please use the commands
"<kerneldir>/Documentation/dvb/get_dvb_firmware nxt2002" and
"<kerneldir>/Documentation/dvb/get_dvb_firmware nxt2004" to
download/extract them, and then copy them to /usr/lib/hotplug/firmware
or /lib/firmware (depending on configuration of firmware hotplug).
config DVB_OR51211 config DVB_OR51211
tristate "or51211 based (pcHDTV HD2000 card)" tristate "or51211 based (pcHDTV HD2000 card)"
depends on DVB_CORE depends on DVB_CORE

View File

@ -32,3 +32,4 @@ obj-$(CONFIG_DVB_OR51132) += or51132.o
obj-$(CONFIG_DVB_BCM3510) += bcm3510.o obj-$(CONFIG_DVB_BCM3510) += bcm3510.o
obj-$(CONFIG_DVB_S5H1420) += s5h1420.o obj-$(CONFIG_DVB_S5H1420) += s5h1420.o
obj-$(CONFIG_DVB_LGDT330X) += lgdt330x.o obj-$(CONFIG_DVB_LGDT330X) += lgdt330x.o
obj-$(CONFIG_DVB_CX24123) += cx24123.o

View File

@ -255,7 +255,7 @@ static int bcm3510_bert_reset(struct bcm3510_state *st)
bcm3510_register_value b; bcm3510_register_value b;
int ret; int ret;
if ((ret < bcm3510_readB(st,0xfa,&b)) < 0) if ((ret = bcm3510_readB(st,0xfa,&b)) < 0)
return ret; return ret;
b.BERCTL_fa.RESYNC = 0; bcm3510_writeB(st,0xfa,b); b.BERCTL_fa.RESYNC = 0; bcm3510_writeB(st,0xfa,b);
@ -623,13 +623,13 @@ static int bcm3510_download_firmware(struct dvb_frontend* fe)
err("could not load firmware (%s): %d",BCM3510_DEFAULT_FIRMWARE,ret); err("could not load firmware (%s): %d",BCM3510_DEFAULT_FIRMWARE,ret);
return ret; return ret;
} }
deb_info("got firmware: %d\n",fw->size); deb_info("got firmware: %zd\n",fw->size);
b = fw->data; b = fw->data;
for (i = 0; i < fw->size;) { for (i = 0; i < fw->size;) {
addr = le16_to_cpu( *( (u16 *)&b[i] ) ); addr = le16_to_cpu( *( (u16 *)&b[i] ) );
len = le16_to_cpu( *( (u16 *)&b[i+2] ) ); len = le16_to_cpu( *( (u16 *)&b[i+2] ) );
deb_info("firmware chunk, addr: 0x%04x, len: 0x%04x, total length: 0x%04x\n",addr,len,fw->size); deb_info("firmware chunk, addr: 0x%04x, len: 0x%04x, total length: 0x%04zx\n",addr,len,fw->size);
if ((ret = bcm3510_write_ram(st,addr,&b[i+4],len)) < 0) { if ((ret = bcm3510_write_ram(st,addr,&b[i+4],len)) < 0) {
err("firmware download failed: %d\n",ret); err("firmware download failed: %d\n",ret);
return ret; return ret;

View File

@ -195,6 +195,16 @@ static int cx22702_get_tps (struct cx22702_state *state, struct dvb_ofdm_paramet
return 0; return 0;
} }
static int cx22702_i2c_gate_ctrl(struct dvb_frontend* fe, int enable)
{
struct cx22702_state* state = fe->demodulator_priv;
dprintk ("%s(%d)\n", __FUNCTION__, enable);
if (enable)
return cx22702_writereg (state, 0x0D, cx22702_readreg(state, 0x0D) & 0xfe);
else
return cx22702_writereg (state, 0x0D, cx22702_readreg(state, 0x0D) | 1);
}
/* Talk to the demod, set the FEC, GUARD, QAM settings etc */ /* Talk to the demod, set the FEC, GUARD, QAM settings etc */
static int cx22702_set_tps (struct dvb_frontend* fe, struct dvb_frontend_parameters *p) static int cx22702_set_tps (struct dvb_frontend* fe, struct dvb_frontend_parameters *p)
{ {
@ -202,7 +212,7 @@ static int cx22702_set_tps (struct dvb_frontend* fe, struct dvb_frontend_paramet
struct cx22702_state* state = fe->demodulator_priv; struct cx22702_state* state = fe->demodulator_priv;
/* set PLL */ /* set PLL */
cx22702_writereg (state, 0x0D, cx22702_readreg(state,0x0D) &0xfe); cx22702_i2c_gate_ctrl(fe, 1);
if (state->config->pll_set) { if (state->config->pll_set) {
state->config->pll_set(fe, p); state->config->pll_set(fe, p);
} else if (state->config->pll_desc) { } else if (state->config->pll_desc) {
@ -216,7 +226,7 @@ static int cx22702_set_tps (struct dvb_frontend* fe, struct dvb_frontend_paramet
} else { } else {
BUG(); BUG();
} }
cx22702_writereg (state, 0x0D, cx22702_readreg(state,0x0D) | 1); cx22702_i2c_gate_ctrl(fe, 0);
/* set inversion */ /* set inversion */
cx22702_set_inversion (state, p->inversion); cx22702_set_inversion (state, p->inversion);
@ -349,11 +359,10 @@ static int cx22702_init (struct dvb_frontend* fe)
cx22702_writereg (state, 0xf8, (state->config->output_mode << 1) & 0x02); cx22702_writereg (state, 0xf8, (state->config->output_mode << 1) & 0x02);
/* init PLL */ /* init PLL */
if (state->config->pll_init) { if (state->config->pll_init)
cx22702_writereg (state, 0x0D, cx22702_readreg(state,0x0D) & 0xfe);
state->config->pll_init(fe); state->config->pll_init(fe);
cx22702_writereg (state, 0x0D, cx22702_readreg(state,0x0D) | 1);
} cx22702_i2c_gate_ctrl(fe, 0);
return 0; return 0;
} }
@ -531,6 +540,7 @@ static struct dvb_frontend_ops cx22702_ops = {
.read_signal_strength = cx22702_read_signal_strength, .read_signal_strength = cx22702_read_signal_strength,
.read_snr = cx22702_read_snr, .read_snr = cx22702_read_snr,
.read_ucblocks = cx22702_read_ucblocks, .read_ucblocks = cx22702_read_ucblocks,
.i2c_gate_ctrl = cx22702_i2c_gate_ctrl,
}; };
module_param(debug, int, 0644); module_param(debug, int, 0644);

View File

@ -27,7 +27,6 @@
#include <linux/module.h> #include <linux/module.h>
#include <linux/moduleparam.h> #include <linux/moduleparam.h>
#include <linux/init.h> #include <linux/init.h>
#include <linux/jiffies.h>
#include "dvb_frontend.h" #include "dvb_frontend.h"
#include "cx24110.h" #include "cx24110.h"

View File

@ -0,0 +1,889 @@
/*
Conexant cx24123/cx24109 - DVB QPSK Satellite demod/tuner driver
Copyright (C) 2005 Steven Toth <stoth@hauppauge.com>
Support for KWorld DVB-S 100 by Vadim Catana <skystar@moldova.cc>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 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 General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include <linux/slab.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/init.h>
#include "dvb_frontend.h"
#include "cx24123.h"
static int debug;
#define dprintk(args...) \
do { \
if (debug) printk (KERN_DEBUG "cx24123: " args); \
} while (0)
struct cx24123_state
{
struct i2c_adapter* i2c;
struct dvb_frontend_ops ops;
const struct cx24123_config* config;
struct dvb_frontend frontend;
u32 lastber;
u16 snr;
u8 lnbreg;
/* Some PLL specifics for tuning */
u32 VCAarg;
u32 VGAarg;
u32 bandselectarg;
u32 pllarg;
/* The Demod/Tuner can't easily provide these, we cache them */
u32 currentfreq;
u32 currentsymbolrate;
};
/* Various tuner defaults need to be established for a given symbol rate Sps */
static struct
{
u32 symbolrate_low;
u32 symbolrate_high;
u32 VCAslope;
u32 VCAoffset;
u32 VGA1offset;
u32 VGA2offset;
u32 VCAprogdata;
u32 VGAprogdata;
} cx24123_AGC_vals[] =
{
{
.symbolrate_low = 1000000,
.symbolrate_high = 4999999,
.VCAslope = 0x07,
.VCAoffset = 0x0f,
.VGA1offset = 0x1f8,
.VGA2offset = 0x1f8,
.VGAprogdata = (2 << 18) | (0x1f8 << 9) | 0x1f8,
.VCAprogdata = (4 << 18) | (0x07 << 9) | 0x07,
},
{
.symbolrate_low = 5000000,
.symbolrate_high = 14999999,
.VCAslope = 0x1f,
.VCAoffset = 0x1f,
.VGA1offset = 0x1e0,
.VGA2offset = 0x180,
.VGAprogdata = (2 << 18) | (0x180 << 9) | 0x1e0,
.VCAprogdata = (4 << 18) | (0x07 << 9) | 0x1f,
},
{
.symbolrate_low = 15000000,
.symbolrate_high = 45000000,
.VCAslope = 0x3f,
.VCAoffset = 0x3f,
.VGA1offset = 0x180,
.VGA2offset = 0x100,
.VGAprogdata = (2 << 18) | (0x100 << 9) | 0x180,
.VCAprogdata = (4 << 18) | (0x07 << 9) | 0x3f,
},
};
/*
* Various tuner defaults need to be established for a given frequency kHz.
* fixme: The bounds on the bands do not match the doc in real life.
* fixme: Some of them have been moved, other might need adjustment.
*/
static struct
{
u32 freq_low;
u32 freq_high;
u32 bandselect;
u32 VCOdivider;
u32 VCOnumber;
u32 progdata;
} cx24123_bandselect_vals[] =
{
{
.freq_low = 950000,
.freq_high = 1018999,
.bandselect = 0x40,
.VCOdivider = 4,
.VCOnumber = 7,
.progdata = (0 << 18) | (0 << 9) | 0x40,
},
{
.freq_low = 1019000,
.freq_high = 1074999,
.bandselect = 0x80,
.VCOdivider = 4,
.VCOnumber = 8,
.progdata = (0 << 18) | (0 << 9) | 0x80,
},
{
.freq_low = 1075000,
.freq_high = 1227999,
.bandselect = 0x01,
.VCOdivider = 2,
.VCOnumber = 1,
.progdata = (0 << 18) | (1 << 9) | 0x01,
},
{
.freq_low = 1228000,
.freq_high = 1349999,
.bandselect = 0x02,
.VCOdivider = 2,
.VCOnumber = 2,
.progdata = (0 << 18) | (1 << 9) | 0x02,
},
{
.freq_low = 1350000,
.freq_high = 1481999,
.bandselect = 0x04,
.VCOdivider = 2,
.VCOnumber = 3,
.progdata = (0 << 18) | (1 << 9) | 0x04,
},
{
.freq_low = 1482000,
.freq_high = 1595999,
.bandselect = 0x08,
.VCOdivider = 2,
.VCOnumber = 4,
.progdata = (0 << 18) | (1 << 9) | 0x08,
},
{
.freq_low = 1596000,
.freq_high = 1717999,
.bandselect = 0x10,
.VCOdivider = 2,
.VCOnumber = 5,
.progdata = (0 << 18) | (1 << 9) | 0x10,
},
{
.freq_low = 1718000,
.freq_high = 1855999,
.bandselect = 0x20,
.VCOdivider = 2,
.VCOnumber = 6,
.progdata = (0 << 18) | (1 << 9) | 0x20,
},
{
.freq_low = 1856000,
.freq_high = 2035999,
.bandselect = 0x40,
.VCOdivider = 2,
.VCOnumber = 7,
.progdata = (0 << 18) | (1 << 9) | 0x40,
},
{
.freq_low = 2036000,
.freq_high = 2149999,
.bandselect = 0x80,
.VCOdivider = 2,
.VCOnumber = 8,
.progdata = (0 << 18) | (1 << 9) | 0x80,
},
};
static struct {
u8 reg;
u8 data;
} cx24123_regdata[] =
{
{0x00, 0x03}, /* Reset system */
{0x00, 0x00}, /* Clear reset */
{0x01, 0x3b}, /* Apply sensible defaults, from an i2c sniffer */
{0x03, 0x07},
{0x04, 0x10},
{0x05, 0x04},
{0x06, 0x31},
{0x0d, 0x02},
{0x0e, 0x03},
{0x0f, 0xfe},
{0x10, 0x01},
{0x14, 0x01},
{0x15, 0x98},
{0x16, 0x00},
{0x17, 0x01},
{0x1b, 0x05},
{0x1c, 0x80},
{0x1d, 0x00},
{0x1e, 0x00},
{0x20, 0x41},
{0x21, 0x15},
{0x27, 0x14},
{0x28, 0x46},
{0x29, 0x00},
{0x2a, 0xb0},
{0x2b, 0x73},
{0x2c, 0x00},
{0x2d, 0x00},
{0x2e, 0x00},
{0x2f, 0x00},
{0x30, 0x00},
{0x31, 0x00},
{0x32, 0x8c},
{0x33, 0x00},
{0x34, 0x00},
{0x35, 0x03},
{0x36, 0x02},
{0x37, 0x3a},
{0x3a, 0x00}, /* Enable AGC accumulator */
{0x44, 0x00},
{0x45, 0x00},
{0x46, 0x05},
{0x56, 0x41},
{0x57, 0xff},
{0x67, 0x83},
};
static int cx24123_writereg(struct cx24123_state* state, int reg, int data)
{
u8 buf[] = { reg, data };
struct i2c_msg msg = { .addr = state->config->demod_address, .flags = 0, .buf = buf, .len = 2 };
int err;
if ((err = i2c_transfer(state->i2c, &msg, 1)) != 1) {
printk("%s: writereg error(err == %i, reg == 0x%02x,"
" data == 0x%02x)\n", __FUNCTION__, err, reg, data);
return -EREMOTEIO;
}
return 0;
}
static int cx24123_writelnbreg(struct cx24123_state* state, int reg, int data)
{
u8 buf[] = { reg, data };
/* fixme: put the intersil addr int the config */
struct i2c_msg msg = { .addr = 0x08, .flags = 0, .buf = buf, .len = 2 };
int err;
if ((err = i2c_transfer(state->i2c, &msg, 1)) != 1) {
printk("%s: writelnbreg error (err == %i, reg == 0x%02x,"
" data == 0x%02x)\n", __FUNCTION__, err, reg, data);
return -EREMOTEIO;
}
/* cache the write, no way to read back */
state->lnbreg = data;
return 0;
}
static int cx24123_readreg(struct cx24123_state* state, u8 reg)
{
int ret;
u8 b0[] = { reg };
u8 b1[] = { 0 };
struct i2c_msg msg[] = {
{ .addr = state->config->demod_address, .flags = 0, .buf = b0, .len = 1 },
{ .addr = state->config->demod_address, .flags = I2C_M_RD, .buf = b1, .len = 1 }
};
ret = i2c_transfer(state->i2c, msg, 2);
if (ret != 2) {
printk("%s: reg=0x%x (error=%d)\n", __FUNCTION__, reg, ret);
return ret;
}
return b1[0];
}
static int cx24123_readlnbreg(struct cx24123_state* state, u8 reg)
{
return state->lnbreg;
}
static int cx24123_set_inversion(struct cx24123_state* state, fe_spectral_inversion_t inversion)
{
switch (inversion) {
case INVERSION_OFF:
cx24123_writereg(state, 0x0e, cx24123_readreg(state, 0x0e) & 0x7f);
cx24123_writereg(state, 0x10, cx24123_readreg(state, 0x10) | 0x80);
break;
case INVERSION_ON:
cx24123_writereg(state, 0x0e, cx24123_readreg(state, 0x0e) | 0x80);
cx24123_writereg(state, 0x10, cx24123_readreg(state, 0x10) | 0x80);
break;
case INVERSION_AUTO:
cx24123_writereg(state, 0x10, cx24123_readreg(state, 0x10) & 0x7f);
break;
default:
return -EINVAL;
}
return 0;
}
static int cx24123_get_inversion(struct cx24123_state* state, fe_spectral_inversion_t *inversion)
{
u8 val;
val = cx24123_readreg(state, 0x1b) >> 7;
if (val == 0)
*inversion = INVERSION_OFF;
else
*inversion = INVERSION_ON;
return 0;
}
static int cx24123_set_fec(struct cx24123_state* state, fe_code_rate_t fec)
{
if ( (fec < FEC_NONE) || (fec > FEC_AUTO) )
fec = FEC_AUTO;
/* Hardware has 5/11 and 3/5 but are never unused */
switch (fec) {
case FEC_NONE:
return cx24123_writereg(state, 0x0f, 0x01);
case FEC_1_2:
return cx24123_writereg(state, 0x0f, 0x02);
case FEC_2_3:
return cx24123_writereg(state, 0x0f, 0x04);
case FEC_3_4:
return cx24123_writereg(state, 0x0f, 0x08);
case FEC_5_6:
return cx24123_writereg(state, 0x0f, 0x20);
case FEC_7_8:
return cx24123_writereg(state, 0x0f, 0x80);
case FEC_AUTO:
return cx24123_writereg(state, 0x0f, 0xae);
default:
return -EOPNOTSUPP;
}
}
static int cx24123_get_fec(struct cx24123_state* state, fe_code_rate_t *fec)
{
int ret;
u8 val;
ret = cx24123_readreg (state, 0x1b);
if (ret < 0)
return ret;
val = ret & 0x07;
switch (val) {
case 1:
*fec = FEC_1_2;
break;
case 3:
*fec = FEC_2_3;
break;
case 4:
*fec = FEC_3_4;
break;
case 5:
*fec = FEC_4_5;
break;
case 6:
*fec = FEC_5_6;
break;
case 7:
*fec = FEC_7_8;
break;
case 2: /* *fec = FEC_3_5; break; */
case 0: /* *fec = FEC_5_11; break; */
*fec = FEC_AUTO;
break;
default:
*fec = FEC_NONE; // can't happen
}
return 0;
}
/* fixme: Symbol rates < 3MSps may not work because of precision loss */
static int cx24123_set_symbolrate(struct cx24123_state* state, u32 srate)
{
u32 val;
val = (srate / 1185) * 100;
/* Compensate for scaling up, by removing 17 symbols per 1Msps */
val = val - (17 * (srate / 1000000));
cx24123_writereg(state, 0x08, (val >> 16) & 0xff );
cx24123_writereg(state, 0x09, (val >> 8) & 0xff );
cx24123_writereg(state, 0x0a, (val ) & 0xff );
return 0;
}
/*
* Based on the required frequency and symbolrate, the tuner AGC has to be configured
* and the correct band selected. Calculate those values
*/
static int cx24123_pll_calculate(struct dvb_frontend* fe, struct dvb_frontend_parameters *p)
{
struct cx24123_state *state = fe->demodulator_priv;
u32 ndiv = 0, adiv = 0, vco_div = 0;
int i = 0;
/* Defaults for low freq, low rate */
state->VCAarg = cx24123_AGC_vals[0].VCAprogdata;
state->VGAarg = cx24123_AGC_vals[0].VGAprogdata;
state->bandselectarg = cx24123_bandselect_vals[0].progdata;
vco_div = cx24123_bandselect_vals[0].VCOdivider;
/* For the given symbolerate, determine the VCA and VGA programming bits */
for (i = 0; i < sizeof(cx24123_AGC_vals) / sizeof(cx24123_AGC_vals[0]); i++)
{
if ((cx24123_AGC_vals[i].symbolrate_low <= p->u.qpsk.symbol_rate) &&
(cx24123_AGC_vals[i].symbolrate_high >= p->u.qpsk.symbol_rate) ) {
state->VCAarg = cx24123_AGC_vals[i].VCAprogdata;
state->VGAarg = cx24123_AGC_vals[i].VGAprogdata;
}
}
/* For the given frequency, determine the bandselect programming bits */
for (i = 0; i < sizeof(cx24123_bandselect_vals) / sizeof(cx24123_bandselect_vals[0]); i++)
{
if ((cx24123_bandselect_vals[i].freq_low <= p->frequency) &&
(cx24123_bandselect_vals[i].freq_high >= p->frequency) ) {
state->bandselectarg = cx24123_bandselect_vals[i].progdata;
vco_div = cx24123_bandselect_vals[i].VCOdivider;
}
}
/* Determine the N/A dividers for the requested lband freq (in kHz). */
/* Note: 10111 (kHz) is the Crystal Freq and divider of 10. */
ndiv = ( ((p->frequency * vco_div) / (10111 / 10) / 2) / 32) & 0x1ff;
adiv = ( ((p->frequency * vco_div) / (10111 / 10) / 2) % 32) & 0x1f;
if (adiv == 0)
adiv++;
/* determine the correct pll frequency values. */
/* Command 11, refdiv 11, cpump polarity 1, cpump current 3mA 10. */
state->pllarg = (3 << 19) | (3 << 17) | (1 << 16) | (2 << 14);
state->pllarg |= (ndiv << 5) | adiv;
return 0;
}
/*
* Tuner data is 21 bits long, must be left-aligned in data.
* Tuner cx24109 is written through a dedicated 3wire interface on the demod chip.
*/
static int cx24123_pll_writereg(struct dvb_frontend* fe, struct dvb_frontend_parameters *p, u32 data)
{
struct cx24123_state *state = fe->demodulator_priv;
unsigned long timeout;
/* align the 21 bytes into to bit23 boundary */
data = data << 3;
/* Reset the demod pll word length to 0x15 bits */
cx24123_writereg(state, 0x21, 0x15);
/* write the msb 8 bits, wait for the send to be completed */
timeout = jiffies + msecs_to_jiffies(40);
cx24123_writereg(state, 0x22, (data >> 16) & 0xff);
while ((cx24123_readreg(state, 0x20) & 0x40) == 0) {
if (time_after(jiffies, timeout)) {
printk("%s: demodulator is not responding, possibly hung, aborting.\n", __FUNCTION__);
return -EREMOTEIO;
}
msleep(10);
}
/* send another 8 bytes, wait for the send to be completed */
timeout = jiffies + msecs_to_jiffies(40);
cx24123_writereg(state, 0x22, (data>>8) & 0xff );
while ((cx24123_readreg(state, 0x20) & 0x40) == 0) {
if (time_after(jiffies, timeout)) {
printk("%s: demodulator is not responding, possibly hung, aborting.\n", __FUNCTION__);
return -EREMOTEIO;
}
msleep(10);
}
/* send the lower 5 bits of this byte, padded with 3 LBB, wait for the send to be completed */
timeout = jiffies + msecs_to_jiffies(40);
cx24123_writereg(state, 0x22, (data) & 0xff );
while ((cx24123_readreg(state, 0x20) & 0x80)) {
if (time_after(jiffies, timeout)) {
printk("%s: demodulator is not responding, possibly hung, aborting.\n", __FUNCTION__);
return -EREMOTEIO;
}
msleep(10);
}
/* Trigger the demod to configure the tuner */
cx24123_writereg(state, 0x20, cx24123_readreg(state, 0x20) | 2);
cx24123_writereg(state, 0x20, cx24123_readreg(state, 0x20) & 0xfd);
return 0;
}
static int cx24123_pll_tune(struct dvb_frontend* fe, struct dvb_frontend_parameters *p)
{
struct cx24123_state *state = fe->demodulator_priv;
if (cx24123_pll_calculate(fe, p) != 0) {
printk("%s: cx24123_pll_calcutate failed\n",__FUNCTION__);
return -EINVAL;
}
/* Write the new VCO/VGA */
cx24123_pll_writereg(fe, p, state->VCAarg);
cx24123_pll_writereg(fe, p, state->VGAarg);
/* Write the new bandselect and pll args */
cx24123_pll_writereg(fe, p, state->bandselectarg);
cx24123_pll_writereg(fe, p, state->pllarg);
return 0;
}
static int cx24123_initfe(struct dvb_frontend* fe)
{
struct cx24123_state *state = fe->demodulator_priv;
int i;
/* Configure the demod to a good set of defaults */
for (i = 0; i < sizeof(cx24123_regdata) / sizeof(cx24123_regdata[0]); i++)
cx24123_writereg(state, cx24123_regdata[i].reg, cx24123_regdata[i].data);
if (state->config->pll_init)
state->config->pll_init(fe);
/* Configure the LNB for 14V */
if (state->config->use_isl6421)
cx24123_writelnbreg(state, 0x0, 0x2a);
return 0;
}
static int cx24123_set_voltage(struct dvb_frontend* fe, fe_sec_voltage_t voltage)
{
struct cx24123_state *state = fe->demodulator_priv;
u8 val;
switch (state->config->use_isl6421) {
case 1:
val = cx24123_readlnbreg(state, 0x0);
switch (voltage) {
case SEC_VOLTAGE_13:
return cx24123_writelnbreg(state, 0x0, val & 0x32); /* V 13v */
case SEC_VOLTAGE_18:
return cx24123_writelnbreg(state, 0x0, val | 0x04); /* H 18v */
case SEC_VOLTAGE_OFF:
return cx24123_writelnbreg(state, 0x0, val & 0x30);
default:
return -EINVAL;
};
case 0:
val = cx24123_readreg(state, 0x29);
switch (voltage) {
case SEC_VOLTAGE_13:
dprintk("%s: setting voltage 13V\n", __FUNCTION__);
if (state->config->enable_lnb_voltage)
state->config->enable_lnb_voltage(fe, 1);
return cx24123_writereg(state, 0x29, val | 0x80);
case SEC_VOLTAGE_18:
dprintk("%s: setting voltage 18V\n", __FUNCTION__);
if (state->config->enable_lnb_voltage)
state->config->enable_lnb_voltage(fe, 1);
return cx24123_writereg(state, 0x29, val & 0x7f);
case SEC_VOLTAGE_OFF:
dprintk("%s: setting voltage off\n", __FUNCTION__);
if (state->config->enable_lnb_voltage)
state->config->enable_lnb_voltage(fe, 0);
return 0;
default:
return -EINVAL;
};
}
return 0;
}
static int cx24123_send_diseqc_msg(struct dvb_frontend* fe,
struct dvb_diseqc_master_cmd *cmd)
{
/* fixme: Implement diseqc */
printk("%s: No support yet\n",__FUNCTION__);
return -ENOTSUPP;
}
static int cx24123_read_status(struct dvb_frontend* fe, fe_status_t* status)
{
struct cx24123_state *state = fe->demodulator_priv;
int sync = cx24123_readreg(state, 0x14);
int lock = cx24123_readreg(state, 0x20);
*status = 0;
if (lock & 0x01)
*status |= FE_HAS_CARRIER | FE_HAS_SIGNAL;
if (sync & 0x04)
*status |= FE_HAS_VITERBI;
if (sync & 0x08)
*status |= FE_HAS_CARRIER;
if (sync & 0x80)
*status |= FE_HAS_SYNC | FE_HAS_LOCK;
return 0;
}
/*
* Configured to return the measurement of errors in blocks, because no UCBLOCKS value
* is available, so this value doubles up to satisfy both measurements
*/
static int cx24123_read_ber(struct dvb_frontend* fe, u32* ber)
{
struct cx24123_state *state = fe->demodulator_priv;
state->lastber =
((cx24123_readreg(state, 0x1c) & 0x3f) << 16) |
(cx24123_readreg(state, 0x1d) << 8 |
cx24123_readreg(state, 0x1e));
/* Do the signal quality processing here, it's derived from the BER. */
/* Scale the BER from a 24bit to a SNR 16 bit where higher = better */
if (state->lastber < 5000)
state->snr = 655*100;
else if ( (state->lastber >= 5000) && (state->lastber < 55000) )
state->snr = 655*90;
else if ( (state->lastber >= 55000) && (state->lastber < 150000) )
state->snr = 655*80;
else if ( (state->lastber >= 150000) && (state->lastber < 250000) )
state->snr = 655*70;
else if ( (state->lastber >= 250000) && (state->lastber < 450000) )
state->snr = 655*65;
else
state->snr = 0;
*ber = state->lastber;
return 0;
}
static int cx24123_read_signal_strength(struct dvb_frontend* fe, u16* signal_strength)
{
struct cx24123_state *state = fe->demodulator_priv;
*signal_strength = cx24123_readreg(state, 0x3b) << 8; /* larger = better */
return 0;
}
static int cx24123_read_snr(struct dvb_frontend* fe, u16* snr)
{
struct cx24123_state *state = fe->demodulator_priv;
*snr = state->snr;
return 0;
}
static int cx24123_read_ucblocks(struct dvb_frontend* fe, u32* ucblocks)
{
struct cx24123_state *state = fe->demodulator_priv;
*ucblocks = state->lastber;
return 0;
}
static int cx24123_set_frontend(struct dvb_frontend* fe, struct dvb_frontend_parameters *p)
{
struct cx24123_state *state = fe->demodulator_priv;
if (state->config->set_ts_params)
state->config->set_ts_params(fe, 0);
state->currentfreq=p->frequency;
state->currentsymbolrate = p->u.qpsk.symbol_rate;
cx24123_set_inversion(state, p->inversion);
cx24123_set_fec(state, p->u.qpsk.fec_inner);
cx24123_set_symbolrate(state, p->u.qpsk.symbol_rate);
cx24123_pll_tune(fe, p);
/* Enable automatic aquisition and reset cycle */
cx24123_writereg(state, 0x03, (cx24123_readreg(state, 0x03) | 0x07));
cx24123_writereg(state, 0x00, 0x10);
cx24123_writereg(state, 0x00, 0);
return 0;
}
static int cx24123_get_frontend(struct dvb_frontend* fe, struct dvb_frontend_parameters *p)
{
struct cx24123_state *state = fe->demodulator_priv;
if (cx24123_get_inversion(state, &p->inversion) != 0) {
printk("%s: Failed to get inversion status\n",__FUNCTION__);
return -EREMOTEIO;
}
if (cx24123_get_fec(state, &p->u.qpsk.fec_inner) != 0) {
printk("%s: Failed to get fec status\n",__FUNCTION__);
return -EREMOTEIO;
}
p->frequency = state->currentfreq;
p->u.qpsk.symbol_rate = state->currentsymbolrate;
return 0;
}
static int cx24123_set_tone(struct dvb_frontend* fe, fe_sec_tone_mode_t tone)
{
struct cx24123_state *state = fe->demodulator_priv;
u8 val;
switch (state->config->use_isl6421) {
case 1:
val = cx24123_readlnbreg(state, 0x0);
switch (tone) {
case SEC_TONE_ON:
return cx24123_writelnbreg(state, 0x0, val | 0x10);
case SEC_TONE_OFF:
return cx24123_writelnbreg(state, 0x0, val & 0x2f);
default:
printk("%s: CASE reached default with tone=%d\n", __FUNCTION__, tone);
return -EINVAL;
}
case 0:
val = cx24123_readreg(state, 0x29);
switch (tone) {
case SEC_TONE_ON:
dprintk("%s: setting tone on\n", __FUNCTION__);
return cx24123_writereg(state, 0x29, val | 0x10);
case SEC_TONE_OFF:
dprintk("%s: setting tone off\n",__FUNCTION__);
return cx24123_writereg(state, 0x29, val & 0xef);
default:
printk("%s: CASE reached default with tone=%d\n", __FUNCTION__, tone);
return -EINVAL;
}
}
return 0;
}
static void cx24123_release(struct dvb_frontend* fe)
{
struct cx24123_state* state = fe->demodulator_priv;
dprintk("%s\n",__FUNCTION__);
kfree(state);
}
static struct dvb_frontend_ops cx24123_ops;
struct dvb_frontend* cx24123_attach(const struct cx24123_config* config,
struct i2c_adapter* i2c)
{
struct cx24123_state* state = NULL;
int ret;
dprintk("%s\n",__FUNCTION__);
/* allocate memory for the internal state */
state = kmalloc(sizeof(struct cx24123_state), GFP_KERNEL);
if (state == NULL) {
printk("Unable to kmalloc\n");
goto error;
}
/* setup the state */
state->config = config;
state->i2c = i2c;
memcpy(&state->ops, &cx24123_ops, sizeof(struct dvb_frontend_ops));
state->lastber = 0;
state->snr = 0;
state->lnbreg = 0;
state->VCAarg = 0;
state->VGAarg = 0;
state->bandselectarg = 0;
state->pllarg = 0;
state->currentfreq = 0;
state->currentsymbolrate = 0;
/* check if the demod is there */
ret = cx24123_readreg(state, 0x00);
if ((ret != 0xd1) && (ret != 0xe1)) {
printk("Version != d1 or e1\n");
goto error;
}
/* create dvb_frontend */
state->frontend.ops = &state->ops;
state->frontend.demodulator_priv = state;
return &state->frontend;
error:
kfree(state);
return NULL;
}
static struct dvb_frontend_ops cx24123_ops = {
.info = {
.name = "Conexant CX24123/CX24109",
.type = FE_QPSK,
.frequency_min = 950000,
.frequency_max = 2150000,
.frequency_stepsize = 1011, /* kHz for QPSK frontends */
.frequency_tolerance = 29500,
.symbol_rate_min = 1000000,
.symbol_rate_max = 45000000,
.caps = FE_CAN_INVERSION_AUTO |
FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 |
FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO |
FE_CAN_QPSK | FE_CAN_RECOVER
},
.release = cx24123_release,
.init = cx24123_initfe,
.set_frontend = cx24123_set_frontend,
.get_frontend = cx24123_get_frontend,
.read_status = cx24123_read_status,
.read_ber = cx24123_read_ber,
.read_signal_strength = cx24123_read_signal_strength,
.read_snr = cx24123_read_snr,
.read_ucblocks = cx24123_read_ucblocks,
.diseqc_send_master_cmd = cx24123_send_diseqc_msg,
.set_tone = cx24123_set_tone,
.set_voltage = cx24123_set_voltage,
};
module_param(debug, int, 0644);
MODULE_PARM_DESC(debug, "Turn on/off frontend debugging (default:off).");
MODULE_DESCRIPTION("DVB Frontend module for Conexant cx24123/cx24109 hardware");
MODULE_AUTHOR("Steven Toth");
MODULE_LICENSE("GPL");
EXPORT_SYMBOL(cx24123_attach);

View File

@ -0,0 +1,51 @@
/*
Conexant cx24123/cx24109 - DVB QPSK Satellite demod/tuner driver
Copyright (C) 2005 Steven Toth <stoth@hauppauge.com>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 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 General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#ifndef CX24123_H
#define CX24123_H
#include <linux/dvb/frontend.h>
struct cx24123_config
{
/* the demodulator's i2c address */
u8 demod_address;
/*
cards like Hauppauge Nova-S Plus/Nova-SE2 use an Intersil ISL6421 chip
for LNB control, while KWorld DVB-S 100 use the LNBDC and LNBTone bits
from register 0x29 of the CX24123 demodulator
*/
int use_isl6421;
/* PLL maintenance */
int (*pll_init)(struct dvb_frontend* fe);
int (*pll_set)(struct dvb_frontend* fe, struct dvb_frontend_parameters* params);
/* Need to set device param for start_dma */
int (*set_ts_params)(struct dvb_frontend* fe, int is_punctured);
void (*enable_lnb_voltage)(struct dvb_frontend* fe, int on);
};
extern struct dvb_frontend* cx24123_attach(const struct cx24123_config* config,
struct i2c_adapter* i2c);
#endif /* CX24123_H */

View File

@ -107,18 +107,19 @@ struct dvb_pll_desc dvb_pll_microtune_4042 = {
}; };
EXPORT_SYMBOL(dvb_pll_microtune_4042); EXPORT_SYMBOL(dvb_pll_microtune_4042);
struct dvb_pll_desc dvb_pll_thomson_dtt7611 = { struct dvb_pll_desc dvb_pll_thomson_dtt761x = {
.name = "Thomson dtt7611", /* DTT 7611 7611A 7612 7613 7613A 7614 7615 7615A */
.min = 44000000, .name = "Thomson dtt761x",
.max = 958000000, .min = 57000000,
.max = 863000000,
.count = 3, .count = 3,
.entries = { .entries = {
{ 157250000, 44000000, 62500, 0x8e, 0x39 }, { 147000000, 44000000, 62500, 0x8e, 0x39 },
{ 454000000, 44000000, 62500, 0x8e, 0x3a }, { 417000000, 44000000, 62500, 0x8e, 0x3a },
{ 999999999, 44000000, 62500, 0x8e, 0x3c }, { 999999999, 44000000, 62500, 0x8e, 0x3c },
}, },
}; };
EXPORT_SYMBOL(dvb_pll_thomson_dtt7611); EXPORT_SYMBOL(dvb_pll_thomson_dtt761x);
struct dvb_pll_desc dvb_pll_unknown_1 = { struct dvb_pll_desc dvb_pll_unknown_1 = {
.name = "unknown 1", /* used by dntv live dvb-t */ .name = "unknown 1", /* used by dntv live dvb-t */

View File

@ -25,7 +25,7 @@ extern struct dvb_pll_desc dvb_pll_thomson_dtt759x;
extern struct dvb_pll_desc dvb_pll_thomson_dtt7610; extern struct dvb_pll_desc dvb_pll_thomson_dtt7610;
extern struct dvb_pll_desc dvb_pll_lg_z201; extern struct dvb_pll_desc dvb_pll_lg_z201;
extern struct dvb_pll_desc dvb_pll_microtune_4042; extern struct dvb_pll_desc dvb_pll_microtune_4042;
extern struct dvb_pll_desc dvb_pll_thomson_dtt7611; extern struct dvb_pll_desc dvb_pll_thomson_dtt761x;
extern struct dvb_pll_desc dvb_pll_unknown_1; extern struct dvb_pll_desc dvb_pll_unknown_1;
extern struct dvb_pll_desc dvb_pll_tua6010xs; extern struct dvb_pll_desc dvb_pll_tua6010xs;

View File

@ -27,6 +27,7 @@
* DViCO FusionHDTV 3 Gold-T * DViCO FusionHDTV 3 Gold-T
* DViCO FusionHDTV 5 Gold * DViCO FusionHDTV 5 Gold
* DViCO FusionHDTV 5 Lite * DViCO FusionHDTV 5 Lite
* DViCO FusionHDTV 5 USB Gold
* Air2PC/AirStar 2 ATSC 3rd generation (HD5000) * Air2PC/AirStar 2 ATSC 3rd generation (HD5000)
* *
* TODO: * TODO:
@ -402,6 +403,8 @@ static int lgdt330x_set_parameters(struct dvb_frontend* fe,
state->config->pll_set(fe, param); state->config->pll_set(fe, param);
/* Keep track of the new frequency */ /* Keep track of the new frequency */
/* FIXME this is the wrong way to do this... */
/* The tuner is shared with the video4linux analog API */
state->current_frequency = param->frequency; state->current_frequency = param->frequency;
lgdt330x_SwReset(state); lgdt330x_SwReset(state);

View File

@ -22,7 +22,8 @@
/* /*
* This driver needs external firmware. Please use the command * This driver needs external firmware. Please use the command
* "<kerneldir>/Documentation/dvb/get_dvb_firmware nxt2002" to * "<kerneldir>/Documentation/dvb/get_dvb_firmware nxt2002" to
* download/extract it, and then copy it to /usr/lib/hotplug/firmware. * download/extract it, and then copy it to /usr/lib/hotplug/firmware
* or /lib/firmware (depending on configuration of firmware hotplug).
*/ */
#define NXT2002_DEFAULT_FIRMWARE "dvb-fe-nxt2002.fw" #define NXT2002_DEFAULT_FIRMWARE "dvb-fe-nxt2002.fw"
#define CRC_CCIT_MASK 0x1021 #define CRC_CCIT_MASK 0x1021

View File

@ -25,7 +25,8 @@
/* /*
* This driver needs external firmware. Please use the command * This driver needs external firmware. Please use the command
* "<kerneldir>/Documentation/dvb/get_dvb_firmware or51211" to * "<kerneldir>/Documentation/dvb/get_dvb_firmware or51211" to
* download/extract it, and then copy it to /usr/lib/hotplug/firmware. * download/extract it, and then copy it to /usr/lib/hotplug/firmware
* or /lib/firmware (depending on configuration of firmware hotplug).
*/ */
#define OR51211_DEFAULT_FIRMWARE "dvb-fe-or51211.fw" #define OR51211_DEFAULT_FIRMWARE "dvb-fe-or51211.fw"
@ -112,7 +113,7 @@ static int or51211_load_firmware (struct dvb_frontend* fe,
u8 tudata[585]; u8 tudata[585];
int i; int i;
dprintk("Firmware is %d bytes\n",fw->size); dprintk("Firmware is %zd bytes\n",fw->size);
/* Get eprom data */ /* Get eprom data */
tudata[0] = 17; tudata[0] = 17;

View File

@ -22,7 +22,8 @@
/* /*
* This driver needs external firmware. Please use the command * This driver needs external firmware. Please use the command
* "<kerneldir>/Documentation/dvb/get_dvb_firmware alps_tdlb7" to * "<kerneldir>/Documentation/dvb/get_dvb_firmware alps_tdlb7" to
* download/extract it, and then copy it to /usr/lib/hotplug/firmware. * download/extract it, and then copy it to /usr/lib/hotplug/firmware
* or /lib/firmware (depending on configuration of firmware hotplug).
*/ */
#define SP8870_DEFAULT_FIRMWARE "dvb-fe-sp8870.fw" #define SP8870_DEFAULT_FIRMWARE "dvb-fe-sp8870.fw"

View File

@ -5,7 +5,8 @@
/* /*
* This driver needs external firmware. Please use the command * This driver needs external firmware. Please use the command
* "<kerneldir>/Documentation/dvb/get_dvb_firmware sp887x" to * "<kerneldir>/Documentation/dvb/get_dvb_firmware sp887x" to
* download/extract it, and then copy it to /usr/lib/hotplug/firmware. * download/extract it, and then copy it to /usr/lib/hotplug/firmware
* or /lib/firmware (depending on configuration of firmware hotplug).
*/ */
#define SP887X_DEFAULT_FIRMWARE "dvb-fe-sp887x.fw" #define SP887X_DEFAULT_FIRMWARE "dvb-fe-sp887x.fw"

View File

@ -131,6 +131,13 @@ static int stv0299_readregs (struct stv0299_state* state, u8 reg1, u8 *b, u8 len
return ret == 2 ? 0 : ret; return ret == 2 ? 0 : ret;
} }
int stv0299_enable_plli2c (struct dvb_frontend* fe)
{
struct stv0299_state* state = fe->demodulator_priv;
return stv0299_writeregI(state, 0x05, 0xb5); /* enable i2c repeater on stv0299 */
}
static int stv0299_set_FEC (struct stv0299_state* state, fe_code_rate_t fec) static int stv0299_set_FEC (struct stv0299_state* state, fe_code_rate_t fec)
{ {
dprintk ("%s\n", __FUNCTION__); dprintk ("%s\n", __FUNCTION__);
@ -387,7 +394,7 @@ static int stv0299_set_voltage (struct dvb_frontend* fe, fe_sec_voltage_t voltag
}; };
} }
static int stv0299_send_legacy_dish_cmd (struct dvb_frontend* fe, u32 cmd) static int stv0299_send_legacy_dish_cmd (struct dvb_frontend* fe, unsigned long cmd)
{ {
struct stv0299_state* state = fe->demodulator_priv; struct stv0299_state* state = fe->demodulator_priv;
u8 reg0x08; u8 reg0x08;
@ -407,7 +414,7 @@ static int stv0299_send_legacy_dish_cmd (struct dvb_frontend* fe, u32 cmd)
cmd = cmd << 1; cmd = cmd << 1;
if (debug_legacy_dish_switch) if (debug_legacy_dish_switch)
printk ("%s switch command: 0x%04x\n",__FUNCTION__, cmd); printk ("%s switch command: 0x%04lx\n",__FUNCTION__, cmd);
do_gettimeofday (&nexttime); do_gettimeofday (&nexttime);
if (debug_legacy_dish_switch) if (debug_legacy_dish_switch)
@ -717,5 +724,6 @@ MODULE_AUTHOR("Ralph Metzler, Holger Waechtler, Peter Schildmann, Felix Domke, "
"Andreas Oberritter, Andrew de Quincey, Kenneth Aafløy"); "Andreas Oberritter, Andrew de Quincey, Kenneth Aafløy");
MODULE_LICENSE("GPL"); MODULE_LICENSE("GPL");
EXPORT_SYMBOL(stv0299_enable_plli2c);
EXPORT_SYMBOL(stv0299_writereg); EXPORT_SYMBOL(stv0299_writereg);
EXPORT_SYMBOL(stv0299_attach); EXPORT_SYMBOL(stv0299_attach);

View File

@ -94,6 +94,7 @@ struct stv0299_config
}; };
extern int stv0299_writereg (struct dvb_frontend* fe, u8 reg, u8 data); extern int stv0299_writereg (struct dvb_frontend* fe, u8 reg, u8 data);
extern int stv0299_enable_plli2c (struct dvb_frontend* fe);
extern struct dvb_frontend* stv0299_attach(const struct stv0299_config* config, extern struct dvb_frontend* stv0299_attach(const struct stv0299_config* config,
struct i2c_adapter* i2c); struct i2c_adapter* i2c);

View File

@ -23,7 +23,8 @@
* This driver needs external firmware. Please use the commands * This driver needs external firmware. Please use the commands
* "<kerneldir>/Documentation/dvb/get_dvb_firmware tda10045", * "<kerneldir>/Documentation/dvb/get_dvb_firmware tda10045",
* "<kerneldir>/Documentation/dvb/get_dvb_firmware tda10046" to * "<kerneldir>/Documentation/dvb/get_dvb_firmware tda10046" to
* download/extract them, and then copy them to /usr/lib/hotplug/firmware. * download/extract them, and then copy them to /usr/lib/hotplug/firmware
* or /lib/firmware (depending on configuration of firmware hotplug).
*/ */
#define TDA10045_DEFAULT_FIRMWARE "dvb-fe-tda10045.fw" #define TDA10045_DEFAULT_FIRMWARE "dvb-fe-tda10045.fw"
#define TDA10046_DEFAULT_FIRMWARE "dvb-fe-tda10046.fw" #define TDA10046_DEFAULT_FIRMWARE "dvb-fe-tda10046.fw"
@ -271,32 +272,57 @@ static int tda10045h_set_bandwidth(struct tda1004x_state *state,
static int tda10046h_set_bandwidth(struct tda1004x_state *state, static int tda10046h_set_bandwidth(struct tda1004x_state *state,
fe_bandwidth_t bandwidth) fe_bandwidth_t bandwidth)
{ {
static u8 bandwidth_6mhz[] = { 0x80, 0x15, 0xfe, 0xab, 0x8e }; static u8 bandwidth_6mhz_53M[] = { 0x7b, 0x2e, 0x11, 0xf0, 0xd2 };
static u8 bandwidth_7mhz[] = { 0x6e, 0x02, 0x53, 0xc8, 0x25 }; static u8 bandwidth_7mhz_53M[] = { 0x6a, 0x02, 0x6a, 0x43, 0x9f };
static u8 bandwidth_8mhz[] = { 0x60, 0x12, 0xa8, 0xe4, 0xbd }; static u8 bandwidth_8mhz_53M[] = { 0x5c, 0x32, 0xc2, 0x96, 0x6d };
static u8 bandwidth_6mhz_48M[] = { 0x70, 0x02, 0x49, 0x24, 0x92 };
static u8 bandwidth_7mhz_48M[] = { 0x60, 0x02, 0xaa, 0xaa, 0xab };
static u8 bandwidth_8mhz_48M[] = { 0x54, 0x03, 0x0c, 0x30, 0xc3 };
int tda10046_clk53m;
if ((state->config->if_freq == TDA10046_FREQ_045) ||
(state->config->if_freq == TDA10046_FREQ_052))
tda10046_clk53m = 0;
else
tda10046_clk53m = 1;
switch (bandwidth) { switch (bandwidth) {
case BANDWIDTH_6_MHZ: case BANDWIDTH_6_MHZ:
tda1004x_write_buf(state, TDA10046H_TIME_WREF1, bandwidth_6mhz, sizeof(bandwidth_6mhz)); if (tda10046_clk53m)
tda1004x_write_buf(state, TDA10046H_TIME_WREF1, bandwidth_6mhz_53M,
sizeof(bandwidth_6mhz_53M));
else
tda1004x_write_buf(state, TDA10046H_TIME_WREF1, bandwidth_6mhz_48M,
sizeof(bandwidth_6mhz_48M));
if (state->config->if_freq == TDA10046_FREQ_045) { if (state->config->if_freq == TDA10046_FREQ_045) {
tda1004x_write_byteI(state, TDA10046H_FREQ_PHY2_MSB, 0x09); tda1004x_write_byteI(state, TDA10046H_FREQ_PHY2_MSB, 0x0a);
tda1004x_write_byteI(state, TDA10046H_FREQ_PHY2_LSB, 0x4f); tda1004x_write_byteI(state, TDA10046H_FREQ_PHY2_LSB, 0xab);
} }
break; break;
case BANDWIDTH_7_MHZ: case BANDWIDTH_7_MHZ:
tda1004x_write_buf(state, TDA10046H_TIME_WREF1, bandwidth_7mhz, sizeof(bandwidth_7mhz)); if (tda10046_clk53m)
tda1004x_write_buf(state, TDA10046H_TIME_WREF1, bandwidth_7mhz_53M,
sizeof(bandwidth_7mhz_53M));
else
tda1004x_write_buf(state, TDA10046H_TIME_WREF1, bandwidth_7mhz_48M,
sizeof(bandwidth_7mhz_48M));
if (state->config->if_freq == TDA10046_FREQ_045) { if (state->config->if_freq == TDA10046_FREQ_045) {
tda1004x_write_byteI(state, TDA10046H_FREQ_PHY2_MSB, 0x0a); tda1004x_write_byteI(state, TDA10046H_FREQ_PHY2_MSB, 0x0c);
tda1004x_write_byteI(state, TDA10046H_FREQ_PHY2_LSB, 0x79); tda1004x_write_byteI(state, TDA10046H_FREQ_PHY2_LSB, 0x00);
} }
break; break;
case BANDWIDTH_8_MHZ: case BANDWIDTH_8_MHZ:
tda1004x_write_buf(state, TDA10046H_TIME_WREF1, bandwidth_8mhz, sizeof(bandwidth_8mhz)); if (tda10046_clk53m)
tda1004x_write_buf(state, TDA10046H_TIME_WREF1, bandwidth_8mhz_53M,
sizeof(bandwidth_8mhz_53M));
else
tda1004x_write_buf(state, TDA10046H_TIME_WREF1, bandwidth_8mhz_48M,
sizeof(bandwidth_8mhz_48M));
if (state->config->if_freq == TDA10046_FREQ_045) { if (state->config->if_freq == TDA10046_FREQ_045) {
tda1004x_write_byteI(state, TDA10046H_FREQ_PHY2_MSB, 0x0b); tda1004x_write_byteI(state, TDA10046H_FREQ_PHY2_MSB, 0x0d);
tda1004x_write_byteI(state, TDA10046H_FREQ_PHY2_LSB, 0xa3); tda1004x_write_byteI(state, TDA10046H_FREQ_PHY2_LSB, 0x55);
} }
break; break;
@ -418,9 +444,22 @@ static int tda10045_fwupload(struct dvb_frontend* fe)
static void tda10046_init_plls(struct dvb_frontend* fe) static void tda10046_init_plls(struct dvb_frontend* fe)
{ {
struct tda1004x_state* state = fe->demodulator_priv; struct tda1004x_state* state = fe->demodulator_priv;
int tda10046_clk53m;
if ((state->config->if_freq == TDA10046_FREQ_045) ||
(state->config->if_freq == TDA10046_FREQ_052))
tda10046_clk53m = 0;
else
tda10046_clk53m = 1;
tda1004x_write_byteI(state, TDA10046H_CONFPLL1, 0xf0); tda1004x_write_byteI(state, TDA10046H_CONFPLL1, 0xf0);
tda1004x_write_byteI(state, TDA10046H_CONFPLL2, 0x0a); // PLL M = 10 if(tda10046_clk53m) {
printk(KERN_INFO "tda1004x: setting up plls for 53MHz sampling clock\n");
tda1004x_write_byteI(state, TDA10046H_CONFPLL2, 0x08); // PLL M = 8
} else {
printk(KERN_INFO "tda1004x: setting up plls for 48MHz sampling clock\n");
tda1004x_write_byteI(state, TDA10046H_CONFPLL2, 0x03); // PLL M = 3
}
if (state->config->xtal_freq == TDA10046_XTAL_4M ) { if (state->config->xtal_freq == TDA10046_XTAL_4M ) {
dprintk("%s: setting up PLLs for a 4 MHz Xtal\n", __FUNCTION__); dprintk("%s: setting up PLLs for a 4 MHz Xtal\n", __FUNCTION__);
tda1004x_write_byteI(state, TDA10046H_CONFPLL3, 0); // PLL P = N = 0 tda1004x_write_byteI(state, TDA10046H_CONFPLL3, 0); // PLL P = N = 0
@ -428,26 +467,32 @@ static void tda10046_init_plls(struct dvb_frontend* fe)
dprintk("%s: setting up PLLs for a 16 MHz Xtal\n", __FUNCTION__); dprintk("%s: setting up PLLs for a 16 MHz Xtal\n", __FUNCTION__);
tda1004x_write_byteI(state, TDA10046H_CONFPLL3, 3); // PLL P = 0, N = 3 tda1004x_write_byteI(state, TDA10046H_CONFPLL3, 3); // PLL P = 0, N = 3
} }
tda1004x_write_byteI(state, TDA10046H_FREQ_OFFSET, 99); if(tda10046_clk53m)
tda1004x_write_byteI(state, TDA10046H_FREQ_OFFSET, 0x67);
else
tda1004x_write_byteI(state, TDA10046H_FREQ_OFFSET, 0x72);
/* Note clock frequency is handled implicitly */
switch (state->config->if_freq) { switch (state->config->if_freq) {
case TDA10046_FREQ_3617:
tda1004x_write_byteI(state, TDA10046H_FREQ_PHY2_MSB, 0xd4);
tda1004x_write_byteI(state, TDA10046H_FREQ_PHY2_LSB, 0x2c);
break;
case TDA10046_FREQ_3613:
tda1004x_write_byteI(state, TDA10046H_FREQ_PHY2_MSB, 0xd4);
tda1004x_write_byteI(state, TDA10046H_FREQ_PHY2_LSB, 0x13);
break;
case TDA10046_FREQ_045: case TDA10046_FREQ_045:
tda1004x_write_byteI(state, TDA10046H_FREQ_PHY2_MSB, 0x0b); tda1004x_write_byteI(state, TDA10046H_FREQ_PHY2_MSB, 0x0c);
tda1004x_write_byteI(state, TDA10046H_FREQ_PHY2_LSB, 0xa3); tda1004x_write_byteI(state, TDA10046H_FREQ_PHY2_LSB, 0x00);
break; break;
case TDA10046_FREQ_052: case TDA10046_FREQ_052:
tda1004x_write_byteI(state, TDA10046H_FREQ_PHY2_MSB, 0x0c); tda1004x_write_byteI(state, TDA10046H_FREQ_PHY2_MSB, 0x0d);
tda1004x_write_byteI(state, TDA10046H_FREQ_PHY2_LSB, 0x06); tda1004x_write_byteI(state, TDA10046H_FREQ_PHY2_LSB, 0xc7);
break;
case TDA10046_FREQ_3617:
tda1004x_write_byteI(state, TDA10046H_FREQ_PHY2_MSB, 0xd7);
tda1004x_write_byteI(state, TDA10046H_FREQ_PHY2_LSB, 0x59);
break;
case TDA10046_FREQ_3613:
tda1004x_write_byteI(state, TDA10046H_FREQ_PHY2_MSB, 0xd7);
tda1004x_write_byteI(state, TDA10046H_FREQ_PHY2_LSB, 0x3f);
break; break;
} }
tda10046h_set_bandwidth(state, BANDWIDTH_8_MHZ); // default bandwidth 8 MHz tda10046h_set_bandwidth(state, BANDWIDTH_8_MHZ); // default bandwidth 8 MHz
/* let the PLLs settle */
msleep(120);
} }
static int tda10046_fwupload(struct dvb_frontend* fe) static int tda10046_fwupload(struct dvb_frontend* fe)
@ -462,13 +507,13 @@ static int tda10046_fwupload(struct dvb_frontend* fe)
/* let the clocks recover from sleep */ /* let the clocks recover from sleep */
msleep(5); msleep(5);
/* The PLLs need to be reprogrammed after sleep */
tda10046_init_plls(fe);
/* don't re-upload unless necessary */ /* don't re-upload unless necessary */
if (tda1004x_check_upload_ok(state) == 0) if (tda1004x_check_upload_ok(state) == 0)
return 0; return 0;
/* set parameters */
tda10046_init_plls(fe);
if (state->config->request_firmware != NULL) { if (state->config->request_firmware != NULL) {
/* request the firmware, this will block until someone uploads it */ /* request the firmware, this will block until someone uploads it */
printk(KERN_INFO "tda1004x: waiting for firmware upload...\n"); printk(KERN_INFO "tda1004x: waiting for firmware upload...\n");
@ -484,7 +529,6 @@ static int tda10046_fwupload(struct dvb_frontend* fe)
return ret; return ret;
} else { } else {
/* boot from firmware eeprom */ /* boot from firmware eeprom */
/* Hac Note: we might need to do some GPIO Magic here */
printk(KERN_INFO "tda1004x: booting from eeprom\n"); printk(KERN_INFO "tda1004x: booting from eeprom\n");
tda1004x_write_mask(state, TDA1004X_CONFC4, 4, 4); tda1004x_write_mask(state, TDA1004X_CONFC4, 4, 4);
msleep(300); msleep(300);
@ -606,10 +650,9 @@ static int tda10046_init(struct dvb_frontend* fe)
// tda setup // tda setup
tda1004x_write_mask(state, TDA1004X_CONFC4, 0x20, 0); // disable DSP watchdog timer tda1004x_write_mask(state, TDA1004X_CONFC4, 0x20, 0); // disable DSP watchdog timer
tda1004x_write_byteI(state, TDA1004X_AUTO, 7); // select HP stream tda1004x_write_byteI(state, TDA1004X_AUTO, 0x87); // 100 ppm crystal, select HP stream
tda1004x_write_byteI(state, TDA1004X_CONFC1, 8); // disable pulse killer tda1004x_write_byteI(state, TDA1004X_CONFC1, 8); // disable pulse killer
tda10046_init_plls(fe);
switch (state->config->agc_config) { switch (state->config->agc_config) {
case TDA10046_AGC_DEFAULT: case TDA10046_AGC_DEFAULT:
tda1004x_write_byteI(state, TDA10046H_AGC_CONF, 0x00); // AGC setup tda1004x_write_byteI(state, TDA10046H_AGC_CONF, 0x00); // AGC setup
@ -626,25 +669,22 @@ static int tda10046_init(struct dvb_frontend* fe)
case TDA10046_AGC_TDA827X: case TDA10046_AGC_TDA827X:
tda1004x_write_byteI(state, TDA10046H_AGC_CONF, 0x02); // AGC setup tda1004x_write_byteI(state, TDA10046H_AGC_CONF, 0x02); // AGC setup
tda1004x_write_byteI(state, TDA10046H_AGC_THR, 0x70); // AGC Threshold tda1004x_write_byteI(state, TDA10046H_AGC_THR, 0x70); // AGC Threshold
tda1004x_write_byteI(state, TDA10046H_AGC_RENORM, 0x0E); // Gain Renormalize tda1004x_write_byteI(state, TDA10046H_AGC_RENORM, 0x08); // Gain Renormalize
tda1004x_write_byteI(state, TDA10046H_CONF_POLARITY, 0x60); // set AGC polarities tda1004x_write_byteI(state, TDA10046H_CONF_POLARITY, 0x6a); // set AGC polarities
break; break;
} }
tda1004x_write_byteI(state, TDA1004X_CONFADC2, 0x38);
tda1004x_write_byteI(state, TDA10046H_CONF_TRISTATE1, 0x61); // Turn both AGC outputs on tda1004x_write_byteI(state, TDA10046H_CONF_TRISTATE1, 0x61); // Turn both AGC outputs on
tda1004x_write_byteI(state, TDA10046H_AGC_TUN_MIN, 0); // } tda1004x_write_byteI(state, TDA10046H_AGC_TUN_MIN, 0); // }
tda1004x_write_byteI(state, TDA10046H_AGC_TUN_MAX, 0xff); // } AGC min/max values tda1004x_write_byteI(state, TDA10046H_AGC_TUN_MAX, 0xff); // } AGC min/max values
tda1004x_write_byteI(state, TDA10046H_AGC_IF_MIN, 0); // } tda1004x_write_byteI(state, TDA10046H_AGC_IF_MIN, 0); // }
tda1004x_write_byteI(state, TDA10046H_AGC_IF_MAX, 0xff); // } tda1004x_write_byteI(state, TDA10046H_AGC_IF_MAX, 0xff); // }
tda1004x_write_byteI(state, TDA10046H_AGC_GAINS, 1); // IF gain 2, TUN gain 1 tda1004x_write_byteI(state, TDA10046H_AGC_GAINS, 0x12); // IF gain 2, TUN gain 1
tda1004x_write_byteI(state, TDA10046H_CVBER_CTRL, 0x1a); // 10^6 VBER measurement bits tda1004x_write_byteI(state, TDA10046H_CVBER_CTRL, 0x1a); // 10^6 VBER measurement bits
tda1004x_write_byteI(state, TDA1004X_CONF_TS1, 7); // MPEG2 interface config tda1004x_write_byteI(state, TDA1004X_CONF_TS1, 7); // MPEG2 interface config
tda1004x_write_byteI(state, TDA1004X_CONF_TS2, 0xc0); // MPEG2 interface config tda1004x_write_byteI(state, TDA1004X_CONF_TS2, 0xc0); // MPEG2 interface config
tda1004x_write_mask(state, 0x3a, 0x80, state->config->invert_oclk << 7); tda1004x_write_mask(state, 0x3a, 0x80, state->config->invert_oclk << 7);
tda1004x_write_byteI(state, TDA10046H_CONF_TRISTATE2, 0xe1); // tristate setup
tda1004x_write_byteI(state, TDA10046H_GPIO_OUT_SEL, 0xcc); // GPIO output config
tda1004x_write_byteI(state, TDA10046H_GPIO_SELECT, 8); // GPIO select
state->initialised = 1; state->initialised = 1;
return 0; return 0;
} }
@ -851,6 +891,7 @@ static int tda1004x_set_fe(struct dvb_frontend* fe,
static int tda1004x_get_fe(struct dvb_frontend* fe, struct dvb_frontend_parameters *fe_params) static int tda1004x_get_fe(struct dvb_frontend* fe, struct dvb_frontend_parameters *fe_params)
{ {
struct tda1004x_state* state = fe->demodulator_priv; struct tda1004x_state* state = fe->demodulator_priv;
dprintk("%s\n", __FUNCTION__); dprintk("%s\n", __FUNCTION__);
// inversion status // inversion status
@ -875,16 +916,18 @@ static int tda1004x_get_fe(struct dvb_frontend* fe, struct dvb_frontend_paramete
break; break;
} }
break; break;
case TDA1004X_DEMOD_TDA10046: case TDA1004X_DEMOD_TDA10046:
switch (tda1004x_read_byte(state, TDA10046H_TIME_WREF1)) { switch (tda1004x_read_byte(state, TDA10046H_TIME_WREF1)) {
case 0x60: case 0x5c:
case 0x54:
fe_params->u.ofdm.bandwidth = BANDWIDTH_8_MHZ; fe_params->u.ofdm.bandwidth = BANDWIDTH_8_MHZ;
break; break;
case 0x6e: case 0x6a:
case 0x60:
fe_params->u.ofdm.bandwidth = BANDWIDTH_7_MHZ; fe_params->u.ofdm.bandwidth = BANDWIDTH_7_MHZ;
break; break;
case 0x80: case 0x7b:
case 0x70:
fe_params->u.ofdm.bandwidth = BANDWIDTH_6_MHZ; fe_params->u.ofdm.bandwidth = BANDWIDTH_6_MHZ;
break; break;
} }

View File

@ -20,7 +20,8 @@ config DVB_AV7110
This driver needs an external firmware. Please use the script This driver needs an external firmware. Please use the script
"<kerneldir>/Documentation/dvb/get_dvb_firmware av7110" to "<kerneldir>/Documentation/dvb/get_dvb_firmware av7110" to
download/extract it, and then copy it to /usr/lib/hotplug/firmware. download/extract it, and then copy it to /usr/lib/hotplug/firmware
or /lib/firmware (depending on configuration of firmware hotplug).
Say Y if you own such a card and want to use it. Say Y if you own such a card and want to use it.

View File

@ -133,7 +133,13 @@ static void init_av7110_av(struct av7110 *av7110)
/* remaining inits according to card and frontend type */ /* remaining inits according to card and frontend type */
av7110->analog_tuner_flags = 0; av7110->analog_tuner_flags = 0;
av7110->current_input = 0; av7110->current_input = 0;
if (i2c_writereg(av7110, 0x20, 0x00, 0x00) == 1) { if (dev->pci->subsystem_vendor == 0x13c2 && dev->pci->subsystem_device == 0x000a) {
printk("dvb-ttpci: MSP3415 audio DAC @ card %d\n",
av7110->dvb_adapter.num);
av7110->adac_type = DVB_ADAC_MSP34x5;
av7110_fw_cmd(av7110, COMTYPE_AUDIODAC, ADSwitch, 1, 0); // SPDIF on
}
else if (i2c_writereg(av7110, 0x20, 0x00, 0x00) == 1) {
printk ("dvb-ttpci: Crystal audio DAC @ card %d detected\n", printk ("dvb-ttpci: Crystal audio DAC @ card %d detected\n",
av7110->dvb_adapter.num); av7110->dvb_adapter.num);
av7110->adac_type = DVB_ADAC_CRYSTAL; av7110->adac_type = DVB_ADAC_CRYSTAL;
@ -156,10 +162,10 @@ static void init_av7110_av(struct av7110 *av7110)
else { else {
av7110->adac_type = adac; av7110->adac_type = adac;
printk("dvb-ttpci: adac type set to %d @ card %d\n", printk("dvb-ttpci: adac type set to %d @ card %d\n",
av7110->dvb_adapter.num, av7110->adac_type); av7110->adac_type, av7110->dvb_adapter.num);
} }
if (av7110->adac_type == DVB_ADAC_NONE || av7110->adac_type == DVB_ADAC_MSP) { if (av7110->adac_type == DVB_ADAC_NONE || av7110->adac_type == DVB_ADAC_MSP34x0) {
// switch DVB SCART on // switch DVB SCART on
ret = av7110_fw_cmd(av7110, COMTYPE_AUDIODAC, MainSwitch, 1, 0); ret = av7110_fw_cmd(av7110, COMTYPE_AUDIODAC, MainSwitch, 1, 0);
if (ret < 0) if (ret < 0)
@ -190,19 +196,17 @@ static void recover_arm(struct av7110 *av7110)
av7110_bootarm(av7110); av7110_bootarm(av7110);
msleep(100); msleep(100);
init_av7110_av(av7110);
/* card-specific recovery */
if (av7110->recover)
av7110->recover(av7110);
restart_feeds(av7110); restart_feeds(av7110);
av7110_fw_cmd(av7110, COMTYPE_PIDFILTER, SetIR, 1, av7110->ir_config); av7110_fw_cmd(av7110, COMTYPE_PIDFILTER, SetIR, 1, av7110->ir_config);
} }
static void arm_error(struct av7110 *av7110)
{
dprintk(4, "%p\n",av7110);
av7110->arm_errors++;
av7110->arm_ready = 0;
recover_arm(av7110);
}
static void av7110_arm_sync(struct av7110 *av7110) static void av7110_arm_sync(struct av7110 *av7110)
{ {
av7110->arm_rmmod = 1; av7110->arm_rmmod = 1;
@ -240,26 +244,22 @@ static int arm_thread(void *data)
if (down_interruptible(&av7110->dcomlock)) if (down_interruptible(&av7110->dcomlock))
break; break;
newloops = rdebi(av7110, DEBINOSWAP, STATUS_LOOPS, 0, 2); newloops = rdebi(av7110, DEBINOSWAP, STATUS_LOOPS, 0, 2);
up(&av7110->dcomlock); up(&av7110->dcomlock);
if (newloops == av7110->arm_loops) { if (newloops == av7110->arm_loops || av7110->arm_errors > 3) {
printk(KERN_ERR "dvb-ttpci: ARM crashed @ card %d\n", printk(KERN_ERR "dvb-ttpci: ARM crashed @ card %d\n",
av7110->dvb_adapter.num); av7110->dvb_adapter.num);
arm_error(av7110); recover_arm(av7110);
av7710_set_video_mode(av7110, vidmode);
init_av7110_av(av7110);
if (down_interruptible(&av7110->dcomlock)) if (down_interruptible(&av7110->dcomlock))
break; break;
newloops = rdebi(av7110, DEBINOSWAP, STATUS_LOOPS, 0, 2) - 1; newloops = rdebi(av7110, DEBINOSWAP, STATUS_LOOPS, 0, 2) - 1;
up(&av7110->dcomlock); up(&av7110->dcomlock);
} }
av7110->arm_loops = newloops; av7110->arm_loops = newloops;
av7110->arm_errors = 0;
} }
av7110->arm_thread = NULL; av7110->arm_thread = NULL;
@ -510,10 +510,6 @@ static void gpioirq(unsigned long data)
iwdebi(av7110, DEBINOSWAP, RX_BUFF, 0, 2); iwdebi(av7110, DEBINOSWAP, RX_BUFF, 0, 2);
av7110->video_size.h = h_ar & 0xfff; av7110->video_size.h = h_ar & 0xfff;
dprintk(8, "GPIO0 irq: DATA_MPEG_VIDEO_EVENT: w/h/ar = %u/%u/%u\n",
av7110->video_size.w,
av7110->video_size.h,
av7110->video_size.aspect_ratio);
event.type = VIDEO_EVENT_SIZE_CHANGED; event.type = VIDEO_EVENT_SIZE_CHANGED;
event.u.size.w = av7110->video_size.w; event.u.size.w = av7110->video_size.w;
@ -535,6 +531,11 @@ static void gpioirq(unsigned long data)
event.u.size.aspect_ratio = VIDEO_FORMAT_4_3; event.u.size.aspect_ratio = VIDEO_FORMAT_4_3;
av7110->videostate.video_format = VIDEO_FORMAT_4_3; av7110->videostate.video_format = VIDEO_FORMAT_4_3;
} }
dprintk(8, "GPIO0 irq: DATA_MPEG_VIDEO_EVENT: w/h/ar = %u/%u/%u\n",
av7110->video_size.w, av7110->video_size.h,
av7110->video_size.aspect_ratio);
dvb_video_add_event(av7110, &event); dvb_video_add_event(av7110, &event);
break; break;
} }
@ -714,6 +715,8 @@ static struct dvb_device dvbdev_osd = {
static inline int SetPIDs(struct av7110 *av7110, u16 vpid, u16 apid, u16 ttpid, static inline int SetPIDs(struct av7110 *av7110, u16 vpid, u16 apid, u16 ttpid,
u16 subpid, u16 pcrpid) u16 subpid, u16 pcrpid)
{ {
u16 aflags = 0;
dprintk(4, "%p\n", av7110); dprintk(4, "%p\n", av7110);
if (vpid == 0x1fff || apid == 0x1fff || if (vpid == 0x1fff || apid == 0x1fff ||
@ -725,8 +728,11 @@ static inline int SetPIDs(struct av7110 *av7110, u16 vpid, u16 apid, u16 ttpid,
av7110->pids[DMX_PES_PCR] = 0; av7110->pids[DMX_PES_PCR] = 0;
} }
return av7110_fw_cmd(av7110, COMTYPE_PIDFILTER, MultiPID, 5, if (av7110->audiostate.bypass_mode)
pcrpid, vpid, apid, ttpid, subpid); aflags |= 0x8000;
return av7110_fw_cmd(av7110, COMTYPE_PIDFILTER, MultiPID, 6,
pcrpid, vpid, apid, ttpid, subpid, aflags);
} }
int ChangePIDs(struct av7110 *av7110, u16 vpid, u16 apid, u16 ttpid, int ChangePIDs(struct av7110 *av7110, u16 vpid, u16 apid, u16 ttpid,
@ -1043,7 +1049,7 @@ static void restart_feeds(struct av7110 *av7110)
struct dvb_demux *dvbdmx = &av7110->demux; struct dvb_demux *dvbdmx = &av7110->demux;
struct dvb_demux_feed *feed; struct dvb_demux_feed *feed;
int mode; int mode;
int i; int i, j;
dprintk(4, "%p\n", av7110); dprintk(4, "%p\n", av7110);
@ -1051,11 +1057,22 @@ static void restart_feeds(struct av7110 *av7110)
av7110->playing = 0; av7110->playing = 0;
av7110->rec_mode = 0; av7110->rec_mode = 0;
for (i = 0; i < dvbdmx->filternum; i++) { for (i = 0; i < dvbdmx->feednum; i++) {
feed = &dvbdmx->feed[i]; feed = &dvbdmx->feed[i];
if (feed->state == DMX_STATE_GO) if (feed->state == DMX_STATE_GO) {
if (feed->type == DMX_TYPE_SEC) {
for (j = 0; j < dvbdmx->filternum; j++) {
if (dvbdmx->filter[j].type != DMX_TYPE_SEC)
continue;
if (dvbdmx->filter[j].filter.parent != &feed->feed.sec)
continue;
if (dvbdmx->filter[j].state == DMX_STATE_GO)
dvbdmx->filter[j].state = DMX_STATE_READY;
}
}
av7110_start_feed(feed); av7110_start_feed(feed);
} }
}
if (mode) if (mode)
av7110_av_start_play(av7110, mode); av7110_av_start_play(av7110, mode);
@ -1484,8 +1501,8 @@ static int get_firmware(struct av7110* av7110)
printk(KERN_ERR "dvb-ttpci: could not load firmware," printk(KERN_ERR "dvb-ttpci: could not load firmware,"
" file not found: dvb-ttpci-01.fw\n"); " file not found: dvb-ttpci-01.fw\n");
printk(KERN_ERR "dvb-ttpci: usually this should be in " printk(KERN_ERR "dvb-ttpci: usually this should be in "
" /usr/lib/hotplug/firmware\n"); "/usr/lib/hotplug/firmware or /lib/firmware\n");
printk(KERN_ERR "dvb-ttpci: and can be downloaded here" printk(KERN_ERR "dvb-ttpci: and can be downloaded from"
" http://www.linuxtv.org/download/dvb/firmware/\n"); " http://www.linuxtv.org/download/dvb/firmware/\n");
} else } else
printk(KERN_ERR "dvb-ttpci: cannot request firmware" printk(KERN_ERR "dvb-ttpci: cannot request firmware"
@ -2110,8 +2127,10 @@ static int av7110_fe_set_frontend(struct dvb_frontend* fe, struct dvb_frontend_p
struct av7110* av7110 = fe->dvb->priv; struct av7110* av7110 = fe->dvb->priv;
int ret = av7110_fe_lock_fix(av7110, 0); int ret = av7110_fe_lock_fix(av7110, 0);
if (!ret) if (!ret) {
av7110->saved_fe_params = *params;
ret = av7110->fe_set_frontend(fe, params); ret = av7110->fe_set_frontend(fe, params);
}
return ret; return ret;
} }
@ -2153,8 +2172,10 @@ static int av7110_fe_diseqc_send_master_cmd(struct dvb_frontend* fe,
struct av7110* av7110 = fe->dvb->priv; struct av7110* av7110 = fe->dvb->priv;
int ret = av7110_fe_lock_fix(av7110, 0); int ret = av7110_fe_lock_fix(av7110, 0);
if (!ret) if (!ret) {
av7110->saved_master_cmd = *cmd;
ret = av7110->fe_diseqc_send_master_cmd(fe, cmd); ret = av7110->fe_diseqc_send_master_cmd(fe, cmd);
}
return ret; return ret;
} }
@ -2163,8 +2184,10 @@ static int av7110_fe_diseqc_send_burst(struct dvb_frontend* fe, fe_sec_mini_cmd_
struct av7110* av7110 = fe->dvb->priv; struct av7110* av7110 = fe->dvb->priv;
int ret = av7110_fe_lock_fix(av7110, 0); int ret = av7110_fe_lock_fix(av7110, 0);
if (!ret) if (!ret) {
av7110->saved_minicmd = minicmd;
ret = av7110->fe_diseqc_send_burst(fe, minicmd); ret = av7110->fe_diseqc_send_burst(fe, minicmd);
}
return ret; return ret;
} }
@ -2173,8 +2196,10 @@ static int av7110_fe_set_tone(struct dvb_frontend* fe, fe_sec_tone_mode_t tone)
struct av7110* av7110 = fe->dvb->priv; struct av7110* av7110 = fe->dvb->priv;
int ret = av7110_fe_lock_fix(av7110, 0); int ret = av7110_fe_lock_fix(av7110, 0);
if (!ret) if (!ret) {
av7110->saved_tone = tone;
ret = av7110->fe_set_tone(fe, tone); ret = av7110->fe_set_tone(fe, tone);
}
return ret; return ret;
} }
@ -2183,12 +2208,14 @@ static int av7110_fe_set_voltage(struct dvb_frontend* fe, fe_sec_voltage_t volta
struct av7110* av7110 = fe->dvb->priv; struct av7110* av7110 = fe->dvb->priv;
int ret = av7110_fe_lock_fix(av7110, 0); int ret = av7110_fe_lock_fix(av7110, 0);
if (!ret) if (!ret) {
av7110->saved_voltage = voltage;
ret = av7110->fe_set_voltage(fe, voltage); ret = av7110->fe_set_voltage(fe, voltage);
}
return ret; return ret;
} }
static int av7110_fe_dishnetwork_send_legacy_command(struct dvb_frontend* fe, unsigned int cmd) static int av7110_fe_dishnetwork_send_legacy_command(struct dvb_frontend* fe, unsigned long cmd)
{ {
struct av7110* av7110 = fe->dvb->priv; struct av7110* av7110 = fe->dvb->priv;
@ -2198,6 +2225,23 @@ static int av7110_fe_dishnetwork_send_legacy_command(struct dvb_frontend* fe, un
return ret; return ret;
} }
static void dvb_s_recover(struct av7110* av7110)
{
av7110_fe_init(av7110->fe);
av7110_fe_set_voltage(av7110->fe, av7110->saved_voltage);
if (av7110->saved_master_cmd.msg_len) {
msleep(20);
av7110_fe_diseqc_send_master_cmd(av7110->fe, &av7110->saved_master_cmd);
}
msleep(20);
av7110_fe_diseqc_send_burst(av7110->fe, av7110->saved_minicmd);
msleep(20);
av7110_fe_set_tone(av7110->fe, av7110->saved_tone);
av7110_fe_set_frontend(av7110->fe, &av7110->saved_fe_params);
}
static u8 read_pwm(struct av7110* av7110) static u8 read_pwm(struct av7110* av7110)
{ {
u8 b = 0xff; u8 b = 0xff;
@ -2235,6 +2279,7 @@ static int frontend_init(struct av7110 *av7110)
av7110->fe->ops->diseqc_send_master_cmd = av7110_diseqc_send_master_cmd; av7110->fe->ops->diseqc_send_master_cmd = av7110_diseqc_send_master_cmd;
av7110->fe->ops->diseqc_send_burst = av7110_diseqc_send_burst; av7110->fe->ops->diseqc_send_burst = av7110_diseqc_send_burst;
av7110->fe->ops->set_tone = av7110_set_tone; av7110->fe->ops->set_tone = av7110_set_tone;
av7110->recover = dvb_s_recover;
break; break;
} }
@ -2244,6 +2289,7 @@ static int frontend_init(struct av7110 *av7110)
av7110->fe->ops->diseqc_send_master_cmd = av7110_diseqc_send_master_cmd; av7110->fe->ops->diseqc_send_master_cmd = av7110_diseqc_send_master_cmd;
av7110->fe->ops->diseqc_send_burst = av7110_diseqc_send_burst; av7110->fe->ops->diseqc_send_burst = av7110_diseqc_send_burst;
av7110->fe->ops->set_tone = av7110_set_tone; av7110->fe->ops->set_tone = av7110_set_tone;
av7110->recover = dvb_s_recover;
break; break;
} }
@ -2253,6 +2299,7 @@ static int frontend_init(struct av7110 *av7110)
av7110->fe->ops->diseqc_send_master_cmd = av7110_diseqc_send_master_cmd; av7110->fe->ops->diseqc_send_master_cmd = av7110_diseqc_send_master_cmd;
av7110->fe->ops->diseqc_send_burst = av7110_diseqc_send_burst; av7110->fe->ops->diseqc_send_burst = av7110_diseqc_send_burst;
av7110->fe->ops->set_tone = av7110_set_tone; av7110->fe->ops->set_tone = av7110_set_tone;
av7110->recover = dvb_s_recover;
break; break;
} }
@ -2289,6 +2336,7 @@ static int frontend_init(struct av7110 *av7110)
av7110->fe->ops->diseqc_send_master_cmd = av7110_diseqc_send_master_cmd; av7110->fe->ops->diseqc_send_master_cmd = av7110_diseqc_send_master_cmd;
av7110->fe->ops->diseqc_send_burst = av7110_diseqc_send_burst; av7110->fe->ops->diseqc_send_burst = av7110_diseqc_send_burst;
av7110->fe->ops->set_tone = av7110_set_tone; av7110->fe->ops->set_tone = av7110_set_tone;
av7110->recover = dvb_s_recover;
} }
break; break;
@ -2314,8 +2362,11 @@ static int frontend_init(struct av7110 *av7110)
case 0x000E: /* Hauppauge/TT Nexus-S rev 2.3 */ case 0x000E: /* Hauppauge/TT Nexus-S rev 2.3 */
/* ALPS BSBE1 */ /* ALPS BSBE1 */
av7110->fe = stv0299_attach(&alps_bsbe1_config, &av7110->i2c_adap); av7110->fe = stv0299_attach(&alps_bsbe1_config, &av7110->i2c_adap);
if (av7110->fe) if (av7110->fe) {
av7110->fe->ops->set_voltage = lnbp21_set_voltage; av7110->fe->ops->set_voltage = lnbp21_set_voltage;
av7110->fe->ops->dishnetwork_send_legacy_command = NULL;
av7110->recover = dvb_s_recover;
}
break; break;
} }
} }

View File

@ -98,7 +98,8 @@ struct av7110 {
int adac_type; /* audio DAC type */ int adac_type; /* audio DAC type */
#define DVB_ADAC_TI 0 #define DVB_ADAC_TI 0
#define DVB_ADAC_CRYSTAL 1 #define DVB_ADAC_CRYSTAL 1
#define DVB_ADAC_MSP 2 #define DVB_ADAC_MSP34x0 2
#define DVB_ADAC_MSP34x5 3
#define DVB_ADAC_NONE -1 #define DVB_ADAC_NONE -1
@ -228,6 +229,9 @@ struct av7110 {
struct dvb_video_events video_events; struct dvb_video_events video_events;
video_size_t video_size; video_size_t video_size;
u16 wssMode;
u16 wssData;
u32 ir_config; u32 ir_config;
u32 ir_command; u32 ir_command;
void (*ir_handler)(struct av7110 *av7110, u32 ircom); void (*ir_handler)(struct av7110 *av7110, u32 ircom);
@ -245,6 +249,15 @@ struct av7110 {
struct dvb_frontend* fe; struct dvb_frontend* fe;
fe_status_t fe_status; fe_status_t fe_status;
/* crash recovery */
void (*recover)(struct av7110* av7110);
struct dvb_frontend_parameters saved_fe_params;
fe_sec_voltage_t saved_voltage;
fe_sec_tone_mode_t saved_tone;
struct dvb_diseqc_master_cmd saved_master_cmd;
fe_sec_mini_cmd_t saved_minicmd;
int (*fe_init)(struct dvb_frontend* fe); int (*fe_init)(struct dvb_frontend* fe);
int (*fe_read_status)(struct dvb_frontend* fe, fe_status_t* status); int (*fe_read_status)(struct dvb_frontend* fe, fe_status_t* status);
int (*fe_diseqc_reset_overload)(struct dvb_frontend* fe); int (*fe_diseqc_reset_overload)(struct dvb_frontend* fe);
@ -252,7 +265,7 @@ struct av7110 {
int (*fe_diseqc_send_burst)(struct dvb_frontend* fe, fe_sec_mini_cmd_t minicmd); int (*fe_diseqc_send_burst)(struct dvb_frontend* fe, fe_sec_mini_cmd_t minicmd);
int (*fe_set_tone)(struct dvb_frontend* fe, fe_sec_tone_mode_t tone); int (*fe_set_tone)(struct dvb_frontend* fe, fe_sec_tone_mode_t tone);
int (*fe_set_voltage)(struct dvb_frontend* fe, fe_sec_voltage_t voltage); int (*fe_set_voltage)(struct dvb_frontend* fe, fe_sec_voltage_t voltage);
int (*fe_dishnetwork_send_legacy_command)(struct dvb_frontend* fe, unsigned int cmd); int (*fe_dishnetwork_send_legacy_command)(struct dvb_frontend* fe, unsigned long cmd);
int (*fe_set_frontend)(struct dvb_frontend* fe, struct dvb_frontend_parameters* params); int (*fe_set_frontend)(struct dvb_frontend* fe, struct dvb_frontend_parameters* params);
}; };

View File

@ -309,7 +309,7 @@ int av7110_set_volume(struct av7110 *av7110, int volleft, int volright)
i2c_writereg(av7110, 0x20, 0x04, volright); i2c_writereg(av7110, 0x20, 0x04, volright);
return 0; return 0;
case DVB_ADAC_MSP: case DVB_ADAC_MSP34x0:
vol = (volleft > volright) ? volleft : volright; vol = (volleft > volright) ? volleft : volright;
val = (vol * 0x73 / 255) << 8; val = (vol * 0x73 / 255) << 8;
if (vol > 0) if (vol > 0)
@ -1256,7 +1256,9 @@ static int dvb_audio_ioctl(struct inode *inode, struct file *file,
break; break;
case AUDIO_SET_BYPASS_MODE: case AUDIO_SET_BYPASS_MODE:
if (FW_VERSION(av7110->arm_app) < 0x2621)
ret = -EINVAL; ret = -EINVAL;
av7110->audiostate.bypass_mode = (int)arg;
break; break;
case AUDIO_CHANNEL_SELECT: case AUDIO_CHANNEL_SELECT:
@ -1295,7 +1297,11 @@ static int dvb_audio_ioctl(struct inode *inode, struct file *file,
break; break;
case AUDIO_GET_CAPABILITIES: case AUDIO_GET_CAPABILITIES:
*(int *)parg = AUDIO_CAP_LPCM | AUDIO_CAP_MP1 | AUDIO_CAP_MP2; if (FW_VERSION(av7110->arm_app) < 0x2621)
*(unsigned int *)parg = AUDIO_CAP_LPCM | AUDIO_CAP_MP1 | AUDIO_CAP_MP2;
else
*(unsigned int *)parg = AUDIO_CAP_LPCM | AUDIO_CAP_DTS | AUDIO_CAP_AC3 |
AUDIO_CAP_MP1 | AUDIO_CAP_MP2;
break; break;
case AUDIO_CLEAR_BUFFER: case AUDIO_CLEAR_BUFFER:

View File

@ -230,6 +230,8 @@ int av7110_bootarm(struct av7110 *av7110)
dprintk(4, "%p\n", av7110); dprintk(4, "%p\n", av7110);
av7110->arm_ready = 0;
saa7146_setgpio(dev, RESET_LINE, SAA7146_GPIO_OUTLO); saa7146_setgpio(dev, RESET_LINE, SAA7146_GPIO_OUTLO);
/* Disable DEBI and GPIO irq */ /* Disable DEBI and GPIO irq */
@ -361,6 +363,7 @@ static int __av7110_send_fw_cmd(struct av7110 *av7110, u16* buf, int length)
break; break;
if (err) { if (err) {
printk(KERN_ERR "dvb-ttpci: %s(): timeout waiting for COMMAND idle\n", __FUNCTION__); printk(KERN_ERR "dvb-ttpci: %s(): timeout waiting for COMMAND idle\n", __FUNCTION__);
av7110->arm_errors++;
return -ETIMEDOUT; return -ETIMEDOUT;
} }
msleep(1); msleep(1);

View File

@ -167,7 +167,8 @@ enum av7110_encoder_command {
LoadVidCode, LoadVidCode,
SetMonitorType, SetMonitorType,
SetPanScanType, SetPanScanType,
SetFreezeMode SetFreezeMode,
SetWSSConfig
}; };
enum av7110_rec_play_state { enum av7110_rec_play_state {

View File

@ -17,6 +17,8 @@ static int av_cnt;
static struct av7110 *av_list[4]; static struct av7110 *av_list[4];
static struct input_dev *input_dev; static struct input_dev *input_dev;
static u8 delay_timer_finished;
static u16 key_map [256] = { static u16 key_map [256] = {
KEY_0, KEY_1, KEY_2, KEY_3, KEY_4, KEY_5, KEY_6, KEY_7, KEY_0, KEY_1, KEY_2, KEY_3, KEY_4, KEY_5, KEY_6, KEY_7,
KEY_8, KEY_9, KEY_BACK, 0, KEY_POWER, KEY_MUTE, 0, KEY_INFO, KEY_8, KEY_9, KEY_BACK, 0, KEY_POWER, KEY_MUTE, 0, KEY_INFO,
@ -112,13 +114,16 @@ static void av7110_emit_key(unsigned long parm)
if (timer_pending(&keyup_timer)) { if (timer_pending(&keyup_timer)) {
del_timer(&keyup_timer); del_timer(&keyup_timer);
if (keyup_timer.data != keycode || new_toggle != old_toggle) { if (keyup_timer.data != keycode || new_toggle != old_toggle) {
delay_timer_finished = 0;
input_event(input_dev, EV_KEY, keyup_timer.data, !!0); input_event(input_dev, EV_KEY, keyup_timer.data, !!0);
input_event(input_dev, EV_KEY, keycode, !0); input_event(input_dev, EV_KEY, keycode, !0);
} else } else
if (delay_timer_finished)
input_event(input_dev, EV_KEY, keycode, 2); input_event(input_dev, EV_KEY, keycode, 2);
} else {
} else delay_timer_finished = 0;
input_event(input_dev, EV_KEY, keycode, !0); input_event(input_dev, EV_KEY, keycode, !0);
}
keyup_timer.expires = jiffies + UP_TIMEOUT; keyup_timer.expires = jiffies + UP_TIMEOUT;
keyup_timer.data = keycode; keyup_timer.data = keycode;
@ -145,7 +150,8 @@ static void input_register_keys(void)
static void input_repeat_key(unsigned long data) static void input_repeat_key(unsigned long data)
{ {
/* dummy routine to disable autorepeat in the input driver */ /* called by the input driver after rep[REP_DELAY] ms */
delay_timer_finished = 1;
} }

View File

@ -490,6 +490,58 @@ static int av7110_ioctl(struct saa7146_fh *fh, unsigned int cmd, void *arg)
dprintk(2, "VIDIOC_S_AUDIO: %d\n", a->index); dprintk(2, "VIDIOC_S_AUDIO: %d\n", a->index);
break; break;
} }
case VIDIOC_G_SLICED_VBI_CAP:
{
struct v4l2_sliced_vbi_cap *cap = arg;
dprintk(2, "VIDIOC_G_SLICED_VBI_CAP\n");
memset(cap, 0, sizeof *cap);
if (FW_VERSION(av7110->arm_app) >= 0x2623) {
cap->service_set = V4L2_SLICED_WSS_625;
cap->service_lines[0][23] = V4L2_SLICED_WSS_625;
}
break;
}
case VIDIOC_G_FMT:
{
struct v4l2_format *f = arg;
dprintk(2, "VIDIOC_G_FMT:\n");
if (f->type != V4L2_BUF_TYPE_SLICED_VBI_OUTPUT ||
FW_VERSION(av7110->arm_app) < 0x2623)
return -EAGAIN; /* handled by core driver */
memset(&f->fmt.sliced, 0, sizeof f->fmt.sliced);
if (av7110->wssMode) {
f->fmt.sliced.service_set = V4L2_SLICED_WSS_625;
f->fmt.sliced.service_lines[0][23] = V4L2_SLICED_WSS_625;
f->fmt.sliced.io_size = sizeof (struct v4l2_sliced_vbi_data);
}
break;
}
case VIDIOC_S_FMT:
{
struct v4l2_format *f = arg;
dprintk(2, "VIDIOC_S_FMT\n");
if (f->type != V4L2_BUF_TYPE_SLICED_VBI_OUTPUT ||
FW_VERSION(av7110->arm_app) < 0x2623)
return -EAGAIN; /* handled by core driver */
if (f->fmt.sliced.service_set != V4L2_SLICED_WSS_625 &&
f->fmt.sliced.service_lines[0][23] != V4L2_SLICED_WSS_625) {
memset(&f->fmt.sliced, 0, sizeof f->fmt.sliced);
/* WSS controlled by firmware */
av7110->wssMode = 0;
av7110->wssData = 0;
return av7110_fw_cmd(av7110, COMTYPE_ENCODER,
SetWSSConfig, 1, 0);
} else {
memset(&f->fmt.sliced, 0, sizeof f->fmt.sliced);
f->fmt.sliced.service_set = V4L2_SLICED_WSS_625;
f->fmt.sliced.service_lines[0][23] = V4L2_SLICED_WSS_625;
f->fmt.sliced.io_size = sizeof (struct v4l2_sliced_vbi_data);
/* WSS controlled by userspace */
av7110->wssMode = 1;
av7110->wssData = 0;
}
break;
}
default: default:
printk("no such ioctl\n"); printk("no such ioctl\n");
return -ENOIOCTLCMD; return -ENOIOCTLCMD;
@ -497,6 +549,46 @@ static int av7110_ioctl(struct saa7146_fh *fh, unsigned int cmd, void *arg)
return 0; return 0;
} }
static int av7110_vbi_reset(struct inode *inode, struct file *file)
{
struct saa7146_fh *fh = file->private_data;
struct saa7146_dev *dev = fh->dev;
struct av7110 *av7110 = (struct av7110*) dev->ext_priv;
dprintk(2, "%s\n", __FUNCTION__);
av7110->wssMode = 0;
av7110->wssData = 0;
if (FW_VERSION(av7110->arm_app) < 0x2623)
return 0;
else
return av7110_fw_cmd(av7110, COMTYPE_ENCODER, SetWSSConfig, 1, 0);
}
static ssize_t av7110_vbi_write(struct file *file, const char __user *data, size_t count, loff_t *ppos)
{
struct saa7146_fh *fh = file->private_data;
struct saa7146_dev *dev = fh->dev;
struct av7110 *av7110 = (struct av7110*) dev->ext_priv;
struct v4l2_sliced_vbi_data d;
int rc;
dprintk(2, "%s\n", __FUNCTION__);
if (FW_VERSION(av7110->arm_app) < 0x2623 || !av7110->wssMode || count != sizeof d)
return -EINVAL;
if (copy_from_user(&d, data, count))
return -EFAULT;
if ((d.id != 0 && d.id != V4L2_SLICED_WSS_625) || d.field != 0 || d.line != 23)
return -EINVAL;
if (d.id) {
av7110->wssData = ((d.data[1] << 8) & 0x3f00) | d.data[0];
rc = av7110_fw_cmd(av7110, COMTYPE_ENCODER, SetWSSConfig,
2, 1, av7110->wssData);
} else {
av7110->wssData = 0;
rc = av7110_fw_cmd(av7110, COMTYPE_ENCODER, SetWSSConfig, 1, 0);
}
return (rc < 0) ? rc : count;
}
/**************************************************************************** /****************************************************************************
* INITIALIZATION * INITIALIZATION
@ -512,6 +604,9 @@ static struct saa7146_extension_ioctls ioctls[] = {
{ VIDIOC_S_TUNER, SAA7146_EXCLUSIVE }, { VIDIOC_S_TUNER, SAA7146_EXCLUSIVE },
{ VIDIOC_G_AUDIO, SAA7146_EXCLUSIVE }, { VIDIOC_G_AUDIO, SAA7146_EXCLUSIVE },
{ VIDIOC_S_AUDIO, SAA7146_EXCLUSIVE }, { VIDIOC_S_AUDIO, SAA7146_EXCLUSIVE },
{ VIDIOC_G_SLICED_VBI_CAP, SAA7146_EXCLUSIVE },
{ VIDIOC_G_FMT, SAA7146_BEFORE },
{ VIDIOC_S_FMT, SAA7146_BEFORE },
{ 0, 0 } { 0, 0 }
}; };
@ -587,7 +682,7 @@ int av7110_init_analog_module(struct av7110 *av7110)
printk("dvb-ttpci: DVB-C analog module @ card %d detected, initializing MSP3400\n", printk("dvb-ttpci: DVB-C analog module @ card %d detected, initializing MSP3400\n",
av7110->dvb_adapter.num); av7110->dvb_adapter.num);
av7110->adac_type = DVB_ADAC_MSP; av7110->adac_type = DVB_ADAC_MSP34x0;
msleep(100); // the probing above resets the msp... msleep(100); // the probing above resets the msp...
msp_readreg(av7110, MSP_RD_DSP, 0x001e, &version1); msp_readreg(av7110, MSP_RD_DSP, 0x001e, &version1);
msp_readreg(av7110, MSP_RD_DSP, 0x001f, &version2); msp_readreg(av7110, MSP_RD_DSP, 0x001f, &version2);
@ -692,13 +787,12 @@ int av7110_init_v4l(struct av7110 *av7110)
saa7146_vv_release(dev); saa7146_vv_release(dev);
return -ENODEV; return -ENODEV;
} }
if (av7110->analog_tuner_flags) {
if (saa7146_register_device(&av7110->vbi_dev, dev, "av7110", VFL_TYPE_VBI)) { if (saa7146_register_device(&av7110->vbi_dev, dev, "av7110", VFL_TYPE_VBI)) {
ERR(("cannot register vbi v4l2 device. skipping.\n")); ERR(("cannot register vbi v4l2 device. skipping.\n"));
} else { } else {
if (av7110->analog_tuner_flags)
av7110->analog_tuner_flags |= ANALOG_TUNER_VBI; av7110->analog_tuner_flags |= ANALOG_TUNER_VBI;
} }
}
return 0; return 0;
} }
@ -778,7 +872,7 @@ static int std_callback(struct saa7146_dev* dev, struct saa7146_standard *std)
static struct saa7146_ext_vv av7110_vv_data_st = { static struct saa7146_ext_vv av7110_vv_data_st = {
.inputs = 1, .inputs = 1,
.audios = 1, .audios = 1,
.capabilities = 0, .capabilities = V4L2_CAP_SLICED_VBI_OUTPUT,
.flags = 0, .flags = 0,
.stds = &standard[0], .stds = &standard[0],
@ -787,12 +881,16 @@ static struct saa7146_ext_vv av7110_vv_data_st = {
.ioctls = &ioctls[0], .ioctls = &ioctls[0],
.ioctl = av7110_ioctl, .ioctl = av7110_ioctl,
.vbi_fops.open = av7110_vbi_reset,
.vbi_fops.release = av7110_vbi_reset,
.vbi_fops.write = av7110_vbi_write,
}; };
static struct saa7146_ext_vv av7110_vv_data_c = { static struct saa7146_ext_vv av7110_vv_data_c = {
.inputs = 1, .inputs = 1,
.audios = 1, .audios = 1,
.capabilities = V4L2_CAP_TUNER | V4L2_CAP_VBI_CAPTURE, .capabilities = V4L2_CAP_TUNER | V4L2_CAP_VBI_CAPTURE | V4L2_CAP_SLICED_VBI_OUTPUT,
.flags = SAA7146_USE_PORT_B_FOR_VBI, .flags = SAA7146_USE_PORT_B_FOR_VBI,
.stds = &standard[0], .stds = &standard[0],
@ -801,5 +899,9 @@ static struct saa7146_ext_vv av7110_vv_data_c = {
.ioctls = &ioctls[0], .ioctls = &ioctls[0],
.ioctl = av7110_ioctl, .ioctl = av7110_ioctl,
.vbi_fops.open = av7110_vbi_reset,
.vbi_fops.release = av7110_vbi_reset,
.vbi_fops.write = av7110_vbi_write,
}; };

View File

@ -127,7 +127,7 @@ static int ciintf_read_attribute_mem(struct dvb_ca_en50221 *ca, int slot, int ad
saa7146_setgpio(budget_av->budget.dev, 1, SAA7146_GPIO_OUTHI); saa7146_setgpio(budget_av->budget.dev, 1, SAA7146_GPIO_OUTHI);
udelay(1); udelay(1);
result = ttpci_budget_debiread(&budget_av->budget, DEBICICAM, address & 0xfff, 1, 0, 0); result = ttpci_budget_debiread(&budget_av->budget, DEBICICAM, address & 0xfff, 1, 0, 1);
if (result == -ETIMEDOUT) if (result == -ETIMEDOUT)
budget_av->slot_status = 0; budget_av->slot_status = 0;
@ -145,7 +145,7 @@ static int ciintf_write_attribute_mem(struct dvb_ca_en50221 *ca, int slot, int a
saa7146_setgpio(budget_av->budget.dev, 1, SAA7146_GPIO_OUTHI); saa7146_setgpio(budget_av->budget.dev, 1, SAA7146_GPIO_OUTHI);
udelay(1); udelay(1);
result = ttpci_budget_debiwrite(&budget_av->budget, DEBICICAM, address & 0xfff, 1, value, 0, 0); result = ttpci_budget_debiwrite(&budget_av->budget, DEBICICAM, address & 0xfff, 1, value, 0, 1);
if (result == -ETIMEDOUT) if (result == -ETIMEDOUT)
budget_av->slot_status = 0; budget_av->slot_status = 0;
@ -192,7 +192,7 @@ static int ciintf_slot_reset(struct dvb_ca_en50221 *ca, int slot)
{ {
struct budget_av *budget_av = (struct budget_av *) ca->data; struct budget_av *budget_av = (struct budget_av *) ca->data;
struct saa7146_dev *saa = budget_av->budget.dev; struct saa7146_dev *saa = budget_av->budget.dev;
int timeout = 500; // 5 seconds (4.4.6 Ready) int timeout = 50; // 5 seconds (4.4.6 Ready)
if (slot != 0) if (slot != 0)
return -EINVAL; return -EINVAL;
@ -256,19 +256,37 @@ static int ciintf_poll_slot_status(struct dvb_ca_en50221 *ca, int slot, int open
{ {
struct budget_av *budget_av = (struct budget_av *) ca->data; struct budget_av *budget_av = (struct budget_av *) ca->data;
struct saa7146_dev *saa = budget_av->budget.dev; struct saa7146_dev *saa = budget_av->budget.dev;
int cam_present = 0;
if (slot != 0) if (slot != 0)
return -EINVAL; return -EINVAL;
if (!budget_av->slot_status) { if (!budget_av->slot_status)
{
// first of all test the card detect line
saa7146_setgpio(saa, 3, SAA7146_GPIO_INPUT); saa7146_setgpio(saa, 3, SAA7146_GPIO_INPUT);
udelay(1); udelay(1);
if (saa7146_read(saa, PSR) & MASK_06) if (saa7146_read(saa, PSR) & MASK_06)
{ {
cam_present = 1;
}
saa7146_setgpio(saa, 3, SAA7146_GPIO_OUTLO);
// that is unreliable however, so try and read from IO memory
if (!cam_present)
{
saa7146_setgpio(budget_av->budget.dev, 1, SAA7146_GPIO_OUTLO);
if (ttpci_budget_debiread(&budget_av->budget, DEBICICAM, 0, 1, 0, 1) != -ETIMEDOUT)
{
cam_present = 1;
}
}
// did we find something?
if (cam_present) {
printk(KERN_INFO "budget-av: cam inserted\n"); printk(KERN_INFO "budget-av: cam inserted\n");
budget_av->slot_status = 1; budget_av->slot_status = 1;
} }
saa7146_setgpio(saa, 3, SAA7146_GPIO_OUTLO);
} else if (!open) { } else if (!open) {
saa7146_setgpio(budget_av->budget.dev, 1, SAA7146_GPIO_OUTLO); saa7146_setgpio(budget_av->budget.dev, 1, SAA7146_GPIO_OUTLO);
if (ttpci_budget_debiread(&budget_av->budget, DEBICICAM, 0, 1, 0, 1) == -ETIMEDOUT) if (ttpci_budget_debiread(&budget_av->budget, DEBICICAM, 0, 1, 0, 1) == -ETIMEDOUT)
@ -484,6 +502,140 @@ static int philips_su1278_ty_ci_pll_set(struct dvb_frontend *fe,
return 0; return 0;
} }
#define MIN2(a,b) ((a) < (b) ? (a) : (b))
#define MIN3(a,b,c) MIN2(MIN2(a,b),c)
static int philips_su1278sh2_tua6100_pll_set(struct dvb_frontend *fe,
struct i2c_adapter *i2c,
struct dvb_frontend_parameters *params)
{
u8 reg0 [2] = { 0x00, 0x00 };
u8 reg1 [4] = { 0x01, 0x00, 0x00, 0x00 };
u8 reg2 [3] = { 0x02, 0x00, 0x00 };
int _fband;
int first_ZF;
int R, A, N, P, M;
struct i2c_msg msg = {.addr = 0x60,.flags = 0,.buf = NULL,.len = 0 };
int freq = params->frequency;
first_ZF = (freq) / 1000;
if (abs(MIN2(abs(first_ZF-1190),abs(first_ZF-1790))) <
abs(MIN3(abs(first_ZF-1202),abs(first_ZF-1542),abs(first_ZF-1890))))
_fband = 2;
else
_fband = 3;
if (_fband == 2) {
if (((first_ZF >= 950) && (first_ZF < 1350)) ||
((first_ZF >= 1430) && (first_ZF < 1950)))
reg0[1] = 0x07;
else if (((first_ZF >= 1350) && (first_ZF < 1430)) ||
((first_ZF >= 1950) && (first_ZF < 2150)))
reg0[1] = 0x0B;
}
if(_fband == 3) {
if (((first_ZF >= 950) && (first_ZF < 1350)) ||
((first_ZF >= 1455) && (first_ZF < 1950)))
reg0[1] = 0x07;
else if (((first_ZF >= 1350) && (first_ZF < 1420)) ||
((first_ZF >= 1950) && (first_ZF < 2150)))
reg0[1] = 0x0B;
else if ((first_ZF >= 1420) && (first_ZF < 1455))
reg0[1] = 0x0F;
}
if (first_ZF > 1525)
reg1[1] |= 0x80;
else
reg1[1] &= 0x7F;
if (_fband == 2) {
if (first_ZF > 1430) { /* 1430MHZ */
reg1[1] &= 0xCF; /* N2 */
reg2[1] &= 0xCF; /* R2 */
reg2[1] |= 0x10;
} else {
reg1[1] &= 0xCF; /* N2 */
reg1[1] |= 0x20;
reg2[1] &= 0xCF; /* R2 */
reg2[1] |= 0x10;
}
}
if (_fband == 3) {
if ((first_ZF >= 1455) &&
(first_ZF < 1630)) {
reg1[1] &= 0xCF; /* N2 */
reg1[1] |= 0x20;
reg2[1] &= 0xCF; /* R2 */
} else {
if (first_ZF < 1455) {
reg1[1] &= 0xCF; /* N2 */
reg1[1] |= 0x20;
reg2[1] &= 0xCF; /* R2 */
reg2[1] |= 0x10;
} else {
if (first_ZF >= 1630) {
reg1[1] &= 0xCF; /* N2 */
reg2[1] &= 0xCF; /* R2 */
reg2[1] |= 0x10;
}
}
}
}
/* set ports, enable P0 for symbol rates > 4Ms/s */
if (params->u.qpsk.symbol_rate >= 4000000)
reg1[1] |= 0x0c;
else
reg1[1] |= 0x04;
reg2[1] |= 0x0c;
R = 64;
A = 64;
P = 64; //32
M = (freq * R) / 4; /* in Mhz */
N = (M - A * 1000) / (P * 1000);
reg1[1] |= (N >> 9) & 0x03;
reg1[2] = (N >> 1) & 0xff;
reg1[3] = (N << 7) & 0x80;
reg2[1] |= (R >> 8) & 0x03;
reg2[2] = R & 0xFF; /* R */
reg1[3] |= A & 0x7f; /* A */
if (P == 64)
reg1[1] |= 0x40; /* Prescaler 64/65 */
reg0[1] |= 0x03;
/* already enabled - do not reenable i2c repeater or TX fails */
msg.buf = reg0;
msg.len = sizeof(reg0);
if (i2c_transfer(i2c, &msg, 1) != 1)
return -EIO;
stv0299_enable_plli2c(fe);
msg.buf = reg1;
msg.len = sizeof(reg1);
if (i2c_transfer(i2c, &msg, 1) != 1)
return -EIO;
stv0299_enable_plli2c(fe);
msg.buf = reg2;
msg.len = sizeof(reg2);
if (i2c_transfer(i2c, &msg, 1) != 1)
return -EIO;
return 0;
}
static u8 typhoon_cinergy1200s_inittab[] = { static u8 typhoon_cinergy1200s_inittab[] = {
0x01, 0x15, 0x01, 0x15,
0x02, 0x30, 0x02, 0x30,
@ -553,6 +705,18 @@ static struct stv0299_config cinergy_1200s_config = {
.pll_set = philips_su1278_ty_ci_pll_set, .pll_set = philips_su1278_ty_ci_pll_set,
}; };
static struct stv0299_config cinergy_1200s_1894_0010_config = {
.demod_address = 0x68,
.inittab = typhoon_cinergy1200s_inittab,
.mclk = 88000000UL,
.invert = 1,
.skip_reinit = 0,
.lock_output = STV0229_LOCKOUTPUT_1,
.volt13_op0_op1 = STV0299_VOLT13_OP0,
.min_delay_ms = 100,
.set_symbol_rate = philips_su1278_ty_ci_set_symbol_rate,
.pll_set = philips_su1278sh2_tua6100_pll_set,
};
static int philips_cu1216_pll_set(struct dvb_frontend *fe, struct dvb_frontend_parameters *params) static int philips_cu1216_pll_set(struct dvb_frontend *fe, struct dvb_frontend_parameters *params)
{ {
@ -749,6 +913,15 @@ static void frontend_init(struct budget_av *budget_av)
switch (saa->pci->subsystem_device) { switch (saa->pci->subsystem_device) {
case SUBID_DVBS_KNC1: case SUBID_DVBS_KNC1:
if (saa->pci->subsystem_vendor == 0x1894) {
fe = stv0299_attach(&cinergy_1200s_1894_0010_config,
&budget_av->budget.i2c_adap);
} else {
fe = stv0299_attach(&typhoon_config,
&budget_av->budget.i2c_adap);
}
break;
case SUBID_DVBS_KNC1_PLUS: case SUBID_DVBS_KNC1_PLUS:
case SUBID_DVBS_TYPHOON: case SUBID_DVBS_TYPHOON:
fe = stv0299_attach(&typhoon_config, fe = stv0299_attach(&typhoon_config,
@ -1003,6 +1176,7 @@ MAKE_BUDGET_INFO(cin1200t, "Terratec Cinergy 1200 DVB-T", BUDGET_CIN1200T);
static struct pci_device_id pci_tbl[] = { static struct pci_device_id pci_tbl[] = {
MAKE_EXTENSION_PCI(knc1s, 0x1131, 0x4f56), MAKE_EXTENSION_PCI(knc1s, 0x1131, 0x4f56),
MAKE_EXTENSION_PCI(knc1s, 0x1131, 0x0010), MAKE_EXTENSION_PCI(knc1s, 0x1131, 0x0010),
MAKE_EXTENSION_PCI(knc1s, 0x1894, 0x0010),
MAKE_EXTENSION_PCI(knc1sp, 0x1131, 0x0011), MAKE_EXTENSION_PCI(knc1sp, 0x1131, 0x0011),
MAKE_EXTENSION_PCI(knc1c, 0x1894, 0x0020), MAKE_EXTENSION_PCI(knc1c, 0x1894, 0x0020),
MAKE_EXTENSION_PCI(knc1cp, 0x1894, 0x0021), MAKE_EXTENSION_PCI(knc1cp, 0x1894, 0x0021),

View File

@ -404,9 +404,7 @@ int ttpci_budget_init(struct budget *budget, struct saa7146_dev *dev,
tasklet_init(&budget->vpe_tasklet, vpeirq, (unsigned long) budget); tasklet_init(&budget->vpe_tasklet, vpeirq, (unsigned long) budget);
/* frontend power on */ /* frontend power on */
if (bi->type == BUDGET_FS_ACTIVY) if (bi->type != BUDGET_FS_ACTIVY)
saa7146_setgpio(dev, 1, SAA7146_GPIO_OUTHI);
else
saa7146_setgpio(dev, 2, SAA7146_GPIO_OUTHI); saa7146_setgpio(dev, 2, SAA7146_GPIO_OUTHI);
if (budget_register(budget) == 0) { if (budget_register(budget) == 0) {

View File

@ -112,6 +112,7 @@ static int SendDiSEqCMsg (struct budget *budget, int len, u8 *msg, unsigned long
* Routines for the Fujitsu Siemens Activy budget card * Routines for the Fujitsu Siemens Activy budget card
* 22 kHz tone and DiSEqC are handled by the frontend. * 22 kHz tone and DiSEqC are handled by the frontend.
* Voltage must be set here. * Voltage must be set here.
* GPIO 1: LNBP EN, GPIO 2: LNBP VSEL
*/ */
static int SetVoltage_Activy (struct budget *budget, fe_sec_voltage_t voltage) static int SetVoltage_Activy (struct budget *budget, fe_sec_voltage_t voltage)
{ {
@ -121,11 +122,16 @@ static int SetVoltage_Activy (struct budget *budget, fe_sec_voltage_t voltage)
switch (voltage) { switch (voltage) {
case SEC_VOLTAGE_13: case SEC_VOLTAGE_13:
saa7146_setgpio(dev, 1, SAA7146_GPIO_OUTHI);
saa7146_setgpio(dev, 2, SAA7146_GPIO_OUTLO); saa7146_setgpio(dev, 2, SAA7146_GPIO_OUTLO);
break; break;
case SEC_VOLTAGE_18: case SEC_VOLTAGE_18:
saa7146_setgpio(dev, 1, SAA7146_GPIO_OUTHI);
saa7146_setgpio(dev, 2, SAA7146_GPIO_OUTHI); saa7146_setgpio(dev, 2, SAA7146_GPIO_OUTHI);
break; break;
case SEC_VOLTAGE_OFF:
saa7146_setgpio(dev, 1, SAA7146_GPIO_OUTLO);
break;
default: default:
return -EINVAL; return -EINVAL;
} }
@ -206,7 +212,7 @@ static int lnbp21_set_voltage(struct dvb_frontend* fe, fe_sec_voltage_t voltage)
return 0; return 0;
} }
static int lnbp21_enable_high_lnb_voltage(struct dvb_frontend* fe, int arg) static int lnbp21_enable_high_lnb_voltage(struct dvb_frontend* fe, long arg)
{ {
struct budget* budget = (struct budget*) fe->dvb->priv; struct budget* budget = (struct budget*) fe->dvb->priv;
u8 buf; u8 buf;
@ -580,6 +586,7 @@ static void frontend_init(struct budget *budget)
if (budget->dvb_frontend) { if (budget->dvb_frontend) {
budget->dvb_frontend->ops->set_voltage = lnbp21_set_voltage; budget->dvb_frontend->ops->set_voltage = lnbp21_set_voltage;
budget->dvb_frontend->ops->enable_high_lnb_voltage = lnbp21_enable_high_lnb_voltage; budget->dvb_frontend->ops->enable_high_lnb_voltage = lnbp21_enable_high_lnb_voltage;
budget->dvb_frontend->ops->dishnetwork_send_legacy_command = NULL;
if (lnbp21_init(budget)) { if (lnbp21_init(budget)) {
printk("%s: No LNBP21 found!\n", __FUNCTION__); printk("%s: No LNBP21 found!\n", __FUNCTION__);
goto error_out; goto error_out;
@ -624,7 +631,7 @@ static void frontend_init(struct budget *budget)
budget->dvb_frontend = stv0299_attach(&alps_bsru6_config, &budget->i2c_adap); budget->dvb_frontend = stv0299_attach(&alps_bsru6_config, &budget->i2c_adap);
if (budget->dvb_frontend) { if (budget->dvb_frontend) {
budget->dvb_frontend->ops->set_voltage = siemens_budget_set_voltage; budget->dvb_frontend->ops->set_voltage = siemens_budget_set_voltage;
break; budget->dvb_frontend->ops->dishnetwork_send_legacy_command = NULL;
} }
break; break;
@ -632,7 +639,7 @@ static void frontend_init(struct budget *budget)
budget->dvb_frontend = tda8083_attach(&grundig_29504_451_config, &budget->i2c_adap); budget->dvb_frontend = tda8083_attach(&grundig_29504_451_config, &budget->i2c_adap);
if (budget->dvb_frontend) { if (budget->dvb_frontend) {
budget->dvb_frontend->ops->set_voltage = siemens_budget_set_voltage; budget->dvb_frontend->ops->set_voltage = siemens_budget_set_voltage;
break; budget->dvb_frontend->ops->dishnetwork_send_legacy_command = NULL;
} }
break; break;

View File

@ -16,6 +16,7 @@ config DVB_TTUSB_DEC
"<kerneldir>/Documentation/dvb/get_dvb_firmware dec2000t", "<kerneldir>/Documentation/dvb/get_dvb_firmware dec2000t",
"<kerneldir>/Documentation/dvb/get_dvb_firmware dec2540t", "<kerneldir>/Documentation/dvb/get_dvb_firmware dec2540t",
"<kerneldir>/Documentation/dvb/get_dvb_firmware dec3000s", "<kerneldir>/Documentation/dvb/get_dvb_firmware dec3000s",
download/extract them, and then copy them to /usr/lib/hotplug/firmware. download/extract them, and then copy them to /usr/lib/hotplug/firmware
or /lib/firmware (depending on configuration of firmware hotplug).
Say Y if you own such a device and want to use it. Say Y if you own such a device and want to use it.

View File

@ -369,7 +369,7 @@ static int ttusb_dec_get_stb_state (struct ttusb_dec *dec, unsigned int *mode,
static int ttusb_dec_audio_pes2ts_cb(void *priv, unsigned char *data) static int ttusb_dec_audio_pes2ts_cb(void *priv, unsigned char *data)
{ {
struct ttusb_dec *dec = (struct ttusb_dec *)priv; struct ttusb_dec *dec = priv;
dec->audio_filter->feed->cb.ts(data, 188, NULL, 0, dec->audio_filter->feed->cb.ts(data, 188, NULL, 0,
&dec->audio_filter->feed->feed.ts, &dec->audio_filter->feed->feed.ts,
@ -380,7 +380,7 @@ static int ttusb_dec_audio_pes2ts_cb(void *priv, unsigned char *data)
static int ttusb_dec_video_pes2ts_cb(void *priv, unsigned char *data) static int ttusb_dec_video_pes2ts_cb(void *priv, unsigned char *data)
{ {
struct ttusb_dec *dec = (struct ttusb_dec *)priv; struct ttusb_dec *dec = priv;
dec->video_filter->feed->cb.ts(data, 188, NULL, 0, dec->video_filter->feed->cb.ts(data, 188, NULL, 0,
&dec->video_filter->feed->feed.ts, &dec->video_filter->feed->feed.ts,
@ -965,8 +965,8 @@ static int ttusb_dec_start_ts_feed(struct dvb_demux_feed *dvbdmxfeed)
case DMX_TS_PES_TELETEXT: case DMX_TS_PES_TELETEXT:
dec->pid[DMX_PES_TELETEXT] = dvbdmxfeed->pid; dec->pid[DMX_PES_TELETEXT] = dvbdmxfeed->pid;
dprintk(" pes_type: DMX_TS_PES_TELETEXT\n"); dprintk(" pes_type: DMX_TS_PES_TELETEXT(not supported)\n");
break; return -ENOSYS;
case DMX_TS_PES_PCR: case DMX_TS_PES_PCR:
dprintk(" pes_type: DMX_TS_PES_PCR\n"); dprintk(" pes_type: DMX_TS_PES_PCR\n");
@ -975,8 +975,8 @@ static int ttusb_dec_start_ts_feed(struct dvb_demux_feed *dvbdmxfeed)
break; break;
case DMX_TS_PES_OTHER: case DMX_TS_PES_OTHER:
dprintk(" pes_type: DMX_TS_PES_OTHER\n"); dprintk(" pes_type: DMX_TS_PES_OTHER(not supported)\n");
break; return -ENOSYS;
default: default:
dprintk(" pes_type: unknown (%d)\n", dvbdmxfeed->pes_type); dprintk(" pes_type: unknown (%d)\n", dvbdmxfeed->pes_type);
@ -1209,7 +1209,6 @@ static int ttusb_init_rc(struct ttusb_dec *dec)
if (usb_submit_urb(dec->irq_urb, GFP_KERNEL)) if (usb_submit_urb(dec->irq_urb, GFP_KERNEL))
printk("%s: usb_submit_urb failed\n",__FUNCTION__); printk("%s: usb_submit_urb failed\n",__FUNCTION__);
/* enable irq pipe */ /* enable irq pipe */
ttusb_dec_send_command(dec,0xb0,sizeof(b),b,NULL,NULL); ttusb_dec_send_command(dec,0xb0,sizeof(b),b,NULL,NULL);
@ -1395,6 +1394,7 @@ static int ttusb_dec_init_stb(struct ttusb_dec *dec)
/* We can't trust the USB IDs that some firmwares /* We can't trust the USB IDs that some firmwares
give the box */ give the box */
switch (model) { switch (model) {
case 0x00070001:
case 0x00070008: case 0x00070008:
case 0x0007000c: case 0x0007000c:
ttusb_dec_set_model(dec, TTUSB_DEC3000S); ttusb_dec_set_model(dec, TTUSB_DEC3000S);
@ -1588,7 +1588,7 @@ static int fe_send_command(struct dvb_frontend* fe, const u8 command,
int param_length, const u8 params[], int param_length, const u8 params[],
int *result_length, u8 cmd_result[]) int *result_length, u8 cmd_result[])
{ {
struct ttusb_dec* dec = (struct ttusb_dec*) fe->dvb->priv; struct ttusb_dec* dec = fe->dvb->priv;
return ttusb_dec_send_command(dec, command, param_length, params, result_length, cmd_result); return ttusb_dec_send_command(dec, command, param_length, params, result_length, cmd_result);
} }

View File

@ -42,8 +42,39 @@ struct ttusbdecfe_state {
static int ttusbdecfe_read_status(struct dvb_frontend* fe, fe_status_t* status) static int ttusbdecfe_read_status(struct dvb_frontend* fe, fe_status_t* status)
{ {
struct ttusbdecfe_state* state = fe->demodulator_priv;
u8 b[] = { 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00 };
u8 result[4];
int len, ret;
*status=0;
ret=state->config->send_command(fe, 0x73, sizeof(b), b, &len, result);
if(ret)
return ret;
if(len != 4) {
printk(KERN_ERR "%s: unexpected reply\n", __FUNCTION__);
return -EIO;
}
switch(result[3]) {
case 1: /* not tuned yet */
case 2: /* no signal/no lock*/
break;
case 3: /* signal found and locked*/
*status = FE_HAS_SIGNAL | FE_HAS_VITERBI | *status = FE_HAS_SIGNAL | FE_HAS_VITERBI |
FE_HAS_SYNC | FE_HAS_CARRIER | FE_HAS_LOCK; FE_HAS_SYNC | FE_HAS_CARRIER | FE_HAS_LOCK;
break;
case 4:
*status = FE_TIMEDOUT;
break;
default:
pr_info("%s: returned unknown value: %d\n",
__FUNCTION__, result[3]);
return -EIO;
}
return 0; return 0;
} }
@ -64,6 +95,16 @@ static int ttusbdecfe_dvbt_set_frontend(struct dvb_frontend* fe, struct dvb_fron
return 0; return 0;
} }
static int ttusbdecfe_dvbt_get_tune_settings(struct dvb_frontend* fe,
struct dvb_frontend_tune_settings* fesettings)
{
fesettings->min_delay_ms = 1500;
/* Drift compensation makes no sense for DVB-T */
fesettings->step_size = 0;
fesettings->max_drift = 0;
return 0;
}
static int ttusbdecfe_dvbs_set_frontend(struct dvb_frontend* fe, struct dvb_frontend_parameters *p) static int ttusbdecfe_dvbs_set_frontend(struct dvb_frontend* fe, struct dvb_frontend_parameters *p)
{ {
struct ttusbdecfe_state* state = (struct ttusbdecfe_state*) fe->demodulator_priv; struct ttusbdecfe_state* state = (struct ttusbdecfe_state*) fe->demodulator_priv;
@ -212,6 +253,8 @@ static struct dvb_frontend_ops ttusbdecfe_dvbt_ops = {
.set_frontend = ttusbdecfe_dvbt_set_frontend, .set_frontend = ttusbdecfe_dvbt_set_frontend,
.get_tune_settings = ttusbdecfe_dvbt_get_tune_settings,
.read_status = ttusbdecfe_read_status, .read_status = ttusbdecfe_read_status,
}; };
@ -223,11 +266,11 @@ static struct dvb_frontend_ops ttusbdecfe_dvbs_ops = {
.frequency_min = 950000, .frequency_min = 950000,
.frequency_max = 2150000, .frequency_max = 2150000,
.frequency_stepsize = 125, .frequency_stepsize = 125,
.symbol_rate_min = 1000000, /* guessed */
.symbol_rate_max = 45000000, /* guessed */
.caps = FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 | .caps = FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 |
FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO | FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO |
FE_CAN_QAM_16 | FE_CAN_QAM_64 | FE_CAN_QAM_AUTO | FE_CAN_QPSK
FE_CAN_TRANSMISSION_MODE_AUTO | FE_CAN_GUARD_INTERVAL_AUTO |
FE_CAN_HIERARCHY_AUTO,
}, },
.release = ttusbdecfe_release, .release = ttusbdecfe_release,

View File

@ -220,6 +220,7 @@ static struct file_operations pcm20_fops = {
.open = video_exclusive_open, .open = video_exclusive_open,
.release = video_exclusive_release, .release = video_exclusive_release,
.ioctl = pcm20_ioctl, .ioctl = pcm20_ioctl,
.compat_ioctl = v4l_compat_ioctl32,
.llseek = no_llseek, .llseek = no_llseek,
}; };

View File

@ -299,6 +299,7 @@ static struct file_operations rtrack_fops = {
.open = video_exclusive_open, .open = video_exclusive_open,
.release = video_exclusive_release, .release = video_exclusive_release,
.ioctl = rt_ioctl, .ioctl = rt_ioctl,
.compat_ioctl = v4l_compat_ioctl32,
.llseek = no_llseek, .llseek = no_llseek,
}; };

View File

@ -256,6 +256,7 @@ static struct file_operations aztech_fops = {
.open = video_exclusive_open, .open = video_exclusive_open,
.release = video_exclusive_release, .release = video_exclusive_release,
.ioctl = az_ioctl, .ioctl = az_ioctl,
.compat_ioctl = v4l_compat_ioctl32,
.llseek = no_llseek, .llseek = no_llseek,
}; };

View File

@ -490,6 +490,7 @@ static struct file_operations cadet_fops = {
.release = cadet_release, .release = cadet_release,
.read = cadet_read, .read = cadet_read,
.ioctl = cadet_ioctl, .ioctl = cadet_ioctl,
.compat_ioctl = v4l_compat_ioctl32,
.llseek = no_llseek, .llseek = no_llseek,
}; };

View File

@ -301,6 +301,7 @@ static struct file_operations gemtek_pci_fops = {
.open = video_exclusive_open, .open = video_exclusive_open,
.release = video_exclusive_release, .release = video_exclusive_release,
.ioctl = gemtek_pci_ioctl, .ioctl = gemtek_pci_ioctl,
.compat_ioctl = v4l_compat_ioctl32,
.llseek = no_llseek, .llseek = no_llseek,
}; };

View File

@ -233,6 +233,7 @@ static struct file_operations gemtek_fops = {
.open = video_exclusive_open, .open = video_exclusive_open,
.release = video_exclusive_release, .release = video_exclusive_release,
.ioctl = gemtek_ioctl, .ioctl = gemtek_ioctl,
.compat_ioctl = v4l_compat_ioctl32,
.llseek = no_llseek, .llseek = no_llseek,
}; };

View File

@ -72,6 +72,7 @@ static struct file_operations maestro_fops = {
.open = video_exclusive_open, .open = video_exclusive_open,
.release = video_exclusive_release, .release = video_exclusive_release,
.ioctl = radio_ioctl, .ioctl = radio_ioctl,
.compat_ioctl = v4l_compat_ioctl32,
.llseek = no_llseek, .llseek = no_llseek,
}; };

View File

@ -80,6 +80,7 @@ static struct file_operations maxiradio_fops = {
.open = video_exclusive_open, .open = video_exclusive_open,
.release = video_exclusive_release, .release = video_exclusive_release,
.ioctl = radio_ioctl, .ioctl = radio_ioctl,
.compat_ioctl = v4l_compat_ioctl32,
.llseek = no_llseek, .llseek = no_llseek,
}; };
static struct video_device maxiradio_radio = static struct video_device maxiradio_radio =

View File

@ -199,6 +199,7 @@ static struct file_operations rtrack2_fops = {
.open = video_exclusive_open, .open = video_exclusive_open,
.release = video_exclusive_release, .release = video_exclusive_release,
.ioctl = rt_ioctl, .ioctl = rt_ioctl,
.compat_ioctl = v4l_compat_ioctl32,
.llseek = no_llseek, .llseek = no_llseek,
}; };

View File

@ -225,6 +225,7 @@ static struct file_operations fmi_fops = {
.open = video_exclusive_open, .open = video_exclusive_open,
.release = video_exclusive_release, .release = video_exclusive_release,
.ioctl = fmi_ioctl, .ioctl = fmi_ioctl,
.compat_ioctl = v4l_compat_ioctl32,
.llseek = no_llseek, .llseek = no_llseek,
}; };

View File

@ -356,6 +356,7 @@ static struct file_operations fmr2_fops = {
.open = video_exclusive_open, .open = video_exclusive_open,
.release = video_exclusive_release, .release = video_exclusive_release,
.ioctl = fmr2_ioctl, .ioctl = fmr2_ioctl,
.compat_ioctl = v4l_compat_ioctl32,
.llseek = no_llseek, .llseek = no_llseek,
}; };

View File

@ -276,6 +276,7 @@ static struct file_operations terratec_fops = {
.open = video_exclusive_open, .open = video_exclusive_open,
.release = video_exclusive_release, .release = video_exclusive_release,
.ioctl = tt_ioctl, .ioctl = tt_ioctl,
.compat_ioctl = v4l_compat_ioctl32,
.llseek = no_llseek, .llseek = no_llseek,
}; };

View File

@ -255,6 +255,7 @@ static struct file_operations trust_fops = {
.open = video_exclusive_open, .open = video_exclusive_open,
.release = video_exclusive_release, .release = video_exclusive_release,
.ioctl = tr_ioctl, .ioctl = tr_ioctl,
.compat_ioctl = v4l_compat_ioctl32,
.llseek = no_llseek, .llseek = no_llseek,
}; };

View File

@ -261,6 +261,7 @@ static struct file_operations typhoon_fops = {
.open = video_exclusive_open, .open = video_exclusive_open,
.release = video_exclusive_release, .release = video_exclusive_release,
.ioctl = typhoon_ioctl, .ioctl = typhoon_ioctl,
.compat_ioctl = v4l_compat_ioctl32,
.llseek = no_llseek, .llseek = no_llseek,
}; };

View File

@ -313,6 +313,7 @@ static struct file_operations zoltrix_fops =
.open = video_exclusive_open, .open = video_exclusive_open,
.release = video_exclusive_release, .release = video_exclusive_release,
.ioctl = zol_ioctl, .ioctl = zol_ioctl,
.compat_ioctl = v4l_compat_ioctl32,
.llseek = no_llseek, .llseek = no_llseek,
}; };

View File

@ -7,6 +7,15 @@ menu "Video For Linux"
comment "Video Adapters" comment "Video Adapters"
config VIDEO_ADV_DEBUG
bool "Enable advanced debug functionality"
depends on VIDEO_DEV
default n
---help---
Say Y here to enable advanced debugging functionality on some
V4L devices.
In doubt, say N.
config VIDEO_BT848 config VIDEO_BT848
tristate "BT848 Video For Linux" tristate "BT848 Video For Linux"
depends on VIDEO_DEV && PCI && I2C depends on VIDEO_DEV && PCI && I2C

View File

@ -3,15 +3,19 @@
# #
bttv-objs := bttv-driver.o bttv-cards.o bttv-if.o \ bttv-objs := bttv-driver.o bttv-cards.o bttv-if.o \
bttv-risc.o bttv-vbi.o bttv-i2c.o bttv-gpio.o bttv-risc.o bttv-vbi.o bttv-i2c.o bttv-gpio.o \
bttv-input.o
zoran-objs := zr36120.o zr36120_i2c.o zr36120_mem.o zoran-objs := zr36120.o zr36120_i2c.o zr36120_mem.o
zr36067-objs := zoran_procfs.o zoran_device.o \ zr36067-objs := zoran_procfs.o zoran_device.o \
zoran_driver.o zoran_card.o zoran_driver.o zoran_card.o
tuner-objs := tuner-core.o tuner-simple.o mt20xx.o tda8290.o tea5767.o tuner-objs := tuner-core.o tuner-simple.o mt20xx.o tda8290.o tea5767.o
obj-$(CONFIG_VIDEO_DEV) += videodev.o v4l2-common.o v4l1-compat.o
msp3400-objs := msp3400-driver.o msp3400-kthreads.o
obj-$(CONFIG_VIDEO_DEV) += videodev.o v4l2-common.o v4l1-compat.o compat_ioctl32.o
obj-$(CONFIG_VIDEO_BT848) += bttv.o msp3400.o tvaudio.o \ obj-$(CONFIG_VIDEO_BT848) += bttv.o msp3400.o tvaudio.o \
tda7432.o tda9875.o ir-kbd-i2c.o ir-kbd-gpio.o tda7432.o tda9875.o ir-kbd-i2c.o
obj-$(CONFIG_SOUND_TVMIXER) += tvmixer.o obj-$(CONFIG_SOUND_TVMIXER) += tvmixer.o
obj-$(CONFIG_VIDEO_ZR36120) += zoran.o obj-$(CONFIG_VIDEO_ZR36120) += zoran.o

View File

@ -749,6 +749,7 @@ static struct file_operations ar_fops = {
.release = video_exclusive_release, .release = video_exclusive_release,
.read = ar_read, .read = ar_read,
.ioctl = ar_ioctl, .ioctl = ar_ioctl,
.compat_ioctl = v4l_compat_ioctl32,
.llseek = no_llseek, .llseek = no_llseek,
}; };

View File

@ -30,8 +30,9 @@
#include <linux/init.h> #include <linux/init.h>
#include <linux/errno.h> #include <linux/errno.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <media/audiochip.h> #include <media/audiochip.h>
#include <media/v4l2-common.h>
#include "bttv.h" #include "bttv.h"
#include "bt832.h" #include "bt832.h"
@ -42,9 +43,10 @@ static unsigned short normal_i2c[] = { I2C_BT832_ALT1>>1, I2C_BT832_ALT2>>1,
I2C_CLIENT_END }; I2C_CLIENT_END };
I2C_CLIENT_INSMOD; I2C_CLIENT_INSMOD;
/* ---------------------------------------------------------------------- */ int debug = 0; /* debug output */
module_param(debug, int, 0644);
#define dprintk if (debug) printk /* ---------------------------------------------------------------------- */
static int bt832_detach(struct i2c_client *client); static int bt832_detach(struct i2c_client *client);
@ -61,23 +63,26 @@ int bt832_hexdump(struct i2c_client *i2c_client_s, unsigned char *buf)
int i,rc; int i,rc;
buf[0]=0x80; // start at register 0 with auto-increment buf[0]=0x80; // start at register 0 with auto-increment
if (1 != (rc = i2c_master_send(i2c_client_s,buf,1))) if (1 != (rc = i2c_master_send(i2c_client_s,buf,1)))
printk("bt832: i2c i/o error: rc == %d (should be 1)\n",rc); v4l_err(i2c_client_s,"i2c i/o error: rc == %d (should be 1)\n",rc);
for(i=0;i<65;i++) for(i=0;i<65;i++)
buf[i]=0; buf[i]=0;
if (65 != (rc=i2c_master_recv(i2c_client_s,buf,65))) if (65 != (rc=i2c_master_recv(i2c_client_s,buf,65)))
printk("bt832: i2c i/o error: rc == %d (should be 65)\n",rc); v4l_err(i2c_client_s,"i2c i/o error: rc == %d (should be 65)\n",rc);
// Note: On READ the first byte is the current index // Note: On READ the first byte is the current index
// (e.g. 0x80, what we just wrote) // (e.g. 0x80, what we just wrote)
if(1) { if(debug>1) {
int i; int i;
printk("BT832 hexdump:\n"); v4l_dbg(2,i2c_client_s,"hexdump:");
for(i=1;i<65;i++) { for(i=1;i<65;i++) {
if(i!=1) { if(i!=1) {
if(((i-1)%8)==0) printk(" "); if(((i-1)%8)==0) printk(" ");
if(((i-1)%16)==0) printk("\n"); if(((i-1)%16)==0) {
printk("\n");
v4l_dbg(2,i2c_client_s,"hexdump:");
}
} }
printk(" %02x",buf[i]); printk(" %02x",buf[i]);
} }
@ -96,56 +101,56 @@ int bt832_init(struct i2c_client *i2c_client_s)
bt832_hexdump(i2c_client_s,buf); bt832_hexdump(i2c_client_s,buf);
if(buf[0x40] != 0x31) { if(buf[0x40] != 0x31) {
printk("bt832: this i2c chip is no bt832 (id=%02x). Detaching.\n",buf[0x40]); v4l_err(i2c_client_s,"This i2c chip is no bt832 (id=%02x). Detaching.\n",buf[0x40]);
kfree(buf); kfree(buf);
return 0; return 0;
} }
printk("Write 0 tp VPSTATUS\n"); v4l_err(i2c_client_s,"Write 0 tp VPSTATUS\n");
buf[0]=BT832_VP_STATUS; // Reg.52 buf[0]=BT832_VP_STATUS; // Reg.52
buf[1]= 0x00; buf[1]= 0x00;
if (2 != (rc = i2c_master_send(i2c_client_s,buf,2))) if (2 != (rc = i2c_master_send(i2c_client_s,buf,2)))
printk("bt832: i2c i/o error VPS: rc == %d (should be 2)\n",rc); v4l_err(i2c_client_s,"i2c i/o error VPS: rc == %d (should be 2)\n",rc);
bt832_hexdump(i2c_client_s,buf); bt832_hexdump(i2c_client_s,buf);
// Leave low power mode: // Leave low power mode:
printk("Bt832: leave low power mode.\n"); v4l_err(i2c_client_s,"leave low power mode.\n");
buf[0]=BT832_CAM_SETUP0; //0x39 57 buf[0]=BT832_CAM_SETUP0; //0x39 57
buf[1]=0x08; buf[1]=0x08;
if (2 != (rc = i2c_master_send(i2c_client_s,buf,2))) if (2 != (rc = i2c_master_send(i2c_client_s,buf,2)))
printk("bt832: i2c i/o error LLPM: rc == %d (should be 2)\n",rc); v4l_err(i2c_client_s,"i2c i/o error LLPM: rc == %d (should be 2)\n",rc);
bt832_hexdump(i2c_client_s,buf); bt832_hexdump(i2c_client_s,buf);
printk("Write 0 tp VPSTATUS\n"); v4l_info(i2c_client_s,"Write 0 tp VPSTATUS\n");
buf[0]=BT832_VP_STATUS; // Reg.52 buf[0]=BT832_VP_STATUS; // Reg.52
buf[1]= 0x00; buf[1]= 0x00;
if (2 != (rc = i2c_master_send(i2c_client_s,buf,2))) if (2 != (rc = i2c_master_send(i2c_client_s,buf,2)))
printk("bt832: i2c i/o error VPS: rc == %d (should be 2)\n",rc); v4l_err(i2c_client_s,"i2c i/o error VPS: rc == %d (should be 2)\n",rc);
bt832_hexdump(i2c_client_s,buf); bt832_hexdump(i2c_client_s,buf);
// Enable Output // Enable Output
printk("Enable Output\n"); v4l_info(i2c_client_s,"Enable Output\n");
buf[0]=BT832_VP_CONTROL1; // Reg.40 buf[0]=BT832_VP_CONTROL1; // Reg.40
buf[1]= 0x27 & (~0x01); // Default | !skip buf[1]= 0x27 & (~0x01); // Default | !skip
if (2 != (rc = i2c_master_send(i2c_client_s,buf,2))) if (2 != (rc = i2c_master_send(i2c_client_s,buf,2)))
printk("bt832: i2c i/o error EO: rc == %d (should be 2)\n",rc); v4l_err(i2c_client_s,"i2c i/o error EO: rc == %d (should be 2)\n",rc);
bt832_hexdump(i2c_client_s,buf); bt832_hexdump(i2c_client_s,buf);
// for testing (even works when no camera attached) // for testing (even works when no camera attached)
printk("bt832: *** Generate NTSC M Bars *****\n"); v4l_info(i2c_client_s,"*** Generate NTSC M Bars *****\n");
buf[0]=BT832_VP_TESTCONTROL0; // Reg. 42 buf[0]=BT832_VP_TESTCONTROL0; // Reg. 42
buf[1]=3; // Generate NTSC System M bars, Generate Frame timing internally buf[1]=3; // Generate NTSC System M bars, Generate Frame timing internally
if (2 != (rc = i2c_master_send(i2c_client_s,buf,2))) if (2 != (rc = i2c_master_send(i2c_client_s,buf,2)))
printk("bt832: i2c i/o error MBAR: rc == %d (should be 2)\n",rc); v4l_info(i2c_client_s,"i2c i/o error MBAR: rc == %d (should be 2)\n",rc);
printk("Bt832: Camera Present: %s\n", v4l_info(i2c_client_s,"Camera Present: %s\n",
(buf[1+BT832_CAM_STATUS] & BT832_56_CAMERA_PRESENT) ? "yes":"no"); (buf[1+BT832_CAM_STATUS] & BT832_56_CAMERA_PRESENT) ? "yes":"no");
bt832_hexdump(i2c_client_s,buf); bt832_hexdump(i2c_client_s,buf);
@ -159,13 +164,9 @@ static int bt832_attach(struct i2c_adapter *adap, int addr, int kind)
{ {
struct bt832 *t; struct bt832 *t;
printk("bt832_attach\n");
client_template.adapter = adap; client_template.adapter = adap;
client_template.addr = addr; client_template.addr = addr;
printk("bt832: chip found @ 0x%x\n", addr<<1);
if (NULL == (t = kmalloc(sizeof(*t), GFP_KERNEL))) if (NULL == (t = kmalloc(sizeof(*t), GFP_KERNEL)))
return -ENOMEM; return -ENOMEM;
memset(t,0,sizeof(*t)); memset(t,0,sizeof(*t));
@ -173,6 +174,9 @@ static int bt832_attach(struct i2c_adapter *adap, int addr, int kind)
i2c_set_clientdata(&t->client, t); i2c_set_clientdata(&t->client, t);
i2c_attach_client(&t->client); i2c_attach_client(&t->client);
v4l_info(&t->client,"chip found @ 0x%x\n", addr<<1);
if(! bt832_init(&t->client)) { if(! bt832_init(&t->client)) {
bt832_detach(&t->client); bt832_detach(&t->client);
return -1; return -1;
@ -183,13 +187,8 @@ static int bt832_attach(struct i2c_adapter *adap, int addr, int kind)
static int bt832_probe(struct i2c_adapter *adap) static int bt832_probe(struct i2c_adapter *adap)
{ {
#ifdef I2C_CLASS_TV_ANALOG
if (adap->class & I2C_CLASS_TV_ANALOG) if (adap->class & I2C_CLASS_TV_ANALOG)
return i2c_probe(adap, &addr_data, bt832_attach); return i2c_probe(adap, &addr_data, bt832_attach);
#else
if (adap->id == I2C_HW_B_BT848)
return i2c_probe(adap, &addr_data, bt832_attach);
#endif
return 0; return 0;
} }
@ -197,7 +196,7 @@ static int bt832_detach(struct i2c_client *client)
{ {
struct bt832 *t = i2c_get_clientdata(client); struct bt832 *t = i2c_get_clientdata(client);
printk("bt832: detach.\n"); v4l_info(&t->client,"dettach\n");
i2c_detach_client(client); i2c_detach_client(client);
kfree(t); kfree(t);
return 0; return 0;
@ -208,7 +207,8 @@ bt832_command(struct i2c_client *client, unsigned int cmd, void *arg)
{ {
struct bt832 *t = i2c_get_clientdata(client); struct bt832 *t = i2c_get_clientdata(client);
printk("bt832: command %x\n",cmd); if (debug>1)
v4l_i2c_print_ioctl(&t->client,cmd);
switch (cmd) { switch (cmd) {
case BT832_HEXDUMP: { case BT832_HEXDUMP: {
@ -219,7 +219,7 @@ bt832_command(struct i2c_client *client, unsigned int cmd, void *arg)
} }
break; break;
case BT832_REATTACH: case BT832_REATTACH:
printk("bt832: re-attach\n"); v4l_info(&t->client,"re-attach\n");
i2c_del_driver(&driver); i2c_del_driver(&driver);
i2c_add_driver(&driver); i2c_add_driver(&driver);
break; break;
@ -231,9 +231,9 @@ bt832_command(struct i2c_client *client, unsigned int cmd, void *arg)
static struct i2c_driver driver = { static struct i2c_driver driver = {
.driver = { .driver = {
.name = "i2c bt832 driver", .name = "bt832",
}, },
.id = -1, /* FIXME */ .id = 0, /* FIXME */
.attach_adapter = bt832_probe, .attach_adapter = bt832_probe,
.detach_client = bt832_detach, .detach_client = bt832_detach,
.command = bt832_command, .command = bt832_command,

View File

@ -38,6 +38,7 @@
#include <asm/io.h> #include <asm/io.h>
#include "bttvp.h" #include "bttvp.h"
#include <media/v4l2-common.h>
/* fwd decl */ /* fwd decl */
static void boot_msp34xx(struct bttv *btv, int pin); static void boot_msp34xx(struct bttv *btv, int pin);
@ -292,6 +293,9 @@ static struct CARD {
/* likely broken, vendor id doesn't match the other magic views ... /* likely broken, vendor id doesn't match the other magic views ...
* { 0xa0fca04f, BTTV_BOARD_MAGICTVIEW063, "Guillemot Maxi TV Video 3" }, */ * { 0xa0fca04f, BTTV_BOARD_MAGICTVIEW063, "Guillemot Maxi TV Video 3" }, */
/* Duplicate PCI ID, reconfigure for this board during the eeprom read.
* { 0x13eb0070, BTTV_BOARD_HAUPPAUGE_IMPACTVCB, "Hauppauge ImpactVCB" }, */
/* DVB cards (using pci function .1 for mpeg data xfer) */ /* DVB cards (using pci function .1 for mpeg data xfer) */
{ 0x01010071, BTTV_BOARD_NEBULA_DIGITV, "Nebula Electronics DigiTV" }, { 0x01010071, BTTV_BOARD_NEBULA_DIGITV, "Nebula Electronics DigiTV" },
{ 0x07611461, BTTV_BOARD_AVDVBT_761, "AverMedia AverTV DVB-T 761" }, { 0x07611461, BTTV_BOARD_AVDVBT_761, "AverMedia AverTV DVB-T 761" },
@ -2136,7 +2140,6 @@ struct tvcard bttv_tvcards[] = {
.has_remote = 1, .has_remote = 1,
.gpiomask = 0x1b, .gpiomask = 0x1b,
.no_gpioirq = 1, .no_gpioirq = 1,
.any_irq = 1,
}, },
[BTTV_BOARD_PV143] = { [BTTV_BOARD_PV143] = {
/* Jorge Boncompte - DTI2 <jorge@dti2.net> */ /* Jorge Boncompte - DTI2 <jorge@dti2.net> */
@ -2817,6 +2820,22 @@ struct tvcard bttv_tvcards[] = {
.tuner_addr = ADDR_UNSET, .tuner_addr = ADDR_UNSET,
.has_radio = 1, .has_radio = 1,
}, },
/* ---- card 0x8f ---------------------------------- */
[BTTV_BOARD_HAUPPAUGE_IMPACTVCB] = {
.name = "Hauppauge ImpactVCB (bt878)",
.video_inputs = 4,
.audio_inputs = 0,
.tuner = -1,
.svhs = -1,
.gpiomask = 0x0f, /* old: 7 */
.muxsel = { 0, 1, 3, 2}, /* Composite 0-3 */
.no_msp34xx = 1,
.no_tda9875 = 1,
.no_tda7432 = 1,
.tuner_type = -1,
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
},
}; };
static const unsigned int bttv_num_tvcards = ARRAY_SIZE(bttv_tvcards); static const unsigned int bttv_num_tvcards = ARRAY_SIZE(bttv_tvcards);
@ -3037,26 +3056,33 @@ static void miro_pinnacle_gpio(struct bttv *btv)
switch (id) { switch (id) {
case 1: case 1:
info = "PAL / mono"; info = "PAL / mono";
btv->tda9887_conf = TDA9887_INTERCARRIER;
break; break;
case 2: case 2:
info = "PAL+SECAM / stereo"; info = "PAL+SECAM / stereo";
btv->has_radio = 1; btv->has_radio = 1;
btv->tda9887_conf = TDA9887_QSS;
break; break;
case 3: case 3:
info = "NTSC / stereo"; info = "NTSC / stereo";
btv->has_radio = 1; btv->has_radio = 1;
btv->tda9887_conf = TDA9887_QSS;
break; break;
case 4: case 4:
info = "PAL+SECAM / mono"; info = "PAL+SECAM / mono";
btv->tda9887_conf = TDA9887_QSS;
break; break;
case 5: case 5:
info = "NTSC / mono"; info = "NTSC / mono";
btv->tda9887_conf = TDA9887_INTERCARRIER;
break; break;
case 6: case 6:
info = "NTSC / stereo"; info = "NTSC / stereo";
btv->tda9887_conf = TDA9887_INTERCARRIER;
break; break;
case 7: case 7:
info = "PAL / stereo"; info = "PAL / stereo";
btv->tda9887_conf = TDA9887_INTERCARRIER;
break; break;
default: default:
info = "oops: unknown card"; info = "oops: unknown card";
@ -3067,8 +3093,7 @@ static void miro_pinnacle_gpio(struct bttv *btv)
printk(KERN_INFO printk(KERN_INFO
"bttv%d: pinnacle/mt: id=%d info=\"%s\" radio=%s\n", "bttv%d: pinnacle/mt: id=%d info=\"%s\" radio=%s\n",
btv->c.nr, id, info, btv->has_radio ? "yes" : "no"); btv->c.nr, id, info, btv->has_radio ? "yes" : "no");
btv->tuner_type = 33; btv->tuner_type = TUNER_MT2032;
btv->pinnacle_id = id;
} }
} }
@ -3370,9 +3395,9 @@ void __devinit bttv_init_card2(struct bttv *btv)
bttv_call_i2c_clients(btv, TUNER_SET_TYPE_ADDR, &tun_setup); bttv_call_i2c_clients(btv, TUNER_SET_TYPE_ADDR, &tun_setup);
} }
if (btv->pinnacle_id != UNSET) { if (btv->tda9887_conf) {
bttv_call_i2c_clients(btv, AUDC_CONFIG_PINNACLE, bttv_call_i2c_clients(btv, TDA9887_SET_CONFIG,
&btv->pinnacle_id); &btv->tda9887_conf);
} }
btv->svhs = bttv_tvcards[btv->c.type].svhs; btv->svhs = bttv_tvcards[btv->c.type].svhs;
@ -3387,8 +3412,6 @@ void __devinit bttv_init_card2(struct bttv *btv)
btv->has_remote=1; btv->has_remote=1;
if (!bttv_tvcards[btv->c.type].no_gpioirq) if (!bttv_tvcards[btv->c.type].no_gpioirq)
btv->gpioirq=1; btv->gpioirq=1;
if (bttv_tvcards[btv->c.type].any_irq)
btv->any_irq = 1;
if (bttv_tvcards[btv->c.type].audio_hook) if (bttv_tvcards[btv->c.type].audio_hook)
btv->audio_hook=bttv_tvcards[btv->c.type].audio_hook; btv->audio_hook=bttv_tvcards[btv->c.type].audio_hook;
@ -3424,7 +3447,7 @@ void __devinit bttv_init_card2(struct bttv *btv)
/* tuner modules */ /* tuner modules */
tda9887 = 0; tda9887 = 0;
if (btv->pinnacle_id != UNSET) if (btv->tda9887_conf)
tda9887 = 1; tda9887 = 1;
if (0 == tda9887 && 0 == bttv_tvcards[btv->c.type].has_dvb && if (0 == tda9887 && 0 == bttv_tvcards[btv->c.type].has_dvb &&
bttv_I2CRead(btv, I2C_TDA9887, "TDA9887") >=0) bttv_I2CRead(btv, I2C_TDA9887, "TDA9887") >=0)
@ -3471,6 +3494,21 @@ static void __devinit hauppauge_eeprom(struct bttv *btv)
tveeprom_hauppauge_analog(&btv->i2c_client, &tv, eeprom_data); tveeprom_hauppauge_analog(&btv->i2c_client, &tv, eeprom_data);
btv->tuner_type = tv.tuner_type; btv->tuner_type = tv.tuner_type;
btv->has_radio = tv.has_radio; btv->has_radio = tv.has_radio;
printk("bttv%d: Hauppauge eeprom indicates model#%d\n",
btv->c.nr, tv.model);
/*
* Some of the 878 boards have duplicate PCI IDs. Switch the board
* type based on model #.
*/
if(tv.model == 64900) {
printk("bttv%d: Switching board type from %s to %s\n",
btv->c.nr,
bttv_tvcards[btv->c.type].name,
bttv_tvcards[BTTV_BOARD_HAUPPAUGE_IMPACTVCB].name);
btv->c.type = BTTV_BOARD_HAUPPAUGE_IMPACTVCB;
}
} }
static int terratec_active_radio_upgrade(struct bttv *btv) static int terratec_active_radio_upgrade(struct bttv *btv)

View File

@ -34,13 +34,14 @@
#include <linux/sched.h> #include <linux/sched.h>
#include <linux/interrupt.h> #include <linux/interrupt.h>
#include <linux/kdev_t.h> #include <linux/kdev_t.h>
#include "bttvp.h"
#include <media/v4l2-common.h>
#include <linux/dma-mapping.h> #include <linux/dma-mapping.h>
#include <asm/io.h> #include <asm/io.h>
#include <asm/byteorder.h> #include <asm/byteorder.h>
#include "bttvp.h"
#include "rds.h" #include "rds.h"
@ -210,6 +211,9 @@ const struct bttv_tvnorm bttv_tvnorms[] = {
.vdelay = 0x20, .vdelay = 0x20,
.vbipack = 255, .vbipack = 255,
.sram = 0, .sram = 0,
/* ITU-R frame line number of the first VBI line
we can capture, of the first and second field. */
.vbistart = { 7,320 },
},{ },{
.v4l2_id = V4L2_STD_NTSC_M, .v4l2_id = V4L2_STD_NTSC_M,
.name = "NTSC", .name = "NTSC",
@ -226,6 +230,7 @@ const struct bttv_tvnorm bttv_tvnorms[] = {
.vdelay = 0x1a, .vdelay = 0x1a,
.vbipack = 144, .vbipack = 144,
.sram = 1, .sram = 1,
.vbistart = { 10, 273 },
},{ },{
.v4l2_id = V4L2_STD_SECAM, .v4l2_id = V4L2_STD_SECAM,
.name = "SECAM", .name = "SECAM",
@ -242,6 +247,7 @@ const struct bttv_tvnorm bttv_tvnorms[] = {
.vdelay = 0x20, .vdelay = 0x20,
.vbipack = 255, .vbipack = 255,
.sram = 0, /* like PAL, correct? */ .sram = 0, /* like PAL, correct? */
.vbistart = { 7, 320 },
},{ },{
.v4l2_id = V4L2_STD_PAL_Nc, .v4l2_id = V4L2_STD_PAL_Nc,
.name = "PAL-Nc", .name = "PAL-Nc",
@ -258,6 +264,7 @@ const struct bttv_tvnorm bttv_tvnorms[] = {
.vdelay = 0x1a, .vdelay = 0x1a,
.vbipack = 144, .vbipack = 144,
.sram = -1, .sram = -1,
.vbistart = { 7, 320 },
},{ },{
.v4l2_id = V4L2_STD_PAL_M, .v4l2_id = V4L2_STD_PAL_M,
.name = "PAL-M", .name = "PAL-M",
@ -274,6 +281,7 @@ const struct bttv_tvnorm bttv_tvnorms[] = {
.vdelay = 0x1a, .vdelay = 0x1a,
.vbipack = 144, .vbipack = 144,
.sram = -1, .sram = -1,
.vbistart = { 10, 273 },
},{ },{
.v4l2_id = V4L2_STD_PAL_N, .v4l2_id = V4L2_STD_PAL_N,
.name = "PAL-N", .name = "PAL-N",
@ -290,6 +298,7 @@ const struct bttv_tvnorm bttv_tvnorms[] = {
.vdelay = 0x20, .vdelay = 0x20,
.vbipack = 144, .vbipack = 144,
.sram = -1, .sram = -1,
.vbistart = { 7, 320},
},{ },{
.v4l2_id = V4L2_STD_NTSC_M_JP, .v4l2_id = V4L2_STD_NTSC_M_JP,
.name = "NTSC-JP", .name = "NTSC-JP",
@ -306,6 +315,7 @@ const struct bttv_tvnorm bttv_tvnorms[] = {
.vdelay = 0x16, .vdelay = 0x16,
.vbipack = 144, .vbipack = 144,
.sram = -1, .sram = -1,
.vbistart = {10, 273},
},{ },{
/* that one hopefully works with the strange timing /* that one hopefully works with the strange timing
* which video recorders produce when playing a NTSC * which video recorders produce when playing a NTSC
@ -326,6 +336,7 @@ const struct bttv_tvnorm bttv_tvnorms[] = {
.vbipack = 255, .vbipack = 255,
.vtotal = 524, .vtotal = 524,
.sram = -1, .sram = -1,
.vbistart = { 10, 273 },
} }
}; };
static const unsigned int BTTV_TVNORMS = ARRAY_SIZE(bttv_tvnorms); static const unsigned int BTTV_TVNORMS = ARRAY_SIZE(bttv_tvnorms);
@ -1510,14 +1521,6 @@ static struct videobuf_queue_ops bttv_video_qops = {
.buf_release = buffer_release, .buf_release = buffer_release,
}; };
static const char *v4l1_ioctls[] = {
"?", "CGAP", "GCHAN", "SCHAN", "GTUNER", "STUNER", "GPICT", "SPICT",
"CCAPTURE", "GWIN", "SWIN", "GFBUF", "SFBUF", "KEY", "GFREQ",
"SFREQ", "GAUDIO", "SAUDIO", "SYNC", "MCAPTURE", "GMBUF", "GUNIT",
"GCAPTURE", "SCAPTURE", "SPLAYMODE", "SWRITEMODE", "GPLAYINFO",
"SMICROCODE", "GVBIFMT", "SVBIFMT" };
#define V4L1_IOCTLS ARRAY_SIZE(v4l1_ioctls)
static int bttv_common_ioctls(struct bttv *btv, unsigned int cmd, void *arg) static int bttv_common_ioctls(struct bttv *btv, unsigned int cmd, void *arg)
{ {
switch (cmd) { switch (cmd) {
@ -2206,22 +2209,9 @@ static int bttv_do_ioctl(struct inode *inode, struct file *file,
unsigned long flags; unsigned long flags;
int retval = 0; int retval = 0;
if (bttv_debug > 1) { if (bttv_debug > 1)
switch (_IOC_TYPE(cmd)) { v4l_print_ioctl(btv->c.name, cmd);
case 'v':
printk("bttv%d: ioctl 0x%x (v4l1, VIDIOC%s)\n",
btv->c.nr, cmd, (_IOC_NR(cmd) < V4L1_IOCTLS) ?
v4l1_ioctls[_IOC_NR(cmd)] : "???");
break;
case 'V':
printk("bttv%d: ioctl 0x%x (v4l2, %s)\n",
btv->c.nr, cmd, v4l2_ioctl_names[_IOC_NR(cmd)]);
break;
default:
printk("bttv%d: ioctl 0x%x (???)\n",
btv->c.nr, cmd);
}
}
if (btv->errors) if (btv->errors)
bttv_reinit_bt848(btv); bttv_reinit_bt848(btv);
@ -2570,10 +2560,10 @@ static int bttv_do_ioctl(struct inode *inode, struct file *file,
fmt->count[0] = fmt2.fmt.vbi.count[0]; fmt->count[0] = fmt2.fmt.vbi.count[0];
fmt->start[1] = fmt2.fmt.vbi.start[1]; fmt->start[1] = fmt2.fmt.vbi.start[1];
fmt->count[1] = fmt2.fmt.vbi.count[1]; fmt->count[1] = fmt2.fmt.vbi.count[1];
if (fmt2.fmt.vbi.flags & VBI_UNSYNC) if (fmt2.fmt.vbi.flags & V4L2_VBI_UNSYNC)
fmt->flags |= V4L2_VBI_UNSYNC; fmt->flags |= VBI_UNSYNC;
if (fmt2.fmt.vbi.flags & VBI_INTERLACED) if (fmt2.fmt.vbi.flags & V4L2_VBI_INTERLACED)
fmt->flags |= V4L2_VBI_INTERLACED; fmt->flags |= VBI_INTERLACED;
return 0; return 0;
} }
case VIDIOCSVBIFMT: case VIDIOCSVBIFMT:
@ -3120,6 +3110,7 @@ static struct file_operations bttv_fops =
.open = bttv_open, .open = bttv_open,
.release = bttv_release, .release = bttv_release,
.ioctl = bttv_ioctl, .ioctl = bttv_ioctl,
.compat_ioctl = v4l_compat_ioctl32,
.llseek = no_llseek, .llseek = no_llseek,
.read = bttv_read, .read = bttv_read,
.mmap = bttv_mmap, .mmap = bttv_mmap,
@ -3229,6 +3220,7 @@ static int radio_do_ioctl(struct inode *inode, struct file *file,
case VIDIOCSFREQ: case VIDIOCSFREQ:
case VIDIOCGAUDIO: case VIDIOCGAUDIO:
case VIDIOCSAUDIO: case VIDIOCSAUDIO:
case VIDIOC_LOG_STATUS:
return bttv_common_ioctls(btv,cmd,arg); return bttv_common_ioctls(btv,cmd,arg);
default: default:
@ -3701,8 +3693,8 @@ static irqreturn_t bttv_irq(int irq, void *dev_id, struct pt_regs * regs)
btv=(struct bttv *)dev_id; btv=(struct bttv *)dev_id;
if (btv->any_irq) if (btv->custom_irq)
handled = bttv_any_irq(&btv->c); handled = btv->custom_irq(btv);
count=0; count=0;
while (1) { while (1) {
@ -3738,9 +3730,9 @@ static irqreturn_t bttv_irq(int irq, void *dev_id, struct pt_regs * regs)
if (astat&BT848_INT_VSYNC) if (astat&BT848_INT_VSYNC)
btv->field_count++; btv->field_count++;
if (astat & BT848_INT_GPINT) { if ((astat & BT848_INT_GPINT) && btv->remote) {
wake_up(&btv->gpioq); wake_up(&btv->gpioq);
bttv_gpio_irq(&btv->c); bttv_input_irq(btv);
} }
if (astat & BT848_INT_I2CDONE) { if (astat & BT848_INT_I2CDONE) {
@ -3946,7 +3938,6 @@ static int __devinit bttv_probe(struct pci_dev *dev,
btv->i2c_rc = -1; btv->i2c_rc = -1;
btv->tuner_type = UNSET; btv->tuner_type = UNSET;
btv->pinnacle_id = UNSET;
btv->new_input = UNSET; btv->new_input = UNSET;
btv->has_radio=radio[btv->c.nr]; btv->has_radio=radio[btv->c.nr];
@ -4065,11 +4056,11 @@ static int __devinit bttv_probe(struct pci_dev *dev,
} }
/* add subdevices */ /* add subdevices */
if (btv->has_remote)
bttv_sub_add_device(&btv->c, "remote");
if (bttv_tvcards[btv->c.type].has_dvb) if (bttv_tvcards[btv->c.type].has_dvb)
bttv_sub_add_device(&btv->c, "dvb"); bttv_sub_add_device(&btv->c, "dvb");
bttv_input_init(btv);
/* everything is fine */ /* everything is fine */
bttv_num++; bttv_num++;
return 0; return 0;
@ -4104,6 +4095,7 @@ static void __devexit bttv_remove(struct pci_dev *pci_dev)
/* tell gpio modules we are leaving ... */ /* tell gpio modules we are leaving ... */
btv->shutdown=1; btv->shutdown=1;
wake_up(&btv->gpioq); wake_up(&btv->gpioq);
bttv_input_fini(btv);
bttv_sub_del_devices(&btv->c); bttv_sub_del_devices(&btv->c);
/* unregister i2c_bus + input */ /* unregister i2c_bus + input */
@ -4253,7 +4245,7 @@ static int bttv_init_module(void)
bttv_check_chipset(); bttv_check_chipset();
bus_register(&bttv_sub_bus_type); bus_register(&bttv_sub_bus_type);
return pci_module_init(&bttv_pci_driver); return pci_register_driver(&bttv_pci_driver);
} }
static void bttv_cleanup_module(void) static void bttv_cleanup_module(void)

View File

@ -113,24 +113,6 @@ void bttv_gpio_irq(struct bttv_core *core)
} }
} }
int bttv_any_irq(struct bttv_core *core)
{
struct bttv_sub_driver *drv;
struct bttv_sub_device *dev;
struct list_head *item;
int handled = 0;
list_for_each(item,&core->subs) {
dev = list_entry(item,struct bttv_sub_device,list);
drv = to_bttv_sub_drv(dev->dev.driver);
if (drv && drv->any_irq) {
if (drv->any_irq(dev))
handled = 1;
}
}
return handled;
}
/* ----------------------------------------------------------------------- */ /* ----------------------------------------------------------------------- */
/* external: sub-driver register/unregister */ /* external: sub-driver register/unregister */

View File

@ -28,10 +28,11 @@
#include <linux/moduleparam.h> #include <linux/moduleparam.h>
#include <linux/init.h> #include <linux/init.h>
#include <linux/delay.h> #include <linux/delay.h>
#include <linux/jiffies.h>
#include <asm/io.h>
#include "bttvp.h" #include "bttvp.h"
#include <media/v4l2-common.h>
#include <linux/jiffies.h>
#include <asm/io.h>
static struct i2c_algo_bit_data bttv_i2c_algo_bit_template; static struct i2c_algo_bit_data bttv_i2c_algo_bit_template;
static struct i2c_adapter bttv_i2c_adap_sw_template; static struct i2c_adapter bttv_i2c_adap_sw_template;
@ -105,10 +106,8 @@ static struct i2c_algo_bit_data bttv_i2c_algo_bit_template = {
static struct i2c_adapter bttv_i2c_adap_sw_template = { static struct i2c_adapter bttv_i2c_adap_sw_template = {
.owner = THIS_MODULE, .owner = THIS_MODULE,
#ifdef I2C_CLASS_TV_ANALOG
.class = I2C_CLASS_TV_ANALOG, .class = I2C_CLASS_TV_ANALOG,
#endif .name = "bttv",
.name = "bt848",
.id = I2C_HW_B_BT848, .id = I2C_HW_B_BT848,
.client_register = attach_inform, .client_register = attach_inform,
}; };
@ -276,9 +275,7 @@ static struct i2c_algorithm bttv_algo = {
static struct i2c_adapter bttv_i2c_adap_hw_template = { static struct i2c_adapter bttv_i2c_adap_hw_template = {
.owner = THIS_MODULE, .owner = THIS_MODULE,
#ifdef I2C_CLASS_TV_ANALOG
.class = I2C_CLASS_TV_ANALOG, .class = I2C_CLASS_TV_ANALOG,
#endif
.name = "bt878", .name = "bt878",
.id = I2C_HW_B_BT848 /* FIXME */, .id = I2C_HW_B_BT848 /* FIXME */,
.algo = &bttv_algo, .algo = &bttv_algo,
@ -441,12 +438,10 @@ int __devinit init_bttv_i2c(struct bttv *btv)
i2c_set_adapdata(&btv->c.i2c_adap, btv); i2c_set_adapdata(&btv->c.i2c_adap, btv);
btv->i2c_client.adapter = &btv->c.i2c_adap; btv->i2c_client.adapter = &btv->c.i2c_adap;
#ifdef I2C_CLASS_TV_ANALOG
if (bttv_tvcards[btv->c.type].no_video) if (bttv_tvcards[btv->c.type].no_video)
btv->c.i2c_adap.class &= ~I2C_CLASS_TV_ANALOG; btv->c.i2c_adap.class &= ~I2C_CLASS_TV_ANALOG;
if (bttv_tvcards[btv->c.type].has_dvb) if (bttv_tvcards[btv->c.type].has_dvb)
btv->c.i2c_adap.class |= I2C_CLASS_TV_DIGITAL; btv->c.i2c_adap.class |= I2C_CLASS_TV_DIGITAL;
#endif
if (btv->use_i2c_hw) { if (btv->use_i2c_hw) {
btv->i2c_rc = i2c_add_adapter(&btv->c.i2c_adap); btv->i2c_rc = i2c_add_adapter(&btv->c.i2c_adap);

View File

@ -24,11 +24,9 @@
#include <linux/delay.h> #include <linux/delay.h>
#include <linux/interrupt.h> #include <linux/interrupt.h>
#include <linux/input.h> #include <linux/input.h>
#include <linux/pci.h>
#include <media/ir-common.h>
#include "bttv.h" #include "bttv.h"
#include "bttvp.h"
/* ---------------------------------------------------------------------- */ /* ---------------------------------------------------------------------- */
@ -156,9 +154,6 @@ static IR_KEYTAB_TYPE ir_codes_apac_viewcomp[IR_KEYTAB_SIZE] = {
/* ---------------------------------------------------------------------- */ /* ---------------------------------------------------------------------- */
/* Ricardo Cerqueira <v4l@cerqueira.org> */
/* Weird matching, since the remote has "uncommon" keys */
static IR_KEYTAB_TYPE ir_codes_conceptronic[IR_KEYTAB_SIZE] = { static IR_KEYTAB_TYPE ir_codes_conceptronic[IR_KEYTAB_SIZE] = {
[ 30 ] = KEY_POWER, // power [ 30 ] = KEY_POWER, // power
@ -279,34 +274,6 @@ static IR_KEYTAB_TYPE ir_codes_nebula[IR_KEYTAB_SIZE] = {
[0x36] = KEY_PC [0x36] = KEY_PC
}; };
struct IR {
struct bttv_sub_device *sub;
struct input_dev *input;
struct ir_input_state ir;
char name[32];
char phys[32];
/* Usual gpio signalling */
u32 mask_keycode;
u32 mask_keydown;
u32 mask_keyup;
u32 polling;
u32 last_gpio;
struct work_struct work;
struct timer_list timer;
/* RC5 gpio */
u32 rc5_gpio;
struct timer_list timer_end; /* timer_end for code completion */
struct timer_list timer_keyup; /* timer_end for key release */
u32 last_rc5; /* last good rc5 code */
u32 last_bit; /* last raw bit seen */
u32 code; /* raw code under construction */
struct timeval base_time; /* time of last seen code */
int active; /* building raw code */
};
static int debug; static int debug;
module_param(debug, int, 0644); /* debug level (0,1,2) */ module_param(debug, int, 0644); /* debug level (0,1,2) */
static int repeat_delay = 500; static int repeat_delay = 500;
@ -314,31 +281,17 @@ module_param(repeat_delay, int, 0644);
static int repeat_period = 33; static int repeat_period = 33;
module_param(repeat_period, int, 0644); module_param(repeat_period, int, 0644);
#define DEVNAME "ir-kbd-gpio" #define DEVNAME "bttv-input"
#define dprintk(fmt, arg...) if (debug) \
printk(KERN_DEBUG DEVNAME ": " fmt , ## arg)
static void ir_irq(struct bttv_sub_device *sub);
static int ir_probe(struct device *dev);
static int ir_remove(struct device *dev);
static struct bttv_sub_driver driver = {
.drv = {
.name = DEVNAME,
.probe = ir_probe,
.remove = ir_remove,
},
.gpio_irq = ir_irq,
};
/* ---------------------------------------------------------------------- */ /* ---------------------------------------------------------------------- */
static void ir_handle_key(struct IR *ir) static void ir_handle_key(struct bttv *btv)
{ {
struct bttv_ir *ir = btv->remote;
u32 gpio,data; u32 gpio,data;
/* read gpio value */ /* read gpio value */
gpio = bttv_gpio_read(ir->sub->core); gpio = bttv_gpio_read(&btv->c);
if (ir->polling) { if (ir->polling) {
if (ir->last_gpio == gpio) if (ir->last_gpio == gpio)
return; return;
@ -347,56 +300,36 @@ static void ir_handle_key(struct IR *ir)
/* extract data */ /* extract data */
data = ir_extract_bits(gpio, ir->mask_keycode); data = ir_extract_bits(gpio, ir->mask_keycode);
dprintk(DEVNAME ": irq gpio=0x%x code=%d | %s%s%s\n", dprintk(KERN_INFO DEVNAME ": irq gpio=0x%x code=%d | %s%s%s\n",
gpio, data, gpio, data,
ir->polling ? "poll" : "irq", ir->polling ? "poll" : "irq",
(gpio & ir->mask_keydown) ? " down" : "", (gpio & ir->mask_keydown) ? " down" : "",
(gpio & ir->mask_keyup) ? " up" : ""); (gpio & ir->mask_keyup) ? " up" : "");
if (ir->mask_keydown) { if ((ir->mask_keydown && (0 != (gpio & ir->mask_keydown))) ||
/* bit set on keydown */ (ir->mask_keyup && (0 == (gpio & ir->mask_keyup)))) {
if (gpio & ir->mask_keydown) { ir_input_keydown(ir->dev,&ir->ir,data,data);
ir_input_keydown(ir->input, &ir->ir, data, data);
} else { } else {
ir_input_nokey(ir->input, &ir->ir); ir_input_nokey(ir->dev,&ir->ir);
} }
} else if (ir->mask_keyup) {
/* bit cleared on keydown */
if (0 == (gpio & ir->mask_keyup)) {
ir_input_keydown(ir->input, &ir->ir, data, data);
} else {
ir_input_nokey(ir->input, &ir->ir);
} }
} else { void bttv_input_irq(struct bttv *btv)
/* can't disturgissh keydown/up :-/ */
ir_input_keydown(ir->input, &ir->ir, data, data);
ir_input_nokey(ir->input, &ir->ir);
}
}
static void ir_irq(struct bttv_sub_device *sub)
{ {
struct IR *ir = dev_get_drvdata(&sub->dev); struct bttv_ir *ir = btv->remote;
if (!ir->polling) if (!ir->polling)
ir_handle_key(ir); ir_handle_key(btv);
} }
static void ir_timer(unsigned long data) static void bttv_input_timer(unsigned long data)
{ {
struct IR *ir = (struct IR*)data; struct bttv *btv = (struct bttv*)data;
struct bttv_ir *ir = btv->remote;
schedule_work(&ir->work);
}
static void ir_work(void *data)
{
struct IR *ir = data;
unsigned long timeout; unsigned long timeout;
ir_handle_key(ir); ir_handle_key(btv);
timeout = jiffies + (ir->polling * HZ / 1000); timeout = jiffies + (ir->polling * HZ / 1000);
mod_timer(&ir->timer, timeout); mod_timer(&ir->timer, timeout);
} }
@ -435,26 +368,26 @@ static u32 rc5_decode(unsigned int code)
rc5 |= 1; rc5 |= 1;
break; break;
case 3: case 3:
dprintk("bad code: %x\n", org_code); dprintk(KERN_WARNING "bad code: %x\n", org_code);
return 0; return 0;
} }
} }
dprintk("code=%x, rc5=%x, start=%x, toggle=%x, address=%x, " dprintk(KERN_WARNING "code=%x, rc5=%x, start=%x, toggle=%x, address=%x, "
"instr=%x\n", rc5, org_code, RC5_START(rc5), "instr=%x\n", rc5, org_code, RC5_START(rc5),
RC5_TOGGLE(rc5), RC5_ADDR(rc5), RC5_INSTR(rc5)); RC5_TOGGLE(rc5), RC5_ADDR(rc5), RC5_INSTR(rc5));
return rc5; return rc5;
} }
static int ir_rc5_irq(struct bttv_sub_device *sub) static int bttv_rc5_irq(struct bttv *btv)
{ {
struct IR *ir = dev_get_drvdata(&sub->dev); struct bttv_ir *ir = btv->remote;
struct timeval tv; struct timeval tv;
u32 gpio; u32 gpio;
u32 gap; u32 gap;
unsigned long current_jiffies, timeout; unsigned long current_jiffies, timeout;
/* read gpio port */ /* read gpio port */
gpio = bttv_gpio_read(ir->sub->core); gpio = bttv_gpio_read(&btv->c);
/* remote IRQ? */ /* remote IRQ? */
if (!(gpio & 0x20)) if (!(gpio & 0x20))
@ -493,14 +426,15 @@ static int ir_rc5_irq(struct bttv_sub_device *sub)
} }
/* toggle GPIO pin 4 to reset the irq */ /* toggle GPIO pin 4 to reset the irq */
bttv_gpio_write(ir->sub->core, gpio & ~(1 << 4)); bttv_gpio_write(&btv->c, gpio & ~(1 << 4));
bttv_gpio_write(ir->sub->core, gpio | (1 << 4)); bttv_gpio_write(&btv->c, gpio | (1 << 4));
return 1; return 1;
} }
static void ir_rc5_timer_end(unsigned long data)
static void bttv_rc5_timer_end(unsigned long data)
{ {
struct IR *ir = (struct IR *)data; struct bttv_ir *ir = (struct bttv_ir *)data;
struct timeval tv; struct timeval tv;
unsigned long current_jiffies, timeout; unsigned long current_jiffies, timeout;
u32 gap; u32 gap;
@ -519,20 +453,20 @@ static void ir_rc5_timer_end(unsigned long data)
/* Allow some timmer jitter (RC5 is ~24ms anyway so this is ok) */ /* Allow some timmer jitter (RC5 is ~24ms anyway so this is ok) */
if (gap < 28000) { if (gap < 28000) {
dprintk("spurious timer_end\n"); dprintk(KERN_WARNING "spurious timer_end\n");
return; return;
} }
ir->active = 0; ir->active = 0;
if (ir->last_bit < 20) { if (ir->last_bit < 20) {
/* ignore spurious codes (caused by light/other remotes) */ /* ignore spurious codes (caused by light/other remotes) */
dprintk("short code: %x\n", ir->code); dprintk(KERN_WARNING "short code: %x\n", ir->code);
} else { } else {
u32 rc5 = rc5_decode(ir->code); u32 rc5 = rc5_decode(ir->code);
/* two start bits? */ /* two start bits? */
if (RC5_START(rc5) != 3) { if (RC5_START(rc5) != 3) {
dprintk("rc5 start bits invalid: %u\n", RC5_START(rc5)); dprintk(KERN_WARNING "rc5 start bits invalid: %u\n", RC5_START(rc5));
/* right address? */ /* right address? */
} else if (RC5_ADDR(rc5) == 0x0) { } else if (RC5_ADDR(rc5) == 0x0) {
@ -542,10 +476,10 @@ static void ir_rc5_timer_end(unsigned long data)
/* Good code, decide if repeat/repress */ /* Good code, decide if repeat/repress */
if (toggle != RC5_TOGGLE(ir->last_rc5) || if (toggle != RC5_TOGGLE(ir->last_rc5) ||
instr != RC5_INSTR(ir->last_rc5)) { instr != RC5_INSTR(ir->last_rc5)) {
dprintk("instruction %x, toggle %x\n", instr, dprintk(KERN_WARNING "instruction %x, toggle %x\n", instr,
toggle); toggle);
ir_input_nokey(ir->input, &ir->ir); ir_input_nokey(ir->dev, &ir->ir);
ir_input_keydown(ir->input, &ir->ir, instr, ir_input_keydown(ir->dev, &ir->ir, instr,
instr); instr);
} }
@ -560,24 +494,26 @@ static void ir_rc5_timer_end(unsigned long data)
} }
} }
static void ir_rc5_timer_keyup(unsigned long data) static void bttv_rc5_timer_keyup(unsigned long data)
{ {
struct IR *ir = (struct IR *)data; struct bttv_ir *ir = (struct bttv_ir *)data;
dprintk("key released\n"); dprintk(KERN_DEBUG "key released\n");
ir_input_nokey(ir->input, &ir->ir); ir_input_nokey(ir->dev, &ir->ir);
} }
/* ---------------------------------------------------------------------- */ /* ---------------------------------------------------------------------- */
static int ir_probe(struct device *dev) int bttv_input_init(struct bttv *btv)
{ {
struct bttv_sub_device *sub = to_bttv_sub_dev(dev); struct bttv_ir *ir;
struct IR *ir;
struct input_dev *input_dev;
IR_KEYTAB_TYPE *ir_codes = NULL; IR_KEYTAB_TYPE *ir_codes = NULL;
struct input_dev *input_dev;
int ir_type = IR_TYPE_OTHER; int ir_type = IR_TYPE_OTHER;
if (!btv->has_remote)
return -ENODEV;
ir = kzalloc(sizeof(*ir),GFP_KERNEL); ir = kzalloc(sizeof(*ir),GFP_KERNEL);
input_dev = input_allocate_device(); input_dev = input_allocate_device();
if (!ir || !input_dev) { if (!ir || !input_dev) {
@ -585,9 +521,10 @@ static int ir_probe(struct device *dev)
input_free_device(input_dev); input_free_device(input_dev);
return -ENOMEM; return -ENOMEM;
} }
memset(ir,0,sizeof(*ir));
/* detect & configure */ /* detect & configure */
switch (sub->core->type) { switch (btv->c.type) {
case BTTV_BOARD_AVERMEDIA: case BTTV_BOARD_AVERMEDIA:
case BTTV_BOARD_AVPHONE98: case BTTV_BOARD_AVPHONE98:
case BTTV_BOARD_AVERMEDIA98: case BTTV_BOARD_AVERMEDIA98:
@ -643,12 +580,12 @@ static int ir_probe(struct device *dev)
break; break;
case BTTV_BOARD_NEBULA_DIGITV: case BTTV_BOARD_NEBULA_DIGITV:
ir_codes = ir_codes_nebula; ir_codes = ir_codes_nebula;
driver.any_irq = ir_rc5_irq; btv->custom_irq = bttv_rc5_irq;
driver.gpio_irq = NULL;
ir->rc5_gpio = 1; ir->rc5_gpio = 1;
break; break;
} }
if (NULL == ir_codes) { if (NULL == ir_codes) {
dprintk(KERN_INFO "Ooops: IR config error [card=%d]\n",btv->c.type);
kfree(ir); kfree(ir);
input_free_device(input_dev); input_free_device(input_dev);
return -ENODEV; return -ENODEV;
@ -657,109 +594,92 @@ static int ir_probe(struct device *dev)
if (ir->rc5_gpio) { if (ir->rc5_gpio) {
u32 gpio; u32 gpio;
/* enable remote irq */ /* enable remote irq */
bttv_gpio_inout(sub->core, (1 << 4), 1 << 4); bttv_gpio_inout(&btv->c, (1 << 4), 1 << 4);
gpio = bttv_gpio_read(sub->core); gpio = bttv_gpio_read(&btv->c);
bttv_gpio_write(sub->core, gpio & ~(1 << 4)); bttv_gpio_write(&btv->c, gpio & ~(1 << 4));
bttv_gpio_write(sub->core, gpio | (1 << 4)); bttv_gpio_write(&btv->c, gpio | (1 << 4));
} else { } else {
/* init hardware-specific stuff */ /* init hardware-specific stuff */
bttv_gpio_inout(sub->core, ir->mask_keycode | ir->mask_keydown, 0); bttv_gpio_inout(&btv->c, ir->mask_keycode | ir->mask_keydown, 0);
} }
/* init input device */ /* init input device */
ir->dev = input_dev;
snprintf(ir->name, sizeof(ir->name), "bttv IR (card=%d)", snprintf(ir->name, sizeof(ir->name), "bttv IR (card=%d)",
sub->core->type); btv->c.type);
snprintf(ir->phys, sizeof(ir->phys), "pci-%s/ir0", snprintf(ir->phys, sizeof(ir->phys), "pci-%s/ir0",
pci_name(sub->core->pci)); pci_name(btv->c.pci));
ir_input_init(input_dev, &ir->ir, ir_type, ir_codes); ir_input_init(input_dev, &ir->ir, ir_type, ir_codes);
input_dev->name = ir->name; input_dev->name = ir->name;
input_dev->phys = ir->phys; input_dev->phys = ir->phys;
input_dev->id.bustype = BUS_PCI; input_dev->id.bustype = BUS_PCI;
input_dev->id.version = 1; input_dev->id.version = 1;
if (sub->core->pci->subsystem_vendor) { if (btv->c.pci->subsystem_vendor) {
input_dev->id.vendor = sub->core->pci->subsystem_vendor; input_dev->id.vendor = btv->c.pci->subsystem_vendor;
input_dev->id.product = sub->core->pci->subsystem_device; input_dev->id.product = btv->c.pci->subsystem_device;
} else { } else {
input_dev->id.vendor = sub->core->pci->vendor; input_dev->id.vendor = btv->c.pci->vendor;
input_dev->id.product = sub->core->pci->device; input_dev->id.product = btv->c.pci->device;
} }
input_dev->cdev.dev = &sub->core->pci->dev; input_dev->cdev.dev = &btv->c.pci->dev;
ir->input = input_dev;
ir->sub = sub;
btv->remote = ir;
if (ir->polling) { if (ir->polling) {
INIT_WORK(&ir->work, ir_work, ir);
init_timer(&ir->timer); init_timer(&ir->timer);
ir->timer.function = ir_timer; ir->timer.function = bttv_input_timer;
ir->timer.data = (unsigned long)ir; ir->timer.data = (unsigned long)btv;
schedule_work(&ir->work); ir->timer.expires = jiffies + HZ;
add_timer(&ir->timer);
} else if (ir->rc5_gpio) { } else if (ir->rc5_gpio) {
/* set timer_end for code completion */ /* set timer_end for code completion */
init_timer(&ir->timer_end); init_timer(&ir->timer_end);
ir->timer_end.function = ir_rc5_timer_end; ir->timer_end.function = bttv_rc5_timer_end;
ir->timer_end.data = (unsigned long)ir; ir->timer_end.data = (unsigned long)ir;
init_timer(&ir->timer_keyup); init_timer(&ir->timer_keyup);
ir->timer_keyup.function = ir_rc5_timer_keyup; ir->timer_keyup.function = bttv_rc5_timer_keyup;
ir->timer_keyup.data = (unsigned long)ir; ir->timer_keyup.data = (unsigned long)ir;
} }
/* all done */ /* all done */
dev_set_drvdata(dev, ir); input_register_device(btv->remote->dev);
input_register_device(ir->input); printk(DEVNAME ": %s detected at %s\n",ir->name,ir->phys);
/* the remote isn't as bouncy as a keyboard */ /* the remote isn't as bouncy as a keyboard */
ir->input->rep[REP_DELAY] = repeat_delay; ir->dev->rep[REP_DELAY] = repeat_delay;
ir->input->rep[REP_PERIOD] = repeat_period; ir->dev->rep[REP_PERIOD] = repeat_period;
return 0; return 0;
} }
static int ir_remove(struct device *dev) void bttv_input_fini(struct bttv *btv)
{ {
struct IR *ir = dev_get_drvdata(dev); if (btv->remote == NULL)
return;
if (ir->polling) { if (btv->remote->polling) {
del_timer(&ir->timer); del_timer_sync(&btv->remote->timer);
flush_scheduled_work(); flush_scheduled_work();
} }
if (ir->rc5_gpio) {
if (btv->remote->rc5_gpio) {
u32 gpio; u32 gpio;
del_timer(&ir->timer_end); del_timer_sync(&btv->remote->timer_end);
flush_scheduled_work(); flush_scheduled_work();
gpio = bttv_gpio_read(ir->sub->core); gpio = bttv_gpio_read(&btv->c);
bttv_gpio_write(ir->sub->core, gpio & ~(1 << 4)); bttv_gpio_write(&btv->c, gpio & ~(1 << 4));
} }
input_unregister_device(ir->input); input_unregister_device(btv->remote->dev);
kfree(ir); kfree(btv->remote);
return 0; btv->remote = NULL;
} }
/* ---------------------------------------------------------------------- */
MODULE_AUTHOR("Gerd Knorr, Pavel Machek");
MODULE_DESCRIPTION("input driver for bt8x8 gpio IR remote controls");
MODULE_LICENSE("GPL");
static int ir_init(void)
{
return bttv_sub_register(&driver, "remote");
}
static void ir_fini(void)
{
bttv_sub_unregister(&driver);
}
module_init(ir_init);
module_exit(ir_fini);
/* /*
* Local variables: * Local variables:

View File

@ -31,6 +31,12 @@
#include <asm/io.h> #include <asm/io.h>
#include "bttvp.h" #include "bttvp.h"
/* Offset from line sync pulse leading edge (0H) in 1 / sampling_rate:
bt8x8 /HRESET pulse starts at 0H and has length 64 / fCLKx1 (E|O_VTC
HSFMT = 0). VBI_HDELAY (always 0) is an offset from the trailing edge
of /HRESET in 1 / fCLKx1, and the sampling_rate tvnorm->Fsc is fCLKx2. */
#define VBI_OFFSET ((64 + 0) * 2)
#define VBI_DEFLINES 16 #define VBI_DEFLINES 16
#define VBI_MAXLINES 32 #define VBI_MAXLINES 32
@ -163,40 +169,30 @@ void bttv_vbi_setlines(struct bttv_fh *fh, struct bttv *btv, int lines)
void bttv_vbi_try_fmt(struct bttv_fh *fh, struct v4l2_format *f) void bttv_vbi_try_fmt(struct bttv_fh *fh, struct v4l2_format *f)
{ {
const struct bttv_tvnorm *tvnorm; const struct bttv_tvnorm *tvnorm;
u32 start0,start1; s64 count0,count1,count;
s32 count0,count1,count;
tvnorm = &bttv_tvnorms[fh->btv->tvnorm]; tvnorm = &bttv_tvnorms[fh->btv->tvnorm];
f->type = V4L2_BUF_TYPE_VBI_CAPTURE; f->type = V4L2_BUF_TYPE_VBI_CAPTURE;
f->fmt.vbi.sampling_rate = tvnorm->Fsc; f->fmt.vbi.sampling_rate = tvnorm->Fsc;
f->fmt.vbi.samples_per_line = 2048; f->fmt.vbi.samples_per_line = 2048;
f->fmt.vbi.sample_format = V4L2_PIX_FMT_GREY; f->fmt.vbi.sample_format = V4L2_PIX_FMT_GREY;
f->fmt.vbi.offset = 244; f->fmt.vbi.offset = VBI_OFFSET;
f->fmt.vbi.flags = 0; f->fmt.vbi.flags = 0;
switch (fh->btv->tvnorm) {
case 1: /* NTSC */
start0 = 10;
start1 = 273;
break;
case 0: /* PAL */
case 2: /* SECAM */
default:
start0 = 7;
start1 = 320;
}
count0 = (f->fmt.vbi.start[0] + f->fmt.vbi.count[0]) - start0; /* s64 to prevent overflow. */
count1 = (f->fmt.vbi.start[1] + f->fmt.vbi.count[1]) - start1; count0 = (s64) f->fmt.vbi.start[0] + f->fmt.vbi.count[0]
count = max(count0,count1); - tvnorm->vbistart[0];
if (count > VBI_MAXLINES) count1 = (s64) f->fmt.vbi.start[1] + f->fmt.vbi.count[1]
count = VBI_MAXLINES; - tvnorm->vbistart[1];
if (count < 1) count = clamp (max (count0, count1), 1LL, (s64) VBI_MAXLINES);
count = 1;
f->fmt.vbi.start[0] = start0; f->fmt.vbi.start[0] = tvnorm->vbistart[0];
f->fmt.vbi.start[1] = start1; f->fmt.vbi.start[1] = tvnorm->vbistart[1];
f->fmt.vbi.count[0] = count; f->fmt.vbi.count[0] = count;
f->fmt.vbi.count[1] = count; f->fmt.vbi.count[1] = count;
f->fmt.vbi.reserved[0] = 0;
f->fmt.vbi.reserved[1] = 0;
} }
void bttv_vbi_get_fmt(struct bttv_fh *fh, struct v4l2_format *f) void bttv_vbi_get_fmt(struct bttv_fh *fh, struct v4l2_format *f)
@ -209,21 +205,12 @@ void bttv_vbi_get_fmt(struct bttv_fh *fh, struct v4l2_format *f)
f->fmt.vbi.sampling_rate = tvnorm->Fsc; f->fmt.vbi.sampling_rate = tvnorm->Fsc;
f->fmt.vbi.samples_per_line = 2048; f->fmt.vbi.samples_per_line = 2048;
f->fmt.vbi.sample_format = V4L2_PIX_FMT_GREY; f->fmt.vbi.sample_format = V4L2_PIX_FMT_GREY;
f->fmt.vbi.offset = 244; f->fmt.vbi.offset = VBI_OFFSET;
f->fmt.vbi.start[0] = tvnorm->vbistart[0];
f->fmt.vbi.start[1] = tvnorm->vbistart[1];
f->fmt.vbi.count[0] = fh->lines; f->fmt.vbi.count[0] = fh->lines;
f->fmt.vbi.count[1] = fh->lines; f->fmt.vbi.count[1] = fh->lines;
f->fmt.vbi.flags = 0; f->fmt.vbi.flags = 0;
switch (fh->btv->tvnorm) {
case 1: /* NTSC */
f->fmt.vbi.start[0] = 10;
f->fmt.vbi.start[1] = 273;
break;
case 0: /* PAL */
case 2: /* SECAM */
default:
f->fmt.vbi.start[0] = 7;
f->fmt.vbi.start[1] = 319;
}
} }
/* ----------------------------------------------------------------------- */ /* ----------------------------------------------------------------------- */

View File

@ -16,6 +16,8 @@
#include <linux/videodev.h> #include <linux/videodev.h>
#include <linux/i2c.h> #include <linux/i2c.h>
#include <media/ir-common.h>
#include <media/ir-kbd-i2c.h>
/* ---------------------------------------------------------- */ /* ---------------------------------------------------------- */
/* exported by bttv-cards.c */ /* exported by bttv-cards.c */
@ -163,6 +165,7 @@
#define BTTV_BOARD_OSPREY440 0x8c #define BTTV_BOARD_OSPREY440 0x8c
#define BTTV_BOARD_ASOUND_SKYEYE 0x8d #define BTTV_BOARD_ASOUND_SKYEYE 0x8d
#define BTTV_BOARD_SABRENT_TVFM 0x8e #define BTTV_BOARD_SABRENT_TVFM 0x8e
#define BTTV_BOARD_HAUPPAUGE_IMPACTVCB 0x8f
/* i2c address list */ /* i2c address list */
#define I2C_TSA5522 0xc2 #define I2C_TSA5522 0xc2
@ -210,6 +213,34 @@ struct bttv_core {
struct bttv; struct bttv;
struct bttv_ir {
struct input_dev *dev;
struct ir_input_state ir;
char name[32];
char phys[32];
/* Usual gpio signalling */
u32 mask_keycode;
u32 mask_keydown;
u32 mask_keyup;
u32 polling;
u32 last_gpio;
struct work_struct work;
struct timer_list timer;
/* RC5 gpio */
u32 rc5_gpio;
struct timer_list timer_end; /* timer_end for code completion */
struct timer_list timer_keyup; /* timer_end for key release */
u32 last_rc5; /* last good rc5 code */
u32 last_bit; /* last raw bit seen */
u32 code; /* raw code under construction */
struct timeval base_time; /* time of last seen code */
int active; /* building raw code */
};
struct tvcard struct tvcard
{ {
char *name; char *name;
@ -235,7 +266,6 @@ struct tvcard
unsigned int has_dvb:1; unsigned int has_dvb:1;
unsigned int has_remote:1; unsigned int has_remote:1;
unsigned int no_gpioirq:1; unsigned int no_gpioirq:1;
unsigned int any_irq:1;
/* other settings */ /* other settings */
unsigned int pll; unsigned int pll;
@ -335,7 +365,6 @@ struct bttv_sub_driver {
struct device_driver drv; struct device_driver drv;
char wanted[BUS_ID_SIZE]; char wanted[BUS_ID_SIZE];
void (*gpio_irq)(struct bttv_sub_device *sub); void (*gpio_irq)(struct bttv_sub_device *sub);
int (*any_irq)(struct bttv_sub_device *sub);
}; };
#define to_bttv_sub_drv(x) container_of((x), struct bttv_sub_driver, drv) #define to_bttv_sub_drv(x) container_of((x), struct bttv_sub_driver, drv)
@ -363,6 +392,10 @@ extern int bttv_I2CWrite(struct bttv *btv, unsigned char addr, unsigned char b1,
unsigned char b2, int both); unsigned char b2, int both);
extern void bttv_readee(struct bttv *btv, unsigned char *eedata, int addr); extern void bttv_readee(struct bttv *btv, unsigned char *eedata, int addr);
extern int bttv_input_init(struct bttv *dev);
extern void bttv_input_fini(struct bttv *dev);
extern void bttv_input_irq(struct bttv *dev);
#endif /* _BTTV_H_ */ #endif /* _BTTV_H_ */
/* /*
* Local variables: * Local variables:

View File

@ -73,6 +73,8 @@
#define UNSET (-1U) #define UNSET (-1U)
#define clamp(x, low, high) min (max (low, x), high)
/* ---------------------------------------------------------- */ /* ---------------------------------------------------------- */
struct bttv_tvnorm { struct bttv_tvnorm {
@ -88,6 +90,9 @@ struct bttv_tvnorm {
u8 vbipack; u8 vbipack;
u16 vtotal; u16 vtotal;
int sram; int sram;
/* ITU-R frame line number of the first VBI line we can
capture, of the first and second field. */
u16 vbistart[2];
}; };
extern const struct bttv_tvnorm bttv_tvnorms[]; extern const struct bttv_tvnorm bttv_tvnorms[];
@ -209,7 +214,6 @@ extern struct bus_type bttv_sub_bus_type;
int bttv_sub_add_device(struct bttv_core *core, char *name); int bttv_sub_add_device(struct bttv_core *core, char *name);
int bttv_sub_del_devices(struct bttv_core *core); int bttv_sub_del_devices(struct bttv_core *core);
void bttv_gpio_irq(struct bttv_core *core); void bttv_gpio_irq(struct bttv_core *core);
int bttv_any_irq(struct bttv_core *core);
/* ---------------------------------------------------------- */ /* ---------------------------------------------------------- */
@ -270,12 +274,13 @@ struct bttv {
/* card configuration info */ /* card configuration info */
unsigned int cardid; /* pci subsystem id (bt878 based ones) */ unsigned int cardid; /* pci subsystem id (bt878 based ones) */
unsigned int tuner_type; /* tuner chip type */ unsigned int tuner_type; /* tuner chip type */
unsigned int pinnacle_id; unsigned int tda9887_conf;
unsigned int svhs; unsigned int svhs;
struct bttv_pll_info pll; struct bttv_pll_info pll;
int triton1; int triton1;
int gpioirq; int gpioirq;
int any_irq; int (*custom_irq)(struct bttv *btv);
int use_i2c_hw; int use_i2c_hw;
/* old gpio interface */ /* old gpio interface */
@ -300,7 +305,7 @@ struct bttv {
/* infrared remote */ /* infrared remote */
int has_remote; int has_remote;
struct bttv_input *remote; struct bttv_ir *remote;
/* locking */ /* locking */
spinlock_t s_lock; spinlock_t s_lock;

View File

@ -875,6 +875,7 @@ static struct file_operations qcam_fops = {
.open = video_exclusive_open, .open = video_exclusive_open,
.release = video_exclusive_release, .release = video_exclusive_release,
.ioctl = qcam_ioctl, .ioctl = qcam_ioctl,
.compat_ioctl = v4l_compat_ioctl32,
.read = qcam_read, .read = qcam_read,
.llseek = no_llseek, .llseek = no_llseek,
}; };

View File

@ -687,6 +687,7 @@ static struct file_operations qcam_fops = {
.open = video_exclusive_open, .open = video_exclusive_open,
.release = video_exclusive_release, .release = video_exclusive_release,
.ioctl = qcam_ioctl, .ioctl = qcam_ioctl,
.compat_ioctl = v4l_compat_ioctl32,
.read = qcam_read, .read = qcam_read,
.llseek = no_llseek, .llseek = no_llseek,
}; };

View File

@ -0,0 +1,732 @@
/*
* ioctl32.c: Conversion between 32bit and 64bit native ioctls.
* Separated from fs stuff by Arnd Bergmann <arnd@arndb.de>
*
* Copyright (C) 1997-2000 Jakub Jelinek (jakub@redhat.com)
* Copyright (C) 1998 Eddie C. Dost (ecd@skynet.be)
* Copyright (C) 2001,2002 Andi Kleen, SuSE Labs
* Copyright (C) 2003 Pavel Machek (pavel@suse.cz)
* Copyright (C) 2005 Philippe De Muyter (phdm@macqel.be)
*
* These routines maintain argument size conversion between 32bit and 64bit
* ioctls.
*/
#include <linux/config.h>
#include <linux/compat.h>
#include <linux/videodev.h>
#include <linux/videodev2.h>
#include <linux/module.h>
#include <linux/smp_lock.h>
#ifdef CONFIG_COMPAT
struct video_tuner32 {
compat_int_t tuner;
char name[32];
compat_ulong_t rangelow, rangehigh;
u32 flags; /* It is really u32 in videodev.h */
u16 mode, signal;
};
static int get_video_tuner32(struct video_tuner *kp, struct video_tuner32 __user *up)
{
if(get_user(kp->tuner, &up->tuner))
return -EFAULT;
__copy_from_user(kp->name, up->name, 32);
__get_user(kp->rangelow, &up->rangelow);
__get_user(kp->rangehigh, &up->rangehigh);
__get_user(kp->flags, &up->flags);
__get_user(kp->mode, &up->mode);
__get_user(kp->signal, &up->signal);
return 0;
}
static int put_video_tuner32(struct video_tuner *kp, struct video_tuner32 __user *up)
{
if(put_user(kp->tuner, &up->tuner))
return -EFAULT;
__copy_to_user(up->name, kp->name, 32);
__put_user(kp->rangelow, &up->rangelow);
__put_user(kp->rangehigh, &up->rangehigh);
__put_user(kp->flags, &up->flags);
__put_user(kp->mode, &up->mode);
__put_user(kp->signal, &up->signal);
return 0;
}
struct video_buffer32 {
compat_caddr_t base;
compat_int_t height, width, depth, bytesperline;
};
static int get_video_buffer32(struct video_buffer *kp, struct video_buffer32 __user *up)
{
u32 tmp;
if (get_user(tmp, &up->base))
return -EFAULT;
/* This is actually a physical address stored
* as a void pointer.
*/
kp->base = (void *)(unsigned long) tmp;
__get_user(kp->height, &up->height);
__get_user(kp->width, &up->width);
__get_user(kp->depth, &up->depth);
__get_user(kp->bytesperline, &up->bytesperline);
return 0;
}
static int put_video_buffer32(struct video_buffer *kp, struct video_buffer32 __user *up)
{
u32 tmp = (u32)((unsigned long)kp->base);
if(put_user(tmp, &up->base))
return -EFAULT;
__put_user(kp->height, &up->height);
__put_user(kp->width, &up->width);
__put_user(kp->depth, &up->depth);
__put_user(kp->bytesperline, &up->bytesperline);
return 0;
}
struct video_clip32 {
s32 x, y, width, height; /* Its really s32 in videodev.h */
compat_caddr_t next;
};
struct video_window32 {
u32 x, y, width, height, chromakey, flags;
compat_caddr_t clips;
compat_int_t clipcount;
};
static int native_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
{
int ret = -ENOIOCTLCMD;
if (file->f_op->unlocked_ioctl)
ret = file->f_op->unlocked_ioctl(file, cmd, arg);
else if (file->f_op->ioctl) {
lock_kernel();
ret = file->f_op->ioctl(file->f_dentry->d_inode, file, cmd, arg);
unlock_kernel();
}
return ret;
}
/* You get back everything except the clips... */
static int put_video_window32(struct video_window *kp, struct video_window32 __user *up)
{
if(put_user(kp->x, &up->x))
return -EFAULT;
__put_user(kp->y, &up->y);
__put_user(kp->width, &up->width);
__put_user(kp->height, &up->height);
__put_user(kp->chromakey, &up->chromakey);
__put_user(kp->flags, &up->flags);
__put_user(kp->clipcount, &up->clipcount);
return 0;
}
struct v4l2_clip32
{
struct v4l2_rect c;
compat_caddr_t next;
};
struct v4l2_window32
{
struct v4l2_rect w;
enum v4l2_field field;
__u32 chromakey;
compat_caddr_t clips; /* actually struct v4l2_clip32 * */
__u32 clipcount;
compat_caddr_t bitmap;
};
static int get_v4l2_window32(struct v4l2_window *kp, struct v4l2_window32 __user *up)
{
if (copy_from_user(&kp->w, &up->w, sizeof(up->w)))
return -EFAULT;
__get_user(kp->field, &up->field);
__get_user(kp->chromakey, &up->chromakey);
__get_user(kp->clipcount, &up->clipcount);
if (kp->clipcount > 2048)
return -EINVAL;
if (kp->clipcount) {
struct v4l2_clip32 *uclips = compat_ptr(up->clips);
struct v4l2_clip *kclips;
int n = kp->clipcount;
kclips = compat_alloc_user_space(n * sizeof(struct v4l2_clip));
kp->clips = kclips;
while (--n >= 0) {
copy_from_user(&kclips->c, &uclips->c, sizeof(uclips->c));
kclips->next = n ? kclips + 1 : 0;
uclips += 1;
kclips += 1;
}
} else
kp->clips = 0;
return 0;
}
static int put_v4l2_window32(struct v4l2_window *kp, struct v4l2_window32 __user *up)
{
if (copy_to_user(&up->w, &kp->w, sizeof(up->w)))
return -EFAULT;
__put_user(kp->field, &up->field);
__put_user(kp->chromakey, &up->chromakey);
__put_user(kp->clipcount, &up->clipcount);
return 0;
}
static inline int get_v4l2_pix_format(struct v4l2_pix_format *kp, struct v4l2_pix_format __user *up)
{
return copy_from_user(kp, up, sizeof(struct v4l2_pix_format));
}
static inline int put_v4l2_pix_format(struct v4l2_pix_format *kp, struct v4l2_pix_format __user *up)
{
return copy_to_user(up, kp, sizeof(struct v4l2_pix_format));
}
static inline int get_v4l2_vbi_format(struct v4l2_vbi_format *kp, struct v4l2_vbi_format __user *up)
{
return copy_from_user(kp, up, sizeof(struct v4l2_vbi_format));
}
static inline int put_v4l2_vbi_format(struct v4l2_vbi_format *kp, struct v4l2_vbi_format __user *up)
{
return copy_to_user(up, kp, sizeof(struct v4l2_vbi_format));
}
struct v4l2_format32
{
enum v4l2_buf_type type;
union
{
struct v4l2_pix_format pix; // V4L2_BUF_TYPE_VIDEO_CAPTURE
struct v4l2_window32 win; // V4L2_BUF_TYPE_VIDEO_OVERLAY
struct v4l2_vbi_format vbi; // V4L2_BUF_TYPE_VBI_CAPTURE
__u8 raw_data[200]; // user-defined
} fmt;
};
static int get_v4l2_format32(struct v4l2_format *kp, struct v4l2_format32 __user *up)
{
if(get_user(kp->type, &up->type))
return -EFAULT;
switch (kp->type) {
case V4L2_BUF_TYPE_VIDEO_CAPTURE:
return get_v4l2_pix_format(&kp->fmt.pix, &up->fmt.pix);
case V4L2_BUF_TYPE_VIDEO_OVERLAY:
return get_v4l2_window32(&kp->fmt.win, &up->fmt.win);
case V4L2_BUF_TYPE_VBI_CAPTURE:
return get_v4l2_vbi_format(&kp->fmt.vbi, &up->fmt.vbi);
default:
printk("compat_ioctl : unexpected VIDIOC_FMT type %d\n",
kp->type);
return -ENXIO;
}
}
static int put_v4l2_format32(struct v4l2_format *kp, struct v4l2_format32 __user *up)
{
if(put_user(kp->type, &up->type))
return -EFAULT;
switch (kp->type) {
case V4L2_BUF_TYPE_VIDEO_CAPTURE:
return put_v4l2_pix_format(&kp->fmt.pix, &up->fmt.pix);
case V4L2_BUF_TYPE_VIDEO_OVERLAY:
return put_v4l2_window32(&kp->fmt.win, &up->fmt.win);
case V4L2_BUF_TYPE_VBI_CAPTURE:
return put_v4l2_vbi_format(&kp->fmt.vbi, &up->fmt.vbi);
default:
return -ENXIO;
}
}
struct v4l2_standard32
{
__u32 index;
__u32 id[2]; /* __u64 would get the alignment wrong */
__u8 name[24];
struct v4l2_fract frameperiod; /* Frames, not fields */
__u32 framelines;
__u32 reserved[4];
};
static int get_v4l2_standard32(struct v4l2_standard *kp, struct v4l2_standard32 __user *up)
{
/* other fields are not set by the user, nor used by the driver */
return get_user(kp->index, &up->index);
}
static int put_v4l2_standard32(struct v4l2_standard *kp, struct v4l2_standard32 __user *up)
{
if(put_user(kp->index, &up->index))
return -EFAULT;
__copy_to_user(up->id, &kp->id, sizeof(__u64));
__copy_to_user(up->name, kp->name, 24);
__put_user(kp->frameperiod, &up->frameperiod);
__put_user(kp->framelines, &up->framelines);
__copy_to_user(up->reserved, kp->reserved, 4 * sizeof(__u32));
return 0;
}
struct v4l2_buffer32
{
__u32 index;
enum v4l2_buf_type type;
__u32 bytesused;
__u32 flags;
enum v4l2_field field;
struct compat_timeval timestamp;
struct v4l2_timecode timecode;
__u32 sequence;
/* memory location */
enum v4l2_memory memory;
union {
__u32 offset;
compat_long_t userptr;
} m;
__u32 length;
__u32 input;
__u32 reserved;
};
static int get_v4l2_buffer32(struct v4l2_buffer *kp, struct v4l2_buffer32 __user *up)
{
if (get_user(kp->index, &up->index))
return -EFAULT;
__get_user(kp->type, &up->type);
__get_user(kp->flags, &up->flags);
__get_user(kp->memory, &up->memory);
__get_user(kp->input, &up->input);
switch(kp->memory) {
case V4L2_MEMORY_MMAP:
break;
case V4L2_MEMORY_USERPTR:
{
unsigned long tmp = (unsigned long)compat_ptr(up->m.userptr);
__get_user(kp->length, &up->length);
__get_user(kp->m.userptr, &tmp);
}
break;
case V4L2_MEMORY_OVERLAY:
__get_user(kp->m.offset, &up->m.offset);
break;
}
return 0;
}
static int put_v4l2_buffer32(struct v4l2_buffer *kp, struct v4l2_buffer32 __user *up)
{
if (put_user(kp->index, &up->index))
return -EFAULT;
__put_user(kp->type, &up->type);
__put_user(kp->flags, &up->flags);
__put_user(kp->memory, &up->memory);
__put_user(kp->input, &up->input);
switch(kp->memory) {
case V4L2_MEMORY_MMAP:
__put_user(kp->length, &up->length);
__put_user(kp->m.offset, &up->m.offset);
break;
case V4L2_MEMORY_USERPTR:
__put_user(kp->length, &up->length);
__put_user(kp->m.userptr, &up->m.userptr);
break;
case V4L2_MEMORY_OVERLAY:
__put_user(kp->m.offset, &up->m.offset);
break;
}
__put_user(kp->bytesused, &up->bytesused);
__put_user(kp->field, &up->field);
__put_user(kp->timestamp.tv_sec, &up->timestamp.tv_sec);
__put_user(kp->timestamp.tv_usec, &up->timestamp.tv_usec);
__copy_to_user(&up->timecode, &kp->timecode, sizeof(struct v4l2_timecode));
__put_user(kp->sequence, &up->sequence);
__put_user(kp->reserved, &up->reserved);
return 0;
}
struct v4l2_framebuffer32
{
__u32 capability;
__u32 flags;
compat_caddr_t base;
struct v4l2_pix_format fmt;
};
static int get_v4l2_framebuffer32(struct v4l2_framebuffer *kp, struct v4l2_framebuffer32 __user *up)
{
u32 tmp;
if (get_user(tmp, &up->base))
return -EFAULT;
kp->base = compat_ptr(tmp);
__get_user(kp->capability, &up->capability);
__get_user(kp->flags, &up->flags);
get_v4l2_pix_format(&kp->fmt, &up->fmt);
return 0;
}
static int put_v4l2_framebuffer32(struct v4l2_framebuffer *kp, struct v4l2_framebuffer32 __user *up)
{
u32 tmp = (u32)((unsigned long)kp->base);
if(put_user(tmp, &up->base))
return -EFAULT;
__put_user(kp->capability, &up->capability);
__put_user(kp->flags, &up->flags);
put_v4l2_pix_format(&kp->fmt, &up->fmt);
return 0;
}
struct v4l2_input32 /* identical layout, but different size */
{
__u32 index; /* Which input */
__u8 name[32]; /* Label */
__u32 type; /* Type of input */
__u32 audioset; /* Associated audios (bitfield) */
__u32 tuner; /* Associated tuner */
__u32 std[2]; /* __u64 would get the padding wrong */
__u32 status;
__u32 reserved[4];
};
#define VIDIOCGTUNER32 _IOWR('v',4, struct video_tuner32)
#define VIDIOCSTUNER32 _IOW('v',5, struct video_tuner32)
#define VIDIOCGWIN32 _IOR('v',9, struct video_window32)
#define VIDIOCSWIN32 _IOW('v',10, struct video_window32)
#define VIDIOCGFBUF32 _IOR('v',11, struct video_buffer32)
#define VIDIOCSFBUF32 _IOW('v',12, struct video_buffer32)
#define VIDIOCGFREQ32 _IOR('v',14, u32)
#define VIDIOCSFREQ32 _IOW('v',15, u32)
#define VIDIOC_G_FMT32 _IOWR ('V', 4, struct v4l2_format32)
#define VIDIOC_S_FMT32 _IOWR ('V', 5, struct v4l2_format32)
#define VIDIOC_QUERYBUF32 _IOWR ('V', 9, struct v4l2_buffer32)
#define VIDIOC_G_FBUF32 _IOR ('V', 10, struct v4l2_framebuffer32)
#define VIDIOC_S_FBUF32 _IOW ('V', 11, struct v4l2_framebuffer32)
/* VIDIOC_OVERLAY is now _IOW, but was _IOWR */
#define VIDIOC_OVERLAY32 _IOWR ('V', 14, compat_int_t)
#define VIDIOC_QBUF32 _IOWR ('V', 15, struct v4l2_buffer32)
#define VIDIOC_DQBUF32 _IOWR ('V', 17, struct v4l2_buffer32)
#define VIDIOC_STREAMON32 _IOW ('V', 18, compat_int_t)
#define VIDIOC_STREAMOFF32 _IOW ('V', 19, compat_int_t)
#define VIDIOC_ENUMSTD32 _IOWR ('V', 25, struct v4l2_standard32)
#define VIDIOC_ENUMINPUT32 _IOWR ('V', 26, struct v4l2_input32)
/* VIDIOC_S_CTRL is now _IOWR, but was _IOW */
#define VIDIOC_S_CTRL32 _IOW ('V', 28, struct v4l2_control)
#define VIDIOC_G_INPUT32 _IOR ('V', 38, compat_int_t)
#define VIDIOC_S_INPUT32 _IOWR ('V', 39, compat_int_t)
#define VIDIOC_TRY_FMT32 _IOWR ('V', 64, struct v4l2_format32)
enum {
MaxClips = (~0U-sizeof(struct video_window))/sizeof(struct video_clip)
};
static int do_set_window(struct file *file, unsigned int cmd, unsigned long arg)
{
struct video_window32 __user *up = compat_ptr(arg);
struct video_window __user *vw;
struct video_clip __user *p;
int nclips;
u32 n;
if (get_user(nclips, &up->clipcount))
return -EFAULT;
/* Peculiar interface... */
if (nclips < 0)
nclips = VIDEO_CLIPMAP_SIZE;
if (nclips > MaxClips)
return -ENOMEM;
vw = compat_alloc_user_space(sizeof(struct video_window) +
nclips * sizeof(struct video_clip));
p = nclips ? (struct video_clip __user *)(vw + 1) : NULL;
if (get_user(n, &up->x) || put_user(n, &vw->x) ||
get_user(n, &up->y) || put_user(n, &vw->y) ||
get_user(n, &up->width) || put_user(n, &vw->width) ||
get_user(n, &up->height) || put_user(n, &vw->height) ||
get_user(n, &up->chromakey) || put_user(n, &vw->chromakey) ||
get_user(n, &up->flags) || put_user(n, &vw->flags) ||
get_user(n, &up->clipcount) || put_user(n, &vw->clipcount) ||
get_user(n, &up->clips) || put_user(p, &vw->clips))
return -EFAULT;
if (nclips) {
struct video_clip32 __user *u = compat_ptr(n);
int i;
if (!u)
return -EINVAL;
for (i = 0; i < nclips; i++, u++, p++) {
s32 v;
if (get_user(v, &u->x) ||
put_user(v, &p->x) ||
get_user(v, &u->y) ||
put_user(v, &p->y) ||
get_user(v, &u->width) ||
put_user(v, &p->width) ||
get_user(v, &u->height) ||
put_user(v, &p->height) ||
put_user(NULL, &p->next))
return -EFAULT;
}
}
return native_ioctl(file, VIDIOCSWIN, (unsigned long)vw);
}
static int do_video_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
{
union {
struct video_tuner vt;
struct video_buffer vb;
struct video_window vw;
struct v4l2_format v2f;
struct v4l2_buffer v2b;
struct v4l2_framebuffer v2fb;
struct v4l2_standard v2s;
unsigned long vx;
} karg;
void __user *up = compat_ptr(arg);
int compatible_arg = 1;
int err = 0;
/* First, convert the command. */
switch(cmd) {
case VIDIOCGTUNER32: cmd = VIDIOCGTUNER; break;
case VIDIOCSTUNER32: cmd = VIDIOCSTUNER; break;
case VIDIOCGWIN32: cmd = VIDIOCGWIN; break;
case VIDIOCGFBUF32: cmd = VIDIOCGFBUF; break;
case VIDIOCSFBUF32: cmd = VIDIOCSFBUF; break;
case VIDIOCGFREQ32: cmd = VIDIOCGFREQ; break;
case VIDIOCSFREQ32: cmd = VIDIOCSFREQ; break;
case VIDIOC_G_FMT32: cmd = VIDIOC_G_FMT; break;
case VIDIOC_S_FMT32: cmd = VIDIOC_S_FMT; break;
case VIDIOC_QUERYBUF32: cmd = VIDIOC_QUERYBUF; break;
case VIDIOC_QBUF32: cmd = VIDIOC_QBUF; break;
case VIDIOC_DQBUF32: cmd = VIDIOC_DQBUF; break;
case VIDIOC_STREAMON32: cmd = VIDIOC_STREAMON; break;
case VIDIOC_STREAMOFF32: cmd = VIDIOC_STREAMOFF; break;
case VIDIOC_G_FBUF32: cmd = VIDIOC_G_FBUF; break;
case VIDIOC_S_FBUF32: cmd = VIDIOC_S_FBUF; break;
case VIDIOC_OVERLAY32: cmd = VIDIOC_OVERLAY; break;
case VIDIOC_ENUMSTD32: cmd = VIDIOC_ENUMSTD; break;
case VIDIOC_ENUMINPUT32: cmd = VIDIOC_ENUMINPUT; break;
case VIDIOC_S_CTRL32: cmd = VIDIOC_S_CTRL; break;
case VIDIOC_G_INPUT32: cmd = VIDIOC_G_INPUT; break;
case VIDIOC_S_INPUT32: cmd = VIDIOC_S_INPUT; break;
case VIDIOC_TRY_FMT32: cmd = VIDIOC_TRY_FMT; break;
};
switch(cmd) {
case VIDIOCSTUNER:
case VIDIOCGTUNER:
err = get_video_tuner32(&karg.vt, up);
compatible_arg = 0;
break;
case VIDIOCSFBUF:
err = get_video_buffer32(&karg.vb, up);
compatible_arg = 0;
break;
case VIDIOCSFREQ:
case VIDIOC_S_INPUT:
case VIDIOC_OVERLAY:
case VIDIOC_STREAMON:
case VIDIOC_STREAMOFF:
err = get_user(karg.vx, (u32 __user *)up);
compatible_arg = 0;
break;
case VIDIOC_S_FBUF:
err = get_v4l2_framebuffer32(&karg.v2fb, up);
compatible_arg = 0;
break;
case VIDIOC_G_FMT:
case VIDIOC_S_FMT:
case VIDIOC_TRY_FMT:
err = get_v4l2_format32(&karg.v2f, up);
compatible_arg = 0;
break;
case VIDIOC_QUERYBUF:
case VIDIOC_QBUF:
case VIDIOC_DQBUF:
err = get_v4l2_buffer32(&karg.v2b, up);
compatible_arg = 0;
break;
case VIDIOC_ENUMSTD:
err = get_v4l2_standard32(&karg.v2s, up);
compatible_arg = 0;
break;
case VIDIOCGWIN:
case VIDIOCGFBUF:
case VIDIOCGFREQ:
case VIDIOC_G_FBUF:
case VIDIOC_G_INPUT:
compatible_arg = 0;
};
if(err)
goto out;
if(compatible_arg)
err = native_ioctl(file, cmd, (unsigned long)up);
else {
mm_segment_t old_fs = get_fs();
set_fs(KERNEL_DS);
err = native_ioctl(file, cmd, (unsigned long)&karg);
set_fs(old_fs);
}
if(err == 0) {
switch(cmd) {
case VIDIOCGTUNER:
err = put_video_tuner32(&karg.vt, up);
break;
case VIDIOCGWIN:
err = put_video_window32(&karg.vw, up);
break;
case VIDIOCGFBUF:
err = put_video_buffer32(&karg.vb, up);
break;
case VIDIOC_G_FBUF:
err = put_v4l2_framebuffer32(&karg.v2fb, up);
break;
case VIDIOC_G_FMT:
case VIDIOC_S_FMT:
case VIDIOC_TRY_FMT:
err = put_v4l2_format32(&karg.v2f, up);
break;
case VIDIOC_QUERYBUF:
case VIDIOC_QBUF:
case VIDIOC_DQBUF:
err = put_v4l2_buffer32(&karg.v2b, up);
break;
case VIDIOC_ENUMSTD:
err = put_v4l2_standard32(&karg.v2s, up);
break;
case VIDIOCGFREQ:
case VIDIOC_G_INPUT:
err = put_user(((u32)karg.vx), (u32 __user *)up);
break;
};
}
out:
return err;
}
long v4l_compat_ioctl32(struct file *file, unsigned int cmd, unsigned long arg)
{
int ret = -ENOIOCTLCMD;
if (!file->f_op->ioctl)
return ret;
switch (cmd) {
case VIDIOCSWIN32:
ret = do_set_window(file, cmd, arg);
break;
case VIDIOCGTUNER32:
case VIDIOCSTUNER32:
case VIDIOCGWIN32:
case VIDIOCGFBUF32:
case VIDIOCSFBUF32:
case VIDIOCGFREQ32:
case VIDIOCSFREQ32:
case VIDIOC_QUERYCAP:
case VIDIOC_ENUM_FMT:
case VIDIOC_G_FMT32:
case VIDIOC_S_FMT32:
case VIDIOC_REQBUFS:
case VIDIOC_QUERYBUF32:
case VIDIOC_G_FBUF32:
case VIDIOC_S_FBUF32:
case VIDIOC_OVERLAY32:
case VIDIOC_QBUF32:
case VIDIOC_DQBUF32:
case VIDIOC_STREAMON32:
case VIDIOC_STREAMOFF32:
case VIDIOC_G_PARM:
case VIDIOC_G_STD:
case VIDIOC_S_STD:
case VIDIOC_ENUMSTD32:
case VIDIOC_ENUMINPUT32:
case VIDIOC_G_CTRL:
case VIDIOC_S_CTRL32:
case VIDIOC_QUERYCTRL:
case VIDIOC_G_INPUT32:
case VIDIOC_S_INPUT32:
case VIDIOC_TRY_FMT32:
ret = do_video_ioctl(file, cmd, arg);
break;
/* Little v, the video4linux ioctls (conflict?) */
case VIDIOCGCAP:
case VIDIOCGCHAN:
case VIDIOCSCHAN:
case VIDIOCGPICT:
case VIDIOCSPICT:
case VIDIOCCAPTURE:
case VIDIOCKEY:
case VIDIOCGAUDIO:
case VIDIOCSAUDIO:
case VIDIOCSYNC:
case VIDIOCMCAPTURE:
case VIDIOCGMBUF:
case VIDIOCGUNIT:
case VIDIOCGCAPTURE:
case VIDIOCSCAPTURE:
/* BTTV specific... */
case _IOW('v', BASE_VIDIOCPRIVATE+0, char [256]):
case _IOR('v', BASE_VIDIOCPRIVATE+1, char [256]):
case _IOR('v' , BASE_VIDIOCPRIVATE+2, unsigned int):
case _IOW('v' , BASE_VIDIOCPRIVATE+3, char [16]): /* struct bttv_pll_info */
case _IOR('v' , BASE_VIDIOCPRIVATE+4, int):
case _IOR('v' , BASE_VIDIOCPRIVATE+5, int):
case _IOR('v' , BASE_VIDIOCPRIVATE+6, int):
case _IOR('v' , BASE_VIDIOCPRIVATE+7, int):
ret = native_ioctl(file, cmd, (unsigned long)compat_ptr(arg));
break;
}
return ret;
}
#else
long v4l_compat_ioctl32(struct file *file, unsigned int cmd, unsigned long arg)
{
return -ENOIOCTLCMD;
}
#endif
EXPORT_SYMBOL_GPL(v4l_compat_ioctl32);
MODULE_LICENSE("GPL");

View File

@ -3807,6 +3807,7 @@ static struct file_operations cpia_fops = {
.read = cpia_read, .read = cpia_read,
.mmap = cpia_mmap, .mmap = cpia_mmap,
.ioctl = cpia_ioctl, .ioctl = cpia_ioctl,
.compat_ioctl = v4l_compat_ioctl32,
.llseek = no_llseek, .llseek = no_llseek,
}; };

View File

@ -27,7 +27,7 @@
#include <linux/i2c.h> #include <linux/i2c.h>
#include <linux/i2c-id.h> #include <linux/i2c-id.h>
#include <linux/videodev.h> #include <linux/videodev.h>
#include <media/audiochip.h> #include <media/v4l2-common.h>
MODULE_DESCRIPTION("i2c device driver for cs53l32a Audio ADC"); MODULE_DESCRIPTION("i2c device driver for cs53l32a Audio ADC");
MODULE_AUTHOR("Martin Vaughan"); MODULE_AUTHOR("Martin Vaughan");
@ -39,21 +39,6 @@ module_param(debug, bool, 0644);
MODULE_PARM_DESC(debug, "Debugging messages\n\t\t\t0=Off (default), 1=On"); MODULE_PARM_DESC(debug, "Debugging messages\n\t\t\t0=Off (default), 1=On");
#define cs53l32a_dbg(fmt, arg...) \
do { \
if (debug) \
printk(KERN_INFO "%s debug %d-%04x: " fmt, \
client->driver->driver.name, \
i2c_adapter_id(client->adapter), client->addr , ## arg); \
} while (0)
#define cs53l32a_err(fmt, arg...) do { \
printk(KERN_ERR "%s %d-%04x: " fmt, client->driver->driver.name, \
i2c_adapter_id(client->adapter), client->addr , ## arg); } while (0)
#define cs53l32a_info(fmt, arg...) do { \
printk(KERN_INFO "%s %d-%04x: " fmt, client->driver->driver.name, \
i2c_adapter_id(client->adapter), client->addr , ## arg); } while (0)
static unsigned short normal_i2c[] = { 0x22 >> 1, I2C_CLIENT_END }; static unsigned short normal_i2c[] = { 0x22 >> 1, I2C_CLIENT_END };
@ -74,50 +59,59 @@ static int cs53l32a_read(struct i2c_client *client, u8 reg)
static int cs53l32a_command(struct i2c_client *client, unsigned int cmd, static int cs53l32a_command(struct i2c_client *client, unsigned int cmd,
void *arg) void *arg)
{ {
int *input = arg; struct v4l2_audio *input = arg;
struct v4l2_control *ctrl = arg;
switch (cmd) { switch (cmd) {
case AUDC_SET_INPUT: case VIDIOC_S_AUDIO:
switch (*input) { /* There are 2 physical inputs, but the second input can be
case AUDIO_TUNER: placed in two modes, the first mode bypasses the PGA (gain),
cs53l32a_write(client, 0x01, 0x01); the second goes through the PGA. Hence there are three
break; possible inputs to choose from. */
case AUDIO_EXTERN: if (input->index > 2) {
cs53l32a_write(client, 0x01, 0x21); v4l_err(client, "Invalid input %d.\n", input->index);
break;
case AUDIO_MUTE:
cs53l32a_write(client, 0x03, 0xF0);
break;
case AUDIO_UNMUTE:
cs53l32a_write(client, 0x03, 0x30);
break;
default:
cs53l32a_err("Invalid input %d.\n", *input);
return -EINVAL; return -EINVAL;
} }
cs53l32a_write(client, 0x01, 0x01 + (input->index << 4));
break;
case VIDIOC_G_AUDIO:
memset(input, 0, sizeof(*input));
input->index = (cs53l32a_read(client, 0x01) >> 4) & 3;
break;
case VIDIOC_G_CTRL:
if (ctrl->id == V4L2_CID_AUDIO_MUTE) {
ctrl->value = (cs53l32a_read(client, 0x03) & 0xc0) != 0;
break;
}
if (ctrl->id != V4L2_CID_AUDIO_VOLUME)
return -EINVAL;
ctrl->value = (s8)cs53l32a_read(client, 0x04);
break; break;
case VIDIOC_S_CTRL: case VIDIOC_S_CTRL:
{ if (ctrl->id == V4L2_CID_AUDIO_MUTE) {
struct v4l2_control *ctrl = arg; cs53l32a_write(client, 0x03, ctrl->value ? 0xf0 : 0x30);
break;
}
if (ctrl->id != V4L2_CID_AUDIO_VOLUME) if (ctrl->id != V4L2_CID_AUDIO_VOLUME)
return -EINVAL; return -EINVAL;
if (ctrl->value > 12 || ctrl->value < -90) if (ctrl->value > 12 || ctrl->value < -96)
return -EINVAL; return -EINVAL;
cs53l32a_write(client, 0x04, (u8) ctrl->value); cs53l32a_write(client, 0x04, (u8) ctrl->value);
cs53l32a_write(client, 0x05, (u8) ctrl->value); cs53l32a_write(client, 0x05, (u8) ctrl->value);
break; break;
}
case VIDIOC_LOG_STATUS: case VIDIOC_LOG_STATUS:
{ {
u8 v = cs53l32a_read(client, 0x01); u8 v = cs53l32a_read(client, 0x01);
u8 m = cs53l32a_read(client, 0x03); u8 m = cs53l32a_read(client, 0x03);
s8 vol = cs53l32a_read(client, 0x04);
cs53l32a_info("Input: %s%s\n", v4l_info(client, "Input: %d%s\n", (v >> 4) & 3,
v == 0x21 ? "external line in" : "tuner",
(m & 0xC0) ? " (muted)" : ""); (m & 0xC0) ? " (muted)" : "");
v4l_info(client, "Volume: %d dB\n", vol);
break; break;
} }
@ -157,12 +151,12 @@ static int cs53l32a_attach(struct i2c_adapter *adapter, int address, int kind)
client->driver = &i2c_driver; client->driver = &i2c_driver;
snprintf(client->name, sizeof(client->name) - 1, "cs53l32a"); snprintf(client->name, sizeof(client->name) - 1, "cs53l32a");
cs53l32a_info("chip found @ 0x%x (%s)\n", address << 1, adapter->name); v4l_info(client, "chip found @ 0x%x (%s)\n", address << 1, adapter->name);
for (i = 1; i <= 7; i++) { for (i = 1; i <= 7; i++) {
u8 v = cs53l32a_read(client, i); u8 v = cs53l32a_read(client, i);
cs53l32a_dbg("Read Reg %d %02x\n", i, v); v4l_dbg(1, client, "Read Reg %d %02x\n", i, v);
} }
/* Set cs53l32a internal register for Adaptec 2010/2410 setup */ /* Set cs53l32a internal register for Adaptec 2010/2410 setup */
@ -180,7 +174,7 @@ static int cs53l32a_attach(struct i2c_adapter *adapter, int address, int kind)
for (i = 1; i <= 7; i++) { for (i = 1; i <= 7; i++) {
u8 v = cs53l32a_read(client, i); u8 v = cs53l32a_read(client, i);
cs53l32a_dbg("Read Reg %d %02x\n", i, v); v4l_dbg(1, client, "Read Reg %d %02x\n", i, v);
} }
i2c_attach_client(client); i2c_attach_client(client);
@ -190,11 +184,7 @@ static int cs53l32a_attach(struct i2c_adapter *adapter, int address, int kind)
static int cs53l32a_probe(struct i2c_adapter *adapter) static int cs53l32a_probe(struct i2c_adapter *adapter)
{ {
#ifdef I2C_CLASS_TV_ANALOG
if (adapter->class & I2C_CLASS_TV_ANALOG) if (adapter->class & I2C_CLASS_TV_ANALOG)
#else
if (adapter->id == I2C_HW_B_BT848)
#endif
return i2c_probe(adapter, &addr_data, cs53l32a_attach); return i2c_probe(adapter, &addr_data, cs53l32a_attach);
return 0; return 0;
} }

View File

@ -23,11 +23,13 @@
#include "cx25840.h" #include "cx25840.h"
inline static int set_audclk_freq(struct i2c_client *client, static int set_audclk_freq(struct i2c_client *client, u32 freq)
enum v4l2_audio_clock_freq freq)
{ {
struct cx25840_state *state = i2c_get_clientdata(client); struct cx25840_state *state = i2c_get_clientdata(client);
if (freq != 32000 && freq != 44100 && freq != 48000)
return -EINVAL;
/* assert soft reset */ /* assert soft reset */
cx25840_and_or(client, 0x810, ~0x1, 0x01); cx25840_and_or(client, 0x810, ~0x1, 0x01);
@ -35,10 +37,9 @@ inline static int set_audclk_freq(struct i2c_client *client,
/* SA_MCLK_SEL=1, SA_MCLK_DIV=0x10 */ /* SA_MCLK_SEL=1, SA_MCLK_DIV=0x10 */
cx25840_write(client, 0x127, 0x50); cx25840_write(client, 0x127, 0x50);
switch (state->audio_input) { if (state->aud_input != CX25840_AUDIO_SERIAL) {
case AUDIO_TUNER:
switch (freq) { switch (freq) {
case V4L2_AUDCLK_32_KHZ: case 32000:
/* VID_PLL and AUX_PLL */ /* VID_PLL and AUX_PLL */
cx25840_write4(client, 0x108, 0x0f040610); cx25840_write4(client, 0x108, 0x0f040610);
@ -51,7 +52,7 @@ inline static int set_audclk_freq(struct i2c_client *client,
cx25840_write4(client, 0x90c, 0x7ff70108); cx25840_write4(client, 0x90c, 0x7ff70108);
break; break;
case V4L2_AUDCLK_441_KHZ: case 44100:
/* VID_PLL and AUX_PLL */ /* VID_PLL and AUX_PLL */
cx25840_write4(client, 0x108, 0x0f040910); cx25840_write4(client, 0x108, 0x0f040910);
@ -64,7 +65,7 @@ inline static int set_audclk_freq(struct i2c_client *client,
cx25840_write4(client, 0x90c, 0x596d0108); cx25840_write4(client, 0x90c, 0x596d0108);
break; break;
case V4L2_AUDCLK_48_KHZ: case 48000:
/* VID_PLL and AUX_PLL */ /* VID_PLL and AUX_PLL */
cx25840_write4(client, 0x108, 0x0f040a10); cx25840_write4(client, 0x108, 0x0f040a10);
@ -77,14 +78,9 @@ inline static int set_audclk_freq(struct i2c_client *client,
cx25840_write4(client, 0x90c, 0xaa4f0108); cx25840_write4(client, 0x90c, 0xaa4f0108);
break; break;
} }
break; } else {
case AUDIO_EXTERN_1:
case AUDIO_EXTERN_2:
case AUDIO_INTERN:
case AUDIO_RADIO:
switch (freq) { switch (freq) {
case V4L2_AUDCLK_32_KHZ: case 32000:
/* VID_PLL and AUX_PLL */ /* VID_PLL and AUX_PLL */
cx25840_write4(client, 0x108, 0x0f04081e); cx25840_write4(client, 0x108, 0x0f04081e);
@ -103,7 +99,7 @@ inline static int set_audclk_freq(struct i2c_client *client,
cx25840_write(client, 0x127, 0x54); cx25840_write(client, 0x127, 0x54);
break; break;
case V4L2_AUDCLK_441_KHZ: case 44100:
/* VID_PLL and AUX_PLL */ /* VID_PLL and AUX_PLL */
cx25840_write4(client, 0x108, 0x0f040918); cx25840_write4(client, 0x108, 0x0f040918);
@ -119,7 +115,7 @@ inline static int set_audclk_freq(struct i2c_client *client,
cx25840_write4(client, 0x90c, 0x85730108); cx25840_write4(client, 0x90c, 0x85730108);
break; break;
case V4L2_AUDCLK_48_KHZ: case 48000:
/* VID_PLL and AUX_PLL */ /* VID_PLL and AUX_PLL */
cx25840_write4(client, 0x108, 0x0f040a18); cx25840_write4(client, 0x108, 0x0f040a18);
@ -135,7 +131,6 @@ inline static int set_audclk_freq(struct i2c_client *client,
cx25840_write4(client, 0x90c, 0x55550108); cx25840_write4(client, 0x90c, 0x55550108);
break; break;
} }
break;
} }
/* deassert soft reset */ /* deassert soft reset */
@ -146,51 +141,36 @@ inline static int set_audclk_freq(struct i2c_client *client,
return 0; return 0;
} }
static int set_input(struct i2c_client *client, int audio_input) void cx25840_audio_set_path(struct i2c_client *client)
{ {
struct cx25840_state *state = i2c_get_clientdata(client); struct cx25840_state *state = i2c_get_clientdata(client);
cx25840_dbg("set audio input (%d)\n", audio_input);
/* stop microcontroller */ /* stop microcontroller */
cx25840_and_or(client, 0x803, ~0x10, 0); cx25840_and_or(client, 0x803, ~0x10, 0);
/* Mute everything to prevent the PFFT! */ /* Mute everything to prevent the PFFT! */
cx25840_write(client, 0x8d3, 0x1f); cx25840_write(client, 0x8d3, 0x1f);
switch (audio_input) { if (state->aud_input == CX25840_AUDIO_SERIAL) {
case AUDIO_TUNER:
/* Set Path1 to Analog Demod Main Channel */
cx25840_write4(client, 0x8d0, 0x7038061f);
/* When the microcontroller detects the
* audio format, it will unmute the lines */
cx25840_and_or(client, 0x803, ~0x10, 0x10);
break;
case AUDIO_EXTERN_1:
case AUDIO_EXTERN_2:
case AUDIO_INTERN:
case AUDIO_RADIO:
/* Set Path1 to Serial Audio Input */ /* Set Path1 to Serial Audio Input */
cx25840_write4(client, 0x8d0, 0x12100101); cx25840_write4(client, 0x8d0, 0x12100101);
/* The microcontroller should not be started for the /* The microcontroller should not be started for the
* non-tuner inputs: autodetection is specific for * non-tuner inputs: autodetection is specific for
* TV audio. */ * TV audio. */
break; } else {
/* Set Path1 to Analog Demod Main Channel */
cx25840_write4(client, 0x8d0, 0x7038061f);
default: /* When the microcontroller detects the
cx25840_dbg("Invalid audio input selection %d\n", audio_input); * audio format, it will unmute the lines */
return -EINVAL; cx25840_and_or(client, 0x803, ~0x10, 0x10);
} }
state->audio_input = audio_input; set_audclk_freq(client, state->audclk_freq);
return set_audclk_freq(client, state->audclk_freq);
} }
inline static int get_volume(struct i2c_client *client) static int get_volume(struct i2c_client *client)
{ {
/* Volume runs +18dB to -96dB in 1/2dB steps /* Volume runs +18dB to -96dB in 1/2dB steps
* change to fit the msp3400 -114dB to +12dB range */ * change to fit the msp3400 -114dB to +12dB range */
@ -201,7 +181,7 @@ inline static int get_volume(struct i2c_client *client)
return vol << 9; return vol << 9;
} }
inline static void set_volume(struct i2c_client *client, int volume) static void set_volume(struct i2c_client *client, int volume)
{ {
/* First convert the volume to msp3400 values (0-127) */ /* First convert the volume to msp3400 values (0-127) */
int vol = volume >> 9; int vol = volume >> 9;
@ -218,7 +198,7 @@ inline static void set_volume(struct i2c_client *client, int volume)
cx25840_write(client, 0x8d4, 228 - (vol * 2)); cx25840_write(client, 0x8d4, 228 - (vol * 2));
} }
inline static int get_bass(struct i2c_client *client) static int get_bass(struct i2c_client *client)
{ {
/* bass is 49 steps +12dB to -12dB */ /* bass is 49 steps +12dB to -12dB */
@ -228,13 +208,13 @@ inline static int get_bass(struct i2c_client *client)
return bass; return bass;
} }
inline static void set_bass(struct i2c_client *client, int bass) static void set_bass(struct i2c_client *client, int bass)
{ {
/* PATH1_EQ_BASS_VOL */ /* PATH1_EQ_BASS_VOL */
cx25840_and_or(client, 0x8d9, ~0x3f, 48 - (bass * 48 / 0xffff)); cx25840_and_or(client, 0x8d9, ~0x3f, 48 - (bass * 48 / 0xffff));
} }
inline static int get_treble(struct i2c_client *client) static int get_treble(struct i2c_client *client)
{ {
/* treble is 49 steps +12dB to -12dB */ /* treble is 49 steps +12dB to -12dB */
@ -244,13 +224,13 @@ inline static int get_treble(struct i2c_client *client)
return treble; return treble;
} }
inline static void set_treble(struct i2c_client *client, int treble) static void set_treble(struct i2c_client *client, int treble)
{ {
/* PATH1_EQ_TREBLE_VOL */ /* PATH1_EQ_TREBLE_VOL */
cx25840_and_or(client, 0x8db, ~0x3f, 48 - (treble * 48 / 0xffff)); cx25840_and_or(client, 0x8db, ~0x3f, 48 - (treble * 48 / 0xffff));
} }
inline static int get_balance(struct i2c_client *client) static int get_balance(struct i2c_client *client)
{ {
/* balance is 7 bit, 0 to -96dB */ /* balance is 7 bit, 0 to -96dB */
@ -264,7 +244,7 @@ inline static int get_balance(struct i2c_client *client)
return balance << 8; return balance << 8;
} }
inline static void set_balance(struct i2c_client *client, int balance) static void set_balance(struct i2c_client *client, int balance)
{ {
int bal = balance >> 8; int bal = balance >> 8;
if (bal > 0x80) { if (bal > 0x80) {
@ -280,17 +260,17 @@ inline static void set_balance(struct i2c_client *client, int balance)
} }
} }
inline static int get_mute(struct i2c_client *client) static int get_mute(struct i2c_client *client)
{ {
/* check SRC1_MUTE_EN */ /* check SRC1_MUTE_EN */
return cx25840_read(client, 0x8d3) & 0x2 ? 1 : 0; return cx25840_read(client, 0x8d3) & 0x2 ? 1 : 0;
} }
inline static void set_mute(struct i2c_client *client, int mute) static void set_mute(struct i2c_client *client, int mute)
{ {
struct cx25840_state *state = i2c_get_clientdata(client); struct cx25840_state *state = i2c_get_clientdata(client);
if (state->audio_input == AUDIO_TUNER) { if (state->aud_input != CX25840_AUDIO_SERIAL) {
/* Must turn off microcontroller in order to mute sound. /* Must turn off microcontroller in order to mute sound.
* Not sure if this is the best method, but it does work. * Not sure if this is the best method, but it does work.
* If the microcontroller is running, then it will undo any * If the microcontroller is running, then it will undo any
@ -314,10 +294,9 @@ int cx25840_audio(struct i2c_client *client, unsigned int cmd, void *arg)
struct v4l2_control *ctrl = arg; struct v4l2_control *ctrl = arg;
switch (cmd) { switch (cmd) {
case AUDC_SET_INPUT:
return set_input(client, *(int *)arg);
case VIDIOC_INT_AUDIO_CLOCK_FREQ: case VIDIOC_INT_AUDIO_CLOCK_FREQ:
return set_audclk_freq(client, *(enum v4l2_audio_clock_freq *)arg); return set_audclk_freq(client, *(u32 *)arg);
case VIDIOC_G_CTRL: case VIDIOC_G_CTRL:
switch (ctrl->id) { switch (ctrl->id) {
case V4L2_CID_AUDIO_VOLUME: case V4L2_CID_AUDIO_VOLUME:
@ -339,6 +318,7 @@ int cx25840_audio(struct i2c_client *client, unsigned int cmd, void *arg)
return -EINVAL; return -EINVAL;
} }
break; break;
case VIDIOC_S_CTRL: case VIDIOC_S_CTRL:
switch (ctrl->id) { switch (ctrl->id) {
case V4L2_CID_AUDIO_VOLUME: case V4L2_CID_AUDIO_VOLUME:
@ -360,6 +340,7 @@ int cx25840_audio(struct i2c_client *client, unsigned int cmd, void *arg)
return -EINVAL; return -EINVAL;
} }
break; break;
default: default:
return -EINVAL; return -EINVAL;
} }

Some files were not shown because too many files have changed in this diff Show More