diff options
Diffstat (limited to 'drivers/media/dvb')
29 files changed, 787 insertions, 284 deletions
diff --git a/drivers/media/dvb/Kconfig b/drivers/media/dvb/Kconfig index 3f0ec6be03a..a97c8f5e9a5 100644 --- a/drivers/media/dvb/Kconfig +++ b/drivers/media/dvb/Kconfig @@ -22,26 +22,26 @@ config DVB source "drivers/media/dvb/dvb-core/Kconfig" comment "Supported SAA7146 based PCI Adapters" - depends on DVB_CORE && PCI + depends on DVB_CORE && PCI && I2C source "drivers/media/dvb/ttpci/Kconfig" comment "Supported USB Adapters" - depends on DVB_CORE && USB + depends on DVB_CORE && USB && I2C source "drivers/media/dvb/dvb-usb/Kconfig" source "drivers/media/dvb/ttusb-budget/Kconfig" source "drivers/media/dvb/ttusb-dec/Kconfig" source "drivers/media/dvb/cinergyT2/Kconfig" comment "Supported FlexCopII (B2C2) Adapters" - depends on DVB_CORE && (PCI || USB) + depends on DVB_CORE && (PCI || USB) && I2C source "drivers/media/dvb/b2c2/Kconfig" comment "Supported BT878 Adapters" - depends on DVB_CORE && PCI + depends on DVB_CORE && PCI && I2C source "drivers/media/dvb/bt8xx/Kconfig" comment "Supported Pluto2 Adapters" - depends on DVB_CORE && PCI + depends on DVB_CORE && PCI && I2C source "drivers/media/dvb/pluto2/Kconfig" comment "Supported DVB Frontends" diff --git a/drivers/media/dvb/b2c2/Kconfig b/drivers/media/dvb/b2c2/Kconfig index 2963605c0ec..d7f1fd5b7b0 100644 --- a/drivers/media/dvb/b2c2/Kconfig +++ b/drivers/media/dvb/b2c2/Kconfig @@ -1,6 +1,6 @@ config DVB_B2C2_FLEXCOP tristate "Technisat/B2C2 FlexCopII(b) and FlexCopIII adapters" - depends on DVB_CORE + depends on DVB_CORE && I2C select DVB_STV0299 select DVB_MT352 select DVB_MT312 @@ -16,7 +16,7 @@ config DVB_B2C2_FLEXCOP config DVB_B2C2_FLEXCOP_PCI tristate "Technisat/B2C2 Air/Sky/Cable2PC PCI" - depends on DVB_B2C2_FLEXCOP && PCI + depends on DVB_B2C2_FLEXCOP && PCI && I2C help Support for the Air/Sky/CableStar2 PCI card (DVB/ATSC) by Technisat/B2C2. @@ -24,7 +24,7 @@ config DVB_B2C2_FLEXCOP_PCI config DVB_B2C2_FLEXCOP_USB tristate "Technisat/B2C2 Air/Sky/Cable2PC USB" - depends on DVB_B2C2_FLEXCOP && USB + depends on DVB_B2C2_FLEXCOP && USB && I2C help Support for the Air/Sky/Cable2PC USB1.1 box (DVB/ATSC) by Technisat/B2C2, diff --git a/drivers/media/dvb/bt8xx/Kconfig b/drivers/media/dvb/bt8xx/Kconfig index 2337b41714e..f394002118f 100644 --- a/drivers/media/dvb/bt8xx/Kconfig +++ b/drivers/media/dvb/bt8xx/Kconfig @@ -1,12 +1,14 @@ config DVB_BT8XX tristate "BT8xx based PCI cards" - depends on DVB_CORE && PCI && VIDEO_BT848 + depends on DVB_CORE && PCI && I2C && VIDEO_BT848 select DVB_MT352 select DVB_SP887X select DVB_NXT6000 select DVB_CX24110 select DVB_OR51211 select DVB_LGDT330X + select DVB_ZL10353 + select FW_LOADER help Support for PCI cards based on the Bt8xx PCI bridge. Examples are the Nebula cards, the Pinnacle PCTV cards, the Twinhan DST cards, diff --git a/drivers/media/dvb/bt8xx/dvb-bt8xx.c b/drivers/media/dvb/bt8xx/dvb-bt8xx.c index baa8227ef87..ccc7b2eb4a2 100644 --- a/drivers/media/dvb/bt8xx/dvb-bt8xx.c +++ b/drivers/media/dvb/bt8xx/dvb-bt8xx.c @@ -115,7 +115,7 @@ static int is_pci_slot_eq(struct pci_dev* adev, struct pci_dev* bdev) return 0; } -static struct bt878 __init *dvb_bt8xx_878_match(unsigned int bttv_nr, struct pci_dev* bttv_pci_dev) +static struct bt878 __devinit *dvb_bt8xx_878_match(unsigned int bttv_nr, struct pci_dev* bttv_pci_dev) { unsigned int card_nr; @@ -709,7 +709,7 @@ static void frontend_init(struct dvb_bt8xx_card *card, u32 type) } } -static int __init dvb_bt8xx_load_card(struct dvb_bt8xx_card *card, u32 type) +static int __devinit dvb_bt8xx_load_card(struct dvb_bt8xx_card *card, u32 type) { int result; @@ -794,7 +794,7 @@ static int __init dvb_bt8xx_load_card(struct dvb_bt8xx_card *card, u32 type) return 0; } -static int dvb_bt8xx_probe(struct bttv_sub_device *sub) +static int __devinit dvb_bt8xx_probe(struct bttv_sub_device *sub) { struct dvb_bt8xx_card *card; struct pci_dev* bttv_pci_dev; diff --git a/drivers/media/dvb/cinergyT2/cinergyT2.c b/drivers/media/dvb/cinergyT2/cinergyT2.c index 71b575dc22b..9325d039ea6 100644 --- a/drivers/media/dvb/cinergyT2/cinergyT2.c +++ b/drivers/media/dvb/cinergyT2/cinergyT2.c @@ -902,7 +902,10 @@ static int cinergyt2_probe (struct usb_interface *intf, return -ENOMEM; } - dvb_register_adapter(&cinergyt2->adapter, DRIVER_NAME, THIS_MODULE); + if ((err = dvb_register_adapter(&cinergyt2->adapter, DRIVER_NAME, THIS_MODULE)) < 0) { + kfree(cinergyt2); + return err; + } cinergyt2->demux.priv = cinergyt2; cinergyt2->demux.filternum = 256; diff --git a/drivers/media/dvb/dvb-core/dmxdev.c b/drivers/media/dvb/dvb-core/dmxdev.c index 09e96e9ddbd..04578df3f24 100644 --- a/drivers/media/dvb/dvb-core/dmxdev.c +++ b/drivers/media/dvb/dvb-core/dmxdev.c @@ -141,12 +141,18 @@ static int dvb_dvr_open(struct inode *inode, struct file *file) } if ((file->f_flags & O_ACCMODE) == O_RDONLY) { - void *mem = vmalloc(DVR_BUFFER_SIZE); + void *mem; + if (!dvbdev->readers) { + mutex_unlock(&dmxdev->mutex); + return -EBUSY; + } + mem = vmalloc(DVR_BUFFER_SIZE); if (!mem) { mutex_unlock(&dmxdev->mutex); return -ENOMEM; } dvb_ringbuffer_init(&dmxdev->dvr_buffer, mem, DVR_BUFFER_SIZE); + dvbdev->readers--; } if ((file->f_flags & O_ACCMODE) == O_WRONLY) { @@ -184,6 +190,7 @@ static int dvb_dvr_release(struct inode *inode, struct file *file) dmxdev->dvr_orig_fe); } if ((file->f_flags & O_ACCMODE) == O_RDONLY) { + dvbdev->readers++; if (dmxdev->dvr_buffer.data) { void *mem = dmxdev->dvr_buffer.data; mb(); @@ -1029,8 +1036,7 @@ static struct file_operations dvb_dvr_fops = { static struct dvb_device dvbdev_dvr = { .priv = NULL, - .users = 1, - .writers = 1, + .readers = 1, .fops = &dvb_dvr_fops }; diff --git a/drivers/media/dvb/dvb-core/dvb_frontend.c b/drivers/media/dvb/dvb-core/dvb_frontend.c index 2c3ea8f95dc..a051790161b 100644 --- a/drivers/media/dvb/dvb-core/dvb_frontend.c +++ b/drivers/media/dvb/dvb-core/dvb_frontend.c @@ -105,6 +105,9 @@ struct dvb_frontend_private { fe_status_t status; unsigned long tune_mode_flags; unsigned int delay; + unsigned int reinitialise; + int tone; + int voltage; /* swzigzag values */ unsigned int state; @@ -121,6 +124,7 @@ struct dvb_frontend_private { unsigned int check_wrapped; }; +static void dvb_frontend_wakeup(struct dvb_frontend *fe); static void dvb_frontend_add_event(struct dvb_frontend *fe, fe_status_t status) { @@ -213,6 +217,15 @@ static void dvb_frontend_init(struct dvb_frontend *fe) fe->ops->init(fe); } +void dvb_frontend_reinitialise(struct dvb_frontend *fe) +{ + struct dvb_frontend_private *fepriv = fe->frontend_priv; + + fepriv->reinitialise = 1; + dvb_frontend_wakeup(fe); +} +EXPORT_SYMBOL(dvb_frontend_reinitialise); + static void dvb_frontend_swzigzag_update_delay(struct dvb_frontend_private *fepriv, int locked) { int q2; @@ -505,8 +518,8 @@ static int dvb_frontend_thread(void *data) fepriv->quality = 0; fepriv->delay = 3*HZ; fepriv->status = 0; - dvb_frontend_init(fe); fepriv->wakeup = 0; + fepriv->reinitialise = 1; while (1) { up(&fepriv->sem); /* is locked when we enter the thread... */ @@ -524,6 +537,17 @@ static int dvb_frontend_thread(void *data) if (down_interruptible(&fepriv->sem)) break; + if (fepriv->reinitialise) { + dvb_frontend_init(fe); + if (fepriv->tone != -1) { + fe->ops->set_tone(fe, fepriv->tone); + } + if (fepriv->voltage != -1) { + fe->ops->set_voltage(fe, fepriv->voltage); + } + fepriv->reinitialise = 0; + } + /* do an iteration of the tuning loop */ if (fe->ops->tune) { /* have we been asked to retune? */ @@ -772,6 +796,7 @@ static int dvb_frontend_ioctl(struct inode *inode, struct file *file, case FE_SET_TONE: if (fe->ops->set_tone) { err = fe->ops->set_tone(fe, (fe_sec_tone_mode_t) parg); + fepriv->tone = (fe_sec_tone_mode_t) parg; fepriv->state = FESTATE_DISEQC; fepriv->status = 0; } @@ -780,6 +805,7 @@ static int dvb_frontend_ioctl(struct inode *inode, struct file *file, case FE_SET_VOLTAGE: if (fe->ops->set_voltage) { err = fe->ops->set_voltage(fe, (fe_sec_voltage_t) parg); + fepriv->voltage = (fe_sec_voltage_t) parg; fepriv->state = FESTATE_DISEQC; fepriv->status = 0; } @@ -979,6 +1005,8 @@ static int dvb_frontend_open(struct inode *inode, struct file *file) /* normal tune mode when opened R/W */ fepriv->tune_mode_flags &= ~FE_TUNE_MODE_ONESHOT; + fepriv->tone = -1; + fepriv->voltage = -1; } return ret; diff --git a/drivers/media/dvb/dvb-core/dvb_frontend.h b/drivers/media/dvb/dvb-core/dvb_frontend.h index d5aee5ad67a..5926a3b745c 100644 --- a/drivers/media/dvb/dvb-core/dvb_frontend.h +++ b/drivers/media/dvb/dvb-core/dvb_frontend.h @@ -112,6 +112,8 @@ extern int dvb_register_frontend(struct dvb_adapter* dvb, extern int dvb_unregister_frontend(struct dvb_frontend* fe); +extern void dvb_frontend_reinitialise(struct dvb_frontend *fe); + extern void dvb_frontend_sleep_until(struct timeval *waketime, u32 add_usec); extern s32 timeval_usec_diff(struct timeval lasttime, struct timeval curtime); diff --git a/drivers/media/dvb/dvb-core/dvbdev.c b/drivers/media/dvb/dvb-core/dvbdev.c index 96fe0ecae25..3852430d026 100644 --- a/drivers/media/dvb/dvb-core/dvbdev.c +++ b/drivers/media/dvb/dvb-core/dvbdev.c @@ -219,8 +219,6 @@ int dvb_register_device(struct dvb_adapter *adap, struct dvb_device **pdvbdev, return -ENOMEM; } - mutex_unlock(&dvbdev_register_lock); - memcpy(dvbdev, template, sizeof(struct dvb_device)); dvbdev->type = type; dvbdev->id = id; @@ -231,6 +229,8 @@ int dvb_register_device(struct dvb_adapter *adap, struct dvb_device **pdvbdev, list_add_tail (&dvbdev->list_head, &adap->device_list); + mutex_unlock(&dvbdev_register_lock); + devfs_mk_cdev(MKDEV(DVB_MAJOR, nums2minor(adap->num, type, id)), S_IFCHR | S_IRUSR | S_IWUSR, "dvb/adapter%d/%s%d", adap->num, dnames[type], id); diff --git a/drivers/media/dvb/dvb-usb/Kconfig b/drivers/media/dvb/dvb-usb/Kconfig index d3df12039b0..e388fb1567d 100644 --- a/drivers/media/dvb/dvb-usb/Kconfig +++ b/drivers/media/dvb/dvb-usb/Kconfig @@ -1,6 +1,6 @@ config DVB_USB tristate "Support for various USB DVB devices" - depends on DVB_CORE && USB + depends on DVB_CORE && USB && I2C select FW_LOADER help By enabling this you will be able to choose the various supported diff --git a/drivers/media/dvb/dvb-usb/cxusb.c b/drivers/media/dvb/dvb-usb/cxusb.c index a14e737ec84..1f0d3e995c8 100644 --- a/drivers/media/dvb/dvb-usb/cxusb.c +++ b/drivers/media/dvb/dvb-usb/cxusb.c @@ -150,6 +150,15 @@ static int cxusb_power_ctrl(struct dvb_usb_device *d, int onoff) return cxusb_ctrl_msg(d, CMD_POWER_OFF, &b, 1, NULL, 0); } +static int cxusb_bluebird_power_ctrl(struct dvb_usb_device *d, int onoff) +{ + u8 b = 0; + if (onoff) + return cxusb_ctrl_msg(d, CMD_POWER_ON, &b, 1, NULL, 0); + else + return 0; +} + static int cxusb_streaming_ctrl(struct dvb_usb_device *d, int onoff) { u8 buf[2] = { 0x03, 0x00 }; @@ -233,6 +242,45 @@ static struct dvb_usb_rc_key dvico_mce_rc_keys[] = { { 0xfe, 0x4e, KEY_POWER }, }; +static struct dvb_usb_rc_key dvico_portable_rc_keys[] = { + { 0xfc, 0x02, KEY_SETUP }, /* Profile */ + { 0xfc, 0x43, KEY_POWER2 }, + { 0xfc, 0x06, KEY_EPG }, + { 0xfc, 0x5a, KEY_BACK }, + { 0xfc, 0x05, KEY_MENU }, + { 0xfc, 0x47, KEY_INFO }, + { 0xfc, 0x01, KEY_TAB }, + { 0xfc, 0x42, KEY_PREVIOUSSONG },/* Replay */ + { 0xfc, 0x49, KEY_VOLUMEUP }, + { 0xfc, 0x09, KEY_VOLUMEDOWN }, + { 0xfc, 0x54, KEY_CHANNELUP }, + { 0xfc, 0x0b, KEY_CHANNELDOWN }, + { 0xfc, 0x16, KEY_CAMERA }, + { 0xfc, 0x40, KEY_TUNER }, /* ATV/DTV */ + { 0xfc, 0x45, KEY_OPEN }, + { 0xfc, 0x19, KEY_1 }, + { 0xfc, 0x18, KEY_2 }, + { 0xfc, 0x1b, KEY_3 }, + { 0xfc, 0x1a, KEY_4 }, + { 0xfc, 0x58, KEY_5 }, + { 0xfc, 0x59, KEY_6 }, + { 0xfc, 0x15, KEY_7 }, + { 0xfc, 0x14, KEY_8 }, + { 0xfc, 0x17, KEY_9 }, + { 0xfc, 0x44, KEY_ANGLE }, /* Aspect */ + { 0xfc, 0x55, KEY_0 }, + { 0xfc, 0x07, KEY_ZOOM }, + { 0xfc, 0x0a, KEY_REWIND }, + { 0xfc, 0x08, KEY_PLAYPAUSE }, + { 0xfc, 0x4b, KEY_FASTFORWARD }, + { 0xfc, 0x5b, KEY_MUTE }, + { 0xfc, 0x04, KEY_STOP }, + { 0xfc, 0x56, KEY_RECORD }, + { 0xfc, 0x57, KEY_POWER }, + { 0xfc, 0x41, KEY_UNKNOWN }, /* INPUT */ + { 0xfc, 0x00, KEY_UNKNOWN }, /* HD */ +}; + static int cxusb_dee1601_demod_init(struct dvb_frontend* fe) { static u8 clock_config [] = { CLOCK_CTL, 0x38, 0x28 }; @@ -505,12 +553,17 @@ static struct dvb_usb_properties cxusb_bluebird_lgh064f_properties = { .size_of_priv = sizeof(struct cxusb_state), .streaming_ctrl = cxusb_streaming_ctrl, - .power_ctrl = cxusb_power_ctrl, + .power_ctrl = cxusb_bluebird_power_ctrl, .frontend_attach = cxusb_lgdt3303_frontend_attach, .tuner_attach = cxusb_lgh064f_tuner_attach, .i2c_algo = &cxusb_i2c_algo, + .rc_interval = 100, + .rc_key_map = dvico_portable_rc_keys, + .rc_key_map_size = ARRAY_SIZE(dvico_portable_rc_keys), + .rc_query = cxusb_rc_query, + .generic_bulk_ctrl_endpoint = 0x01, /* parameter for the MPEG2-data transfer */ .urb = { @@ -545,7 +598,7 @@ static struct dvb_usb_properties cxusb_bluebird_dee1601_properties = { .size_of_priv = sizeof(struct cxusb_state), .streaming_ctrl = cxusb_streaming_ctrl, - .power_ctrl = cxusb_power_ctrl, + .power_ctrl = cxusb_bluebird_power_ctrl, .frontend_attach = cxusb_dee1601_frontend_attach, .tuner_attach = cxusb_dee1601_tuner_attach, @@ -594,12 +647,17 @@ static struct dvb_usb_properties cxusb_bluebird_lgz201_properties = { .size_of_priv = sizeof(struct cxusb_state), .streaming_ctrl = cxusb_streaming_ctrl, - .power_ctrl = cxusb_power_ctrl, + .power_ctrl = cxusb_bluebird_power_ctrl, .frontend_attach = cxusb_mt352_frontend_attach, .tuner_attach = cxusb_lgz201_tuner_attach, .i2c_algo = &cxusb_i2c_algo, + .rc_interval = 100, + .rc_key_map = dvico_portable_rc_keys, + .rc_key_map_size = ARRAY_SIZE(dvico_portable_rc_keys), + .rc_query = cxusb_rc_query, + .generic_bulk_ctrl_endpoint = 0x01, /* parameter for the MPEG2-data transfer */ .urb = { @@ -634,12 +692,17 @@ static struct dvb_usb_properties cxusb_bluebird_dtt7579_properties = { .size_of_priv = sizeof(struct cxusb_state), .streaming_ctrl = cxusb_streaming_ctrl, - .power_ctrl = cxusb_power_ctrl, + .power_ctrl = cxusb_bluebird_power_ctrl, .frontend_attach = cxusb_mt352_frontend_attach, .tuner_attach = cxusb_dtt7579_tuner_attach, .i2c_algo = &cxusb_i2c_algo, + .rc_interval = 100, + .rc_key_map = dvico_portable_rc_keys, + .rc_key_map_size = ARRAY_SIZE(dvico_portable_rc_keys), + .rc_query = cxusb_rc_query, + .generic_bulk_ctrl_endpoint = 0x01, /* parameter for the MPEG2-data transfer */ .urb = { diff --git a/drivers/media/dvb/dvb-usb/dtt200u.c b/drivers/media/dvb/dvb-usb/dtt200u.c index 12ebaf8bddc..70afcfd141c 100644 --- a/drivers/media/dvb/dvb-usb/dtt200u.c +++ b/drivers/media/dvb/dvb-usb/dtt200u.c @@ -94,12 +94,14 @@ static int dtt200u_frontend_attach(struct dvb_usb_device *d) static struct dvb_usb_properties dtt200u_properties; static struct dvb_usb_properties wt220u_properties; +static struct dvb_usb_properties wt220u_zl0353_properties; static int dtt200u_usb_probe(struct usb_interface *intf, const struct usb_device_id *id) { if (dvb_usb_device_init(intf,&dtt200u_properties,THIS_MODULE,NULL) == 0 || - dvb_usb_device_init(intf,&wt220u_properties,THIS_MODULE,NULL) == 0) + dvb_usb_device_init(intf,&wt220u_properties,THIS_MODULE,NULL) == 0 || + dvb_usb_device_init(intf,&wt220u_zl0353_properties,THIS_MODULE,NULL) == 0) return 0; return -ENODEV; @@ -110,6 +112,8 @@ static struct usb_device_id dtt200u_usb_table [] = { { USB_DEVICE(USB_VID_WIDEVIEW, USB_PID_DTT200U_WARM) }, { USB_DEVICE(USB_VID_WIDEVIEW, USB_PID_WT220U_COLD) }, { USB_DEVICE(USB_VID_WIDEVIEW, USB_PID_WT220U_WARM) }, + { USB_DEVICE(USB_VID_WIDEVIEW, USB_PID_WT220U_ZL0353_COLD) }, + { USB_DEVICE(USB_VID_WIDEVIEW, USB_PID_WT220U_ZL0353_WARM) }, { 0 }, }; MODULE_DEVICE_TABLE(usb, dtt200u_usb_table); @@ -196,6 +200,47 @@ static struct dvb_usb_properties wt220u_properties = { } }; +static struct dvb_usb_properties wt220u_zl0353_properties = { + .caps = DVB_USB_HAS_PID_FILTER | DVB_USB_NEED_PID_FILTERING, + .pid_filter_count = 15, + + .usb_ctrl = CYPRESS_FX2, + .firmware = "dvb-usb-wt220u-zl0353-01.fw", + + .power_ctrl = dtt200u_power_ctrl, + .streaming_ctrl = dtt200u_streaming_ctrl, + .pid_filter = dtt200u_pid_filter, + .frontend_attach = dtt200u_frontend_attach, + + .rc_interval = 300, + .rc_key_map = dtt200u_rc_keys, + .rc_key_map_size = ARRAY_SIZE(dtt200u_rc_keys), + .rc_query = dtt200u_rc_query, + + .generic_bulk_ctrl_endpoint = 0x01, + + /* parameter for the MPEG2-data transfer */ + .urb = { + .type = DVB_USB_BULK, + .count = 7, + .endpoint = 0x02, + .u = { + .bulk = { + .buffersize = 4096, + } + } + }, + + .num_device_descs = 1, + .devices = { + { .name = "WideView WT-220U PenType Receiver (based on ZL353)", + .cold_ids = { &dtt200u_usb_table[4], NULL }, + .warm_ids = { &dtt200u_usb_table[5], NULL }, + }, + { NULL }, + } +}; + /* usb specific object needed to register this driver with the usb subsystem */ static struct usb_driver dtt200u_usb_driver = { .name = "dvb_usb_dtt200u", diff --git a/drivers/media/dvb/dvb-usb/dvb-usb-ids.h b/drivers/media/dvb/dvb-usb/dvb-usb-ids.h index 4a1b9e77e33..cb239049b09 100644 --- a/drivers/media/dvb/dvb-usb/dvb-usb-ids.h +++ b/drivers/media/dvb/dvb-usb/dvb-usb-ids.h @@ -83,6 +83,8 @@ #define USB_PID_DTT200U_WARM 0x0301 #define USB_PID_WT220U_COLD 0x0222 #define USB_PID_WT220U_WARM 0x0221 +#define USB_PID_WT220U_ZL0353_COLD 0x022a +#define USB_PID_WT220U_ZL0353_WARM 0x022b #define USB_PID_WINTV_NOVA_T_USB2_COLD 0x9300 #define USB_PID_WINTV_NOVA_T_USB2_WARM 0x9301 #define USB_PID_NEBULA_DIGITV 0x0201 diff --git a/drivers/media/dvb/dvb-usb/vp702x-fe.c b/drivers/media/dvb/dvb-usb/vp702x-fe.c index b6d95e1c9c5..2a89f8c5da9 100644 --- a/drivers/media/dvb/dvb-usb/vp702x-fe.c +++ b/drivers/media/dvb/dvb-usb/vp702x-fe.c @@ -147,8 +147,9 @@ static int vp702x_fe_set_frontend(struct dvb_frontend* fe, cmd[4] = (sr >> 4) & 0xff; cmd[5] = (sr << 4) & 0xf0; - deb_fe("setting frontend to: %u -> %u (%x) LNB-based GHz, symbolrate: %d -> %Lu (%Lx)\n", - fep->frequency,freq,freq, fep->u.qpsk.symbol_rate, sr, sr); + deb_fe("setting frontend to: %u -> %u (%x) LNB-based GHz, symbolrate: %d -> %lu (%lx)\n", + fep->frequency,freq,freq, fep->u.qpsk.symbol_rate, + (unsigned long) sr, (unsigned long) sr); /* if (fep->inversion == INVERSION_ON) cmd[6] |= 0x80; */ diff --git a/drivers/media/dvb/frontends/Kconfig b/drivers/media/dvb/frontends/Kconfig index 94233168d24..37d5e0af168 100644 --- a/drivers/media/dvb/frontends/Kconfig +++ b/drivers/media/dvb/frontends/Kconfig @@ -181,6 +181,11 @@ config DVB_OR51211 help 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 or51211" to + download it, and then copy it to /usr/lib/hotplug/firmware + or /lib/firmware (depending on configuration of firmware hotplug). + config DVB_OR51132 tristate "Oren OR51132 based" depends on DVB_CORE @@ -189,6 +194,13 @@ config DVB_OR51132 An ATSC 8VSB and QAM64/256 tuner module. Say Y when you want to support this frontend. + This driver needs external firmware. Please use the commands + "<kerneldir>/Documentation/dvb/get_dvb_firmware or51132_vsb" and/or + "<kerneldir>/Documentation/dvb/get_dvb_firmware or51132_qam" to + download firmwares for 8VSB and QAM64/256, respectively. Copy them to + /usr/lib/hotplug/firmware or /lib/firmware (depending on + configuration of firmware hotplug). + config DVB_BCM3510 tristate "Broadcom BCM3510" depends on DVB_CORE diff --git a/drivers/media/dvb/frontends/cx24123.c b/drivers/media/dvb/frontends/cx24123.c index d661c6f9cbe..691dc840dcc 100644 --- a/drivers/media/dvb/frontends/cx24123.c +++ b/drivers/media/dvb/frontends/cx24123.c @@ -29,6 +29,9 @@ #include "dvb_frontend.h" #include "cx24123.h" +#define XTAL 10111000 + +static int force_band; static int debug; #define dprintk(args...) \ do { \ @@ -52,6 +55,7 @@ struct cx24123_state u32 VGAarg; u32 bandselectarg; u32 pllarg; + u32 FILTune; /* The Demod/Tuner can't easily provide these, we cache them */ u32 currentfreq; @@ -63,43 +67,33 @@ static struct { u32 symbolrate_low; u32 symbolrate_high; - u32 VCAslope; - u32 VCAoffset; - u32 VGA1offset; - u32 VGA2offset; u32 VCAprogdata; u32 VGAprogdata; + u32 FILTune; } 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, + /* the specs recommend other values for VGA offsets, + but tests show they are wrong */ + .VGAprogdata = (1 << 19) | (0x180 << 9) | 0x1e0, + .VCAprogdata = (2 << 19) | (0x07 << 9) | 0x07, + .FILTune = 0x27f /* 0.41 V */ }, { .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, + .VGAprogdata = (1 << 19) | (0x180 << 9) | 0x1e0, + .VCAprogdata = (2 << 19) | (0x07 << 9) | 0x1f, + .FILTune = 0x317 /* 0.90 V */ }, { .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, + .VGAprogdata = (1 << 19) | (0x100 << 9) | 0x180, + .VCAprogdata = (2 << 19) | (0x07 << 9) | 0x3f, + .FILTune = 0x145 /* 2.70 V */ }, }; @@ -112,91 +106,80 @@ static struct { u32 freq_low; u32 freq_high; - u32 bandselect; u32 VCOdivider; - u32 VCOnumber; u32 progdata; } cx24123_bandselect_vals[] = { + /* band 1 */ { .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, + .progdata = (0 << 19) | (0 << 9) | 0x40, }, + + /* band 2 */ { .freq_low = 1075000, - .freq_high = 1227999, - .bandselect = 0x01, - .VCOdivider = 2, - .VCOnumber = 1, - .progdata = (0 << 18) | (1 << 9) | 0x01, + .freq_high = 1177999, + .VCOdivider = 4, + .progdata = (0 << 19) | (0 << 9) | 0x80, }, + + /* band 3 */ { - .freq_low = 1228000, - .freq_high = 1349999, - .bandselect = 0x02, + .freq_low = 1178000, + .freq_high = 1295999, .VCOdivider = 2, - .VCOnumber = 2, - .progdata = (0 << 18) | (1 << 9) | 0x02, + .progdata = (0 << 19) | (1 << 9) | 0x01, }, + + /* band 4 */ { - .freq_low = 1350000, - .freq_high = 1481999, - .bandselect = 0x04, + .freq_low = 1296000, + .freq_high = 1431999, .VCOdivider = 2, - .VCOnumber = 3, - .progdata = (0 << 18) | (1 << 9) | 0x04, + .progdata = (0 << 19) | (1 << 9) | 0x02, }, + + /* band 5 */ { - .freq_low = 1482000, - .freq_high = 1595999, - .bandselect = 0x08, + .freq_low = 1432000, + .freq_high = 1575999, .VCOdivider = 2, - .VCOnumber = 4, - .progdata = (0 << 18) | (1 << 9) | 0x08, + .progdata = (0 << 19) | (1 << 9) | 0x04, }, + + /* band 6 */ { - .freq_low = 1596000, + .freq_low = 1576000, .freq_high = 1717999, - .bandselect = 0x10, .VCOdivider = 2, - .VCOnumber = 5, - .progdata = (0 << 18) | (1 << 9) | 0x10, + .progdata = (0 << 19) | (1 << 9) | 0x08, }, + + /* band 7 */ { .freq_low = 1718000, .freq_high = 1855999, - .bandselect = 0x20, .VCOdivider = 2, - .VCOnumber = 6, - .progdata = (0 << 18) | (1 << 9) | 0x20, + .progdata = (0 << 19) | (1 << 9) | 0x10, }, + + /* band 8 */ { .freq_low = 1856000, .freq_high = 2035999, - .bandselect = 0x40, .VCOdivider = 2, - .VCOnumber = 7, - .progdata = (0 << 18) | (1 << 9) | 0x40, + .progdata = (0 << 19) | (1 << 9) | 0x20, }, + + /* band 9 */ { .freq_low = 2036000, - .freq_high = 2149999, - .bandselect = 0x80, + .freq_high = 2150000, .VCOdivider = 2, - .VCOnumber = 8, - .progdata = (0 << 18) | (1 << 9) | 0x80, + .progdata = (0 << 19) | (1 << 9) | 0x40, }, }; @@ -207,49 +190,44 @@ static struct { { {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}, + {0x03, 0x07}, /* QPSK, DVB, Auto Acquisition (default) */ + {0x04, 0x10}, /* MPEG */ + {0x05, 0x04}, /* MPEG */ + {0x06, 0x31}, /* MPEG (default) */ + {0x0b, 0x00}, /* Freq search start point (default) */ + {0x0c, 0x00}, /* Demodulator sample gain (default) */ + {0x0d, 0x02}, /* Frequency search range = Fsymbol / 4 (default) */ + {0x0e, 0x03}, /* Default non-inverted, FEC 3/4 (default) */ + {0x0f, 0xfe}, /* FEC search mask (all supported codes) */ + {0x10, 0x01}, /* Default search inversion, no repeat (default) */ + {0x16, 0x00}, /* Enable reading of frequency */ + {0x17, 0x01}, /* Enable EsNO Ready Counter */ + {0x1c, 0x80}, /* Enable error counter */ + {0x20, 0x00}, /* Tuner burst clock rate = 500KHz */ + {0x21, 0x15}, /* Tuner burst mode, word length = 0x15 */ + {0x28, 0x00}, /* Enable FILTERV with positive pol., DiSEqC 2.x off */ + {0x29, 0x00}, /* DiSEqC LNB_DC off */ + {0x2a, 0xb0}, /* DiSEqC Parameters (default) */ + {0x2b, 0x73}, /* DiSEqC Tone Frequency (default) */ + {0x2c, 0x00}, /* DiSEqC Message (0x2c - 0x31) */ {0x2d, 0x00}, {0x2e, 0x00}, {0x2f, 0x00}, {0x30, 0x00}, {0x31, 0x00}, - {0x32, 0x8c}, - {0x33, 0x00}, + {0x32, 0x8c}, /* DiSEqC Parameters (default) */ + {0x33, 0x00}, /* Interrupts off (0x33 - 0x34) */ {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}, + {0x35, 0x03}, /* DiSEqC Tone Amplitude (default) */ + {0x36, 0x02}, /* DiSEqC Parameters (default) */ + {0x37, 0x3a}, /* DiSEqC Parameters (default) */ + {0x3a, 0x00}, /* Enable AGC accumulator (for signal strength) */ + {0x44, 0x00}, /* Constellation (default) */ + {0x45, 0x00}, /* Symbol count (default) */ + {0x46, 0x0d}, /* Symbol rate estimator on (default) */ + {0x56, 0x41}, /* Various (default) */ + {0x57, 0xff}, /* Error Counter Window (default) */ + {0x67, 0x83}, /* Non-DCII symbol clock */ }; static int cx24123_writereg(struct cx24123_state* state, int reg, int data) @@ -258,6 +236,10 @@ static int cx24123_writereg(struct cx24123_state* state, int reg, int data) struct i2c_msg msg = { .addr = state->config->demod_address, .flags = 0, .buf = buf, .len = 2 }; int err; + if (debug>1) + printk("cx24123: %s: write reg 0x%02x, value 0x%02x\n", + __FUNCTION__,reg, data); + 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); @@ -274,6 +256,10 @@ static int cx24123_writelnbreg(struct cx24123_state* state, int reg, int data) struct i2c_msg msg = { .addr = 0x08, .flags = 0, .buf = buf, .len = 2 }; int err; + if (debug>1) + printk("cx24123: %s: writeln addr=0x08, reg 0x%02x, value 0x%02x\n", + __FUNCTION__,reg, data); + 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); @@ -303,6 +289,9 @@ static int cx24123_readreg(struct cx24123_state* state, u8 reg) return ret; } + if (debug>1) + printk("cx24123: read reg 0x%02x, value 0x%02x\n",reg, ret); + return b1[0]; } @@ -313,17 +302,23 @@ static int cx24123_readlnbreg(struct cx24123_state* state, u8 reg) static int cx24123_set_inversion(struct cx24123_state* state, fe_spectral_inversion_t inversion) { + u8 nom_reg = cx24123_readreg(state, 0x0e); + u8 auto_reg = cx24123_readreg(state, 0x10); + switch (inversion) { case INVERSION_OFF: - cx24123_writereg(state, 0x0e, cx24123_readreg(state, 0x0e) & 0x7f); - cx24123_writereg(state, 0x10, cx24123_readreg(state, 0x10) | 0x80); + dprintk("%s: inversion off\n",__FUNCTION__); + cx24123_writereg(state, 0x0e, nom_reg & ~0x80); + cx24123_writereg(state, 0x10, auto_reg | 0x80); break; case INVERSION_ON: - cx24123_writereg(state, 0x0e, cx24123_readreg(state, 0x0e) | 0x80); - cx24123_writereg(state, 0x10, cx24123_readreg(state, 0x10) | 0x80); + dprintk("%s: inversion on\n",__FUNCTION__); + cx24123_writereg(state, 0x0e, nom_reg | 0x80); + cx24123_writereg(state, 0x10, auto_reg | 0x80); break; case INVERSION_AUTO: - cx24123_writereg(state, 0x10, cx24123_readreg(state, 0x10) & 0x7f); + dprintk("%s: inversion auto\n",__FUNCTION__); + cx24123_writereg(state, 0x10, auto_reg & ~0x80); break; default: return -EINVAL; @@ -338,92 +333,191 @@ static int cx24123_get_inversion(struct cx24123_state* state, fe_spectral_invers val = cx24123_readreg(state, 0x1b) >> 7; - if (val == 0) + if (val == 0) { + dprintk("%s: read inversion off\n",__FUNCTION__); *inversion = INVERSION_OFF; - else + } else { + dprintk("%s: read inversion on\n",__FUNCTION__); *inversion = INVERSION_ON; + } return 0; } static int cx24123_set_fec(struct cx24123_state* state, fe_code_rate_t fec) { + u8 nom_reg = cx24123_readreg(state, 0x0e) & ~0x07; + 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); + dprintk("%s: set FEC to 1/2\n",__FUNCTION__); + cx24123_writereg(state, 0x0e, nom_reg | 0x01); + cx24123_writereg(state, 0x0f, 0x02); + break; case FEC_2_3: - return cx24123_writereg(state, 0x0f, 0x04); + dprintk("%s: set FEC to 2/3\n",__FUNCTION__); + cx24123_writereg(state, 0x0e, nom_reg | 0x02); + cx24123_writereg(state, 0x0f, 0x04); + break; case FEC_3_4: - return cx24123_writereg(state, 0x0f, 0x08); + dprintk("%s: set FEC to 3/4\n",__FUNCTION__); + cx24123_writereg(state, 0x0e, nom_reg | 0x03); + cx24123_writereg(state, 0x0f, 0x08); + break; + case FEC_4_5: + dprintk("%s: set FEC to 4/5\n",__FUNCTION__); + cx24123_writereg(state, 0x0e, nom_reg | 0x04); + cx24123_writereg(state, 0x0f, 0x10); + break; case FEC_5_6: - return cx24123_writereg(state, 0x0f, 0x20); + dprintk("%s: set FEC to 5/6\n",__FUNCTION__); + cx24123_writereg(state, 0x0e, nom_reg | 0x05); + cx24123_writereg(state, 0x0f, 0x20); + break; + case FEC_6_7: + dprintk("%s: set FEC to 6/7\n",__FUNCTION__); + cx24123_writereg(state, 0x0e, nom_reg | 0x06); + cx24123_writereg(state, 0x0f, 0x40); + break; case FEC_7_8: - return cx24123_writereg(state, 0x0f, 0x80); + dprintk("%s: set FEC to 7/8\n",__FUNCTION__); + cx24123_writereg(state, 0x0e, nom_reg | 0x07); + cx24123_writereg(state, 0x0f, 0x80); + break; case FEC_AUTO: - return cx24123_writereg(state, 0x0f, 0xae); + dprintk("%s: set FEC to auto\n",__FUNCTION__); + cx24123_writereg(state, 0x0f, 0xfe); + break; default: return -EOPNOTSUPP; } + + return 0; } 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) { + ret = ret & 0x07; + + switch (ret) { case 1: *fec = FEC_1_2; break; - case 3: + case 2: *fec = FEC_2_3; break; - case 4: + case 3: *fec = FEC_3_4; break; - case 5: + case 4: *fec = FEC_4_5; break; - case 6: + case 5: *fec = FEC_5_6; break; + case 6: + *fec = FEC_6_7; + 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 + /* this can happen when there's no lock */ + *fec = FEC_NONE; } return 0; } -/* fixme: Symbol rates < 3MSps may not work because of precision loss */ +/* Approximation of closest integer of log2(a/b). It actually gives the + lowest integer i such that 2^i >= round(a/b) */ +static u32 cx24123_int_log2(u32 a, u32 b) +{ + u32 exp, nearest = 0; + u32 div = a / b; + if(a % b >= b / 2) ++div; + if(div < (1 << 31)) + { + for(exp = 1; div > exp; nearest++) + exp += exp; + } + return nearest; +} + static int cx24123_set_symbolrate(struct cx24123_state* state, u32 srate) { - u32 val; + u32 tmp, sample_rate, ratio, sample_gain; + u8 pll_mult; + + /* check if symbol rate is within limits */ + if ((srate > state->ops.info.symbol_rate_max) || + (srate < state->ops.info.symbol_rate_min)) + return -EOPNOTSUPP;; + + /* choose the sampling rate high enough for the required operation, + while optimizing the power consumed by the demodulator */ + if (srate < (XTAL*2)/2) + pll_mult = 2; + else if (srate < (XTAL*3)/2) + pll_mult = 3; + else if (srate < (XTAL*4)/2) + pll_mult = 4; + else if (srate < (XTAL*5)/2) + pll_mult = 5; + else if (srate < (XTAL*6)/2) + pll_mult = 6; + else if (srate < (XTAL*7)/2) + pll_mult = 7; + else if (srate < (XTAL*8)/2) + pll_mult = 8; + else + pll_mult = 9; + + + sample_rate = pll_mult * XTAL; + + /* + SYSSymbolRate[21:0] = (srate << 23) / sample_rate + + We have to use 32 bit unsigned arithmetic without precision loss. + The maximum srate is 45000000 or 0x02AEA540. This number has + only 6 clear bits on top, hence we can shift it left only 6 bits + at a time. Borrowed from cx24110.c + */ + + tmp = srate << 6; + ratio = tmp / sample_rate; + + tmp = (tmp % sample_rate) << 6; + ratio = (ratio << 6) + (tmp / sample_rate); + + tmp = (tmp % sample_rate) << 6; + ratio = (ratio << 6) + (tmp / sample_rate); + + tmp = (tmp % sample_rate) << 5; + ratio = (ratio << 5) + (tmp / sample_rate); + + + cx24123_writereg(state, 0x01, pll_mult * 6); - val = (srate / 1185) * 100; + cx24123_writereg(state, 0x08, (ratio >> 16) & 0x3f ); + cx24123_writereg(state, 0x09, (ratio >> 8) & 0xff ); + cx24123_writereg(state, 0x0a, (ratio ) & 0xff ); - /* Compensate for scaling up, by removing 17 symbols per 1Msps */ - val = val - (17 * (srate / 1000000)); + /* also set the demodulator sample gain */ + sample_gain = cx24123_int_log2(sample_rate, srate); + tmp = cx24123_readreg(state, 0x0c) & ~0xe0; + cx24123_writereg(state, 0x0c, tmp | sample_gain << 5); - cx24123_writereg(state, 0x08, (val >> 16) & 0xff ); - cx24123_writereg(state, 0x09, (val >> 8) & 0xff ); - cx24123_writereg(state, 0x0a, (val ) & 0xff ); + dprintk("%s: srate=%d, ratio=0x%08x, sample_rate=%i sample_gain=%d\n", __FUNCTION__, srate, ratio, sample_rate, sample_gain); return 0; } @@ -437,6 +531,9 @@ static int cx24123_pll_calculate(struct dvb_frontend* fe, struct dvb_frontend_pa struct cx24123_state *state = fe->demodulator_priv; u32 ndiv = 0, adiv = 0, vco_div = 0; int i = 0; + int pump = 2; + int band = 0; + int num_bands = sizeof(cx24123_bandselect_vals) / sizeof(cx24123_bandselect_vals[0]); /* Defaults for low freq, low rate */ state->VCAarg = cx24123_AGC_vals[0].VCAprogdata; @@ -444,38 +541,49 @@ static int cx24123_pll_calculate(struct dvb_frontend* fe, struct dvb_frontend_pa 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 the given symbol rate, determine the VCA, VGA and FILTUNE 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) ) { + (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; + state->FILTune = cx24123_AGC_vals[i].FILTune; } } - /* For the given frequency, determine the bandselect programming bits */ - for (i = 0; i < sizeof(cx24123_bandselect_vals) / sizeof(cx24123_bandselect_vals[0]); i++) + /* determine the band to use */ + if(force_band < 1 || force_band > num_bands) { - 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; + for (i = 0; i < num_bands; i++) + { + if ((cx24123_bandselect_vals[i].freq_low <= p->frequency) && + (cx24123_bandselect_vals[i].freq_high >= p->frequency) ) + band = i; } } + else + band = force_band - 1; + + state->bandselectarg = cx24123_bandselect_vals[band].progdata; + vco_div = cx24123_bandselect_vals[band].VCOdivider; + + /* determine the charge pump current */ + if ( p->frequency < (cx24123_bandselect_vals[band].freq_low + cx24123_bandselect_vals[band].freq_high)/2 ) + pump = 0x01; + else + pump = 0x02; /* 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; + /* Note: the reference divider R=10, frequency is in KHz, XTAL is in Hz */ + ndiv = ( ((p->frequency * vco_div * 10) / (2 * XTAL / 1000)) / 32) & 0x1ff; + adiv = ( ((p->frequency * vco_div * 10) / (2 * XTAL / 1000)) % 32) & 0x1f; if (adiv == 0) - adiv++; + ndiv++; - /* 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; + /* control bits 11, refdiv 11, charge pump polarity 1, charge pump current, ndiv, adiv */ + state->pllarg = (3 << 19) | (3 << 17) | (1 << 16) | (pump << 14) | (ndiv << 5) | adiv; return 0; } @@ -489,6 +597,8 @@ static int cx24123_pll_writereg(struct dvb_frontend* fe, struct dvb_frontend_par struct cx24123_state *state = fe->demodulator_priv; unsigned long timeout; + dprintk("%s: pll writereg called, data=0x%08x\n",__FUNCTION__,data); + /* align the 21 bytes into to bit23 boundary */ data = data << 3; @@ -538,6 +648,9 @@ static int cx24123_pll_writereg(struct dvb_frontend* fe, struct dvb_frontend_par static int cx24123_pll_tune(struct dvb_frontend* fe, struct dvb_frontend_parameters *p) { struct cx24123_state *state = fe->demodulator_priv; + u8 val; + + dprintk("frequency=%i\n", p->frequency); if (cx24123_pll_calculate(fe, p) != 0) { printk("%s: cx24123_pll_calcutate failed\n",__FUNCTION__); @@ -552,6 +665,14 @@ static int cx24123_pll_tune(struct dvb_frontend* fe, struct dvb_frontend_paramet cx24123_pll_writereg(fe, p, state->bandselectarg); cx24123_pll_writereg(fe, p, state->pllarg); + /* set the FILTUNE voltage */ + val = cx24123_readreg(state, 0x28) & ~0x3; + cx24123_writereg(state, 0x27, state->FILTune >> 2); + cx24123_writereg(state, 0x28, val | (state->FILTune & 0x3)); + + dprintk("%s: pll tune VCA=%d, band=%d, pll=%d\n",__FUNCTION__,state->VCAarg, + state->bandselectarg,state->pllarg); + return 0; } @@ -560,6 +681,8 @@ static int cx24123_initfe(struct dvb_frontend* fe) struct cx24123_state *state = fe->demodulator_priv; int i; + dprintk("%s: init frontend\n",__FUNCTION__); + /* 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); @@ -587,10 +710,13 @@ static int cx24123_set_voltage(struct dvb_frontend* fe, fe_sec_voltage_t voltage switch (voltage) { case SEC_VOLTAGE_13: + dprintk("%s: isl6421 voltage = 13V\n",__FUNCTION__); return cx24123_writelnbreg(state, 0x0, val & 0x32); /* V 13v */ case SEC_VOLTAGE_18: + dprintk("%s: isl6421 voltage = 18V\n",__FUNCTION__); return cx24123_writelnbreg(state, 0x0, val | 0x04); /* H 18v */ case SEC_VOLTAGE_OFF: + dprintk("%s: isl5421 voltage off\n",__FUNCTION__); return cx24123_writelnbreg(state, 0x0, val & 0x30); default: return -EINVAL; @@ -624,13 +750,93 @@ static int cx24123_set_voltage(struct dvb_frontend* fe, fe_sec_voltage_t voltage return 0; } -static int cx24123_send_diseqc_msg(struct dvb_frontend* fe, - struct dvb_diseqc_master_cmd *cmd) +/* wait for diseqc queue to become ready (or timeout) */ +static void cx24123_wait_for_diseqc(struct cx24123_state *state) +{ + unsigned long timeout = jiffies + msecs_to_jiffies(200); + while (!(cx24123_readreg(state, 0x29) & 0x40)) { + if(time_after(jiffies, timeout)) { + printk("%s: diseqc queue not ready, command may be lost.\n", __FUNCTION__); + break; + } + msleep(10); + } +} + +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__); + struct cx24123_state *state = fe->demodulator_priv; + int i, val; + + dprintk("%s:\n",__FUNCTION__); + + /* check if continuous tone has been stopped */ + if (state->config->use_isl6421) + val = cx24123_readlnbreg(state, 0x00) & 0x10; + else + val = cx24123_readreg(state, 0x29) & 0x10; - return -ENOTSUPP; + + if (val) { + printk("%s: ERROR: attempt to send diseqc command before tone is off\n", __FUNCTION__); + return -ENOTSUPP; + } + + /* wait for diseqc queue ready */ + cx24123_wait_for_diseqc(state); + + /* select tone mode */ + cx24123_writereg(state, 0x2a, cx24123_readreg(state, 0x2a) & 0xf8); + + for (i = 0; i < cmd->msg_len; i++) + cx24123_writereg(state, 0x2C + i, cmd->msg[i]); + + val = cx24123_readreg(state, 0x29); + cx24123_writereg(state, 0x29, ((val & 0x90) | 0x40) | ((cmd->msg_len-3) & 3)); + + /* wait for diseqc message to finish sending */ + cx24123_wait_for_diseqc(state); + + return 0; +} + +static int cx24123_diseqc_send_burst(struct dvb_frontend* fe, fe_sec_mini_cmd_t burst) +{ + struct cx24123_state *state = fe->demodulator_priv; + int val; + + dprintk("%s:\n", __FUNCTION__); + + /* check if continuous tone has been stoped */ + if (state->config->use_isl6421) + val = cx24123_readlnbreg(state, 0x00) & 0x10; + else + val = cx24123_readreg(state, 0x29) & 0x10; + + + if (val) { + printk("%s: ERROR: attempt to send diseqc command before tone is off\n", __FUNCTION__); + return -ENOTSUPP; + } + + cx24123_wait_for_diseqc(state); + + /* select tone mode */ + val = cx24123_readreg(state, 0x2a) & 0xf8; + cx24123_writereg(state, 0x2a, val | 0x04); + + val = cx24123_readreg(state, 0x29); + + if (burst == SEC_MINI_A) + cx24123_writereg(state, 0x29, ((val & 0x90) | 0x40 | 0x00)); + else if (burst == SEC_MINI_B) + cx24123_writereg(state, 0x29, ((val & 0x90) | 0x40 | 0x08)); + else + return -EINVAL; + + cx24123_wait_for_diseqc(state); + + return 0; } static int cx24123_read_status(struct dvb_frontend* fe, fe_status_t* status) @@ -642,13 +848,15 @@ static int cx24123_read_status(struct dvb_frontend* fe, fe_status_t* status) *status = 0; if (lock & 0x01) - *status |= FE_HAS_CARRIER | FE_HAS_SIGNAL; + *status |= FE_HAS_SIGNAL; + if (sync & 0x02) + *status |= FE_HAS_CARRIER; if (sync & 0x04) *status |= FE_HAS_VITERBI; if (sync & 0x08) - *status |= FE_HAS_CARRIER; + *status |= FE_HAS_SYNC; if (sync & 0x80) - *status |= FE_HAS_SYNC | FE_HAS_LOCK; + *status |= FE_HAS_LOCK; return 0; } @@ -681,6 +889,8 @@ static int cx24123_read_ber(struct dvb_frontend* fe, u32* ber) else state->snr = 0; + dprintk("%s: BER = %d, S/N index = %d\n",__FUNCTION__,state->lastber, state->snr); + *ber = state->lastber; return 0; @@ -691,6 +901,8 @@ static int cx24123_read_signal_strength(struct dvb_frontend* fe, u16* signal_str struct cx24123_state *state = fe->demodulator_priv; *signal_strength = cx24123_readreg(state, 0x3b) << 8; /* larger = better */ + dprintk("%s: Signal strength = %d\n",__FUNCTION__,*signal_strength); + return 0; } @@ -699,6 +911,8 @@ static int cx24123_read_snr(struct dvb_frontend* fe, u16* snr) struct cx24123_state *state = fe->demodulator_priv; *snr = state->snr; + dprintk("%s: read S/N index = %d\n",__FUNCTION__,*snr); + return 0; } @@ -707,6 +921,8 @@ static int cx24123_read_ucblocks(struct dvb_frontend* fe, u32* ucblocks) struct cx24123_state *state = fe->demodulator_priv; *ucblocks = state->lastber; + dprintk("%s: ucblocks (ber) = %d\n",__FUNCTION__,*ucblocks); + return 0; } @@ -714,6 +930,8 @@ static int cx24123_set_frontend(struct dvb_frontend* fe, struct dvb_frontend_par { struct cx24123_state *state = fe->demodulator_priv; + dprintk("%s: set_frontend\n",__FUNCTION__); + if (state->config->set_ts_params) state->config->set_ts_params(fe, 0); @@ -737,6 +955,8 @@ static int cx24123_get_frontend(struct dvb_frontend* fe, struct dvb_frontend_par { struct cx24123_state *state = fe->demodulator_priv; + dprintk("%s: get_frontend\n",__FUNCTION__); + if (cx24123_get_inversion(state, &p->inversion) != 0) { printk("%s: Failed to get inversion status\n",__FUNCTION__); return -EREMOTEIO; @@ -763,8 +983,10 @@ static int cx24123_set_tone(struct dvb_frontend* fe, fe_sec_tone_mode_t tone) switch (tone) { case SEC_TONE_ON: + dprintk("%s: isl6421 sec tone on\n",__FUNCTION__); return cx24123_writelnbreg(state, 0x0, val | 0x10); case SEC_TONE_OFF: + dprintk("%s: isl6421 sec tone off\n",__FUNCTION__); return cx24123_writelnbreg(state, 0x0, val & 0x2f); default: printk("%s: CASE reached default with tone=%d\n", __FUNCTION__, tone); @@ -855,12 +1077,13 @@ static struct dvb_frontend_ops cx24123_ops = { .frequency_min = 950000, .frequency_max = 2150000, .frequency_stepsize = 1011, /* kHz for QPSK frontends */ - .frequency_tolerance = 29500, + .frequency_tolerance = 5000, .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_FEC_4_5 | FE_CAN_FEC_5_6 | FE_CAN_FEC_6_7 | + FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO | FE_CAN_QPSK | FE_CAN_RECOVER }, @@ -875,12 +1098,16 @@ static struct dvb_frontend_ops cx24123_ops = { .read_snr = cx24123_read_snr, .read_ucblocks = cx24123_read_ucblocks, .diseqc_send_master_cmd = cx24123_send_diseqc_msg, + .diseqc_send_burst = cx24123_diseqc_send_burst, .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_PARM_DESC(debug, "Activates frontend debugging (default:0)"); + +module_param(force_band, int, 0644); +MODULE_PARM_DESC(force_band, "Force a specific band select (1-9, default:off)."); MODULE_DESCRIPTION("DVB Frontend module for Conexant cx24123/cx24109 hardware"); MODULE_AUTHOR("Steven Toth"); diff --git a/drivers/media/dvb/frontends/dvb-pll.c b/drivers/media/dvb/frontends/dvb-pll.c index b6e2c387a04..791706ec1da 100644 --- a/drivers/media/dvb/frontends/dvb-pll.c +++ b/drivers/media/dvb/frontends/dvb-pll.c @@ -235,8 +235,8 @@ struct dvb_pll_desc dvb_pll_tdvs_tua6034 = { .max = 863000000, .count = 3, .entries = { - { 160000000, 44000000, 62500, 0xce, 0x01 }, - { 455000000, 44000000, 62500, 0xce, 0x02 }, + { 165000000, 44000000, 62500, 0xce, 0x01 }, + { 450000000, 44000000, 62500, 0xce, 0x02 }, { 999999999, 44000000, 62500, 0xce, 0x04 }, }, }; diff --git a/drivers/media/dvb/frontends/tda1004x.c b/drivers/media/dvb/frontends/tda1004x.c index 8e8df7b4ca0..b83dafa4e12 100644 --- a/drivers/media/dvb/frontends/tda1004x.c +++ b/drivers/media/dvb/frontends/tda1004x.c @@ -52,7 +52,6 @@ struct tda1004x_state { struct dvb_frontend frontend; /* private demod data */ - u8 initialised; enum tda1004x_demod demod_type; }; @@ -594,9 +593,6 @@ static int tda10045_init(struct dvb_frontend* fe) dprintk("%s\n", __FUNCTION__); - if (state->initialised) - return 0; - if (tda10045_fwupload(fe)) { printk("tda1004x: firmware upload failed\n"); return -EIO; @@ -626,7 +622,6 @@ static int tda10045_init(struct dvb_frontend* fe) tda1004x_write_mask(state, 0x1f, 0x01, state->config->invert_oclk); - state->initialised = 1; return 0; } @@ -635,9 +630,6 @@ static int tda10046_init(struct dvb_frontend* fe) struct tda1004x_state* state = fe->demodulator_priv; dprintk("%s\n", __FUNCTION__); - if (state->initialised) - return 0; - if (tda10046_fwupload(fe)) { printk("tda1004x: firmware upload failed\n"); return -EIO; @@ -697,7 +689,6 @@ static int tda10046_init(struct dvb_frontend* fe) // tda1004x_write_mask(state, 0x50, 0x80, 0x80); // handle out of guard echoes tda1004x_write_mask(state, 0x3a, 0x80, state->config->invert_oclk << 7); - state->initialised = 1; return 0; } @@ -1207,7 +1198,6 @@ static int tda1004x_sleep(struct dvb_frontend* fe) tda1004x_write_mask(state, TDA1004X_CONFC4, 1, 1); break; } - state->initialised = 0; return 0; } @@ -1271,7 +1261,6 @@ struct dvb_frontend* tda10045_attach(const struct tda1004x_config* config, state->config = config; state->i2c = i2c; memcpy(&state->ops, &tda10045_ops, sizeof(struct dvb_frontend_ops)); - state->initialised = 0; state->demod_type = TDA1004X_DEMOD_TDA10045; /* check if the demod is there */ @@ -1330,7 +1319,6 @@ struct dvb_frontend* tda10046_attach(const struct tda1004x_config* config, state->config = config; state->i2c = i2c; memcpy(&state->ops, &tda10046_ops, sizeof(struct dvb_frontend_ops)); - state->initialised = 0; state->demod_type = TDA1004X_DEMOD_TDA10046; /* check if the demod is there */ diff --git a/drivers/media/dvb/pluto2/Kconfig b/drivers/media/dvb/pluto2/Kconfig index 84f8f9f5286..7d8e6e87bdb 100644 --- a/drivers/media/dvb/pluto2/Kconfig +++ b/drivers/media/dvb/pluto2/Kconfig @@ -1,7 +1,6 @@ config DVB_PLUTO2 tristate "Pluto2 cards" - depends on DVB_CORE && PCI - select I2C + depends on DVB_CORE && PCI && I2C select I2C_ALGOBIT select DVB_TDA1004X help diff --git a/drivers/media/dvb/pluto2/Makefile b/drivers/media/dvb/pluto2/Makefile index 86ca84b2be6..ce6a9aaf937 100644 --- a/drivers/media/dvb/pluto2/Makefile +++ b/drivers/media/dvb/pluto2/Makefile @@ -1,3 +1,3 @@ -obj-$(CONFIG_DVB_PLUTO2) = pluto2.o +obj-$(CONFIG_DVB_PLUTO2) += pluto2.o EXTRA_CFLAGS = -Idrivers/media/dvb/dvb-core/ -Idrivers/media/dvb/frontends/ diff --git a/drivers/media/dvb/ttpci/Kconfig b/drivers/media/dvb/ttpci/Kconfig index 5b2aadb8385..b5ac7dfde52 100644 --- a/drivers/media/dvb/ttpci/Kconfig +++ b/drivers/media/dvb/ttpci/Kconfig @@ -1,8 +1,7 @@ config DVB_AV7110 tristate "AV7110 cards" - depends on DVB_CORE && PCI + depends on DVB_CORE && PCI && I2C && VIDEO_V4L1 select FW_LOADER - select VIDEO_DEV select VIDEO_SAA7146_VV select DVB_VES1820 select DVB_VES1X93 @@ -59,7 +58,7 @@ config DVB_AV7110_OSD config DVB_BUDGET tristate "Budget cards" - depends on DVB_CORE && PCI + depends on DVB_CORE && PCI && I2C && VIDEO_V4L1 select VIDEO_SAA7146 select DVB_STV0299 select DVB_VES1X93 @@ -80,7 +79,7 @@ config DVB_BUDGET config DVB_BUDGET_CI tristate "Budget cards with onboard CI connector" - depends on DVB_CORE && PCI + depends on DVB_CORE && PCI && I2C && VIDEO_V4L1 select VIDEO_SAA7146 select DVB_STV0297 select DVB_STV0299 @@ -100,8 +99,7 @@ config DVB_BUDGET_CI config DVB_BUDGET_AV tristate "Budget cards with analog video inputs" - depends on DVB_CORE && PCI - select VIDEO_DEV + depends on DVB_CORE && PCI && I2C && VIDEO_V4L1 select VIDEO_SAA7146_VV select DVB_STV0299 select DVB_TDA1004X @@ -119,7 +117,7 @@ config DVB_BUDGET_AV config DVB_BUDGET_PATCH tristate "AV7110 cards with Budget Patch" - depends on DVB_CORE && DVB_BUDGET + depends on DVB_CORE && DVB_BUDGET && VIDEO_V4L1 select DVB_AV7110 select DVB_STV0299 select DVB_VES1X93 diff --git a/drivers/media/dvb/ttpci/av7110.c b/drivers/media/dvb/ttpci/av7110.c index 840efec32cb..d028245c8ee 100644 --- a/drivers/media/dvb/ttpci/av7110.c +++ b/drivers/media/dvb/ttpci/av7110.c @@ -87,6 +87,7 @@ static int volume = 255; static int budgetpatch; static int wss_cfg_4_3 = 0x4008; static int wss_cfg_16_9 = 0x0007; +static int tv_standard; module_param_named(debug, av7110_debug, int, 0644); MODULE_PARM_DESC(debug, "debug level (bitmask, default 0)"); @@ -109,6 +110,8 @@ module_param(wss_cfg_4_3, int, 0444); MODULE_PARM_DESC(wss_cfg_4_3, "WSS 4:3 - default 0x4008 - bit 15: disable, 14: burst mode, 13..0: wss data"); module_param(wss_cfg_16_9, int, 0444); MODULE_PARM_DESC(wss_cfg_16_9, "WSS 16:9 - default 0x0007 - bit 15: disable, 14: burst mode, 13..0: wss data"); +module_param(tv_standard, int, 0444); +MODULE_PARM_DESC(tv_standard, "TV standard: 0 PAL (default), 1 NTSC"); static void restart_feeds(struct av7110 *av7110); @@ -2123,7 +2126,7 @@ static int frontend_init(struct av7110 *av7110) read_pwm(av7110)); break; case 0x0003: - /* Haupauge DVB-C 2.1 VES1820/ALPS TDBE2 */ + /* Hauppauge DVB-C 2.1 VES1820/ALPS TDBE2 */ av7110->fe = ves1820_attach(&alps_tdbe2_config, &av7110->i2c_adap, read_pwm(av7110)); break; @@ -2543,6 +2546,9 @@ static int __devinit av7110_attach(struct saa7146_dev* dev, av7110->osdwin = 1; mutex_init(&av7110->osd_mutex); + /* TV standard */ + av7110->vidmode = tv_standard == 1 ? VIDEO_MODE_NTSC : VIDEO_MODE_PAL; + /* ARM "watchdog" */ init_waitqueue_head(&av7110->arm_wait); av7110->arm_thread = NULL; diff --git a/drivers/media/dvb/ttpci/av7110_av.c b/drivers/media/dvb/ttpci/av7110_av.c index 400facec740..2eff09f638d 100644 --- a/drivers/media/dvb/ttpci/av7110_av.c +++ b/drivers/media/dvb/ttpci/av7110_av.c @@ -1479,8 +1479,6 @@ int av7110_av_init(struct av7110 *av7110) void (*play[])(u8 *, int, void *) = { play_audio_cb, play_video_cb }; int i, ret; - av7110->vidmode = VIDEO_MODE_PAL; - for (i = 0; i < 2; i++) { struct ipack *ipack = av7110->ipack + i; diff --git a/drivers/media/dvb/ttpci/budget-av.c b/drivers/media/dvb/ttpci/budget-av.c index 9dd4745f531..8a7cd7d505c 100644 --- a/drivers/media/dvb/ttpci/budget-av.c +++ b/drivers/media/dvb/ttpci/budget-av.c @@ -60,11 +60,11 @@ struct budget_av { struct dvb_ca_en50221 ca; }; -/* GPIO CI Connections: - * 0 - Vcc/Reset (Reset is controlled by capacitor) - * 1 - Attribute Memory - * 2 - Card Enable (Active Low) - * 3 - Card Detect +/* GPIO Connections: + * 0 - Vcc/Reset (Reset is controlled by capacitor). Resets the frontend *AS WELL*! + * 1 - CI memory select 0=>IO memory, 1=>Attribute Memory + * 2 - CI Card Enable (Active Low) + * 3 - CI Card Detect */ /**************************************************************************** @@ -214,6 +214,9 @@ static int ciintf_slot_reset(struct dvb_ca_en50221 *ca, int slot) while (--timeout > 0 && ciintf_read_attribute_mem(ca, slot, 0) != 0x1d) msleep(100); + /* reinitialise the frontend */ + dvb_frontend_reinitialise(budget_av->budget.dvb_frontend); + if (timeout <= 0) { printk(KERN_ERR "budget-av: cam reset failed (timeout).\n"); @@ -1187,8 +1190,6 @@ static int budget_av_attach(struct saa7146_dev *dev, struct saa7146_pci_extensio SAA7146_HPS_SYNC_PORT_A); saa7113_setinput(budget_av, 0); - } else { - ciintf_init(budget_av); } /* fixme: find some sane values here... */ @@ -1208,6 +1209,10 @@ static int budget_av_attach(struct saa7146_dev *dev, struct saa7146_pci_extensio budget_av->budget.dvb_adapter.priv = budget_av; frontend_init(budget_av); + if (!budget_av->has_saa7113) { + ciintf_init(budget_av); + } + return 0; } diff --git a/drivers/media/dvb/ttpci/budget-ci.c b/drivers/media/dvb/ttpci/budget-ci.c index 5f91036f5b8..e64a609cf4f 100644 --- a/drivers/media/dvb/ttpci/budget-ci.c +++ b/drivers/media/dvb/ttpci/budget-ci.c @@ -71,6 +71,7 @@ struct budget_ci { struct tasklet_struct msp430_irq_tasklet; struct tasklet_struct ciintf_irq_tasklet; int slot_status; + int ci_irq; struct dvb_ca_en50221 ca; char ir_dev_name[50]; u8 tuner_pll_address; /* used for philips_tdm1316l configs */ @@ -276,8 +277,10 @@ static int ciintf_slot_reset(struct dvb_ca_en50221 *ca, int slot) if (slot != 0) return -EINVAL; - // trigger on RISING edge during reset so we know when READY is re-asserted - saa7146_setgpio(saa, 0, SAA7146_GPIO_IRQHI); + if (budget_ci->ci_irq) { + // trigger on RISING edge during reset so we know when READY is re-asserted + saa7146_setgpio(saa, 0, SAA7146_GPIO_IRQHI); + } budget_ci->slot_status = SLOTSTATUS_RESET; ttpci_budget_debiwrite(&budget_ci->budget, DEBICICTL, DEBIADDR_CICONTROL, 1, 0, 1, 0); msleep(1); @@ -370,11 +373,50 @@ static void ciintf_interrupt(unsigned long data) } } +static int ciintf_poll_slot_status(struct dvb_ca_en50221 *ca, int slot, int open) +{ + struct budget_ci *budget_ci = (struct budget_ci *) ca->data; + unsigned int flags; + + // ensure we don't get spurious IRQs during initialisation + if (!budget_ci->budget.ci_present) + return -EINVAL; + + // read the CAM status + flags = ttpci_budget_debiread(&budget_ci->budget, DEBICICTL, DEBIADDR_CICONTROL, 1, 1, 0); + if (flags & CICONTROL_CAMDETECT) { + // mark it as present if it wasn't before + if (budget_ci->slot_status & SLOTSTATUS_NONE) { + budget_ci->slot_status = SLOTSTATUS_PRESENT; + } + + // during a RESET, we check if we can read from IO memory to see when CAM is ready + if (budget_ci->slot_status & SLOTSTATUS_RESET) { + if (ciintf_read_attribute_mem(ca, slot, 0) == 0x1d) { + budget_ci->slot_status = SLOTSTATUS_READY; + } + } + } else { + budget_ci->slot_status = SLOTSTATUS_NONE; + } + + if (budget_ci->slot_status != SLOTSTATUS_NONE) { + if (budget_ci->slot_status & SLOTSTATUS_READY) { + return DVB_CA_EN50221_POLL_CAM_PRESENT | DVB_CA_EN50221_POLL_CAM_READY; + } + return DVB_CA_EN50221_POLL_CAM_PRESENT; + } + + return 0; +} + static int ciintf_init(struct budget_ci *budget_ci) { struct saa7146_dev *saa = budget_ci->budget.dev; int flags; int result; + int ci_version; + int ca_flags; memset(&budget_ci->ca, 0, sizeof(struct dvb_ca_en50221)); @@ -382,16 +424,29 @@ static int ciintf_init(struct budget_ci *budget_ci) saa7146_write(saa, MC1, saa7146_read(saa, MC1) | (0x800 << 16) | 0x800); // test if it is there - if ((ttpci_budget_debiread(&budget_ci->budget, DEBICICTL, DEBIADDR_CIVERSION, 1, 1, 0) & 0xa0) != 0xa0) { + ci_version = ttpci_budget_debiread(&budget_ci->budget, DEBICICTL, DEBIADDR_CIVERSION, 1, 1, 0); + if ((ci_version & 0xa0) != 0xa0) { result = -ENODEV; goto error; } + // determine whether a CAM is present or not flags = ttpci_budget_debiread(&budget_ci->budget, DEBICICTL, DEBIADDR_CICONTROL, 1, 1, 0); budget_ci->slot_status = SLOTSTATUS_NONE; if (flags & CICONTROL_CAMDETECT) budget_ci->slot_status = SLOTSTATUS_PRESENT; + // version 0xa2 of the CI firmware doesn't generate interrupts + if (ci_version == 0xa2) { + ca_flags = 0; + budget_ci->ci_irq = 0; + } else { + ca_flags = DVB_CA_EN50221_FLAG_IRQ_CAMCHANGE | + DVB_CA_EN50221_FLAG_IRQ_FR | + DVB_CA_EN50221_FLAG_IRQ_DA; + budget_ci->ci_irq = 1; + } + // register CI interface budget_ci->ca.owner = THIS_MODULE; budget_ci->ca.read_attribute_mem = ciintf_read_attribute_mem; @@ -401,23 +456,27 @@ static int ciintf_init(struct budget_ci *budget_ci) budget_ci->ca.slot_reset = ciintf_slot_reset; budget_ci->ca.slot_shutdown = ciintf_slot_shutdown; budget_ci->ca.slot_ts_enable = ciintf_slot_ts_enable; + budget_ci->ca.poll_slot_status = ciintf_poll_slot_status; budget_ci->ca.data = budget_ci; if ((result = dvb_ca_en50221_init(&budget_ci->budget.dvb_adapter, &budget_ci->ca, - DVB_CA_EN50221_FLAG_IRQ_CAMCHANGE | - DVB_CA_EN50221_FLAG_IRQ_FR | - DVB_CA_EN50221_FLAG_IRQ_DA, 1)) != 0) { + ca_flags, 1)) != 0) { printk("budget_ci: CI interface detected, but initialisation failed.\n"); goto error; } + // Setup CI slot IRQ - tasklet_init(&budget_ci->ciintf_irq_tasklet, ciintf_interrupt, (unsigned long) budget_ci); - if (budget_ci->slot_status != SLOTSTATUS_NONE) { - saa7146_setgpio(saa, 0, SAA7146_GPIO_IRQLO); - } else { - saa7146_setgpio(saa, 0, SAA7146_GPIO_IRQHI); + if (budget_ci->ci_irq) { + tasklet_init(&budget_ci->ciintf_irq_tasklet, ciintf_interrupt, (unsigned long) budget_ci); + if (budget_ci->slot_status != SLOTSTATUS_NONE) { + saa7146_setgpio(saa, 0, SAA7146_GPIO_IRQLO); + } else { + saa7146_setgpio(saa, 0, SAA7146_GPIO_IRQHI); + } + saa7146_write(saa, IER, saa7146_read(saa, IER) | MASK_03); } - saa7146_write(saa, IER, saa7146_read(saa, IER) | MASK_03); + + // enable interface ttpci_budget_debiwrite(&budget_ci->budget, DEBICICTL, DEBIADDR_CICONTROL, 1, CICONTROL_RESET, 1, 0); @@ -426,10 +485,12 @@ static int ciintf_init(struct budget_ci *budget_ci) budget_ci->budget.ci_present = 1; // forge a fake CI IRQ so the CAM state is setup correctly - flags = DVB_CA_EN50221_CAMCHANGE_REMOVED; - if (budget_ci->slot_status != SLOTSTATUS_NONE) - flags = DVB_CA_EN50221_CAMCHANGE_INSERTED; - dvb_ca_en50221_camchange_irq(&budget_ci->ca, 0, flags); + if (budget_ci->ci_irq) { + flags = DVB_CA_EN50221_CAMCHANGE_REMOVED; + if (budget_ci->slot_status != SLOTSTATUS_NONE) + flags = DVB_CA_EN50221_CAMCHANGE_INSERTED; + dvb_ca_en50221_camchange_irq(&budget_ci->ca, 0, flags); + } return 0; @@ -443,9 +504,13 @@ static void ciintf_deinit(struct budget_ci *budget_ci) struct saa7146_dev *saa = budget_ci->budget.dev; // disable CI interrupts - saa7146_write(saa, IER, saa7146_read(saa, IER) & ~MASK_03); - saa7146_setgpio(saa, 0, SAA7146_GPIO_INPUT); - tasklet_kill(&budget_ci->ciintf_irq_tasklet); + if (budget_ci->ci_irq) { + saa7146_write(saa, IER, saa7146_read(saa, IER) & ~MASK_03); + saa7146_setgpio(saa, 0, SAA7146_GPIO_INPUT); + tasklet_kill(&budget_ci->ciintf_irq_tasklet); + } + + // reset interface ttpci_budget_debiwrite(&budget_ci->budget, DEBICICTL, DEBIADDR_CICONTROL, 1, 0, 1, 0); msleep(1); ttpci_budget_debiwrite(&budget_ci->budget, DEBICICTL, DEBIADDR_CICONTROL, 1, @@ -473,7 +538,7 @@ static void budget_ci_irq(struct saa7146_dev *dev, u32 * isr) if (*isr & MASK_10) ttpci_budget_irq10_handler(dev, isr); - if ((*isr & MASK_03) && (budget_ci->budget.ci_present)) + if ((*isr & MASK_03) && (budget_ci->budget.ci_present) && (budget_ci->ci_irq)) tasklet_schedule(&budget_ci->ciintf_irq_tasklet); } diff --git a/drivers/media/dvb/ttpci/budget-core.c b/drivers/media/dvb/ttpci/budget-core.c index 633e68c341c..ea2066d461f 100644 --- a/drivers/media/dvb/ttpci/budget-core.c +++ b/drivers/media/dvb/ttpci/budget-core.c @@ -39,9 +39,21 @@ #include "budget.h" #include "ttpci-eeprom.h" +#define TS_WIDTH (2 * TS_SIZE) +#define TS_WIDTH_ACTIVY TS_SIZE +#define TS_HEIGHT_MASK 0xf00 +#define TS_HEIGHT_MASK_ACTIVY 0xc00 +#define TS_MIN_BUFSIZE_K 188 +#define TS_MAX_BUFSIZE_K 1410 +#define TS_MAX_BUFSIZE_K_ACTIVY 564 +#define BUFFER_WARNING_WAIT (30*HZ) + int budget_debug; +static int dma_buffer_size = TS_MIN_BUFSIZE_K; module_param_named(debug, budget_debug, int, 0644); +module_param_named(bufsize, dma_buffer_size, int, 0444); MODULE_PARM_DESC(debug, "Turn on/off budget debugging (default:off)."); +MODULE_PARM_DESC(bufsize, "DMA buffer size in KB, default: 188, min: 188, max: 1410 (Activy: 564)"); /**************************************************************************** * TT budget / WinTV Nova @@ -70,11 +82,10 @@ static int start_ts_capture(struct budget *budget) saa7146_write(dev, MC1, MASK_20); // DMA3 off - memset(budget->grabbing, 0x00, TS_HEIGHT * TS_WIDTH); + memset(budget->grabbing, 0x00, budget->buffer_size); saa7146_write(dev, PCI_BT_V1, 0x001c0000 | (saa7146_read(dev, PCI_BT_V1) & ~0x001f0000)); - budget->tsf = 0xff; budget->ttbp = 0; /* @@ -115,16 +126,12 @@ static int start_ts_capture(struct budget *budget) saa7146_write(dev, BASE_ODD3, 0); saa7146_write(dev, BASE_EVEN3, 0); - saa7146_write(dev, PROT_ADDR3, TS_WIDTH * TS_HEIGHT); + saa7146_write(dev, PROT_ADDR3, budget->buffer_size); saa7146_write(dev, BASE_PAGE3, budget->pt.dma | ME1 | 0x90); - if (budget->card->type == BUDGET_FS_ACTIVY) { - saa7146_write(dev, PITCH3, TS_WIDTH / 2); - saa7146_write(dev, NUM_LINE_BYTE3, ((TS_HEIGHT * 2) << 16) | (TS_WIDTH / 2)); - } else { - saa7146_write(dev, PITCH3, TS_WIDTH); - saa7146_write(dev, NUM_LINE_BYTE3, (TS_HEIGHT << 16) | TS_WIDTH); - } + saa7146_write(dev, PITCH3, budget->buffer_width); + saa7146_write(dev, NUM_LINE_BYTE3, + (budget->buffer_height << 16) | budget->buffer_width); saa7146_write(dev, MC2, (MASK_04 | MASK_20)); @@ -141,11 +148,12 @@ static void vpeirq(unsigned long data) u8 *mem = (u8 *) (budget->grabbing); u32 olddma = budget->ttbp; u32 newdma = saa7146_read(budget->dev, PCI_VDP3); + u32 count; /* nearest lower position divisible by 188 */ newdma -= newdma % 188; - if (newdma >= TS_BUFLEN) + if (newdma >= budget->buffer_size) return; budget->ttbp = newdma; @@ -154,11 +162,24 @@ static void vpeirq(unsigned long data) return; if (newdma > olddma) { /* no wraparound, dump olddma..newdma */ - dvb_dmx_swfilter_packets(&budget->demux, mem + olddma, (newdma - olddma) / 188); + count = newdma - olddma; + dvb_dmx_swfilter_packets(&budget->demux, mem + olddma, count / 188); } else { /* wraparound, dump olddma..buflen and 0..newdma */ - dvb_dmx_swfilter_packets(&budget->demux, mem + olddma, (TS_BUFLEN - olddma) / 188); + count = budget->buffer_size - olddma; + dvb_dmx_swfilter_packets(&budget->demux, mem + olddma, count / 188); + count += newdma; dvb_dmx_swfilter_packets(&budget->demux, mem, newdma / 188); } + + if (count > budget->buffer_warning_threshold) + budget->buffer_warnings++; + + if (budget->buffer_warnings && time_after(jiffies, budget->buffer_warning_time)) { + printk("%s %s: used %d times >80%% of buffer (%u bytes now)\n", + budget->dev->name, __FUNCTION__, budget->buffer_warnings, count); + budget->buffer_warning_time = jiffies + BUFFER_WARNING_WAIT; + budget->buffer_warnings = 0; + } } @@ -341,9 +362,10 @@ int ttpci_budget_init(struct budget *budget, struct saa7146_dev *dev, struct saa7146_pci_extension_data *info, struct module *owner) { - int length = TS_WIDTH * TS_HEIGHT; int ret = 0; struct budget_info *bi = info->ext_priv; + int max_bufsize; + int height_mask; memset(budget, 0, sizeof(struct budget)); @@ -352,6 +374,32 @@ int ttpci_budget_init(struct budget *budget, struct saa7146_dev *dev, budget->card = bi; budget->dev = (struct saa7146_dev *) dev; + if (budget->card->type == BUDGET_FS_ACTIVY) { + budget->buffer_width = TS_WIDTH_ACTIVY; + max_bufsize = TS_MAX_BUFSIZE_K_ACTIVY; + height_mask = TS_HEIGHT_MASK_ACTIVY; + } else { + budget->buffer_width = TS_WIDTH; + max_bufsize = TS_MAX_BUFSIZE_K; + height_mask = TS_HEIGHT_MASK; + } + + if (dma_buffer_size < TS_MIN_BUFSIZE_K) + dma_buffer_size = TS_MIN_BUFSIZE_K; + else if (dma_buffer_size > max_bufsize) + dma_buffer_size = max_bufsize; + + budget->buffer_height = dma_buffer_size * 1024 / budget->buffer_width; + budget->buffer_height &= height_mask; + budget->buffer_size = budget->buffer_height * budget->buffer_width; + budget->buffer_warning_threshold = budget->buffer_size * 80/100; + budget->buffer_warnings = 0; + budget->buffer_warning_time = jiffies; + + dprintk(2, "%s: width = %d, height = %d\n", + budget->dev->name, budget->buffer_width, budget->buffer_height); + printk("%s: dma buffer size %u\n", budget->dev->name, budget->buffer_size); + dvb_register_adapter(&budget->dvb_adapter, budget->card->name, owner); /* set dd1 stream a & b */ @@ -392,7 +440,7 @@ int ttpci_budget_init(struct budget *budget, struct saa7146_dev *dev, ttpci_eeprom_parse_mac(&budget->i2c_adap, budget->dvb_adapter.proposed_mac); if (NULL == - (budget->grabbing = saa7146_vmalloc_build_pgtable(dev->pci, length, &budget->pt))) { + (budget->grabbing = saa7146_vmalloc_build_pgtable(dev->pci, budget->buffer_size, &budget->pt))) { ret = -ENOMEM; goto err; } diff --git a/drivers/media/dvb/ttpci/budget-patch.c b/drivers/media/dvb/ttpci/budget-patch.c index 9fc9185a842..1b3aaac5e76 100644 --- a/drivers/media/dvb/ttpci/budget-patch.c +++ b/drivers/media/dvb/ttpci/budget-patch.c @@ -577,6 +577,17 @@ static int budget_patch_attach (struct saa7146_dev* dev, struct saa7146_pci_exte saa7146_setgpio(dev, 3, SAA7146_GPIO_OUTLO); // Set RPS1 Address register to point to RPS code (r108 p42) saa7146_write(dev, RPS_ADDR1, dev->d_rps1.dma_handle); + + if (!(budget = kmalloc (sizeof(struct budget_patch), GFP_KERNEL))) + return -ENOMEM; + + dprintk(2, "budget: %p\n", budget); + + if ((err = ttpci_budget_init (budget, dev, info, THIS_MODULE))) { + kfree (budget); + return err; + } + // Set Source Line Counter Threshold, using BRS (rCC p43) // It generates HS event every TS_HEIGHT lines // this is related to TS_WIDTH set in register @@ -585,24 +596,13 @@ static int budget_patch_attach (struct saa7146_dev* dev, struct saa7146_pci_exte //,then RPS_THRESH1 // should be set to trigger every TS_HEIGHT (512) lines. // - saa7146_write(dev, RPS_THRESH1, (TS_HEIGHT*1) | MASK_12 ); + saa7146_write(dev, RPS_THRESH1, budget->buffer_height | MASK_12 ); // saa7146_write(dev, RPS_THRESH0, ((TS_HEIGHT/2)<<16) |MASK_28| (TS_HEIGHT/2) |MASK_12 ); // Enable RPS1 (rFC p33) saa7146_write(dev, MC1, (MASK_13 | MASK_29)); - if (!(budget = kmalloc (sizeof(struct budget_patch), GFP_KERNEL))) - return -ENOMEM; - - dprintk(2, "budget: %p\n", budget); - - if ((err = ttpci_budget_init (budget, dev, info, THIS_MODULE))) { - kfree (budget); - return err; - } - - dev->ext_priv = budget; budget->dvb_adapter.priv = budget; diff --git a/drivers/media/dvb/ttpci/budget.h b/drivers/media/dvb/ttpci/budget.h index 4ac0f4d0802..ecea3a13030 100644 --- a/drivers/media/dvb/ttpci/budget.h +++ b/drivers/media/dvb/ttpci/budget.h @@ -58,7 +58,13 @@ struct budget { int ci_present; int video_port; - u8 tsf; + u32 buffer_width; + u32 buffer_height; + u32 buffer_size; + u32 buffer_warning_threshold; + u32 buffer_warnings; + unsigned long buffer_warning_time; + u32 ttbp; int feeding; @@ -79,11 +85,6 @@ static struct saa7146_pci_extension_data x_var = { \ .ext_priv = &x_var ## _info, \ .ext = &budget_extension }; -#define TS_WIDTH (376) -#define TS_HEIGHT (512) -#define TS_BUFLEN (TS_WIDTH*TS_HEIGHT) -#define TS_MAX_PACKETS (TS_BUFLEN/TS_SIZE) - #define BUDGET_TT 0 #define BUDGET_TT_HW_DISEQC 1 #define BUDGET_PATCH 3 diff --git a/drivers/media/dvb/ttusb-budget/dvb-ttusb-budget.c b/drivers/media/dvb/ttusb-budget/dvb-ttusb-budget.c index 248fdc7accf..6ceae38125c 100644 --- a/drivers/media/dvb/ttusb-budget/dvb-ttusb-budget.c +++ b/drivers/media/dvb/ttusb-budget/dvb-ttusb-budget.c @@ -1507,7 +1507,11 @@ static int ttusb_probe(struct usb_interface *intf, const struct usb_device_id *i mutex_unlock(&ttusb->semi2c); - dvb_register_adapter(&ttusb->adapter, "Technotrend/Hauppauge Nova-USB", THIS_MODULE); + if ((result = dvb_register_adapter(&ttusb->adapter, "Technotrend/Hauppauge Nova-USB", THIS_MODULE)) < 0) { + ttusb_free_iso_urbs(ttusb); + kfree(ttusb); + return result; + } ttusb->adapter.priv = ttusb; /* i2c */ |