diff options
Diffstat (limited to 'drivers/media')
200 files changed, 22258 insertions, 4245 deletions
diff --git a/drivers/media/common/ir-keymaps.c b/drivers/media/common/ir-keymaps.c index 03b47a262f27..cbd1184b5219 100644 --- a/drivers/media/common/ir-keymaps.c +++ b/drivers/media/common/ir-keymaps.c | |||
@@ -667,7 +667,7 @@ IR_KEYTAB_TYPE ir_codes_pinnacle_grey[IR_KEYTAB_SIZE] = { | |||
667 | [ 0x1f ] = KEY_L, | 667 | [ 0x1f ] = KEY_L, |
668 | [ 0x2b ] = KEY_I, | 668 | [ 0x2b ] = KEY_I, |
669 | 669 | ||
670 | [ 0x2d ] = KEY_ZOOM, | 670 | [ 0x2d ] = KEY_SCREEN, |
671 | [ 0x1e ] = KEY_ZOOM, | 671 | [ 0x1e ] = KEY_ZOOM, |
672 | [ 0x1b ] = KEY_VOLUMEUP, | 672 | [ 0x1b ] = KEY_VOLUMEUP, |
673 | [ 0x0f ] = KEY_VOLUMEDOWN, | 673 | [ 0x0f ] = KEY_VOLUMEDOWN, |
@@ -682,12 +682,12 @@ IR_KEYTAB_TYPE ir_codes_pinnacle_grey[IR_KEYTAB_SIZE] = { | |||
682 | 682 | ||
683 | [ 0x3f ] = KEY_UP, | 683 | [ 0x3f ] = KEY_UP, |
684 | [ 0x3e ] = KEY_DOWN, | 684 | [ 0x3e ] = KEY_DOWN, |
685 | [ 0x1a ] = KEY_PAUSE, | 685 | [ 0x1a ] = KEY_ENTER, |
686 | 686 | ||
687 | [ 0x1d ] = KEY_MENU, | 687 | [ 0x1d ] = KEY_MENU, |
688 | [ 0x19 ] = KEY_PLAY, | 688 | [ 0x19 ] = KEY_AGAIN, |
689 | [ 0x16 ] = KEY_REWIND, | 689 | [ 0x16 ] = KEY_PREVIOUSSONG, |
690 | [ 0x13 ] = KEY_FORWARD, | 690 | [ 0x13 ] = KEY_NEXTSONG, |
691 | [ 0x15 ] = KEY_PAUSE, | 691 | [ 0x15 ] = KEY_PAUSE, |
692 | [ 0x0e ] = KEY_REWIND, | 692 | [ 0x0e ] = KEY_REWIND, |
693 | [ 0x0d ] = KEY_PLAY, | 693 | [ 0x0d ] = KEY_PLAY, |
@@ -1739,7 +1739,7 @@ IR_KEYTAB_TYPE ir_codes_encore_enltv[IR_KEYTAB_SIZE] = { | |||
1739 | 1739 | ||
1740 | EXPORT_SYMBOL_GPL(ir_codes_encore_enltv); | 1740 | EXPORT_SYMBOL_GPL(ir_codes_encore_enltv); |
1741 | 1741 | ||
1742 | /* for the Technotrend 1500 bundled remote: */ | 1742 | /* for the Technotrend 1500 bundled remotes (grey and black): */ |
1743 | IR_KEYTAB_TYPE ir_codes_tt_1500[IR_KEYTAB_SIZE] = { | 1743 | IR_KEYTAB_TYPE ir_codes_tt_1500[IR_KEYTAB_SIZE] = { |
1744 | [ 0x01 ] = KEY_POWER, | 1744 | [ 0x01 ] = KEY_POWER, |
1745 | [ 0x02 ] = KEY_SHUFFLE, /* ? double-arrow key */ | 1745 | [ 0x02 ] = KEY_SHUFFLE, /* ? double-arrow key */ |
@@ -1774,6 +1774,12 @@ IR_KEYTAB_TYPE ir_codes_tt_1500[IR_KEYTAB_SIZE] = { | |||
1774 | [ 0x25 ] = KEY_VOLUMEUP, | 1774 | [ 0x25 ] = KEY_VOLUMEUP, |
1775 | [ 0x26 ] = KEY_VOLUMEDOWN, | 1775 | [ 0x26 ] = KEY_VOLUMEDOWN, |
1776 | [ 0x27 ] = KEY_SETUP, | 1776 | [ 0x27 ] = KEY_SETUP, |
1777 | [ 0x3a ] = KEY_RECORD, /* these keys are only in the black remote */ | ||
1778 | [ 0x3b ] = KEY_PLAY, | ||
1779 | [ 0x3c ] = KEY_STOP, | ||
1780 | [ 0x3d ] = KEY_REWIND, | ||
1781 | [ 0x3e ] = KEY_PAUSE, | ||
1782 | [ 0x3f ] = KEY_FORWARD, | ||
1777 | }; | 1783 | }; |
1778 | 1784 | ||
1779 | EXPORT_SYMBOL_GPL(ir_codes_tt_1500); | 1785 | EXPORT_SYMBOL_GPL(ir_codes_tt_1500); |
diff --git a/drivers/media/common/saa7146_video.c b/drivers/media/common/saa7146_video.c index 7e0cedc557df..e3d04a4cef4d 100644 --- a/drivers/media/common/saa7146_video.c +++ b/drivers/media/common/saa7146_video.c | |||
@@ -1428,6 +1428,7 @@ static void video_close(struct saa7146_dev *dev, struct file *file) | |||
1428 | { | 1428 | { |
1429 | struct saa7146_fh *fh = (struct saa7146_fh *)file->private_data; | 1429 | struct saa7146_fh *fh = (struct saa7146_fh *)file->private_data; |
1430 | struct saa7146_vv *vv = dev->vv_data; | 1430 | struct saa7146_vv *vv = dev->vv_data; |
1431 | struct videobuf_queue *q = &fh->video_q; | ||
1431 | int err; | 1432 | int err; |
1432 | 1433 | ||
1433 | if (IS_CAPTURE_ACTIVE(fh) != 0) { | 1434 | if (IS_CAPTURE_ACTIVE(fh) != 0) { |
@@ -1436,6 +1437,11 @@ static void video_close(struct saa7146_dev *dev, struct file *file) | |||
1436 | err = saa7146_stop_preview(fh); | 1437 | err = saa7146_stop_preview(fh); |
1437 | } | 1438 | } |
1438 | 1439 | ||
1440 | // release all capture buffers | ||
1441 | mutex_lock(&q->lock); | ||
1442 | videobuf_read_stop(q); | ||
1443 | mutex_unlock(&q->lock); | ||
1444 | |||
1439 | /* hmm, why is this function declared void? */ | 1445 | /* hmm, why is this function declared void? */ |
1440 | /* return err */ | 1446 | /* return err */ |
1441 | } | 1447 | } |
diff --git a/drivers/media/dvb/b2c2/Kconfig b/drivers/media/dvb/b2c2/Kconfig index 79875958930e..a0dcd59da76e 100644 --- a/drivers/media/dvb/b2c2/Kconfig +++ b/drivers/media/dvb/b2c2/Kconfig | |||
@@ -9,7 +9,6 @@ config DVB_B2C2_FLEXCOP | |||
9 | select DVB_STV0297 if !DVB_FE_CUSTOMISE | 9 | select DVB_STV0297 if !DVB_FE_CUSTOMISE |
10 | select DVB_BCM3510 if !DVB_FE_CUSTOMISE | 10 | select DVB_BCM3510 if !DVB_FE_CUSTOMISE |
11 | select DVB_LGDT330X if !DVB_FE_CUSTOMISE | 11 | select DVB_LGDT330X if !DVB_FE_CUSTOMISE |
12 | select DVB_TUNER_LGH06XF if !DVB_FE_CUSTOMISE | ||
13 | help | 12 | help |
14 | Support for the digital TV receiver chip made by B2C2 Inc. included in | 13 | Support for the digital TV receiver chip made by B2C2 Inc. included in |
15 | Technisats PCI cards and USB boxes. | 14 | Technisats PCI cards and USB boxes. |
diff --git a/drivers/media/dvb/b2c2/flexcop-fe-tuner.c b/drivers/media/dvb/b2c2/flexcop-fe-tuner.c index 752cf79c532f..b02c2fd65baa 100644 --- a/drivers/media/dvb/b2c2/flexcop-fe-tuner.c +++ b/drivers/media/dvb/b2c2/flexcop-fe-tuner.c | |||
@@ -14,7 +14,6 @@ | |||
14 | #include "stv0297.h" | 14 | #include "stv0297.h" |
15 | #include "mt312.h" | 15 | #include "mt312.h" |
16 | #include "lgdt330x.h" | 16 | #include "lgdt330x.h" |
17 | #include "lgh06xf.h" | ||
18 | #include "dvb-pll.h" | 17 | #include "dvb-pll.h" |
19 | 18 | ||
20 | /* lnb control */ | 19 | /* lnb control */ |
@@ -507,7 +506,7 @@ int flexcop_frontend_init(struct flexcop_device *fc) | |||
507 | /* try the air atsc 3nd generation (lgdt3303) */ | 506 | /* try the air atsc 3nd generation (lgdt3303) */ |
508 | if ((fc->fe = dvb_attach(lgdt330x_attach, &air2pc_atsc_hd5000_config, &fc->i2c_adap)) != NULL) { | 507 | if ((fc->fe = dvb_attach(lgdt330x_attach, &air2pc_atsc_hd5000_config, &fc->i2c_adap)) != NULL) { |
509 | fc->dev_type = FC_AIR_ATSC3; | 508 | fc->dev_type = FC_AIR_ATSC3; |
510 | dvb_attach(lgh06xf_attach, fc->fe, &fc->i2c_adap); | 509 | dvb_attach(dvb_pll_attach, fc->fe, 0x61, &fc->i2c_adap, &dvb_pll_lg_tdvs_h06xf); |
511 | info("found the lgdt3303 at i2c address: 0x%02x",air2pc_atsc_hd5000_config.demod_address); | 510 | info("found the lgdt3303 at i2c address: 0x%02x",air2pc_atsc_hd5000_config.demod_address); |
512 | } else | 511 | } else |
513 | /* try the air atsc 1nd generation (bcm3510)/panasonic ct10s */ | 512 | /* try the air atsc 1nd generation (bcm3510)/panasonic ct10s */ |
diff --git a/drivers/media/dvb/b2c2/flexcop-pci.c b/drivers/media/dvb/b2c2/flexcop-pci.c index 6e166801505d..01af4d237eb1 100644 --- a/drivers/media/dvb/b2c2/flexcop-pci.c +++ b/drivers/media/dvb/b2c2/flexcop-pci.c | |||
@@ -127,10 +127,11 @@ static irqreturn_t flexcop_pci_isr(int irq, void *dev_id) | |||
127 | { | 127 | { |
128 | struct flexcop_pci *fc_pci = dev_id; | 128 | struct flexcop_pci *fc_pci = dev_id; |
129 | struct flexcop_device *fc = fc_pci->fc_dev; | 129 | struct flexcop_device *fc = fc_pci->fc_dev; |
130 | unsigned long flags; | ||
130 | flexcop_ibi_value v; | 131 | flexcop_ibi_value v; |
131 | irqreturn_t ret = IRQ_HANDLED; | 132 | irqreturn_t ret = IRQ_HANDLED; |
132 | 133 | ||
133 | spin_lock_irq(&fc_pci->irq_lock); | 134 | spin_lock_irqsave(&fc_pci->irq_lock,flags); |
134 | 135 | ||
135 | v = fc->read_ibi_reg(fc,irq_20c); | 136 | v = fc->read_ibi_reg(fc,irq_20c); |
136 | 137 | ||
@@ -194,7 +195,7 @@ static irqreturn_t flexcop_pci_isr(int irq, void *dev_id) | |||
194 | ret = IRQ_NONE; | 195 | ret = IRQ_NONE; |
195 | } | 196 | } |
196 | 197 | ||
197 | spin_unlock_irq(&fc_pci->irq_lock); | 198 | spin_unlock_irqrestore(&fc_pci->irq_lock,flags); |
198 | 199 | ||
199 | return ret; | 200 | return ret; |
200 | } | 201 | } |
@@ -293,12 +294,12 @@ static int flexcop_pci_init(struct flexcop_pci *fc_pci) | |||
293 | } | 294 | } |
294 | 295 | ||
295 | pci_set_drvdata(fc_pci->pdev, fc_pci); | 296 | pci_set_drvdata(fc_pci->pdev, fc_pci); |
296 | 297 | spin_lock_init(&fc_pci->irq_lock); | |
297 | if ((ret = request_irq(fc_pci->pdev->irq, flexcop_pci_isr, | 298 | if ((ret = request_irq(fc_pci->pdev->irq, flexcop_pci_isr, |
298 | IRQF_SHARED, DRIVER_NAME, fc_pci)) != 0) | 299 | IRQF_SHARED, DRIVER_NAME, fc_pci)) != 0) |
299 | goto err_pci_iounmap; | 300 | goto err_pci_iounmap; |
300 | 301 | ||
301 | spin_lock_init(&fc_pci->irq_lock); | 302 | |
302 | 303 | ||
303 | fc_pci->init_state |= FC_PCI_INIT; | 304 | fc_pci->init_state |= FC_PCI_INIT; |
304 | return ret; | 305 | return ret; |
diff --git a/drivers/media/dvb/bt8xx/Kconfig b/drivers/media/dvb/bt8xx/Kconfig index dd66b60fbc98..cfd6fb729a61 100644 --- a/drivers/media/dvb/bt8xx/Kconfig +++ b/drivers/media/dvb/bt8xx/Kconfig | |||
@@ -7,7 +7,7 @@ config DVB_BT8XX | |||
7 | select DVB_CX24110 if !DVB_FE_CUSTOMISE | 7 | select DVB_CX24110 if !DVB_FE_CUSTOMISE |
8 | select DVB_OR51211 if !DVB_FE_CUSTOMISE | 8 | select DVB_OR51211 if !DVB_FE_CUSTOMISE |
9 | select DVB_LGDT330X if !DVB_FE_CUSTOMISE | 9 | select DVB_LGDT330X if !DVB_FE_CUSTOMISE |
10 | select DVB_TUNER_LGH06XF if !DVB_FE_CUSTOMISE | 10 | select DVB_PLL |
11 | select DVB_ZL10353 if !DVB_FE_CUSTOMISE | 11 | select DVB_ZL10353 if !DVB_FE_CUSTOMISE |
12 | select FW_LOADER | 12 | select FW_LOADER |
13 | help | 13 | help |
diff --git a/drivers/media/dvb/bt8xx/bt878.c b/drivers/media/dvb/bt8xx/bt878.c index 83b090ef2445..df72b4b8ee10 100644 --- a/drivers/media/dvb/bt8xx/bt878.c +++ b/drivers/media/dvb/bt8xx/bt878.c | |||
@@ -393,9 +393,7 @@ static struct cards card_list[] __devinitdata = { | |||
393 | { 0xdb1118ac, BTTV_BOARD_DVICO_DVBT_LITE, "Ultraview DVB-T Lite" }, | 393 | { 0xdb1118ac, BTTV_BOARD_DVICO_DVBT_LITE, "Ultraview DVB-T Lite" }, |
394 | { 0xd50018ac, BTTV_BOARD_DVICO_FUSIONHDTV_5_LITE, "DViCO FusionHDTV 5 Lite" }, | 394 | { 0xd50018ac, BTTV_BOARD_DVICO_FUSIONHDTV_5_LITE, "DViCO FusionHDTV 5 Lite" }, |
395 | { 0x20007063, BTTV_BOARD_PC_HDTV, "pcHDTV HD-2000 TV" }, | 395 | { 0x20007063, BTTV_BOARD_PC_HDTV, "pcHDTV HD-2000 TV" }, |
396 | { 0x00261822, BTTV_BOARD_TWINHAN_DST, "DNTV Live! Mini" }, | 396 | { 0x00261822, BTTV_BOARD_TWINHAN_DST, "DNTV Live! Mini" } |
397 | |||
398 | { 0, -1, NULL } | ||
399 | }; | 397 | }; |
400 | 398 | ||
401 | 399 | ||
diff --git a/drivers/media/dvb/bt8xx/dvb-bt8xx.c b/drivers/media/dvb/bt8xx/dvb-bt8xx.c index 58f69f6ae391..4f1c09bee538 100644 --- a/drivers/media/dvb/bt8xx/dvb-bt8xx.c +++ b/drivers/media/dvb/bt8xx/dvb-bt8xx.c | |||
@@ -610,7 +610,8 @@ static void frontend_init(struct dvb_bt8xx_card *card, u32 type) | |||
610 | lgdt330x_reset(card); | 610 | lgdt330x_reset(card); |
611 | card->fe = dvb_attach(lgdt330x_attach, &tdvs_tua6034_config, card->i2c_adapter); | 611 | card->fe = dvb_attach(lgdt330x_attach, &tdvs_tua6034_config, card->i2c_adapter); |
612 | if (card->fe != NULL) { | 612 | if (card->fe != NULL) { |
613 | dvb_attach(lgh06xf_attach, card->fe, card->i2c_adapter); | 613 | dvb_attach(dvb_pll_attach, card->fe, 0x61, |
614 | card->i2c_adapter, &dvb_pll_lg_tdvs_h06xf); | ||
614 | dprintk ("dvb_bt8xx: lgdt330x detected\n"); | 615 | dprintk ("dvb_bt8xx: lgdt330x detected\n"); |
615 | } | 616 | } |
616 | break; | 617 | break; |
diff --git a/drivers/media/dvb/bt8xx/dvb-bt8xx.h b/drivers/media/dvb/bt8xx/dvb-bt8xx.h index e75f4173c059..436880e68672 100644 --- a/drivers/media/dvb/bt8xx/dvb-bt8xx.h +++ b/drivers/media/dvb/bt8xx/dvb-bt8xx.h | |||
@@ -37,8 +37,8 @@ | |||
37 | #include "cx24110.h" | 37 | #include "cx24110.h" |
38 | #include "or51211.h" | 38 | #include "or51211.h" |
39 | #include "lgdt330x.h" | 39 | #include "lgdt330x.h" |
40 | #include "lgh06xf.h" | ||
41 | #include "zl10353.h" | 40 | #include "zl10353.h" |
41 | #include "dvb-pll.h" | ||
42 | 42 | ||
43 | struct dvb_bt8xx_card { | 43 | struct dvb_bt8xx_card { |
44 | struct mutex lock; | 44 | struct mutex lock; |
diff --git a/drivers/media/dvb/dvb-core/dmxdev.c b/drivers/media/dvb/dvb-core/dmxdev.c index a5c0e1a3e6d1..275df65fde99 100644 --- a/drivers/media/dvb/dvb-core/dmxdev.c +++ b/drivers/media/dvb/dvb-core/dmxdev.c | |||
@@ -132,6 +132,11 @@ static int dvb_dvr_open(struct inode *inode, struct file *file) | |||
132 | if (mutex_lock_interruptible(&dmxdev->mutex)) | 132 | if (mutex_lock_interruptible(&dmxdev->mutex)) |
133 | return -ERESTARTSYS; | 133 | return -ERESTARTSYS; |
134 | 134 | ||
135 | if (dmxdev->exit) { | ||
136 | mutex_unlock(&dmxdev->mutex); | ||
137 | return -ENODEV; | ||
138 | } | ||
139 | |||
135 | if ((file->f_flags & O_ACCMODE) == O_RDWR) { | 140 | if ((file->f_flags & O_ACCMODE) == O_RDWR) { |
136 | if (!(dmxdev->capabilities & DMXDEV_CAP_DUPLEX)) { | 141 | if (!(dmxdev->capabilities & DMXDEV_CAP_DUPLEX)) { |
137 | mutex_unlock(&dmxdev->mutex); | 142 | mutex_unlock(&dmxdev->mutex); |
@@ -171,6 +176,7 @@ static int dvb_dvr_open(struct inode *inode, struct file *file) | |||
171 | dmxdev->demux->disconnect_frontend(dmxdev->demux); | 176 | dmxdev->demux->disconnect_frontend(dmxdev->demux); |
172 | dmxdev->demux->connect_frontend(dmxdev->demux, front); | 177 | dmxdev->demux->connect_frontend(dmxdev->demux, front); |
173 | } | 178 | } |
179 | dvbdev->users++; | ||
174 | mutex_unlock(&dmxdev->mutex); | 180 | mutex_unlock(&dmxdev->mutex); |
175 | return 0; | 181 | return 0; |
176 | } | 182 | } |
@@ -198,7 +204,16 @@ static int dvb_dvr_release(struct inode *inode, struct file *file) | |||
198 | vfree(mem); | 204 | vfree(mem); |
199 | } | 205 | } |
200 | } | 206 | } |
201 | mutex_unlock(&dmxdev->mutex); | 207 | /* TODO */ |
208 | dvbdev->users--; | ||
209 | if(dvbdev->users==-1 && dmxdev->exit==1) { | ||
210 | fops_put(file->f_op); | ||
211 | file->f_op = NULL; | ||
212 | mutex_unlock(&dmxdev->mutex); | ||
213 | wake_up(&dvbdev->wait_queue); | ||
214 | } else | ||
215 | mutex_unlock(&dmxdev->mutex); | ||
216 | |||
202 | return 0; | 217 | return 0; |
203 | } | 218 | } |
204 | 219 | ||
@@ -215,6 +230,11 @@ static ssize_t dvb_dvr_write(struct file *file, const char __user *buf, | |||
215 | return -EINVAL; | 230 | return -EINVAL; |
216 | if (mutex_lock_interruptible(&dmxdev->mutex)) | 231 | if (mutex_lock_interruptible(&dmxdev->mutex)) |
217 | return -ERESTARTSYS; | 232 | return -ERESTARTSYS; |
233 | |||
234 | if (dmxdev->exit) { | ||
235 | mutex_unlock(&dmxdev->mutex); | ||
236 | return -ENODEV; | ||
237 | } | ||
218 | ret = dmxdev->demux->write(dmxdev->demux, buf, count); | 238 | ret = dmxdev->demux->write(dmxdev->demux, buf, count); |
219 | mutex_unlock(&dmxdev->mutex); | 239 | mutex_unlock(&dmxdev->mutex); |
220 | return ret; | 240 | return ret; |
@@ -227,6 +247,11 @@ static ssize_t dvb_dvr_read(struct file *file, char __user *buf, size_t count, | |||
227 | struct dmxdev *dmxdev = dvbdev->priv; | 247 | struct dmxdev *dmxdev = dvbdev->priv; |
228 | int ret; | 248 | int ret; |
229 | 249 | ||
250 | if (dmxdev->exit) { | ||
251 | mutex_unlock(&dmxdev->mutex); | ||
252 | return -ENODEV; | ||
253 | } | ||
254 | |||
230 | //mutex_lock(&dmxdev->mutex); | 255 | //mutex_lock(&dmxdev->mutex); |
231 | ret = dvb_dmxdev_buffer_read(&dmxdev->dvr_buffer, | 256 | ret = dvb_dmxdev_buffer_read(&dmxdev->dvr_buffer, |
232 | file->f_flags & O_NONBLOCK, | 257 | file->f_flags & O_NONBLOCK, |
@@ -665,6 +690,8 @@ static int dvb_demux_open(struct inode *inode, struct file *file) | |||
665 | dmxdevfilter->feed.ts = NULL; | 690 | dmxdevfilter->feed.ts = NULL; |
666 | init_timer(&dmxdevfilter->timer); | 691 | init_timer(&dmxdevfilter->timer); |
667 | 692 | ||
693 | dvbdev->users++; | ||
694 | |||
668 | mutex_unlock(&dmxdev->mutex); | 695 | mutex_unlock(&dmxdev->mutex); |
669 | return 0; | 696 | return 0; |
670 | } | 697 | } |
@@ -943,7 +970,21 @@ static int dvb_demux_release(struct inode *inode, struct file *file) | |||
943 | struct dmxdev_filter *dmxdevfilter = file->private_data; | 970 | struct dmxdev_filter *dmxdevfilter = file->private_data; |
944 | struct dmxdev *dmxdev = dmxdevfilter->dev; | 971 | struct dmxdev *dmxdev = dmxdevfilter->dev; |
945 | 972 | ||
946 | return dvb_dmxdev_filter_free(dmxdev, dmxdevfilter); | 973 | int ret; |
974 | |||
975 | ret = dvb_dmxdev_filter_free(dmxdev, dmxdevfilter); | ||
976 | |||
977 | mutex_lock(&dmxdev->mutex); | ||
978 | dmxdev->dvbdev->users--; | ||
979 | if(dmxdev->dvbdev->users==1 && dmxdev->exit==1) { | ||
980 | fops_put(file->f_op); | ||
981 | file->f_op = NULL; | ||
982 | mutex_unlock(&dmxdev->mutex); | ||
983 | wake_up(&dmxdev->dvbdev->wait_queue); | ||
984 | } else | ||
985 | mutex_unlock(&dmxdev->mutex); | ||
986 | |||
987 | return ret; | ||
947 | } | 988 | } |
948 | 989 | ||
949 | static struct file_operations dvb_demux_fops = { | 990 | static struct file_operations dvb_demux_fops = { |
@@ -1027,6 +1068,7 @@ static struct file_operations dvb_dvr_fops = { | |||
1027 | static struct dvb_device dvbdev_dvr = { | 1068 | static struct dvb_device dvbdev_dvr = { |
1028 | .priv = NULL, | 1069 | .priv = NULL, |
1029 | .readers = 1, | 1070 | .readers = 1, |
1071 | .users = 1, | ||
1030 | .fops = &dvb_dvr_fops | 1072 | .fops = &dvb_dvr_fops |
1031 | }; | 1073 | }; |
1032 | 1074 | ||
@@ -1064,6 +1106,16 @@ EXPORT_SYMBOL(dvb_dmxdev_init); | |||
1064 | 1106 | ||
1065 | void dvb_dmxdev_release(struct dmxdev *dmxdev) | 1107 | void dvb_dmxdev_release(struct dmxdev *dmxdev) |
1066 | { | 1108 | { |
1109 | dmxdev->exit=1; | ||
1110 | if (dmxdev->dvbdev->users > 1) { | ||
1111 | wait_event(dmxdev->dvbdev->wait_queue, | ||
1112 | dmxdev->dvbdev->users==1); | ||
1113 | } | ||
1114 | if (dmxdev->dvr_dvbdev->users > 1) { | ||
1115 | wait_event(dmxdev->dvr_dvbdev->wait_queue, | ||
1116 | dmxdev->dvr_dvbdev->users==1); | ||
1117 | } | ||
1118 | |||
1067 | dvb_unregister_device(dmxdev->dvbdev); | 1119 | dvb_unregister_device(dmxdev->dvbdev); |
1068 | dvb_unregister_device(dmxdev->dvr_dvbdev); | 1120 | dvb_unregister_device(dmxdev->dvr_dvbdev); |
1069 | 1121 | ||
diff --git a/drivers/media/dvb/dvb-core/dmxdev.h b/drivers/media/dvb/dvb-core/dmxdev.h index d2bee9ffe43c..29746e70d325 100644 --- a/drivers/media/dvb/dvb-core/dmxdev.h +++ b/drivers/media/dvb/dvb-core/dmxdev.h | |||
@@ -91,6 +91,8 @@ struct dmxdev { | |||
91 | 91 | ||
92 | int filternum; | 92 | int filternum; |
93 | int capabilities; | 93 | int capabilities; |
94 | |||
95 | unsigned int exit:1; | ||
94 | #define DMXDEV_CAP_DUPLEX 1 | 96 | #define DMXDEV_CAP_DUPLEX 1 |
95 | struct dmx_frontend *dvr_orig_fe; | 97 | struct dmx_frontend *dvr_orig_fe; |
96 | 98 | ||
diff --git a/drivers/media/dvb/dvb-core/dvb_frontend.c b/drivers/media/dvb/dvb-core/dvb_frontend.c index a21a894d3f98..f4e4ca2dcade 100644 --- a/drivers/media/dvb/dvb-core/dvb_frontend.c +++ b/drivers/media/dvb/dvb-core/dvb_frontend.c | |||
@@ -606,6 +606,7 @@ static void dvb_frontend_stop(struct dvb_frontend *fe) | |||
606 | return; | 606 | return; |
607 | 607 | ||
608 | kthread_stop(fepriv->thread); | 608 | kthread_stop(fepriv->thread); |
609 | |||
609 | init_MUTEX (&fepriv->sem); | 610 | init_MUTEX (&fepriv->sem); |
610 | fepriv->state = FESTATE_IDLE; | 611 | fepriv->state = FESTATE_IDLE; |
611 | 612 | ||
@@ -1023,6 +1024,7 @@ static int dvb_frontend_release(struct inode *inode, struct file *file) | |||
1023 | struct dvb_device *dvbdev = file->private_data; | 1024 | struct dvb_device *dvbdev = file->private_data; |
1024 | struct dvb_frontend *fe = dvbdev->priv; | 1025 | struct dvb_frontend *fe = dvbdev->priv; |
1025 | struct dvb_frontend_private *fepriv = fe->frontend_priv; | 1026 | struct dvb_frontend_private *fepriv = fe->frontend_priv; |
1027 | int ret; | ||
1026 | 1028 | ||
1027 | dprintk ("%s\n", __FUNCTION__); | 1029 | dprintk ("%s\n", __FUNCTION__); |
1028 | 1030 | ||
@@ -1032,7 +1034,14 @@ static int dvb_frontend_release(struct inode *inode, struct file *file) | |||
1032 | if (fe->ops.ts_bus_ctrl) | 1034 | if (fe->ops.ts_bus_ctrl) |
1033 | fe->ops.ts_bus_ctrl (fe, 0); | 1035 | fe->ops.ts_bus_ctrl (fe, 0); |
1034 | 1036 | ||
1035 | return dvb_generic_release (inode, file); | 1037 | ret = dvb_generic_release (inode, file); |
1038 | |||
1039 | if (dvbdev->users==-1 && fepriv->exit==1) { | ||
1040 | fops_put(file->f_op); | ||
1041 | file->f_op = NULL; | ||
1042 | wake_up(&dvbdev->wait_queue); | ||
1043 | } | ||
1044 | return ret; | ||
1036 | } | 1045 | } |
1037 | 1046 | ||
1038 | static struct file_operations dvb_frontend_fops = { | 1047 | static struct file_operations dvb_frontend_fops = { |
@@ -1092,8 +1101,15 @@ int dvb_unregister_frontend(struct dvb_frontend* fe) | |||
1092 | dprintk ("%s\n", __FUNCTION__); | 1101 | dprintk ("%s\n", __FUNCTION__); |
1093 | 1102 | ||
1094 | mutex_lock(&frontend_mutex); | 1103 | mutex_lock(&frontend_mutex); |
1095 | dvb_unregister_device (fepriv->dvbdev); | ||
1096 | dvb_frontend_stop (fe); | 1104 | dvb_frontend_stop (fe); |
1105 | mutex_unlock(&frontend_mutex); | ||
1106 | |||
1107 | if (fepriv->dvbdev->users < -1) | ||
1108 | wait_event(fepriv->dvbdev->wait_queue, | ||
1109 | fepriv->dvbdev->users==-1); | ||
1110 | |||
1111 | mutex_lock(&frontend_mutex); | ||
1112 | dvb_unregister_device (fepriv->dvbdev); | ||
1097 | 1113 | ||
1098 | /* fe is invalid now */ | 1114 | /* fe is invalid now */ |
1099 | kfree(fepriv); | 1115 | kfree(fepriv); |
diff --git a/drivers/media/dvb/dvb-core/dvb_net.c b/drivers/media/dvb/dvb-core/dvb_net.c index 76e9c36597eb..4ebf33a5ffa2 100644 --- a/drivers/media/dvb/dvb-core/dvb_net.c +++ b/drivers/media/dvb/dvb-core/dvb_net.c | |||
@@ -174,7 +174,7 @@ static unsigned short dvb_net_eth_type_trans(struct sk_buff *skb, | |||
174 | struct ethhdr *eth; | 174 | struct ethhdr *eth; |
175 | unsigned char *rawp; | 175 | unsigned char *rawp; |
176 | 176 | ||
177 | skb->mac.raw=skb->data; | 177 | skb_reset_mac_header(skb); |
178 | skb_pull(skb,dev->hard_header_len); | 178 | skb_pull(skb,dev->hard_header_len); |
179 | eth = eth_hdr(skb); | 179 | eth = eth_hdr(skb); |
180 | 180 | ||
@@ -600,6 +600,7 @@ static void dvb_net_ule( struct net_device *dev, const u8 *buf, size_t buf_len ) | |||
600 | /* Check CRC32, we've got it in our skb already. */ | 600 | /* Check CRC32, we've got it in our skb already. */ |
601 | unsigned short ulen = htons(priv->ule_sndu_len); | 601 | unsigned short ulen = htons(priv->ule_sndu_len); |
602 | unsigned short utype = htons(priv->ule_sndu_type); | 602 | unsigned short utype = htons(priv->ule_sndu_type); |
603 | const u8 *tail; | ||
603 | struct kvec iov[3] = { | 604 | struct kvec iov[3] = { |
604 | { &ulen, sizeof ulen }, | 605 | { &ulen, sizeof ulen }, |
605 | { &utype, sizeof utype }, | 606 | { &utype, sizeof utype }, |
@@ -613,10 +614,11 @@ static void dvb_net_ule( struct net_device *dev, const u8 *buf, size_t buf_len ) | |||
613 | } | 614 | } |
614 | 615 | ||
615 | ule_crc = iov_crc32(ule_crc, iov, 3); | 616 | ule_crc = iov_crc32(ule_crc, iov, 3); |
616 | expected_crc = *((u8 *)priv->ule_skb->tail - 4) << 24 | | 617 | tail = skb_tail_pointer(priv->ule_skb); |
617 | *((u8 *)priv->ule_skb->tail - 3) << 16 | | 618 | expected_crc = *(tail - 4) << 24 | |
618 | *((u8 *)priv->ule_skb->tail - 2) << 8 | | 619 | *(tail - 3) << 16 | |
619 | *((u8 *)priv->ule_skb->tail - 1); | 620 | *(tail - 2) << 8 | |
621 | *(tail - 1); | ||
620 | if (ule_crc != expected_crc) { | 622 | if (ule_crc != expected_crc) { |
621 | printk(KERN_WARNING "%lu: CRC32 check FAILED: %08x / %08x, SNDU len %d type %#x, ts_remain %d, next 2: %x.\n", | 623 | printk(KERN_WARNING "%lu: CRC32 check FAILED: %08x / %08x, SNDU len %d type %#x, ts_remain %d, next 2: %x.\n", |
622 | priv->ts_count, ule_crc, expected_crc, priv->ule_sndu_len, priv->ule_sndu_type, ts_remain, ts_remain > 2 ? *(unsigned short *)from_where : 0); | 624 | priv->ts_count, ule_crc, expected_crc, priv->ule_sndu_len, priv->ule_sndu_type, ts_remain, ts_remain > 2 ? *(unsigned short *)from_where : 0); |
@@ -695,7 +697,9 @@ static void dvb_net_ule( struct net_device *dev, const u8 *buf, size_t buf_len ) | |||
695 | } | 697 | } |
696 | else | 698 | else |
697 | { | 699 | { |
698 | memcpy(dest_addr, priv->ule_skb->data, ETH_ALEN); | 700 | skb_copy_from_linear_data(priv->ule_skb, |
701 | dest_addr, | ||
702 | ETH_ALEN); | ||
699 | skb_pull(priv->ule_skb, ETH_ALEN); | 703 | skb_pull(priv->ule_skb, ETH_ALEN); |
700 | } | 704 | } |
701 | } | 705 | } |
@@ -1435,11 +1439,36 @@ static int dvb_net_ioctl(struct inode *inode, struct file *file, | |||
1435 | return dvb_usercopy(inode, file, cmd, arg, dvb_net_do_ioctl); | 1439 | return dvb_usercopy(inode, file, cmd, arg, dvb_net_do_ioctl); |
1436 | } | 1440 | } |
1437 | 1441 | ||
1442 | static int dvb_net_close(struct inode *inode, struct file *file) | ||
1443 | { | ||
1444 | struct dvb_device *dvbdev = file->private_data; | ||
1445 | struct dvb_net *dvbnet = dvbdev->priv; | ||
1446 | |||
1447 | if (!dvbdev) | ||
1448 | return -ENODEV; | ||
1449 | |||
1450 | if ((file->f_flags & O_ACCMODE) == O_RDONLY) { | ||
1451 | dvbdev->readers++; | ||
1452 | } else { | ||
1453 | dvbdev->writers++; | ||
1454 | } | ||
1455 | |||
1456 | dvbdev->users++; | ||
1457 | |||
1458 | if(dvbdev->users == 1 && dvbnet->exit==1) { | ||
1459 | fops_put(file->f_op); | ||
1460 | file->f_op = NULL; | ||
1461 | wake_up(&dvbdev->wait_queue); | ||
1462 | } | ||
1463 | return 0; | ||
1464 | } | ||
1465 | |||
1466 | |||
1438 | static struct file_operations dvb_net_fops = { | 1467 | static struct file_operations dvb_net_fops = { |
1439 | .owner = THIS_MODULE, | 1468 | .owner = THIS_MODULE, |
1440 | .ioctl = dvb_net_ioctl, | 1469 | .ioctl = dvb_net_ioctl, |
1441 | .open = dvb_generic_open, | 1470 | .open = dvb_generic_open, |
1442 | .release = dvb_generic_release, | 1471 | .release = dvb_net_close, |
1443 | }; | 1472 | }; |
1444 | 1473 | ||
1445 | static struct dvb_device dvbdev_net = { | 1474 | static struct dvb_device dvbdev_net = { |
@@ -1454,6 +1483,11 @@ void dvb_net_release (struct dvb_net *dvbnet) | |||
1454 | { | 1483 | { |
1455 | int i; | 1484 | int i; |
1456 | 1485 | ||
1486 | dvbnet->exit = 1; | ||
1487 | if (dvbnet->dvbdev->users < 1) | ||
1488 | wait_event(dvbnet->dvbdev->wait_queue, | ||
1489 | dvbnet->dvbdev->users==1); | ||
1490 | |||
1457 | dvb_unregister_device(dvbnet->dvbdev); | 1491 | dvb_unregister_device(dvbnet->dvbdev); |
1458 | 1492 | ||
1459 | for (i=0; i<DVB_NET_DEVICES_MAX; i++) { | 1493 | for (i=0; i<DVB_NET_DEVICES_MAX; i++) { |
diff --git a/drivers/media/dvb/dvb-core/dvb_net.h b/drivers/media/dvb/dvb-core/dvb_net.h index f14e4ca38570..3a3126cae03b 100644 --- a/drivers/media/dvb/dvb-core/dvb_net.h +++ b/drivers/media/dvb/dvb-core/dvb_net.h | |||
@@ -36,6 +36,7 @@ struct dvb_net { | |||
36 | struct dvb_device *dvbdev; | 36 | struct dvb_device *dvbdev; |
37 | struct net_device *device[DVB_NET_DEVICES_MAX]; | 37 | struct net_device *device[DVB_NET_DEVICES_MAX]; |
38 | int state[DVB_NET_DEVICES_MAX]; | 38 | int state[DVB_NET_DEVICES_MAX]; |
39 | unsigned int exit:1; | ||
39 | struct dmx_demux *demux; | 40 | struct dmx_demux *demux; |
40 | }; | 41 | }; |
41 | 42 | ||
diff --git a/drivers/media/dvb/dvb-core/dvbdev.c b/drivers/media/dvb/dvb-core/dvbdev.c index 14a372a0fe8b..e23d8a0ea1d3 100644 --- a/drivers/media/dvb/dvb-core/dvbdev.c +++ b/drivers/media/dvb/dvb-core/dvbdev.c | |||
@@ -233,6 +233,7 @@ int dvb_register_device(struct dvb_adapter *adap, struct dvb_device **pdvbdev, | |||
233 | dvbdev->adapter = adap; | 233 | dvbdev->adapter = adap; |
234 | dvbdev->priv = priv; | 234 | dvbdev->priv = priv; |
235 | dvbdev->fops = dvbdevfops; | 235 | dvbdev->fops = dvbdevfops; |
236 | init_waitqueue_head (&dvbdev->wait_queue); | ||
236 | 237 | ||
237 | memcpy(dvbdev->fops, template->fops, sizeof(struct file_operations)); | 238 | memcpy(dvbdev->fops, template->fops, sizeof(struct file_operations)); |
238 | dvbdev->fops->owner = adap->module; | 239 | dvbdev->fops->owner = adap->module; |
diff --git a/drivers/media/dvb/dvb-core/dvbdev.h b/drivers/media/dvb/dvb-core/dvbdev.h index 620e7887b3d3..6dff10ebf470 100644 --- a/drivers/media/dvb/dvb-core/dvbdev.h +++ b/drivers/media/dvb/dvb-core/dvbdev.h | |||
@@ -69,6 +69,7 @@ struct dvb_device { | |||
69 | int writers; | 69 | int writers; |
70 | int users; | 70 | int users; |
71 | 71 | ||
72 | wait_queue_head_t wait_queue; | ||
72 | /* don't really need those !? -- FIXME: use video_usercopy */ | 73 | /* don't really need those !? -- FIXME: use video_usercopy */ |
73 | int (*kernel_ioctl)(struct inode *inode, struct file *file, | 74 | int (*kernel_ioctl)(struct inode *inode, struct file *file, |
74 | unsigned int cmd, void *arg); | 75 | unsigned int cmd, void *arg); |
diff --git a/drivers/media/dvb/dvb-usb/Kconfig b/drivers/media/dvb/dvb-usb/Kconfig index 80f67a51b908..54488737a08f 100644 --- a/drivers/media/dvb/dvb-usb/Kconfig +++ b/drivers/media/dvb/dvb-usb/Kconfig | |||
@@ -33,6 +33,7 @@ config DVB_USB_A800 | |||
33 | config DVB_USB_DIBUSB_MB | 33 | config DVB_USB_DIBUSB_MB |
34 | tristate "DiBcom USB DVB-T devices (based on the DiB3000M-B) (see help for device list)" | 34 | tristate "DiBcom USB DVB-T devices (based on the DiB3000M-B) (see help for device list)" |
35 | depends on DVB_USB | 35 | depends on DVB_USB |
36 | select DVB_PLL | ||
36 | select DVB_DIB3000MB | 37 | select DVB_DIB3000MB |
37 | select DVB_TUNER_MT2060 if !DVB_FE_CUSTOMISE | 38 | select DVB_TUNER_MT2060 if !DVB_FE_CUSTOMISE |
38 | help | 39 | help |
@@ -88,6 +89,7 @@ config DVB_USB_DIB0700 | |||
88 | config DVB_USB_UMT_010 | 89 | config DVB_USB_UMT_010 |
89 | tristate "HanfTek UMT-010 DVB-T USB2.0 support" | 90 | tristate "HanfTek UMT-010 DVB-T USB2.0 support" |
90 | depends on DVB_USB | 91 | depends on DVB_USB |
92 | select DVB_PLL | ||
91 | select DVB_DIB3000MC | 93 | select DVB_DIB3000MC |
92 | select DVB_TUNER_MT2060 if !DVB_FE_CUSTOMISE | 94 | select DVB_TUNER_MT2060 if !DVB_FE_CUSTOMISE |
93 | help | 95 | help |
@@ -96,9 +98,9 @@ config DVB_USB_UMT_010 | |||
96 | config DVB_USB_CXUSB | 98 | config DVB_USB_CXUSB |
97 | tristate "Conexant USB2.0 hybrid reference design support" | 99 | tristate "Conexant USB2.0 hybrid reference design support" |
98 | depends on DVB_USB | 100 | depends on DVB_USB |
101 | select DVB_PLL | ||
99 | select DVB_CX22702 if !DVB_FE_CUSTOMISE | 102 | select DVB_CX22702 if !DVB_FE_CUSTOMISE |
100 | select DVB_LGDT330X if !DVB_FE_CUSTOMISE | 103 | select DVB_LGDT330X if !DVB_FE_CUSTOMISE |
101 | select DVB_TUNER_LGH06XF if !DVB_FE_CUSTOMISE | ||
102 | select DVB_MT352 if !DVB_FE_CUSTOMISE | 104 | select DVB_MT352 if !DVB_FE_CUSTOMISE |
103 | select DVB_ZL10353 if !DVB_FE_CUSTOMISE | 105 | select DVB_ZL10353 if !DVB_FE_CUSTOMISE |
104 | help | 106 | help |
@@ -140,6 +142,7 @@ config DVB_USB_AU6610 | |||
140 | config DVB_USB_DIGITV | 142 | config DVB_USB_DIGITV |
141 | tristate "Nebula Electronics uDigiTV DVB-T USB2.0 support" | 143 | tristate "Nebula Electronics uDigiTV DVB-T USB2.0 support" |
142 | depends on DVB_USB | 144 | depends on DVB_USB |
145 | select DVB_PLL | ||
143 | select DVB_NXT6000 if !DVB_FE_CUSTOMISE | 146 | select DVB_NXT6000 if !DVB_FE_CUSTOMISE |
144 | select DVB_MT352 if !DVB_FE_CUSTOMISE | 147 | select DVB_MT352 if !DVB_FE_CUSTOMISE |
145 | help | 148 | help |
@@ -208,3 +211,10 @@ config DVB_USB_DTT200U | |||
208 | The receivers are also known as DTT200U (Yakumo) and UB300 (Yuan). | 211 | The receivers are also known as DTT200U (Yakumo) and UB300 (Yuan). |
209 | 212 | ||
210 | The WT-220U and its clones are pen-sized. | 213 | The WT-220U and its clones are pen-sized. |
214 | |||
215 | config DVB_USB_OPERA1 | ||
216 | tristate "Opera1 DVB-S USB2.0 receiver" | ||
217 | depends on DVB_USB | ||
218 | select DVB_STV0299 if !DVB_FE_CUSTOMISE | ||
219 | help | ||
220 | Say Y here to support the Opera DVB-S USB2.0 receiver. | ||
diff --git a/drivers/media/dvb/dvb-usb/Makefile b/drivers/media/dvb/dvb-usb/Makefile index 40f28f559b54..976f840cc904 100644 --- a/drivers/media/dvb/dvb-usb/Makefile +++ b/drivers/media/dvb/dvb-usb/Makefile | |||
@@ -51,4 +51,8 @@ obj-$(CONFIG_DVB_USB_TTUSB2) += dvb-usb-ttusb2.o | |||
51 | dvb-usb-dib0700-objs = dib0700_core.o dib0700_devices.o | 51 | dvb-usb-dib0700-objs = dib0700_core.o dib0700_devices.o |
52 | obj-$(CONFIG_DVB_USB_DIB0700) += dvb-usb-dib0700.o | 52 | obj-$(CONFIG_DVB_USB_DIB0700) += dvb-usb-dib0700.o |
53 | 53 | ||
54 | dvb-usb-opera-objs = opera1.o | ||
55 | obj-$(CONFIG_DVB_USB_OPERA1) += dvb-usb-opera.o | ||
56 | |||
57 | |||
54 | EXTRA_CFLAGS = -Idrivers/media/dvb/dvb-core/ -Idrivers/media/dvb/frontends/ | 58 | EXTRA_CFLAGS = -Idrivers/media/dvb/dvb-core/ -Idrivers/media/dvb/frontends/ |
diff --git a/drivers/media/dvb/dvb-usb/au6610.c b/drivers/media/dvb/dvb-usb/au6610.c index 0dc66a8d2baf..18e0b16fb2a9 100644 --- a/drivers/media/dvb/dvb-usb/au6610.c +++ b/drivers/media/dvb/dvb-usb/au6610.c | |||
@@ -40,7 +40,7 @@ static int au6610_usb_msg(struct dvb_usb_device *d, u8 operation, u8 addr, | |||
40 | } | 40 | } |
41 | 41 | ||
42 | ret = usb_control_msg(d->udev, usb_rcvctrlpipe(d->udev, 0), operation, | 42 | ret = usb_control_msg(d->udev, usb_rcvctrlpipe(d->udev, 0), operation, |
43 | USB_TYPE_VENDOR|USB_DIR_IN, addr, index, usb_buf, | 43 | USB_TYPE_VENDOR|USB_DIR_IN, addr << 1, index, usb_buf, |
44 | sizeof(usb_buf), AU6610_USB_TIMEOUT); | 44 | sizeof(usb_buf), AU6610_USB_TIMEOUT); |
45 | 45 | ||
46 | if (ret < 0) | 46 | if (ret < 0) |
@@ -124,7 +124,7 @@ static int au6610_identify_state(struct usb_device *udev, | |||
124 | } | 124 | } |
125 | 125 | ||
126 | static struct zl10353_config au6610_zl10353_config = { | 126 | static struct zl10353_config au6610_zl10353_config = { |
127 | .demod_address = 0x1e, | 127 | .demod_address = 0x0f, |
128 | .no_tuner = 1, | 128 | .no_tuner = 1, |
129 | .parallel_ts = 1, | 129 | .parallel_ts = 1, |
130 | }; | 130 | }; |
@@ -140,7 +140,7 @@ static int au6610_zl10353_frontend_attach(struct dvb_usb_adapter *adap) | |||
140 | } | 140 | } |
141 | 141 | ||
142 | static struct qt1010_config au6610_qt1010_config = { | 142 | static struct qt1010_config au6610_qt1010_config = { |
143 | .i2c_address = 0xc4 | 143 | .i2c_address = 0x62 |
144 | }; | 144 | }; |
145 | 145 | ||
146 | static int au6610_qt1010_tuner_attach(struct dvb_usb_adapter *adap) | 146 | static int au6610_qt1010_tuner_attach(struct dvb_usb_adapter *adap) |
diff --git a/drivers/media/dvb/dvb-usb/cxusb.c b/drivers/media/dvb/dvb-usb/cxusb.c index 127a94b9a1b5..bac2ae3b4a1f 100644 --- a/drivers/media/dvb/dvb-usb/cxusb.c +++ b/drivers/media/dvb/dvb-usb/cxusb.c | |||
@@ -27,7 +27,6 @@ | |||
27 | 27 | ||
28 | #include "cx22702.h" | 28 | #include "cx22702.h" |
29 | #include "lgdt330x.h" | 29 | #include "lgdt330x.h" |
30 | #include "lgh06xf.h" | ||
31 | #include "mt352.h" | 30 | #include "mt352.h" |
32 | #include "mt352_priv.h" | 31 | #include "mt352_priv.h" |
33 | #include "zl10353.h" | 32 | #include "zl10353.h" |
@@ -388,7 +387,8 @@ static int cxusb_dtt7579_tuner_attach(struct dvb_usb_adapter *adap) | |||
388 | 387 | ||
389 | static int cxusb_lgh064f_tuner_attach(struct dvb_usb_adapter *adap) | 388 | static int cxusb_lgh064f_tuner_attach(struct dvb_usb_adapter *adap) |
390 | { | 389 | { |
391 | dvb_attach(lgh06xf_attach, adap->fe, &adap->dev->i2c_adap); | 390 | dvb_attach(dvb_pll_attach, adap->fe, 0x61, &adap->dev->i2c_adap, |
391 | &dvb_pll_lg_tdvs_h06xf); | ||
392 | return 0; | 392 | return 0; |
393 | } | 393 | } |
394 | 394 | ||
diff --git a/drivers/media/dvb/dvb-usb/dib0700_core.c b/drivers/media/dvb/dvb-usb/dib0700_core.c index 6a4d150784a6..dddf164f269a 100644 --- a/drivers/media/dvb/dvb-usb/dib0700_core.c +++ b/drivers/media/dvb/dvb-usb/dib0700_core.c | |||
@@ -56,10 +56,6 @@ static int dib0700_ctrl_rd(struct dvb_usb_device *d, u8 *tx, u8 txlen, u8 *rx, u | |||
56 | if (txlen > 3) | 56 | if (txlen > 3) |
57 | index |= tx[3]; | 57 | index |= tx[3]; |
58 | 58 | ||
59 | /* think about swapping here */ | ||
60 | value = le16_to_cpu(value); | ||
61 | index = le16_to_cpu(index); | ||
62 | |||
63 | status = usb_control_msg(d->udev, usb_rcvctrlpipe(d->udev,0), tx[0], | 59 | status = usb_control_msg(d->udev, usb_rcvctrlpipe(d->udev,0), tx[0], |
64 | USB_TYPE_VENDOR | USB_DIR_IN, value, index, rx, rxlen, | 60 | USB_TYPE_VENDOR | USB_DIR_IN, value, index, rx, rxlen, |
65 | USB_CTRL_GET_TIMEOUT); | 61 | USB_CTRL_GET_TIMEOUT); |
diff --git a/drivers/media/dvb/dvb-usb/dvb-usb-ids.h b/drivers/media/dvb/dvb-usb/dvb-usb-ids.h index 148386aba275..97715f7514d6 100644 --- a/drivers/media/dvb/dvb-usb/dvb-usb-ids.h +++ b/drivers/media/dvb/dvb-usb/dvb-usb-ids.h | |||
@@ -13,6 +13,7 @@ | |||
13 | #define USB_VID_ADSTECH 0x06e1 | 13 | #define USB_VID_ADSTECH 0x06e1 |
14 | #define USB_VID_ALCOR_MICRO 0x058f | 14 | #define USB_VID_ALCOR_MICRO 0x058f |
15 | #define USB_VID_ANCHOR 0x0547 | 15 | #define USB_VID_ANCHOR 0x0547 |
16 | #define USB_VID_ANUBIS_ELECTRONIC 0x10fd | ||
16 | #define USB_VID_AVERMEDIA 0x07ca | 17 | #define USB_VID_AVERMEDIA 0x07ca |
17 | #define USB_VID_COMPRO 0x185b | 18 | #define USB_VID_COMPRO 0x185b |
18 | #define USB_VID_COMPRO_UNK 0x145f | 19 | #define USB_VID_COMPRO_UNK 0x145f |
@@ -31,6 +32,7 @@ | |||
31 | #define USB_VID_LITEON 0x04ca | 32 | #define USB_VID_LITEON 0x04ca |
32 | #define USB_VID_MEDION 0x1660 | 33 | #define USB_VID_MEDION 0x1660 |
33 | #define USB_VID_MSI 0x0db0 | 34 | #define USB_VID_MSI 0x0db0 |
35 | #define USB_VID_OPERA1 0x695c | ||
34 | #define USB_VID_PINNACLE 0x2304 | 36 | #define USB_VID_PINNACLE 0x2304 |
35 | #define USB_VID_VISIONPLUS 0x13d3 | 37 | #define USB_VID_VISIONPLUS 0x13d3 |
36 | #define USB_VID_TWINHAN 0x1822 | 38 | #define USB_VID_TWINHAN 0x1822 |
@@ -127,6 +129,7 @@ | |||
127 | #define USB_PID_KYE_DVB_T_WARM 0x701f | 129 | #define USB_PID_KYE_DVB_T_WARM 0x701f |
128 | #define USB_PID_PCTV_200E 0x020e | 130 | #define USB_PID_PCTV_200E 0x020e |
129 | #define USB_PID_PCTV_400E 0x020f | 131 | #define USB_PID_PCTV_400E 0x020f |
132 | #define USB_PID_PCTV_450E 0x0222 | ||
130 | #define USB_PID_LITEON_DVB_T_COLD 0xf000 | 133 | #define USB_PID_LITEON_DVB_T_COLD 0xf000 |
131 | #define USB_PID_LITEON_DVB_T_WARM 0xf001 | 134 | #define USB_PID_LITEON_DVB_T_WARM 0xf001 |
132 | #define USB_PID_DIGIVOX_MINI_SL_COLD 0xe360 | 135 | #define USB_PID_DIGIVOX_MINI_SL_COLD 0xe360 |
@@ -139,6 +142,9 @@ | |||
139 | #define USB_PID_GENPIX_8PSK_COLD 0x0200 | 142 | #define USB_PID_GENPIX_8PSK_COLD 0x0200 |
140 | #define USB_PID_GENPIX_8PSK_WARM 0x0201 | 143 | #define USB_PID_GENPIX_8PSK_WARM 0x0201 |
141 | #define USB_PID_SIGMATEK_DVB_110 0x6610 | 144 | #define USB_PID_SIGMATEK_DVB_110 0x6610 |
145 | #define USB_PID_MSI_DIGI_VOX_MINI_II 0x1513 | ||
146 | #define USB_PID_OPERA1_COLD 0x2830 | ||
147 | #define USB_PID_OPERA1_WARM 0x3829 | ||
142 | 148 | ||
143 | 149 | ||
144 | #endif | 150 | #endif |
diff --git a/drivers/media/dvb/dvb-usb/dvb-usb-remote.c b/drivers/media/dvb/dvb-usb/dvb-usb-remote.c index 9511a31c8f50..68ed3a788083 100644 --- a/drivers/media/dvb/dvb-usb/dvb-usb-remote.c +++ b/drivers/media/dvb/dvb-usb/dvb-usb-remote.c | |||
@@ -107,8 +107,6 @@ int dvb_usb_remote_init(struct dvb_usb_device *d) | |||
107 | return -ENOMEM; | 107 | return -ENOMEM; |
108 | 108 | ||
109 | input_dev->evbit[0] = BIT(EV_KEY); | 109 | input_dev->evbit[0] = BIT(EV_KEY); |
110 | input_dev->keycodesize = sizeof(unsigned char); | ||
111 | input_dev->keycodemax = KEY_MAX; | ||
112 | input_dev->name = "IR-receiver inside an USB DVB receiver"; | 110 | input_dev->name = "IR-receiver inside an USB DVB receiver"; |
113 | input_dev->phys = d->rc_phys; | 111 | input_dev->phys = d->rc_phys; |
114 | usb_to_input_id(d->udev, &input_dev->id); | 112 | usb_to_input_id(d->udev, &input_dev->id); |
diff --git a/drivers/media/dvb/dvb-usb/gl861.c b/drivers/media/dvb/dvb-usb/gl861.c index c9f38a5e70d3..e0587e663591 100644 --- a/drivers/media/dvb/dvb-usb/gl861.c +++ b/drivers/media/dvb/dvb-usb/gl861.c | |||
@@ -12,7 +12,7 @@ | |||
12 | #include "qt1010.h" | 12 | #include "qt1010.h" |
13 | 13 | ||
14 | /* debug */ | 14 | /* debug */ |
15 | int dvb_usb_gl861_debug; | 15 | static int dvb_usb_gl861_debug; |
16 | module_param_named(debug,dvb_usb_gl861_debug, int, 0644); | 16 | module_param_named(debug,dvb_usb_gl861_debug, int, 0644); |
17 | MODULE_PARM_DESC(debug, "set debugging level (1=rc (or-able))." DVB_USB_DEBUG_STATUS); | 17 | MODULE_PARM_DESC(debug, "set debugging level (1=rc (or-able))." DVB_USB_DEBUG_STATUS); |
18 | 18 | ||
@@ -20,7 +20,7 @@ static int gl861_i2c_msg(struct dvb_usb_device *d, u8 addr, | |||
20 | u8 *wbuf, u16 wlen, u8 *rbuf, u16 rlen) | 20 | u8 *wbuf, u16 wlen, u8 *rbuf, u16 rlen) |
21 | { | 21 | { |
22 | u16 index; | 22 | u16 index; |
23 | u16 value = addr << 8; | 23 | u16 value = addr << (8 + 1); |
24 | int wo = (rbuf == NULL || rlen == 0); /* write-only */ | 24 | int wo = (rbuf == NULL || rlen == 0); /* write-only */ |
25 | u8 req, type; | 25 | u8 req, type; |
26 | 26 | ||
@@ -101,7 +101,7 @@ static int gl861_identify_state(struct usb_device *udev, | |||
101 | } | 101 | } |
102 | 102 | ||
103 | static struct zl10353_config gl861_zl10353_config = { | 103 | static struct zl10353_config gl861_zl10353_config = { |
104 | .demod_address = 0x1e, | 104 | .demod_address = 0x0f, |
105 | .no_tuner = 1, | 105 | .no_tuner = 1, |
106 | .parallel_ts = 1, | 106 | .parallel_ts = 1, |
107 | }; | 107 | }; |
@@ -117,7 +117,7 @@ static int gl861_frontend_attach(struct dvb_usb_adapter *adap) | |||
117 | } | 117 | } |
118 | 118 | ||
119 | static struct qt1010_config gl861_qt1010_config = { | 119 | static struct qt1010_config gl861_qt1010_config = { |
120 | .i2c_address = 0xc4 | 120 | .i2c_address = 0x62 |
121 | }; | 121 | }; |
122 | 122 | ||
123 | static int gl861_tuner_attach(struct dvb_usb_adapter *adap) | 123 | static int gl861_tuner_attach(struct dvb_usb_adapter *adap) |
diff --git a/drivers/media/dvb/dvb-usb/m920x.c b/drivers/media/dvb/dvb-usb/m920x.c index d48b24d9abf4..45d7bc214c18 100644 --- a/drivers/media/dvb/dvb-usb/m920x.c +++ b/drivers/media/dvb/dvb-usb/m920x.c | |||
@@ -14,6 +14,8 @@ | |||
14 | #include "mt352.h" | 14 | #include "mt352.h" |
15 | #include "mt352_priv.h" | 15 | #include "mt352_priv.h" |
16 | #include "qt1010.h" | 16 | #include "qt1010.h" |
17 | #include "tda1004x.h" | ||
18 | #include "tda827x.h" | ||
17 | 19 | ||
18 | /* debug */ | 20 | /* debug */ |
19 | static int dvb_usb_m920x_debug; | 21 | static int dvb_usb_m920x_debug; |
@@ -47,11 +49,15 @@ static inline int m9206_read(struct usb_device *udev, u8 request, u16 value,\ | |||
47 | ret = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0), | 49 | ret = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0), |
48 | request, USB_TYPE_VENDOR | USB_DIR_IN, | 50 | request, USB_TYPE_VENDOR | USB_DIR_IN, |
49 | value, index, data, size, 2000); | 51 | value, index, data, size, 2000); |
50 | if (ret < 0) | 52 | if (ret < 0) { |
53 | printk(KERN_INFO "m920x_read = error: %d\n", ret); | ||
51 | return ret; | 54 | return ret; |
55 | } | ||
52 | 56 | ||
53 | if (ret != size) | 57 | if (ret != size) { |
58 | deb_rc("m920x_read = no data\n"); | ||
54 | return -EIO; | 59 | return -EIO; |
60 | } | ||
55 | 61 | ||
56 | return 0; | 62 | return 0; |
57 | } | 63 | } |
@@ -64,19 +70,22 @@ static inline int m9206_write(struct usb_device *udev, u8 request, | |||
64 | ret = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), | 70 | ret = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), |
65 | request, USB_TYPE_VENDOR | USB_DIR_OUT, | 71 | request, USB_TYPE_VENDOR | USB_DIR_OUT, |
66 | value, index, NULL, 0, 2000); | 72 | value, index, NULL, 0, 2000); |
73 | |||
67 | return ret; | 74 | return ret; |
68 | } | 75 | } |
69 | 76 | ||
70 | static int m9206_rc_init(struct usb_device *udev) | 77 | static int m9206_init(struct dvb_usb_device *d) |
71 | { | 78 | { |
72 | int ret = 0; | 79 | int ret = 0; |
73 | 80 | ||
74 | /* Remote controller init. */ | 81 | /* Remote controller init. */ |
75 | if ((ret = m9206_write(udev, M9206_CORE, 0xa8, M9206_RC_INIT2)) != 0) | 82 | if (d->props.rc_query) { |
76 | return ret; | 83 | if ((ret = m9206_write(d->udev, M9206_CORE, 0xa8, M9206_RC_INIT2)) != 0) |
84 | return ret; | ||
77 | 85 | ||
78 | if ((ret = m9206_write(udev, M9206_CORE, 0x51, M9206_RC_INIT1)) != 0) | 86 | if ((ret = m9206_write(d->udev, M9206_CORE, 0x51, M9206_RC_INIT1)) != 0) |
79 | return ret; | 87 | return ret; |
88 | } | ||
80 | 89 | ||
81 | return ret; | 90 | return ret; |
82 | } | 91 | } |
@@ -87,16 +96,15 @@ static int m9206_rc_query(struct dvb_usb_device *d, u32 *event, int *state) | |||
87 | int i, ret = 0; | 96 | int i, ret = 0; |
88 | u8 rc_state[2]; | 97 | u8 rc_state[2]; |
89 | 98 | ||
90 | |||
91 | if ((ret = m9206_read(d->udev, M9206_CORE, 0x0, M9206_RC_STATE, rc_state, 1)) != 0) | 99 | if ((ret = m9206_read(d->udev, M9206_CORE, 0x0, M9206_RC_STATE, rc_state, 1)) != 0) |
92 | goto unlock; | 100 | goto unlock; |
93 | 101 | ||
94 | if ((ret = m9206_read(d->udev, M9206_CORE, 0x0, M9206_RC_KEY, rc_state + 1, 1)) != 0) | 102 | if ((ret = m9206_read(d->udev, M9206_CORE, 0x0, M9206_RC_KEY, rc_state + 1, 1)) != 0) |
95 | goto unlock; | 103 | goto unlock; |
96 | 104 | ||
97 | for (i = 0; i < ARRAY_SIZE(megasky_rc_keys); i++) | 105 | for (i = 0; i < d->props.rc_key_map_size; i++) |
98 | if (megasky_rc_keys[i].data == rc_state[1]) { | 106 | if (d->props.rc_key_map[i].data == rc_state[1]) { |
99 | *event = megasky_rc_keys[i].event; | 107 | *event = d->props.rc_key_map[i].event; |
100 | 108 | ||
101 | switch(rc_state[0]) { | 109 | switch(rc_state[0]) { |
102 | case 0x80: | 110 | case 0x80: |
@@ -137,53 +145,51 @@ static int m9206_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msg[], | |||
137 | int num) | 145 | int num) |
138 | { | 146 | { |
139 | struct dvb_usb_device *d = i2c_get_adapdata(adap); | 147 | struct dvb_usb_device *d = i2c_get_adapdata(adap); |
140 | struct m9206_state *m = d->priv; | 148 | int i, j; |
141 | int i; | ||
142 | int ret = 0; | 149 | int ret = 0; |
143 | 150 | ||
151 | if (!num) | ||
152 | return -EINVAL; | ||
153 | |||
144 | if (mutex_lock_interruptible(&d->i2c_mutex) < 0) | 154 | if (mutex_lock_interruptible(&d->i2c_mutex) < 0) |
145 | return -EAGAIN; | 155 | return -EAGAIN; |
146 | 156 | ||
147 | if (num > 2) | ||
148 | return -EINVAL; | ||
149 | |||
150 | for (i = 0; i < num; i++) { | 157 | for (i = 0; i < num; i++) { |
151 | if ((ret = m9206_write(d->udev, M9206_I2C, msg[i].addr, 0x80)) != 0) | 158 | if (msg[i].flags & (I2C_M_NO_RD_ACK|I2C_M_IGNORE_NAK|I2C_M_TEN) || |
152 | goto unlock; | 159 | msg[i].len == 0) { |
153 | 160 | /* For a 0 byte message, I think sending the address to index 0x80|0x40 | |
154 | if ((ret = m9206_write(d->udev, M9206_I2C, msg[i].buf[0], 0x0)) != 0) | 161 | * would be the correct thing to do. However, zero byte messages are |
162 | * only used for probing, and since we don't know how to get the slave's | ||
163 | * ack, we can't probe. */ | ||
164 | ret = -ENOTSUPP; | ||
155 | goto unlock; | 165 | goto unlock; |
156 | 166 | } | |
157 | if (i + 1 < num && msg[i + 1].flags & I2C_M_RD) { | 167 | /* Send START & address/RW bit */ |
158 | int i2c_i; | 168 | if (!(msg[i].flags & I2C_M_NOSTART)) { |
159 | 169 | if ((ret = m9206_write(d->udev, M9206_I2C, (msg[i].addr<<1)|(msg[i].flags&I2C_M_RD?0x01:0), 0x80)) != 0) | |
160 | for (i2c_i = 0; i2c_i < M9206_I2C_MAX; i2c_i++) | ||
161 | if (msg[i].addr == m->i2c_r[i2c_i].addr) | ||
162 | break; | ||
163 | |||
164 | if (i2c_i >= M9206_I2C_MAX) { | ||
165 | deb_rc("No magic for i2c addr!\n"); | ||
166 | ret = -EINVAL; | ||
167 | goto unlock; | 170 | goto unlock; |
171 | /* Should check for ack here, if we knew how. */ | ||
172 | } | ||
173 | if (msg[i].flags & I2C_M_RD) { | ||
174 | for (j = 0; j < msg[i].len; j++) { | ||
175 | /* Last byte of transaction? Send STOP, otherwise send ACK. */ | ||
176 | int stop = (i+1 == num && j+1 == msg[i].len)?0x40:0x01; | ||
177 | if ((ret = m9206_read(d->udev, M9206_I2C, 0x0, 0x20|stop, &msg[i].buf[j], 1)) != 0) | ||
178 | goto unlock; | ||
168 | } | 179 | } |
169 | |||
170 | if ((ret = m9206_write(d->udev, M9206_I2C, m->i2c_r[i2c_i].magic, 0x80)) != 0) | ||
171 | goto unlock; | ||
172 | |||
173 | if ((ret = m9206_read(d->udev, M9206_I2C, 0x0, 0x60, msg[i + 1].buf, msg[i + 1].len)) != 0) | ||
174 | goto unlock; | ||
175 | |||
176 | i++; | ||
177 | } else { | 180 | } else { |
178 | if (msg[i].len != 2) | 181 | for (j = 0; j < msg[i].len; j++) { |
179 | return -EINVAL; | 182 | /* Last byte of transaction? Then send STOP. */ |
180 | 183 | int stop = (i+1 == num && j+1 == msg[i].len)?0x40:0x00; | |
181 | if ((ret = m9206_write(d->udev, M9206_I2C, msg[i].buf[1], 0x40)) != 0) | 184 | if ((ret = m9206_write(d->udev, M9206_I2C, msg[i].buf[j], stop)) != 0) |
182 | goto unlock; | 185 | goto unlock; |
186 | /* Should check for ack here too. */ | ||
187 | } | ||
183 | } | 188 | } |
184 | } | 189 | } |
185 | ret = i; | 190 | ret = num; |
186 | unlock: | 191 | |
192 | unlock: | ||
187 | mutex_unlock(&d->i2c_mutex); | 193 | mutex_unlock(&d->i2c_mutex); |
188 | 194 | ||
189 | return ret; | 195 | return ret; |
@@ -324,6 +330,7 @@ static int m9206_firmware_download(struct usb_device *udev, | |||
324 | i += size; | 330 | i += size; |
325 | } | 331 | } |
326 | if (i != fw->size) { | 332 | if (i != fw->size) { |
333 | deb_rc("bad firmware file!\n"); | ||
327 | ret = -EINVAL; | 334 | ret = -EINVAL; |
328 | goto done; | 335 | goto done; |
329 | } | 336 | } |
@@ -342,10 +349,10 @@ static int m9206_firmware_download(struct usb_device *udev, | |||
342 | } | 349 | } |
343 | 350 | ||
344 | /* Callbacks for DVB USB */ | 351 | /* Callbacks for DVB USB */ |
345 | static int megasky_identify_state(struct usb_device *udev, | 352 | static int m920x_identify_state(struct usb_device *udev, |
346 | struct dvb_usb_device_properties *props, | 353 | struct dvb_usb_device_properties *props, |
347 | struct dvb_usb_device_description **desc, | 354 | struct dvb_usb_device_description **desc, |
348 | int *cold) | 355 | int *cold) |
349 | { | 356 | { |
350 | struct usb_host_interface *alt; | 357 | struct usb_host_interface *alt; |
351 | 358 | ||
@@ -381,20 +388,15 @@ static int megasky_mt352_demod_init(struct dvb_frontend *fe) | |||
381 | } | 388 | } |
382 | 389 | ||
383 | static struct mt352_config megasky_mt352_config = { | 390 | static struct mt352_config megasky_mt352_config = { |
384 | .demod_address = 0x1e, | 391 | .demod_address = 0x0f, |
385 | .no_tuner = 1, | 392 | .no_tuner = 1, |
386 | .demod_init = megasky_mt352_demod_init, | 393 | .demod_init = megasky_mt352_demod_init, |
387 | }; | 394 | }; |
388 | 395 | ||
389 | static int megasky_mt352_frontend_attach(struct dvb_usb_adapter *adap) | 396 | static int megasky_mt352_frontend_attach(struct dvb_usb_adapter *adap) |
390 | { | 397 | { |
391 | struct m9206_state *m = adap->dev->priv; | ||
392 | |||
393 | deb_rc("megasky_frontend_attach!\n"); | 398 | deb_rc("megasky_frontend_attach!\n"); |
394 | 399 | ||
395 | m->i2c_r[M9206_I2C_DEMOD].addr = megasky_mt352_config.demod_address; | ||
396 | m->i2c_r[M9206_I2C_DEMOD].magic = 0x1f; | ||
397 | |||
398 | if ((adap->fe = dvb_attach(mt352_attach, &megasky_mt352_config, &adap->dev->i2c_adap)) == NULL) | 400 | if ((adap->fe = dvb_attach(mt352_attach, &megasky_mt352_config, &adap->dev->i2c_adap)) == NULL) |
399 | return -EIO; | 401 | return -EIO; |
400 | 402 | ||
@@ -402,16 +404,11 @@ static int megasky_mt352_frontend_attach(struct dvb_usb_adapter *adap) | |||
402 | } | 404 | } |
403 | 405 | ||
404 | static struct qt1010_config megasky_qt1010_config = { | 406 | static struct qt1010_config megasky_qt1010_config = { |
405 | .i2c_address = 0xc4 | 407 | .i2c_address = 0x62 |
406 | }; | 408 | }; |
407 | 409 | ||
408 | static int megasky_qt1010_tuner_attach(struct dvb_usb_adapter *adap) | 410 | static int megasky_qt1010_tuner_attach(struct dvb_usb_adapter *adap) |
409 | { | 411 | { |
410 | struct m9206_state *m = adap->dev->priv; | ||
411 | |||
412 | m->i2c_r[M9206_I2C_TUNER].addr = megasky_qt1010_config.i2c_address; | ||
413 | m->i2c_r[M9206_I2C_TUNER].magic = 0xc5; | ||
414 | |||
415 | if (dvb_attach(qt1010_attach, adap->fe, &adap->dev->i2c_adap, | 412 | if (dvb_attach(qt1010_attach, adap->fe, &adap->dev->i2c_adap, |
416 | &megasky_qt1010_config) == NULL) | 413 | &megasky_qt1010_config) == NULL) |
417 | return -ENODEV; | 414 | return -ENODEV; |
@@ -419,8 +416,40 @@ static int megasky_qt1010_tuner_attach(struct dvb_usb_adapter *adap) | |||
419 | return 0; | 416 | return 0; |
420 | } | 417 | } |
421 | 418 | ||
419 | static struct tda1004x_config digivox_tda10046_config = { | ||
420 | .demod_address = 0x08, | ||
421 | .invert = 0, | ||
422 | .invert_oclk = 0, | ||
423 | .ts_mode = TDA10046_TS_SERIAL, | ||
424 | .xtal_freq = TDA10046_XTAL_16M, | ||
425 | .if_freq = TDA10046_FREQ_045, | ||
426 | .agc_config = TDA10046_AGC_TDA827X, | ||
427 | .gpio_config = TDA10046_GPTRI, | ||
428 | .request_firmware = NULL, | ||
429 | }; | ||
430 | |||
431 | static int digivox_tda10046_frontend_attach(struct dvb_usb_adapter *adap) | ||
432 | { | ||
433 | deb_rc("digivox_tda10046_frontend_attach!\n"); | ||
434 | |||
435 | if ((adap->fe = dvb_attach(tda10046_attach, &digivox_tda10046_config, | ||
436 | &adap->dev->i2c_adap)) == NULL) | ||
437 | return -EIO; | ||
438 | |||
439 | return 0; | ||
440 | } | ||
441 | |||
442 | static int digivox_tda8275_tuner_attach(struct dvb_usb_adapter *adap) | ||
443 | { | ||
444 | if (dvb_attach(tda827x_attach, adap->fe, 0x60, &adap->dev->i2c_adap, | ||
445 | NULL) == NULL) | ||
446 | return -ENODEV; | ||
447 | return 0; | ||
448 | } | ||
449 | |||
422 | /* DVB USB Driver stuff */ | 450 | /* DVB USB Driver stuff */ |
423 | static struct dvb_usb_device_properties megasky_properties; | 451 | static struct dvb_usb_device_properties megasky_properties; |
452 | static struct dvb_usb_device_properties digivox_mini_ii_properties; | ||
424 | 453 | ||
425 | static int m920x_probe(struct usb_interface *intf, | 454 | static int m920x_probe(struct usb_interface *intf, |
426 | const struct usb_device_id *id) | 455 | const struct usb_device_id *id) |
@@ -429,30 +458,36 @@ static int m920x_probe(struct usb_interface *intf, | |||
429 | struct usb_host_interface *alt; | 458 | struct usb_host_interface *alt; |
430 | int ret; | 459 | int ret; |
431 | 460 | ||
432 | if ((ret = dvb_usb_device_init(intf, &megasky_properties, THIS_MODULE, &d)) == 0) { | 461 | deb_rc("Probed!\n"); |
433 | deb_rc("probed!\n"); | ||
434 | 462 | ||
435 | alt = usb_altnum_to_altsetting(intf, 1); | 463 | if (((ret = dvb_usb_device_init(intf, &megasky_properties, THIS_MODULE, &d)) == 0) || |
436 | if (alt == NULL) { | 464 | ((ret = dvb_usb_device_init(intf, &digivox_mini_ii_properties, THIS_MODULE, &d)) == 0)) |
437 | deb_rc("not alt found!\n"); | 465 | goto found; |
438 | return -ENODEV; | ||
439 | } | ||
440 | 466 | ||
441 | ret = usb_set_interface(d->udev, alt->desc.bInterfaceNumber, | 467 | return ret; |
442 | alt->desc.bAlternateSetting); | ||
443 | if (ret < 0) | ||
444 | return ret; | ||
445 | |||
446 | deb_rc("Changed to alternate setting!\n"); | ||
447 | 468 | ||
448 | if ((ret = m9206_rc_init(d->udev)) != 0) | 469 | found: |
449 | return ret; | 470 | alt = usb_altnum_to_altsetting(intf, 1); |
471 | if (alt == NULL) { | ||
472 | deb_rc("No alt found!\n"); | ||
473 | return -ENODEV; | ||
450 | } | 474 | } |
475 | |||
476 | ret = usb_set_interface(d->udev, alt->desc.bInterfaceNumber, | ||
477 | alt->desc.bAlternateSetting); | ||
478 | if (ret < 0) | ||
479 | return ret; | ||
480 | |||
481 | if ((ret = m9206_init(d)) != 0) | ||
482 | return ret; | ||
483 | |||
451 | return ret; | 484 | return ret; |
452 | } | 485 | } |
453 | 486 | ||
454 | static struct usb_device_id m920x_table [] = { | 487 | static struct usb_device_id m920x_table [] = { |
455 | { USB_DEVICE(USB_VID_MSI, USB_PID_MSI_MEGASKY580) }, | 488 | { USB_DEVICE(USB_VID_MSI, USB_PID_MSI_MEGASKY580) }, |
489 | { USB_DEVICE(USB_VID_ANUBIS_ELECTRONIC, | ||
490 | USB_PID_MSI_DIGI_VOX_MINI_II) }, | ||
456 | { } /* Terminating entry */ | 491 | { } /* Terminating entry */ |
457 | }; | 492 | }; |
458 | MODULE_DEVICE_TABLE (usb, m920x_table); | 493 | MODULE_DEVICE_TABLE (usb, m920x_table); |
@@ -471,7 +506,7 @@ static struct dvb_usb_device_properties megasky_properties = { | |||
471 | 506 | ||
472 | .size_of_priv = sizeof(struct m9206_state), | 507 | .size_of_priv = sizeof(struct m9206_state), |
473 | 508 | ||
474 | .identify_state = megasky_identify_state, | 509 | .identify_state = m920x_identify_state, |
475 | .num_adapters = 1, | 510 | .num_adapters = 1, |
476 | .adapter = {{ | 511 | .adapter = {{ |
477 | .caps = DVB_USB_ADAP_HAS_PID_FILTER | | 512 | .caps = DVB_USB_ADAP_HAS_PID_FILTER | |
@@ -502,6 +537,50 @@ static struct dvb_usb_device_properties megasky_properties = { | |||
502 | { "MSI Mega Sky 580 DVB-T USB2.0", | 537 | { "MSI Mega Sky 580 DVB-T USB2.0", |
503 | { &m920x_table[0], NULL }, | 538 | { &m920x_table[0], NULL }, |
504 | { NULL }, | 539 | { NULL }, |
540 | } | ||
541 | } | ||
542 | }; | ||
543 | |||
544 | static struct dvb_usb_device_properties digivox_mini_ii_properties = { | ||
545 | .caps = DVB_USB_IS_AN_I2C_ADAPTER, | ||
546 | |||
547 | .usb_ctrl = DEVICE_SPECIFIC, | ||
548 | .firmware = "dvb-usb-digivox-02.fw", | ||
549 | .download_firmware = m9206_firmware_download, | ||
550 | |||
551 | .size_of_priv = sizeof(struct m9206_state), | ||
552 | |||
553 | .identify_state = m920x_identify_state, | ||
554 | .num_adapters = 1, | ||
555 | .adapter = {{ | ||
556 | .caps = DVB_USB_ADAP_HAS_PID_FILTER | | ||
557 | DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF, | ||
558 | |||
559 | .pid_filter_count = 8, | ||
560 | .pid_filter = m9206_pid_filter, | ||
561 | .pid_filter_ctrl = m9206_pid_filter_ctrl, | ||
562 | |||
563 | .frontend_attach = digivox_tda10046_frontend_attach, | ||
564 | .tuner_attach = digivox_tda8275_tuner_attach, | ||
565 | |||
566 | .stream = { | ||
567 | .type = USB_BULK, | ||
568 | .count = 8, | ||
569 | .endpoint = 0x81, | ||
570 | .u = { | ||
571 | .bulk = { | ||
572 | .buffersize = 0x4000, | ||
573 | } | ||
574 | } | ||
575 | }, | ||
576 | }}, | ||
577 | .i2c_algo = &m9206_i2c_algo, | ||
578 | |||
579 | .num_device_descs = 1, | ||
580 | .devices = { | ||
581 | { "MSI DIGI VOX mini II DVB-T USB2.0", | ||
582 | { &m920x_table[1], NULL }, | ||
583 | { NULL }, | ||
505 | }, | 584 | }, |
506 | } | 585 | } |
507 | }; | 586 | }; |
diff --git a/drivers/media/dvb/dvb-usb/m920x.h b/drivers/media/dvb/dvb-usb/m920x.h index c354196ffe5d..7dd3db65c80e 100644 --- a/drivers/media/dvb/dvb-usb/m920x.h +++ b/drivers/media/dvb/dvb-usb/m920x.h | |||
@@ -19,17 +19,49 @@ | |||
19 | 19 | ||
20 | #define M9206_MAX_FILTERS 8 | 20 | #define M9206_MAX_FILTERS 8 |
21 | 21 | ||
22 | #define M9206_I2C_TUNER 0 | 22 | /* |
23 | #define M9206_I2C_DEMOD 1 | 23 | sequences found in logs: |
24 | #define M9206_I2C_MAX 2 | 24 | [index value] |
25 | 0x80 write addr | ||
26 | (0x00 out byte)* | ||
27 | 0x40 out byte | ||
28 | |||
29 | 0x80 write addr | ||
30 | (0x00 out byte)* | ||
31 | 0x80 read addr | ||
32 | (0x21 in byte)* | ||
33 | 0x60 in byte | ||
34 | |||
35 | this sequence works: | ||
36 | 0x80 read addr | ||
37 | (0x21 in byte)* | ||
38 | 0x60 in byte | ||
39 | |||
40 | Guess at API of the I2C function: | ||
41 | I2C operation is done one byte at a time with USB control messages. The | ||
42 | index the messages is sent to is made up of a set of flags that control | ||
43 | the I2C bus state: | ||
44 | 0x80: Send START condition. After a START condition, one would normally | ||
45 | always send the 7-bit slave I2C address as the 7 MSB, followed by | ||
46 | the read/write bit as the LSB. | ||
47 | 0x40: Send STOP condition. This should be set on the last byte of an | ||
48 | I2C transaction. | ||
49 | 0x20: Read a byte from the slave. As opposed to writing a byte to the | ||
50 | slave. The slave will normally not produce any data unless you | ||
51 | set the R/W bit to 1 when sending the slave's address after the | ||
52 | START condition. | ||
53 | 0x01: Respond with ACK, as opposed to a NACK. For a multi-byte read, | ||
54 | the master should send an ACK, that is pull SDA low during the 9th | ||
55 | clock cycle, after every byte but the last. This flags only makes | ||
56 | sense when bit 0x20 is set, indicating a read. | ||
57 | |||
58 | What any other bits might mean, or how to get the slave's ACK/NACK | ||
59 | response to a write, is unknown. | ||
60 | */ | ||
25 | 61 | ||
26 | struct m9206_state { | 62 | struct m9206_state { |
27 | u16 filters[M9206_MAX_FILTERS]; | 63 | u16 filters[M9206_MAX_FILTERS]; |
28 | int filtering_enabled; | 64 | int filtering_enabled; |
29 | int rep_count; | 65 | int rep_count; |
30 | struct { | ||
31 | unsigned char addr; | ||
32 | unsigned char magic; | ||
33 | }i2c_r[M9206_I2C_MAX]; | ||
34 | }; | 66 | }; |
35 | #endif | 67 | #endif |
diff --git a/drivers/media/dvb/dvb-usb/opera1.c b/drivers/media/dvb/dvb-usb/opera1.c new file mode 100644 index 000000000000..518d7ad217df --- /dev/null +++ b/drivers/media/dvb/dvb-usb/opera1.c | |||
@@ -0,0 +1,581 @@ | |||
1 | /* DVB USB framework compliant Linux driver for the Opera1 DVB-S Card | ||
2 | * | ||
3 | * Copyright (C) 2006 Mario Hlawitschka (dh1pa@amsat.org) | ||
4 | * Copyright (C) 2006 Marco Gittler (g.marco@freenet.de) | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify it | ||
7 | * under the terms of the GNU General Public License as published by the Free | ||
8 | * Software Foundation, version 2. | ||
9 | * | ||
10 | * see Documentation/dvb/README.dvb-usb for more information | ||
11 | */ | ||
12 | |||
13 | #include "opera1.h" | ||
14 | #include "stv0299.h" | ||
15 | |||
16 | #define OPERA_READ_MSG 0 | ||
17 | #define OPERA_WRITE_MSG 1 | ||
18 | #define OPERA_I2C_TUNER 0xd1 | ||
19 | |||
20 | #define READ_FX2_REG_REQ 0xba | ||
21 | #define READ_MAC_ADDR 0x08 | ||
22 | #define OPERA_WRITE_FX2 0xbb | ||
23 | #define OPERA_TUNER_REQ 0xb1 | ||
24 | #define REG_1F_SYMBOLRATE_BYTE0 0x1f | ||
25 | #define REG_20_SYMBOLRATE_BYTE1 0x20 | ||
26 | #define REG_21_SYMBOLRATE_BYTE2 0x21 | ||
27 | |||
28 | #define ADDR_B600_VOLTAGE_13V (0x02) | ||
29 | #define ADDR_B601_VOLTAGE_18V (0x03) | ||
30 | #define ADDR_B1A6_STREAM_CTRL (0x04) | ||
31 | #define ADDR_B880_READ_REMOTE (0x05) | ||
32 | |||
33 | struct opera1_state { | ||
34 | u32 last_key_pressed; | ||
35 | }; | ||
36 | struct opera_rc_keys { | ||
37 | u32 keycode; | ||
38 | u32 event; | ||
39 | }; | ||
40 | |||
41 | int dvb_usb_opera1_debug; | ||
42 | module_param_named(debug, dvb_usb_opera1_debug, int, 0644); | ||
43 | MODULE_PARM_DESC(debug, | ||
44 | "set debugging level (1=info,xfer=2,pll=4,ts=8,err=16,rc=32,fw=64 (or-able))." | ||
45 | DVB_USB_DEBUG_STATUS); | ||
46 | |||
47 | static int opera1_xilinx_rw(struct usb_device *dev, u8 request, u16 value, | ||
48 | u8 * data, u16 len, int flags) | ||
49 | { | ||
50 | int ret; | ||
51 | u8 r; | ||
52 | u8 u8buf[len]; | ||
53 | |||
54 | unsigned int pipe = (flags == OPERA_READ_MSG) ? | ||
55 | usb_rcvctrlpipe(dev,0) : usb_sndctrlpipe(dev, 0); | ||
56 | u8 request_type = (flags == OPERA_READ_MSG) ? USB_DIR_IN : USB_DIR_OUT; | ||
57 | |||
58 | if (flags == OPERA_WRITE_MSG) | ||
59 | memcpy(u8buf, data, len); | ||
60 | ret = | ||
61 | usb_control_msg(dev, pipe, request, request_type | USB_TYPE_VENDOR, | ||
62 | value, 0x0, u8buf, len, 2000); | ||
63 | |||
64 | if (request == OPERA_TUNER_REQ) { | ||
65 | if (usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), | ||
66 | OPERA_TUNER_REQ, USB_DIR_IN | USB_TYPE_VENDOR, | ||
67 | 0x01, 0x0, &r, 1, 2000)<1 || r!=0x08) | ||
68 | return 0; | ||
69 | } | ||
70 | if (flags == OPERA_READ_MSG) | ||
71 | memcpy(data, u8buf, len); | ||
72 | return ret; | ||
73 | } | ||
74 | |||
75 | /* I2C */ | ||
76 | |||
77 | static int opera1_usb_i2c_msgxfer(struct dvb_usb_device *dev, u16 addr, | ||
78 | u8 * buf, u16 len) | ||
79 | { | ||
80 | int ret = 0; | ||
81 | u8 request; | ||
82 | u16 value; | ||
83 | |||
84 | if (!dev) { | ||
85 | info("no usb_device"); | ||
86 | return -EINVAL; | ||
87 | } | ||
88 | if (mutex_lock_interruptible(&dev->usb_mutex) < 0) | ||
89 | return -EAGAIN; | ||
90 | |||
91 | switch (addr>>1){ | ||
92 | case ADDR_B600_VOLTAGE_13V: | ||
93 | request=0xb6; | ||
94 | value=0x00; | ||
95 | break; | ||
96 | case ADDR_B601_VOLTAGE_18V: | ||
97 | request=0xb6; | ||
98 | value=0x01; | ||
99 | break; | ||
100 | case ADDR_B1A6_STREAM_CTRL: | ||
101 | request=0xb1; | ||
102 | value=0xa6; | ||
103 | break; | ||
104 | case ADDR_B880_READ_REMOTE: | ||
105 | request=0xb8; | ||
106 | value=0x80; | ||
107 | break; | ||
108 | default: | ||
109 | request=0xb1; | ||
110 | value=addr; | ||
111 | } | ||
112 | ret = opera1_xilinx_rw(dev->udev, request, | ||
113 | value, buf, len, | ||
114 | addr&0x01?OPERA_READ_MSG:OPERA_WRITE_MSG); | ||
115 | |||
116 | mutex_unlock(&dev->usb_mutex); | ||
117 | return ret; | ||
118 | } | ||
119 | |||
120 | static int opera1_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msg[], | ||
121 | int num) | ||
122 | { | ||
123 | struct dvb_usb_device *d = i2c_get_adapdata(adap); | ||
124 | int i = 0, tmp = 0; | ||
125 | |||
126 | if (!d) | ||
127 | return -ENODEV; | ||
128 | if (mutex_lock_interruptible(&d->i2c_mutex) < 0) | ||
129 | return -EAGAIN; | ||
130 | |||
131 | for (i = 0; i < num; i++) { | ||
132 | if ((tmp = opera1_usb_i2c_msgxfer(d, | ||
133 | (msg[i].addr<<1)|(msg[i].flags&I2C_M_RD?0x01:0), | ||
134 | msg[i].buf, | ||
135 | msg[i].len | ||
136 | )!= msg[i].len)) { | ||
137 | break; | ||
138 | } | ||
139 | if (dvb_usb_opera1_debug & 0x10) | ||
140 | info("sending i2c mesage %d %d", tmp, msg[i].len); | ||
141 | } | ||
142 | mutex_unlock(&d->i2c_mutex); | ||
143 | return num; | ||
144 | } | ||
145 | |||
146 | static u32 opera1_i2c_func(struct i2c_adapter *adapter) | ||
147 | { | ||
148 | return I2C_FUNC_I2C; | ||
149 | } | ||
150 | |||
151 | static struct i2c_algorithm opera1_i2c_algo = { | ||
152 | .master_xfer = opera1_i2c_xfer, | ||
153 | .functionality = opera1_i2c_func, | ||
154 | }; | ||
155 | |||
156 | static int opera1_set_voltage(struct dvb_frontend *fe, fe_sec_voltage_t voltage) | ||
157 | { | ||
158 | static u8 command_13v[1]={0x00}; | ||
159 | static u8 command_18v[1]={0x01}; | ||
160 | struct i2c_msg msg[] = { | ||
161 | {.addr = ADDR_B600_VOLTAGE_13V,.flags = 0,.buf = command_13v,.len = 1}, | ||
162 | }; | ||
163 | struct dvb_usb_adapter *udev_adap = | ||
164 | (struct dvb_usb_adapter *)(fe->dvb->priv); | ||
165 | if (voltage == SEC_VOLTAGE_18) { | ||
166 | msg[0].addr = ADDR_B601_VOLTAGE_18V; | ||
167 | msg[0].buf = command_18v; | ||
168 | } | ||
169 | i2c_transfer(&udev_adap->dev->i2c_adap, msg, 1); | ||
170 | return 0; | ||
171 | } | ||
172 | |||
173 | static int opera1_stv0299_set_symbol_rate(struct dvb_frontend *fe, u32 srate, | ||
174 | u32 ratio) | ||
175 | { | ||
176 | stv0299_writereg(fe, 0x13, 0x98); | ||
177 | stv0299_writereg(fe, 0x14, 0x95); | ||
178 | stv0299_writereg(fe, REG_1F_SYMBOLRATE_BYTE0, (ratio >> 16) & 0xff); | ||
179 | stv0299_writereg(fe, REG_20_SYMBOLRATE_BYTE1, (ratio >> 8) & 0xff); | ||
180 | stv0299_writereg(fe, REG_21_SYMBOLRATE_BYTE2, (ratio) & 0xf0); | ||
181 | return 0; | ||
182 | |||
183 | } | ||
184 | static u8 opera1_inittab[] = { | ||
185 | 0x00, 0xa1, | ||
186 | 0x01, 0x15, | ||
187 | 0x02, 0x00, | ||
188 | 0x03, 0x00, | ||
189 | 0x04, 0x7d, | ||
190 | 0x05, 0x05, | ||
191 | 0x06, 0x02, | ||
192 | 0x07, 0x00, | ||
193 | 0x0b, 0x00, | ||
194 | 0x0c, 0x01, | ||
195 | 0x0d, 0x81, | ||
196 | 0x0e, 0x44, | ||
197 | 0x0f, 0x19, | ||
198 | 0x10, 0x3f, | ||
199 | 0x11, 0x84, | ||
200 | 0x12, 0xda, | ||
201 | 0x13, 0x98, | ||
202 | 0x14, 0x95, | ||
203 | 0x15, 0xc9, | ||
204 | 0x16, 0xeb, | ||
205 | 0x17, 0x00, | ||
206 | 0x18, 0x19, | ||
207 | 0x19, 0x8b, | ||
208 | 0x1a, 0x00, | ||
209 | 0x1b, 0x82, | ||
210 | 0x1c, 0x7f, | ||
211 | 0x1d, 0x00, | ||
212 | 0x1e, 0x00, | ||
213 | REG_1F_SYMBOLRATE_BYTE0, 0x06, | ||
214 | REG_20_SYMBOLRATE_BYTE1, 0x50, | ||
215 | REG_21_SYMBOLRATE_BYTE2, 0x10, | ||
216 | 0x22, 0x00, | ||
217 | 0x23, 0x00, | ||
218 | 0x24, 0x37, | ||
219 | 0x25, 0xbc, | ||
220 | 0x26, 0x00, | ||
221 | 0x27, 0x00, | ||
222 | 0x28, 0x00, | ||
223 | 0x29, 0x1e, | ||
224 | 0x2a, 0x14, | ||
225 | 0x2b, 0x1f, | ||
226 | 0x2c, 0x09, | ||
227 | 0x2d, 0x0a, | ||
228 | 0x2e, 0x00, | ||
229 | 0x2f, 0x00, | ||
230 | 0x30, 0x00, | ||
231 | 0x31, 0x1f, | ||
232 | 0x32, 0x19, | ||
233 | 0x33, 0xfc, | ||
234 | 0x34, 0x13, | ||
235 | 0xff, 0xff, | ||
236 | }; | ||
237 | |||
238 | static struct stv0299_config opera1_stv0299_config = { | ||
239 | .demod_address = 0xd0>>1, | ||
240 | .min_delay_ms = 100, | ||
241 | .mclk = 88000000UL, | ||
242 | .invert = 1, | ||
243 | .skip_reinit = 0, | ||
244 | .lock_output = STV0229_LOCKOUTPUT_0, | ||
245 | .volt13_op0_op1 = STV0299_VOLT13_OP0, | ||
246 | .inittab = opera1_inittab, | ||
247 | .set_symbol_rate = opera1_stv0299_set_symbol_rate, | ||
248 | }; | ||
249 | |||
250 | static int opera1_frontend_attach(struct dvb_usb_adapter *d) | ||
251 | { | ||
252 | if ((d->fe = | ||
253 | dvb_attach(stv0299_attach, &opera1_stv0299_config, | ||
254 | &d->dev->i2c_adap)) != NULL) { | ||
255 | d->fe->ops.set_voltage = opera1_set_voltage; | ||
256 | return 0; | ||
257 | } | ||
258 | info("not attached stv0299"); | ||
259 | return -EIO; | ||
260 | } | ||
261 | |||
262 | static int opera1_tuner_attach(struct dvb_usb_adapter *adap) | ||
263 | { | ||
264 | dvb_attach( | ||
265 | dvb_pll_attach, adap->fe, 0xc0>>1, | ||
266 | &adap->dev->i2c_adap, &dvb_pll_opera1 | ||
267 | ); | ||
268 | return 0; | ||
269 | } | ||
270 | |||
271 | static int opera1_power_ctrl(struct dvb_usb_device *d, int onoff) | ||
272 | { | ||
273 | u8 val = onoff ? 0x01 : 0x00; | ||
274 | |||
275 | if (dvb_usb_opera1_debug) | ||
276 | info("power %s", onoff ? "on" : "off"); | ||
277 | return opera1_xilinx_rw(d->udev, 0xb7, val, | ||
278 | &val, 1, OPERA_WRITE_MSG); | ||
279 | } | ||
280 | |||
281 | static int opera1_streaming_ctrl(struct dvb_usb_adapter *adap, int onoff) | ||
282 | { | ||
283 | static u8 buf_start[2] = { 0xff, 0x03 }; | ||
284 | static u8 buf_stop[2] = { 0xff, 0x00 }; | ||
285 | struct i2c_msg start_tuner[] = { | ||
286 | {.addr = ADDR_B1A6_STREAM_CTRL,.buf = onoff ? buf_start : buf_stop,.len = 2}, | ||
287 | }; | ||
288 | if (dvb_usb_opera1_debug) | ||
289 | info("streaming %s", onoff ? "on" : "off"); | ||
290 | i2c_transfer(&adap->dev->i2c_adap, start_tuner, 1); | ||
291 | return 0; | ||
292 | } | ||
293 | |||
294 | static int opera1_pid_filter(struct dvb_usb_adapter *adap, int index, u16 pid, | ||
295 | int onoff) | ||
296 | { | ||
297 | u8 b_pid[3]; | ||
298 | struct i2c_msg msg[] = { | ||
299 | {.addr = ADDR_B1A6_STREAM_CTRL,.buf = b_pid,.len = 3}, | ||
300 | }; | ||
301 | if (dvb_usb_opera1_debug) | ||
302 | info("pidfilter index: %d pid: %d %s", index, pid, | ||
303 | onoff ? "on" : "off"); | ||
304 | b_pid[0] = (2 * index) + 4; | ||
305 | b_pid[1] = onoff ? (pid & 0xff) : (0x00); | ||
306 | b_pid[2] = onoff ? ((pid >> 8) & 0xff) : (0x00); | ||
307 | i2c_transfer(&adap->dev->i2c_adap, msg, 1); | ||
308 | return 0; | ||
309 | } | ||
310 | |||
311 | static int opera1_pid_filter_control(struct dvb_usb_adapter *adap, int onoff) | ||
312 | { | ||
313 | int u = 0x04; | ||
314 | u8 b_pid[3]; | ||
315 | struct i2c_msg msg[] = { | ||
316 | {.addr = ADDR_B1A6_STREAM_CTRL,.buf = b_pid,.len = 3}, | ||
317 | }; | ||
318 | if (dvb_usb_opera1_debug) | ||
319 | info("%s hw-pidfilter", onoff ? "enable" : "disable"); | ||
320 | for (; u < 0x7e; u += 2) { | ||
321 | b_pid[0] = u; | ||
322 | b_pid[1] = 0; | ||
323 | b_pid[2] = 0x80; | ||
324 | i2c_transfer(&adap->dev->i2c_adap, msg, 1); | ||
325 | } | ||
326 | return 0; | ||
327 | } | ||
328 | |||
329 | static struct dvb_usb_rc_key opera1_rc_keys[] = { | ||
330 | {0x5f, 0xa0, KEY_1}, | ||
331 | {0x51, 0xaf, KEY_2}, | ||
332 | {0x5d, 0xa2, KEY_3}, | ||
333 | {0x41, 0xbe, KEY_4}, | ||
334 | {0x0b, 0xf5, KEY_5}, | ||
335 | {0x43, 0xbd, KEY_6}, | ||
336 | {0x47, 0xb8, KEY_7}, | ||
337 | {0x49, 0xb6, KEY_8}, | ||
338 | {0x05, 0xfa, KEY_9}, | ||
339 | {0x45, 0xba, KEY_0}, | ||
340 | {0x09, 0xf6, KEY_UP}, /*chanup */ | ||
341 | {0x1b, 0xe5, KEY_DOWN}, /*chandown */ | ||
342 | {0x5d, 0xa3, KEY_LEFT}, /*voldown */ | ||
343 | {0x5f, 0xa1, KEY_RIGHT}, /*volup */ | ||
344 | {0x07, 0xf8, KEY_SPACE}, /*tab */ | ||
345 | {0x1f, 0xe1, KEY_ENTER}, /*play ok */ | ||
346 | {0x1b, 0xe4, KEY_Z}, /*zoom */ | ||
347 | {0x59, 0xa6, KEY_M}, /*mute */ | ||
348 | {0x5b, 0xa5, KEY_F}, /*tv/f */ | ||
349 | {0x19, 0xe7, KEY_R}, /*rec */ | ||
350 | {0x01, 0xfe, KEY_S}, /*Stop */ | ||
351 | {0x03, 0xfd, KEY_P}, /*pause */ | ||
352 | {0x03, 0xfc, KEY_W}, /*<- -> */ | ||
353 | {0x07, 0xf9, KEY_C}, /*capture */ | ||
354 | {0x47, 0xb9, KEY_Q}, /*exit */ | ||
355 | {0x43, 0xbc, KEY_O}, /*power */ | ||
356 | |||
357 | }; | ||
358 | |||
359 | static int opera1_rc_query(struct dvb_usb_device *dev, u32 * event, int *state) | ||
360 | { | ||
361 | struct opera1_state *opst = dev->priv; | ||
362 | u8 rcbuffer[32]; | ||
363 | const u16 startmarker1 = 0x10ed; | ||
364 | const u16 startmarker2 = 0x11ec; | ||
365 | struct i2c_msg read_remote[] = { | ||
366 | {.addr = ADDR_B880_READ_REMOTE,.buf = rcbuffer,.flags = I2C_M_RD,.len = 32}, | ||
367 | }; | ||
368 | int i = 0; | ||
369 | u32 send_key = 0; | ||
370 | |||
371 | if (i2c_transfer(&dev->i2c_adap, read_remote, 1) == 1) { | ||
372 | for (i = 0; i < 32; i++) { | ||
373 | if (rcbuffer[i]) | ||
374 | send_key |= 1; | ||
375 | if (i < 31) | ||
376 | send_key = send_key << 1; | ||
377 | } | ||
378 | if (send_key & 0x8000) | ||
379 | send_key = (send_key << 1) | (send_key >> 15 & 0x01); | ||
380 | |||
381 | if (send_key == 0xffff && opst->last_key_pressed != 0) { | ||
382 | *state = REMOTE_KEY_REPEAT; | ||
383 | *event = opst->last_key_pressed; | ||
384 | return 0; | ||
385 | } | ||
386 | for (; send_key != 0;) { | ||
387 | if (send_key >> 16 == startmarker2) { | ||
388 | break; | ||
389 | } else if (send_key >> 16 == startmarker1) { | ||
390 | send_key = | ||
391 | (send_key & 0xfffeffff) | (startmarker1 << 16); | ||
392 | break; | ||
393 | } else | ||
394 | send_key >>= 1; | ||
395 | } | ||
396 | |||
397 | if (send_key == 0) | ||
398 | return 0; | ||
399 | |||
400 | send_key = (send_key & 0xffff) | 0x0100; | ||
401 | |||
402 | for (i = 0; i < ARRAY_SIZE(opera1_rc_keys); i++) { | ||
403 | if ((opera1_rc_keys[i].custom * 256 + | ||
404 | opera1_rc_keys[i].data) == (send_key & 0xffff)) { | ||
405 | *state = REMOTE_KEY_PRESSED; | ||
406 | *event = opera1_rc_keys[i].event; | ||
407 | opst->last_key_pressed = | ||
408 | opera1_rc_keys[i].event; | ||
409 | break; | ||
410 | } | ||
411 | opst->last_key_pressed = 0; | ||
412 | } | ||
413 | } else | ||
414 | *state = REMOTE_NO_KEY_PRESSED; | ||
415 | return 0; | ||
416 | } | ||
417 | |||
418 | static struct usb_device_id opera1_table[] = { | ||
419 | {USB_DEVICE(USB_VID_CYPRESS, USB_PID_OPERA1_COLD)}, | ||
420 | {USB_DEVICE(USB_VID_OPERA1, USB_PID_OPERA1_WARM)}, | ||
421 | {} | ||
422 | }; | ||
423 | |||
424 | MODULE_DEVICE_TABLE(usb, opera1_table); | ||
425 | |||
426 | static int opera1_read_mac_address(struct dvb_usb_device *d, u8 mac[6]) | ||
427 | { | ||
428 | u8 command[] = { READ_MAC_ADDR }; | ||
429 | opera1_xilinx_rw(d->udev, 0xb1, 0xa0, command, 1, OPERA_WRITE_MSG); | ||
430 | opera1_xilinx_rw(d->udev, 0xb1, 0xa1, mac, 6, OPERA_READ_MSG); | ||
431 | return 0; | ||
432 | } | ||
433 | static int opera1_xilinx_load_firmware(struct usb_device *dev, | ||
434 | const char *filename) | ||
435 | { | ||
436 | const struct firmware *fw = NULL; | ||
437 | u8 *b, *p; | ||
438 | int ret = 0, i; | ||
439 | u8 testval; | ||
440 | info("start downloading fpga firmware"); | ||
441 | |||
442 | if ((ret = request_firmware(&fw, filename, &dev->dev)) != 0) { | ||
443 | err("did not find the firmware file. (%s) " | ||
444 | "Please see linux/Documentation/dvb/ for more details on firmware-problems.", | ||
445 | filename); | ||
446 | return ret; | ||
447 | } else { | ||
448 | p = kmalloc(fw->size, GFP_KERNEL); | ||
449 | opera1_xilinx_rw(dev, 0xbc, 0x00, &testval, 1, OPERA_READ_MSG); | ||
450 | if (p != NULL && testval != 0x67) { | ||
451 | |||
452 | u8 reset = 0, fpga_command = 0; | ||
453 | memcpy(p, fw->data, fw->size); | ||
454 | /* clear fpga ? */ | ||
455 | opera1_xilinx_rw(dev, 0xbc, 0xaa, &fpga_command, 1, | ||
456 | OPERA_WRITE_MSG); | ||
457 | for (i = 0; p[i] != 0 && i < fw->size;) { | ||
458 | b = (u8 *) p + i; | ||
459 | if (opera1_xilinx_rw | ||
460 | (dev, OPERA_WRITE_FX2, 0x0, b + 1, b[0], | ||
461 | OPERA_WRITE_MSG) != b[0] | ||
462 | ) { | ||
463 | err("error while transferring firmware"); | ||
464 | ret = -EINVAL; | ||
465 | break; | ||
466 | } | ||
467 | i = i + 1 + b[0]; | ||
468 | } | ||
469 | /* restart the CPU */ | ||
470 | if (ret || opera1_xilinx_rw | ||
471 | (dev, 0xa0, 0xe600, &reset, 1, | ||
472 | OPERA_WRITE_MSG) != 1) { | ||
473 | err("could not restart the USB controller CPU."); | ||
474 | ret = -EINVAL; | ||
475 | } | ||
476 | kfree(p); | ||
477 | } | ||
478 | } | ||
479 | if (fw) { | ||
480 | release_firmware(fw); | ||
481 | } | ||
482 | return ret; | ||
483 | } | ||
484 | |||
485 | static struct dvb_usb_device_properties opera1_properties = { | ||
486 | .caps = DVB_USB_IS_AN_I2C_ADAPTER, | ||
487 | .usb_ctrl = CYPRESS_FX2, | ||
488 | .firmware = "dvb-usb-opera-01.fw", | ||
489 | .size_of_priv = sizeof(struct opera1_state), | ||
490 | |||
491 | .power_ctrl = opera1_power_ctrl, | ||
492 | .i2c_algo = &opera1_i2c_algo, | ||
493 | |||
494 | .rc_key_map = opera1_rc_keys, | ||
495 | .rc_key_map_size = ARRAY_SIZE(opera1_rc_keys), | ||
496 | .rc_interval = 200, | ||
497 | .rc_query = opera1_rc_query, | ||
498 | .read_mac_address = opera1_read_mac_address, | ||
499 | .generic_bulk_ctrl_endpoint = 0x00, | ||
500 | /* parameter for the MPEG2-data transfer */ | ||
501 | .num_adapters = 1, | ||
502 | .adapter = { | ||
503 | { | ||
504 | .frontend_attach = opera1_frontend_attach, | ||
505 | .streaming_ctrl = opera1_streaming_ctrl, | ||
506 | .tuner_attach = opera1_tuner_attach, | ||
507 | .caps = | ||
508 | DVB_USB_ADAP_HAS_PID_FILTER | | ||
509 | DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF, | ||
510 | .pid_filter = opera1_pid_filter, | ||
511 | .pid_filter_ctrl = opera1_pid_filter_control, | ||
512 | .pid_filter_count = 252, | ||
513 | .stream = { | ||
514 | .type = USB_BULK, | ||
515 | .count = 10, | ||
516 | .endpoint = 0x82, | ||
517 | .u = { | ||
518 | .bulk = { | ||
519 | .buffersize = 4096, | ||
520 | } | ||
521 | } | ||
522 | }, | ||
523 | } | ||
524 | }, | ||
525 | .num_device_descs = 1, | ||
526 | .devices = { | ||
527 | {"Opera1 DVB-S USB2.0", | ||
528 | {&opera1_table[0], NULL}, | ||
529 | {&opera1_table[1], NULL}, | ||
530 | }, | ||
531 | } | ||
532 | }; | ||
533 | |||
534 | static int opera1_probe(struct usb_interface *intf, | ||
535 | const struct usb_device_id *id) | ||
536 | { | ||
537 | struct dvb_usb_device *d; | ||
538 | struct usb_device *udev = interface_to_usbdev(intf); | ||
539 | |||
540 | if (udev->descriptor.idProduct == USB_PID_OPERA1_WARM && | ||
541 | udev->descriptor.idVendor == USB_VID_OPERA1 && | ||
542 | (d == NULL | ||
543 | || opera1_xilinx_load_firmware(udev, "dvb-usb-opera1-fpga.fw") != 0) | ||
544 | ) { | ||
545 | return -EINVAL; | ||
546 | } | ||
547 | |||
548 | if (dvb_usb_device_init(intf, &opera1_properties, THIS_MODULE, &d) != 0) | ||
549 | return -EINVAL; | ||
550 | return 0; | ||
551 | } | ||
552 | |||
553 | static struct usb_driver opera1_driver = { | ||
554 | .name = "opera1", | ||
555 | .probe = opera1_probe, | ||
556 | .disconnect = dvb_usb_device_exit, | ||
557 | .id_table = opera1_table, | ||
558 | }; | ||
559 | |||
560 | static int __init opera1_module_init(void) | ||
561 | { | ||
562 | int result = 0; | ||
563 | if ((result = usb_register(&opera1_driver))) { | ||
564 | err("usb_register failed. Error number %d", result); | ||
565 | } | ||
566 | return result; | ||
567 | } | ||
568 | |||
569 | static void __exit opera1_module_exit(void) | ||
570 | { | ||
571 | usb_deregister(&opera1_driver); | ||
572 | } | ||
573 | |||
574 | module_init(opera1_module_init); | ||
575 | module_exit(opera1_module_exit); | ||
576 | |||
577 | MODULE_AUTHOR("Mario Hlawitschka (c) dh1pa@amsat.org"); | ||
578 | MODULE_AUTHOR("Marco Gittler (c) g.marco@freenet.de"); | ||
579 | MODULE_DESCRIPTION("Driver for Opera1 DVB-S device"); | ||
580 | MODULE_VERSION("0.1"); | ||
581 | MODULE_LICENSE("GPL"); | ||
diff --git a/drivers/media/dvb/dvb-usb/opera1.h b/drivers/media/dvb/dvb-usb/opera1.h new file mode 100644 index 000000000000..53174427902d --- /dev/null +++ b/drivers/media/dvb/dvb-usb/opera1.h | |||
@@ -0,0 +1,9 @@ | |||
1 | #ifndef _OPERA1_H_ | ||
2 | #define _OPERA1_H_ | ||
3 | |||
4 | #define DVB_USB_LOG_PREFIX "opera" | ||
5 | #include "dvb-usb.h" | ||
6 | |||
7 | extern int dvb_usb_opera1_debug; | ||
8 | #define deb_xfer(args...) dprintk(dvb_usb_opera1_debug,0x02,args) | ||
9 | #endif | ||
diff --git a/drivers/media/dvb/dvb-usb/ttusb2.c b/drivers/media/dvb/dvb-usb/ttusb2.c index 95d29976ed78..88dc4367a2e3 100644 --- a/drivers/media/dvb/dvb-usb/ttusb2.c +++ b/drivers/media/dvb/dvb-usb/ttusb2.c | |||
@@ -184,6 +184,7 @@ static int ttusb2_probe(struct usb_interface *intf, | |||
184 | 184 | ||
185 | static struct usb_device_id ttusb2_table [] = { | 185 | static struct usb_device_id ttusb2_table [] = { |
186 | { USB_DEVICE(USB_VID_PINNACLE, USB_PID_PCTV_400E) }, | 186 | { USB_DEVICE(USB_VID_PINNACLE, USB_PID_PCTV_400E) }, |
187 | { USB_DEVICE(USB_VID_PINNACLE, USB_PID_PCTV_450E) }, | ||
187 | {} /* Terminating entry */ | 188 | {} /* Terminating entry */ |
188 | }; | 189 | }; |
189 | MODULE_DEVICE_TABLE (usb, ttusb2_table); | 190 | MODULE_DEVICE_TABLE (usb, ttusb2_table); |
@@ -227,12 +228,16 @@ static struct dvb_usb_device_properties ttusb2_properties = { | |||
227 | 228 | ||
228 | .generic_bulk_ctrl_endpoint = 0x01, | 229 | .generic_bulk_ctrl_endpoint = 0x01, |
229 | 230 | ||
230 | .num_device_descs = 1, | 231 | .num_device_descs = 2, |
231 | .devices = { | 232 | .devices = { |
232 | { "Pinnacle 400e DVB-S USB2.0", | 233 | { "Pinnacle 400e DVB-S USB2.0", |
233 | { &ttusb2_table[0], NULL }, | 234 | { &ttusb2_table[0], NULL }, |
234 | { NULL }, | 235 | { NULL }, |
235 | }, | 236 | }, |
237 | { "Pinnacle 450e DVB-S USB2.0", | ||
238 | { &ttusb2_table[1], NULL }, | ||
239 | { NULL }, | ||
240 | }, | ||
236 | } | 241 | } |
237 | }; | 242 | }; |
238 | 243 | ||
diff --git a/drivers/media/dvb/frontends/Kconfig b/drivers/media/dvb/frontends/Kconfig index 22c2cf2cea98..ff448761dcef 100644 --- a/drivers/media/dvb/frontends/Kconfig +++ b/drivers/media/dvb/frontends/Kconfig | |||
@@ -205,6 +205,13 @@ config DVB_TDA10021 | |||
205 | help | 205 | help |
206 | A DVB-C tuner module. Say Y when you want to support this frontend. | 206 | A DVB-C tuner module. Say Y when you want to support this frontend. |
207 | 207 | ||
208 | config DVB_TDA10023 | ||
209 | tristate "Philips TDA10023 based" | ||
210 | depends on DVB_CORE && I2C | ||
211 | default m if DVB_FE_CUSTOMISE | ||
212 | help | ||
213 | A DVB-C tuner module. Say Y when you want to support this frontend. | ||
214 | |||
208 | config DVB_STV0297 | 215 | config DVB_STV0297 |
209 | tristate "ST STV0297 based" | 216 | tristate "ST STV0297 based" |
210 | depends on DVB_CORE && I2C | 217 | depends on DVB_CORE && I2C |
@@ -280,8 +287,12 @@ comment "Tuners/PLL support" | |||
280 | depends on DVB_CORE | 287 | depends on DVB_CORE |
281 | 288 | ||
282 | config DVB_PLL | 289 | config DVB_PLL |
283 | tristate | 290 | tristate "Generic I2C PLL based tuners" |
284 | depends on DVB_CORE && I2C | 291 | depends on DVB_CORE && I2C |
292 | default m if DVB_FE_CUSTOMISE | ||
293 | help | ||
294 | This module driver a number of tuners based on PLL chips with a | ||
295 | common I2C interface. Say Y when you want to support these tuners. | ||
285 | 296 | ||
286 | config DVB_TDA826X | 297 | config DVB_TDA826X |
287 | tristate "Philips TDA826X silicon tuner" | 298 | tristate "Philips TDA826X silicon tuner" |
@@ -290,6 +301,13 @@ config DVB_TDA826X | |||
290 | help | 301 | help |
291 | A DVB-S silicon tuner module. Say Y when you want to support this tuner. | 302 | A DVB-S silicon tuner module. Say Y when you want to support this tuner. |
292 | 303 | ||
304 | config DVB_TDA827X | ||
305 | tristate "Philips TDA827X silicon tuner" | ||
306 | depends on DVB_CORE && I2C | ||
307 | default m if DVB_FE_CUSTOMISE | ||
308 | help | ||
309 | A DVB-T silicon tuner module. Say Y when you want to support this tuner. | ||
310 | |||
293 | config DVB_TUNER_QT1010 | 311 | config DVB_TUNER_QT1010 |
294 | tristate "Quantek QT1010 silicon tuner" | 312 | tristate "Quantek QT1010 silicon tuner" |
295 | depends on DVB_CORE && I2C | 313 | depends on DVB_CORE && I2C |
@@ -304,14 +322,6 @@ config DVB_TUNER_MT2060 | |||
304 | help | 322 | help |
305 | A driver for the silicon IF tuner MT2060 from Microtune. | 323 | A driver for the silicon IF tuner MT2060 from Microtune. |
306 | 324 | ||
307 | config DVB_TUNER_LGH06XF | ||
308 | tristate "LG TDVS-H06xF ATSC tuner" | ||
309 | depends on DVB_CORE && I2C | ||
310 | select DVB_PLL | ||
311 | default m if DVB_FE_CUSTOMISE | ||
312 | help | ||
313 | A driver for the LG TDVS-H06xF ATSC tuner family. | ||
314 | |||
315 | comment "Miscellaneous devices" | 325 | comment "Miscellaneous devices" |
316 | depends on DVB_CORE | 326 | depends on DVB_CORE |
317 | 327 | ||
diff --git a/drivers/media/dvb/frontends/Makefile b/drivers/media/dvb/frontends/Makefile index a646d9969b71..27f386585d43 100644 --- a/drivers/media/dvb/frontends/Makefile +++ b/drivers/media/dvb/frontends/Makefile | |||
@@ -25,6 +25,7 @@ obj-$(CONFIG_DVB_MT352) += mt352.o | |||
25 | obj-$(CONFIG_DVB_ZL10353) += zl10353.o | 25 | obj-$(CONFIG_DVB_ZL10353) += zl10353.o |
26 | obj-$(CONFIG_DVB_CX22702) += cx22702.o | 26 | obj-$(CONFIG_DVB_CX22702) += cx22702.o |
27 | obj-$(CONFIG_DVB_TDA10021) += tda10021.o | 27 | obj-$(CONFIG_DVB_TDA10021) += tda10021.o |
28 | obj-$(CONFIG_DVB_TDA10023) += tda10023.o | ||
28 | obj-$(CONFIG_DVB_STV0297) += stv0297.o | 29 | obj-$(CONFIG_DVB_STV0297) += stv0297.o |
29 | obj-$(CONFIG_DVB_NXT200X) += nxt200x.o | 30 | obj-$(CONFIG_DVB_NXT200X) += nxt200x.o |
30 | obj-$(CONFIG_DVB_OR51211) += or51211.o | 31 | obj-$(CONFIG_DVB_OR51211) += or51211.o |
@@ -37,7 +38,7 @@ obj-$(CONFIG_DVB_LNBP21) += lnbp21.o | |||
37 | obj-$(CONFIG_DVB_ISL6421) += isl6421.o | 38 | obj-$(CONFIG_DVB_ISL6421) += isl6421.o |
38 | obj-$(CONFIG_DVB_TDA10086) += tda10086.o | 39 | obj-$(CONFIG_DVB_TDA10086) += tda10086.o |
39 | obj-$(CONFIG_DVB_TDA826X) += tda826x.o | 40 | obj-$(CONFIG_DVB_TDA826X) += tda826x.o |
41 | obj-$(CONFIG_DVB_TDA827X) += tda827x.o | ||
40 | obj-$(CONFIG_DVB_TUNER_MT2060) += mt2060.o | 42 | obj-$(CONFIG_DVB_TUNER_MT2060) += mt2060.o |
41 | obj-$(CONFIG_DVB_TUNER_QT1010) += qt1010.o | 43 | obj-$(CONFIG_DVB_TUNER_QT1010) += qt1010.o |
42 | obj-$(CONFIG_DVB_TUA6100) += tua6100.o | 44 | obj-$(CONFIG_DVB_TUA6100) += tua6100.o |
43 | obj-$(CONFIG_DVB_TUNER_LGH06XF) += lgh06xf.o | ||
diff --git a/drivers/media/dvb/frontends/dvb-pll.c b/drivers/media/dvb/frontends/dvb-pll.c index 62de760c844f..5f96ffda91ad 100644 --- a/drivers/media/dvb/frontends/dvb-pll.c +++ b/drivers/media/dvb/frontends/dvb-pll.c | |||
@@ -27,17 +27,29 @@ | |||
27 | /* ----------------------------------------------------------- */ | 27 | /* ----------------------------------------------------------- */ |
28 | /* descriptions */ | 28 | /* descriptions */ |
29 | 29 | ||
30 | /* Set AGC TOP value to 103 dBuV: | ||
31 | 0x80 = Control Byte | ||
32 | 0x40 = 250 uA charge pump (irrelevant) | ||
33 | 0x18 = Aux Byte to follow | ||
34 | 0x06 = 64.5 kHz divider (irrelevant) | ||
35 | 0x01 = Disable Vt (aka sleep) | ||
36 | |||
37 | 0x00 = AGC Time constant 2s Iagc = 300 nA (vs 0x80 = 9 nA) | ||
38 | 0x50 = AGC Take over point = 103 dBuV */ | ||
39 | static u8 tua603x_agc103[] = { 2, 0x80|0x40|0x18|0x06|0x01, 0x00|0x50 }; | ||
40 | |||
30 | struct dvb_pll_desc dvb_pll_thomson_dtt7579 = { | 41 | struct dvb_pll_desc dvb_pll_thomson_dtt7579 = { |
31 | .name = "Thomson dtt7579", | 42 | .name = "Thomson dtt7579", |
32 | .min = 177000000, | 43 | .min = 177000000, |
33 | .max = 858000000, | 44 | .max = 858000000, |
34 | .count = 5, | 45 | .iffreq= 36166667, |
46 | .sleepdata = (u8[]){ 2, 0xb4, 0x03 }, | ||
47 | .count = 4, | ||
35 | .entries = { | 48 | .entries = { |
36 | { 0, 36166667, 166666, 0xb4, 0x03 }, /* go sleep */ | 49 | { 443250000, 166667, 0xb4, 0x02 }, |
37 | { 443250000, 36166667, 166666, 0xb4, 0x02 }, | 50 | { 542000000, 166667, 0xb4, 0x08 }, |
38 | { 542000000, 36166667, 166666, 0xb4, 0x08 }, | 51 | { 771000000, 166667, 0xbc, 0x08 }, |
39 | { 771000000, 36166667, 166666, 0xbc, 0x08 }, | 52 | { 999999999, 166667, 0xf4, 0x08 }, |
40 | { 999999999, 36166667, 166666, 0xf4, 0x08 }, | ||
41 | }, | 53 | }, |
42 | }; | 54 | }; |
43 | EXPORT_SYMBOL(dvb_pll_thomson_dtt7579); | 55 | EXPORT_SYMBOL(dvb_pll_thomson_dtt7579); |
@@ -46,11 +58,12 @@ struct dvb_pll_desc dvb_pll_thomson_dtt7610 = { | |||
46 | .name = "Thomson dtt7610", | 58 | .name = "Thomson dtt7610", |
47 | .min = 44000000, | 59 | .min = 44000000, |
48 | .max = 958000000, | 60 | .max = 958000000, |
61 | .iffreq= 44000000, | ||
49 | .count = 3, | 62 | .count = 3, |
50 | .entries = { | 63 | .entries = { |
51 | { 157250000, 44000000, 62500, 0x8e, 0x39 }, | 64 | { 157250000, 62500, 0x8e, 0x39 }, |
52 | { 454000000, 44000000, 62500, 0x8e, 0x3a }, | 65 | { 454000000, 62500, 0x8e, 0x3a }, |
53 | { 999999999, 44000000, 62500, 0x8e, 0x3c }, | 66 | { 999999999, 62500, 0x8e, 0x3c }, |
54 | }, | 67 | }, |
55 | }; | 68 | }; |
56 | EXPORT_SYMBOL(dvb_pll_thomson_dtt7610); | 69 | EXPORT_SYMBOL(dvb_pll_thomson_dtt7610); |
@@ -66,14 +79,15 @@ struct dvb_pll_desc dvb_pll_thomson_dtt759x = { | |||
66 | .min = 177000000, | 79 | .min = 177000000, |
67 | .max = 896000000, | 80 | .max = 896000000, |
68 | .setbw = thomson_dtt759x_bw, | 81 | .setbw = thomson_dtt759x_bw, |
69 | .count = 6, | 82 | .iffreq= 36166667, |
83 | .sleepdata = (u8[]){ 2, 0x84, 0x03 }, | ||
84 | .count = 5, | ||
70 | .entries = { | 85 | .entries = { |
71 | { 0, 36166667, 166666, 0x84, 0x03 }, | 86 | { 264000000, 166667, 0xb4, 0x02 }, |
72 | { 264000000, 36166667, 166666, 0xb4, 0x02 }, | 87 | { 470000000, 166667, 0xbc, 0x02 }, |
73 | { 470000000, 36166667, 166666, 0xbc, 0x02 }, | 88 | { 735000000, 166667, 0xbc, 0x08 }, |
74 | { 735000000, 36166667, 166666, 0xbc, 0x08 }, | 89 | { 835000000, 166667, 0xf4, 0x08 }, |
75 | { 835000000, 36166667, 166666, 0xf4, 0x08 }, | 90 | { 999999999, 166667, 0xfc, 0x08 }, |
76 | { 999999999, 36166667, 166666, 0xfc, 0x08 }, | ||
77 | }, | 91 | }, |
78 | }; | 92 | }; |
79 | EXPORT_SYMBOL(dvb_pll_thomson_dtt759x); | 93 | EXPORT_SYMBOL(dvb_pll_thomson_dtt759x); |
@@ -82,14 +96,15 @@ struct dvb_pll_desc dvb_pll_lg_z201 = { | |||
82 | .name = "LG z201", | 96 | .name = "LG z201", |
83 | .min = 174000000, | 97 | .min = 174000000, |
84 | .max = 862000000, | 98 | .max = 862000000, |
85 | .count = 6, | 99 | .iffreq= 36166667, |
100 | .sleepdata = (u8[]){ 2, 0xbc, 0x03 }, | ||
101 | .count = 5, | ||
86 | .entries = { | 102 | .entries = { |
87 | { 0, 36166667, 166666, 0xbc, 0x03 }, | 103 | { 157500000, 166667, 0xbc, 0x01 }, |
88 | { 157500000, 36166667, 166666, 0xbc, 0x01 }, | 104 | { 443250000, 166667, 0xbc, 0x02 }, |
89 | { 443250000, 36166667, 166666, 0xbc, 0x02 }, | 105 | { 542000000, 166667, 0xbc, 0x04 }, |
90 | { 542000000, 36166667, 166666, 0xbc, 0x04 }, | 106 | { 830000000, 166667, 0xf4, 0x04 }, |
91 | { 830000000, 36166667, 166666, 0xf4, 0x04 }, | 107 | { 999999999, 166667, 0xfc, 0x04 }, |
92 | { 999999999, 36166667, 166666, 0xfc, 0x04 }, | ||
93 | }, | 108 | }, |
94 | }; | 109 | }; |
95 | EXPORT_SYMBOL(dvb_pll_lg_z201); | 110 | EXPORT_SYMBOL(dvb_pll_lg_z201); |
@@ -98,11 +113,12 @@ struct dvb_pll_desc dvb_pll_microtune_4042 = { | |||
98 | .name = "Microtune 4042 FI5", | 113 | .name = "Microtune 4042 FI5", |
99 | .min = 57000000, | 114 | .min = 57000000, |
100 | .max = 858000000, | 115 | .max = 858000000, |
116 | .iffreq= 44000000, | ||
101 | .count = 3, | 117 | .count = 3, |
102 | .entries = { | 118 | .entries = { |
103 | { 162000000, 44000000, 62500, 0x8e, 0xa1 }, | 119 | { 162000000, 62500, 0x8e, 0xa1 }, |
104 | { 457000000, 44000000, 62500, 0x8e, 0x91 }, | 120 | { 457000000, 62500, 0x8e, 0x91 }, |
105 | { 999999999, 44000000, 62500, 0x8e, 0x31 }, | 121 | { 999999999, 62500, 0x8e, 0x31 }, |
106 | }, | 122 | }, |
107 | }; | 123 | }; |
108 | EXPORT_SYMBOL(dvb_pll_microtune_4042); | 124 | EXPORT_SYMBOL(dvb_pll_microtune_4042); |
@@ -112,11 +128,13 @@ struct dvb_pll_desc dvb_pll_thomson_dtt761x = { | |||
112 | .name = "Thomson dtt761x", | 128 | .name = "Thomson dtt761x", |
113 | .min = 57000000, | 129 | .min = 57000000, |
114 | .max = 863000000, | 130 | .max = 863000000, |
131 | .iffreq= 44000000, | ||
115 | .count = 3, | 132 | .count = 3, |
133 | .initdata = tua603x_agc103, | ||
116 | .entries = { | 134 | .entries = { |
117 | { 147000000, 44000000, 62500, 0x8e, 0x39 }, | 135 | { 147000000, 62500, 0x8e, 0x39 }, |
118 | { 417000000, 44000000, 62500, 0x8e, 0x3a }, | 136 | { 417000000, 62500, 0x8e, 0x3a }, |
119 | { 999999999, 44000000, 62500, 0x8e, 0x3c }, | 137 | { 999999999, 62500, 0x8e, 0x3c }, |
120 | }, | 138 | }, |
121 | }; | 139 | }; |
122 | EXPORT_SYMBOL(dvb_pll_thomson_dtt761x); | 140 | EXPORT_SYMBOL(dvb_pll_thomson_dtt761x); |
@@ -125,17 +143,18 @@ struct dvb_pll_desc dvb_pll_unknown_1 = { | |||
125 | .name = "unknown 1", /* used by dntv live dvb-t */ | 143 | .name = "unknown 1", /* used by dntv live dvb-t */ |
126 | .min = 174000000, | 144 | .min = 174000000, |
127 | .max = 862000000, | 145 | .max = 862000000, |
146 | .iffreq= 36166667, | ||
128 | .count = 9, | 147 | .count = 9, |
129 | .entries = { | 148 | .entries = { |
130 | { 150000000, 36166667, 166666, 0xb4, 0x01 }, | 149 | { 150000000, 166667, 0xb4, 0x01 }, |
131 | { 173000000, 36166667, 166666, 0xbc, 0x01 }, | 150 | { 173000000, 166667, 0xbc, 0x01 }, |
132 | { 250000000, 36166667, 166666, 0xb4, 0x02 }, | 151 | { 250000000, 166667, 0xb4, 0x02 }, |
133 | { 400000000, 36166667, 166666, 0xbc, 0x02 }, | 152 | { 400000000, 166667, 0xbc, 0x02 }, |
134 | { 420000000, 36166667, 166666, 0xf4, 0x02 }, | 153 | { 420000000, 166667, 0xf4, 0x02 }, |
135 | { 470000000, 36166667, 166666, 0xfc, 0x02 }, | 154 | { 470000000, 166667, 0xfc, 0x02 }, |
136 | { 600000000, 36166667, 166666, 0xbc, 0x08 }, | 155 | { 600000000, 166667, 0xbc, 0x08 }, |
137 | { 730000000, 36166667, 166666, 0xf4, 0x08 }, | 156 | { 730000000, 166667, 0xf4, 0x08 }, |
138 | { 999999999, 36166667, 166666, 0xfc, 0x08 }, | 157 | { 999999999, 166667, 0xfc, 0x08 }, |
139 | }, | 158 | }, |
140 | }; | 159 | }; |
141 | EXPORT_SYMBOL(dvb_pll_unknown_1); | 160 | EXPORT_SYMBOL(dvb_pll_unknown_1); |
@@ -147,11 +166,12 @@ struct dvb_pll_desc dvb_pll_tua6010xs = { | |||
147 | .name = "Infineon TUA6010XS", | 166 | .name = "Infineon TUA6010XS", |
148 | .min = 44250000, | 167 | .min = 44250000, |
149 | .max = 858000000, | 168 | .max = 858000000, |
169 | .iffreq= 36125000, | ||
150 | .count = 3, | 170 | .count = 3, |
151 | .entries = { | 171 | .entries = { |
152 | { 115750000, 36125000, 62500, 0x8e, 0x03 }, | 172 | { 115750000, 62500, 0x8e, 0x03 }, |
153 | { 403250000, 36125000, 62500, 0x8e, 0x06 }, | 173 | { 403250000, 62500, 0x8e, 0x06 }, |
154 | { 999999999, 36125000, 62500, 0x8e, 0x85 }, | 174 | { 999999999, 62500, 0x8e, 0x85 }, |
155 | }, | 175 | }, |
156 | }; | 176 | }; |
157 | EXPORT_SYMBOL(dvb_pll_tua6010xs); | 177 | EXPORT_SYMBOL(dvb_pll_tua6010xs); |
@@ -161,12 +181,13 @@ struct dvb_pll_desc dvb_pll_env57h1xd5 = { | |||
161 | .name = "Panasonic ENV57H1XD5", | 181 | .name = "Panasonic ENV57H1XD5", |
162 | .min = 44250000, | 182 | .min = 44250000, |
163 | .max = 858000000, | 183 | .max = 858000000, |
184 | .iffreq= 36125000, | ||
164 | .count = 4, | 185 | .count = 4, |
165 | .entries = { | 186 | .entries = { |
166 | { 153000000, 36291666, 166666, 0xc2, 0x41 }, | 187 | { 153000000, 166667, 0xc2, 0x41 }, |
167 | { 470000000, 36291666, 166666, 0xc2, 0x42 }, | 188 | { 470000000, 166667, 0xc2, 0x42 }, |
168 | { 526000000, 36291666, 166666, 0xc2, 0x84 }, | 189 | { 526000000, 166667, 0xc2, 0x84 }, |
169 | { 999999999, 36291666, 166666, 0xc2, 0xa4 }, | 190 | { 999999999, 166667, 0xc2, 0xa4 }, |
170 | }, | 191 | }, |
171 | }; | 192 | }; |
172 | EXPORT_SYMBOL(dvb_pll_env57h1xd5); | 193 | EXPORT_SYMBOL(dvb_pll_env57h1xd5); |
@@ -185,20 +206,21 @@ struct dvb_pll_desc dvb_pll_tda665x = { | |||
185 | .min = 44250000, | 206 | .min = 44250000, |
186 | .max = 858000000, | 207 | .max = 858000000, |
187 | .setbw = tda665x_bw, | 208 | .setbw = tda665x_bw, |
209 | .iffreq= 36166667, | ||
188 | .count = 12, | 210 | .count = 12, |
189 | .entries = { | 211 | .entries = { |
190 | { 93834000, 36249333, 166667, 0xca, 0x61 /* 011 0 0 0 01 */ }, | 212 | { 93834000, 166667, 0xca, 0x61 /* 011 0 0 0 01 */ }, |
191 | { 123834000, 36249333, 166667, 0xca, 0xa1 /* 101 0 0 0 01 */ }, | 213 | { 123834000, 166667, 0xca, 0xa1 /* 101 0 0 0 01 */ }, |
192 | { 161000000, 36249333, 166667, 0xca, 0xa1 /* 101 0 0 0 01 */ }, | 214 | { 161000000, 166667, 0xca, 0xa1 /* 101 0 0 0 01 */ }, |
193 | { 163834000, 36249333, 166667, 0xca, 0xc2 /* 110 0 0 0 10 */ }, | 215 | { 163834000, 166667, 0xca, 0xc2 /* 110 0 0 0 10 */ }, |
194 | { 253834000, 36249333, 166667, 0xca, 0x62 /* 011 0 0 0 10 */ }, | 216 | { 253834000, 166667, 0xca, 0x62 /* 011 0 0 0 10 */ }, |
195 | { 383834000, 36249333, 166667, 0xca, 0xa2 /* 101 0 0 0 10 */ }, | 217 | { 383834000, 166667, 0xca, 0xa2 /* 101 0 0 0 10 */ }, |
196 | { 443834000, 36249333, 166667, 0xca, 0xc2 /* 110 0 0 0 10 */ }, | 218 | { 443834000, 166667, 0xca, 0xc2 /* 110 0 0 0 10 */ }, |
197 | { 444000000, 36249333, 166667, 0xca, 0xc4 /* 110 0 0 1 00 */ }, | 219 | { 444000000, 166667, 0xca, 0xc4 /* 110 0 0 1 00 */ }, |
198 | { 583834000, 36249333, 166667, 0xca, 0x64 /* 011 0 0 1 00 */ }, | 220 | { 583834000, 166667, 0xca, 0x64 /* 011 0 0 1 00 */ }, |
199 | { 793834000, 36249333, 166667, 0xca, 0xa4 /* 101 0 0 1 00 */ }, | 221 | { 793834000, 166667, 0xca, 0xa4 /* 101 0 0 1 00 */ }, |
200 | { 444834000, 36249333, 166667, 0xca, 0xc4 /* 110 0 0 1 00 */ }, | 222 | { 444834000, 166667, 0xca, 0xc4 /* 110 0 0 1 00 */ }, |
201 | { 861000000, 36249333, 166667, 0xca, 0xe4 /* 111 0 0 1 00 */ }, | 223 | { 861000000, 166667, 0xca, 0xe4 /* 111 0 0 1 00 */ }, |
202 | } | 224 | } |
203 | }; | 225 | }; |
204 | EXPORT_SYMBOL(dvb_pll_tda665x); | 226 | EXPORT_SYMBOL(dvb_pll_tda665x); |
@@ -216,12 +238,13 @@ struct dvb_pll_desc dvb_pll_tua6034 = { | |||
216 | .name = "Infineon TUA6034", | 238 | .name = "Infineon TUA6034", |
217 | .min = 44250000, | 239 | .min = 44250000, |
218 | .max = 858000000, | 240 | .max = 858000000, |
241 | .iffreq= 36166667, | ||
219 | .count = 3, | 242 | .count = 3, |
220 | .setbw = tua6034_bw, | 243 | .setbw = tua6034_bw, |
221 | .entries = { | 244 | .entries = { |
222 | { 174500000, 36166667, 62500, 0xce, 0x01 }, | 245 | { 174500000, 62500, 0xce, 0x01 }, |
223 | { 230000000, 36166667, 62500, 0xce, 0x02 }, | 246 | { 230000000, 62500, 0xce, 0x02 }, |
224 | { 999999999, 36166667, 62500, 0xce, 0x04 }, | 247 | { 999999999, 62500, 0xce, 0x04 }, |
225 | }, | 248 | }, |
226 | }; | 249 | }; |
227 | EXPORT_SYMBOL(dvb_pll_tua6034); | 250 | EXPORT_SYMBOL(dvb_pll_tua6034); |
@@ -233,11 +256,13 @@ struct dvb_pll_desc dvb_pll_lg_tdvs_h06xf = { | |||
233 | .name = "LG TDVS-H06xF", | 256 | .name = "LG TDVS-H06xF", |
234 | .min = 54000000, | 257 | .min = 54000000, |
235 | .max = 863000000, | 258 | .max = 863000000, |
259 | .iffreq= 44000000, | ||
260 | .initdata = tua603x_agc103, | ||
236 | .count = 3, | 261 | .count = 3, |
237 | .entries = { | 262 | .entries = { |
238 | { 165000000, 44000000, 62500, 0xce, 0x01 }, | 263 | { 165000000, 62500, 0xce, 0x01 }, |
239 | { 450000000, 44000000, 62500, 0xce, 0x02 }, | 264 | { 450000000, 62500, 0xce, 0x02 }, |
240 | { 999999999, 44000000, 62500, 0xce, 0x04 }, | 265 | { 999999999, 62500, 0xce, 0x04 }, |
241 | }, | 266 | }, |
242 | }; | 267 | }; |
243 | EXPORT_SYMBOL(dvb_pll_lg_tdvs_h06xf); | 268 | EXPORT_SYMBOL(dvb_pll_lg_tdvs_h06xf); |
@@ -255,16 +280,17 @@ struct dvb_pll_desc dvb_pll_fmd1216me = { | |||
255 | .name = "Philips FMD1216ME", | 280 | .name = "Philips FMD1216ME", |
256 | .min = 50870000, | 281 | .min = 50870000, |
257 | .max = 858000000, | 282 | .max = 858000000, |
283 | .iffreq= 36125000, | ||
258 | .setbw = fmd1216me_bw, | 284 | .setbw = fmd1216me_bw, |
259 | .count = 7, | 285 | .count = 7, |
260 | .entries = { | 286 | .entries = { |
261 | { 143870000, 36213333, 166667, 0xbc, 0x41 }, | 287 | { 143870000, 166667, 0xbc, 0x41 }, |
262 | { 158870000, 36213333, 166667, 0xf4, 0x41 }, | 288 | { 158870000, 166667, 0xf4, 0x41 }, |
263 | { 329870000, 36213333, 166667, 0xbc, 0x42 }, | 289 | { 329870000, 166667, 0xbc, 0x42 }, |
264 | { 441870000, 36213333, 166667, 0xf4, 0x42 }, | 290 | { 441870000, 166667, 0xf4, 0x42 }, |
265 | { 625870000, 36213333, 166667, 0xbc, 0x44 }, | 291 | { 625870000, 166667, 0xbc, 0x44 }, |
266 | { 803870000, 36213333, 166667, 0xf4, 0x44 }, | 292 | { 803870000, 166667, 0xf4, 0x44 }, |
267 | { 999999999, 36213333, 166667, 0xfc, 0x44 }, | 293 | { 999999999, 166667, 0xfc, 0x44 }, |
268 | } | 294 | } |
269 | }; | 295 | }; |
270 | EXPORT_SYMBOL(dvb_pll_fmd1216me); | 296 | EXPORT_SYMBOL(dvb_pll_fmd1216me); |
@@ -282,13 +308,14 @@ struct dvb_pll_desc dvb_pll_tded4 = { | |||
282 | .name = "ALPS TDED4", | 308 | .name = "ALPS TDED4", |
283 | .min = 47000000, | 309 | .min = 47000000, |
284 | .max = 863000000, | 310 | .max = 863000000, |
311 | .iffreq= 36166667, | ||
285 | .setbw = tded4_bw, | 312 | .setbw = tded4_bw, |
286 | .count = 4, | 313 | .count = 4, |
287 | .entries = { | 314 | .entries = { |
288 | { 153000000, 36166667, 166667, 0x85, 0x01 }, | 315 | { 153000000, 166667, 0x85, 0x01 }, |
289 | { 470000000, 36166667, 166667, 0x85, 0x02 }, | 316 | { 470000000, 166667, 0x85, 0x02 }, |
290 | { 823000000, 36166667, 166667, 0x85, 0x08 }, | 317 | { 823000000, 166667, 0x85, 0x08 }, |
291 | { 999999999, 36166667, 166667, 0x85, 0x88 }, | 318 | { 999999999, 166667, 0x85, 0x88 }, |
292 | } | 319 | } |
293 | }; | 320 | }; |
294 | EXPORT_SYMBOL(dvb_pll_tded4); | 321 | EXPORT_SYMBOL(dvb_pll_tded4); |
@@ -300,12 +327,13 @@ struct dvb_pll_desc dvb_pll_tdhu2 = { | |||
300 | .name = "ALPS TDHU2", | 327 | .name = "ALPS TDHU2", |
301 | .min = 54000000, | 328 | .min = 54000000, |
302 | .max = 864000000, | 329 | .max = 864000000, |
330 | .iffreq= 44000000, | ||
303 | .count = 4, | 331 | .count = 4, |
304 | .entries = { | 332 | .entries = { |
305 | { 162000000, 44000000, 62500, 0x85, 0x01 }, | 333 | { 162000000, 62500, 0x85, 0x01 }, |
306 | { 426000000, 44000000, 62500, 0x85, 0x02 }, | 334 | { 426000000, 62500, 0x85, 0x02 }, |
307 | { 782000000, 44000000, 62500, 0x85, 0x08 }, | 335 | { 782000000, 62500, 0x85, 0x08 }, |
308 | { 999999999, 44000000, 62500, 0x85, 0x88 }, | 336 | { 999999999, 62500, 0x85, 0x88 }, |
309 | } | 337 | } |
310 | }; | 338 | }; |
311 | EXPORT_SYMBOL(dvb_pll_tdhu2); | 339 | EXPORT_SYMBOL(dvb_pll_tdhu2); |
@@ -317,11 +345,12 @@ struct dvb_pll_desc dvb_pll_tuv1236d = { | |||
317 | .name = "Philips TUV1236D", | 345 | .name = "Philips TUV1236D", |
318 | .min = 54000000, | 346 | .min = 54000000, |
319 | .max = 864000000, | 347 | .max = 864000000, |
348 | .iffreq= 44000000, | ||
320 | .count = 3, | 349 | .count = 3, |
321 | .entries = { | 350 | .entries = { |
322 | { 157250000, 44000000, 62500, 0xc6, 0x41 }, | 351 | { 157250000, 62500, 0xc6, 0x41 }, |
323 | { 454000000, 44000000, 62500, 0xc6, 0x42 }, | 352 | { 454000000, 62500, 0xc6, 0x42 }, |
324 | { 999999999, 44000000, 62500, 0xc6, 0x44 }, | 353 | { 999999999, 62500, 0xc6, 0x44 }, |
325 | }, | 354 | }, |
326 | }; | 355 | }; |
327 | EXPORT_SYMBOL(dvb_pll_tuv1236d); | 356 | EXPORT_SYMBOL(dvb_pll_tuv1236d); |
@@ -333,14 +362,15 @@ struct dvb_pll_desc dvb_pll_samsung_tbmv = { | |||
333 | .name = "Samsung TBMV30111IN / TBMV30712IN1", | 362 | .name = "Samsung TBMV30111IN / TBMV30712IN1", |
334 | .min = 54000000, | 363 | .min = 54000000, |
335 | .max = 860000000, | 364 | .max = 860000000, |
365 | .iffreq= 44000000, | ||
336 | .count = 6, | 366 | .count = 6, |
337 | .entries = { | 367 | .entries = { |
338 | { 172000000, 44000000, 166666, 0xb4, 0x01 }, | 368 | { 172000000, 166667, 0xb4, 0x01 }, |
339 | { 214000000, 44000000, 166666, 0xb4, 0x02 }, | 369 | { 214000000, 166667, 0xb4, 0x02 }, |
340 | { 467000000, 44000000, 166666, 0xbc, 0x02 }, | 370 | { 467000000, 166667, 0xbc, 0x02 }, |
341 | { 721000000, 44000000, 166666, 0xbc, 0x08 }, | 371 | { 721000000, 166667, 0xbc, 0x08 }, |
342 | { 841000000, 44000000, 166666, 0xf4, 0x08 }, | 372 | { 841000000, 166667, 0xf4, 0x08 }, |
343 | { 999999999, 44000000, 166666, 0xfc, 0x02 }, | 373 | { 999999999, 166667, 0xfc, 0x02 }, |
344 | } | 374 | } |
345 | }; | 375 | }; |
346 | EXPORT_SYMBOL(dvb_pll_samsung_tbmv); | 376 | EXPORT_SYMBOL(dvb_pll_samsung_tbmv); |
@@ -352,12 +382,13 @@ struct dvb_pll_desc dvb_pll_philips_sd1878_tda8261 = { | |||
352 | .name = "Philips SD1878", | 382 | .name = "Philips SD1878", |
353 | .min = 950000, | 383 | .min = 950000, |
354 | .max = 2150000, | 384 | .max = 2150000, |
385 | .iffreq= 249, /* zero-IF, offset 249 is to round up */ | ||
355 | .count = 4, | 386 | .count = 4, |
356 | .entries = { | 387 | .entries = { |
357 | { 1250000, 499, 500, 0xc4, 0x00}, | 388 | { 1250000, 500, 0xc4, 0x00}, |
358 | { 1550000, 499, 500, 0xc4, 0x40}, | 389 | { 1550000, 500, 0xc4, 0x40}, |
359 | { 2050000, 499, 500, 0xc4, 0x80}, | 390 | { 2050000, 500, 0xc4, 0x80}, |
360 | { 2150000, 499, 500, 0xc4, 0xc0}, | 391 | { 2150000, 500, 0xc4, 0xc0}, |
361 | }, | 392 | }, |
362 | }; | 393 | }; |
363 | EXPORT_SYMBOL(dvb_pll_philips_sd1878_tda8261); | 394 | EXPORT_SYMBOL(dvb_pll_philips_sd1878_tda8261); |
@@ -388,18 +419,19 @@ struct dvb_pll_desc dvb_pll_philips_td1316 = { | |||
388 | .name = "Philips TD1316", | 419 | .name = "Philips TD1316", |
389 | .min = 87000000, | 420 | .min = 87000000, |
390 | .max = 895000000, | 421 | .max = 895000000, |
422 | .iffreq= 36166667, | ||
391 | .setbw = td1316_bw, | 423 | .setbw = td1316_bw, |
392 | .count = 9, | 424 | .count = 9, |
393 | .entries = { | 425 | .entries = { |
394 | { 93834000, 36166000, 166666, 0xca, 0x60}, | 426 | { 93834000, 166667, 0xca, 0x60}, |
395 | { 123834000, 36166000, 166666, 0xca, 0xa0}, | 427 | { 123834000, 166667, 0xca, 0xa0}, |
396 | { 163834000, 36166000, 166666, 0xca, 0xc0}, | 428 | { 163834000, 166667, 0xca, 0xc0}, |
397 | { 253834000, 36166000, 166666, 0xca, 0x60}, | 429 | { 253834000, 166667, 0xca, 0x60}, |
398 | { 383834000, 36166000, 166666, 0xca, 0xa0}, | 430 | { 383834000, 166667, 0xca, 0xa0}, |
399 | { 443834000, 36166000, 166666, 0xca, 0xc0}, | 431 | { 443834000, 166667, 0xca, 0xc0}, |
400 | { 583834000, 36166000, 166666, 0xca, 0x60}, | 432 | { 583834000, 166667, 0xca, 0x60}, |
401 | { 793834000, 36166000, 166666, 0xca, 0xa0}, | 433 | { 793834000, 166667, 0xca, 0xa0}, |
402 | { 858834000, 36166000, 166666, 0xca, 0xe0}, | 434 | { 858834000, 166667, 0xca, 0xe0}, |
403 | }, | 435 | }, |
404 | }; | 436 | }; |
405 | EXPORT_SYMBOL(dvb_pll_philips_td1316); | 437 | EXPORT_SYMBOL(dvb_pll_philips_td1316); |
@@ -409,15 +441,41 @@ struct dvb_pll_desc dvb_pll_thomson_fe6600 = { | |||
409 | .name = "Thomson FE6600", | 441 | .name = "Thomson FE6600", |
410 | .min = 44250000, | 442 | .min = 44250000, |
411 | .max = 858000000, | 443 | .max = 858000000, |
444 | .iffreq= 36125000, | ||
412 | .count = 4, | 445 | .count = 4, |
413 | .entries = { | 446 | .entries = { |
414 | { 250000000, 36213333, 166667, 0xb4, 0x12 }, | 447 | { 250000000, 166667, 0xb4, 0x12 }, |
415 | { 455000000, 36213333, 166667, 0xfe, 0x11 }, | 448 | { 455000000, 166667, 0xfe, 0x11 }, |
416 | { 775500000, 36213333, 166667, 0xbc, 0x18 }, | 449 | { 775500000, 166667, 0xbc, 0x18 }, |
417 | { 999999999, 36213333, 166667, 0xf4, 0x18 }, | 450 | { 999999999, 166667, 0xf4, 0x18 }, |
418 | } | 451 | } |
419 | }; | 452 | }; |
420 | EXPORT_SYMBOL(dvb_pll_thomson_fe6600); | 453 | EXPORT_SYMBOL(dvb_pll_thomson_fe6600); |
454 | static void opera1_bw(u8 *buf, u32 freq, int bandwidth) | ||
455 | { | ||
456 | if (bandwidth == BANDWIDTH_8_MHZ) | ||
457 | buf[2] |= 0x08; | ||
458 | } | ||
459 | |||
460 | struct dvb_pll_desc dvb_pll_opera1 = { | ||
461 | .name = "Opera Tuner", | ||
462 | .min = 900000, | ||
463 | .max = 2250000, | ||
464 | .iffreq= 0, | ||
465 | .setbw = opera1_bw, | ||
466 | .count = 8, | ||
467 | .entries = { | ||
468 | { 1064000, 500, 0xe5, 0xc6 }, | ||
469 | { 1169000, 500, 0xe5, 0xe6 }, | ||
470 | { 1299000, 500, 0xe5, 0x24 }, | ||
471 | { 1444000, 500, 0xe5, 0x44 }, | ||
472 | { 1606000, 500, 0xe5, 0x64 }, | ||
473 | { 1777000, 500, 0xe5, 0x84 }, | ||
474 | { 1941000, 500, 0xe5, 0xa4 }, | ||
475 | { 2250000, 500, 0xe5, 0xc4 }, | ||
476 | } | ||
477 | }; | ||
478 | EXPORT_SYMBOL(dvb_pll_opera1); | ||
421 | 479 | ||
422 | struct dvb_pll_priv { | 480 | struct dvb_pll_priv { |
423 | /* i2c details */ | 481 | /* i2c details */ |
@@ -459,7 +517,8 @@ int dvb_pll_configure(struct dvb_pll_desc *desc, u8 *buf, | |||
459 | if (i == desc->count) | 517 | if (i == desc->count) |
460 | return -EINVAL; | 518 | return -EINVAL; |
461 | 519 | ||
462 | div = (freq + desc->entries[i].offset) / desc->entries[i].stepsize; | 520 | div = (freq + desc->iffreq + desc->entries[i].stepsize/2) / |
521 | desc->entries[i].stepsize; | ||
463 | buf[0] = div >> 8; | 522 | buf[0] = div >> 8; |
464 | buf[1] = div & 0xff; | 523 | buf[1] = div & 0xff; |
465 | buf[2] = desc->entries[i].config; | 524 | buf[2] = desc->entries[i].config; |
@@ -473,7 +532,7 @@ int dvb_pll_configure(struct dvb_pll_desc *desc, u8 *buf, | |||
473 | desc->name, div, buf[0], buf[1], buf[2], buf[3]); | 532 | desc->name, div, buf[0], buf[1], buf[2], buf[3]); |
474 | 533 | ||
475 | // calculate the frequency we set it to | 534 | // calculate the frequency we set it to |
476 | return (div * desc->entries[i].stepsize) - desc->entries[i].offset; | 535 | return (div * desc->entries[i].stepsize) - desc->iffreq; |
477 | } | 536 | } |
478 | EXPORT_SYMBOL(dvb_pll_configure); | 537 | EXPORT_SYMBOL(dvb_pll_configure); |
479 | 538 | ||
@@ -487,35 +546,27 @@ static int dvb_pll_release(struct dvb_frontend *fe) | |||
487 | static int dvb_pll_sleep(struct dvb_frontend *fe) | 546 | static int dvb_pll_sleep(struct dvb_frontend *fe) |
488 | { | 547 | { |
489 | struct dvb_pll_priv *priv = fe->tuner_priv; | 548 | struct dvb_pll_priv *priv = fe->tuner_priv; |
490 | u8 buf[4]; | ||
491 | struct i2c_msg msg = | ||
492 | { .addr = priv->pll_i2c_address, .flags = 0, | ||
493 | .buf = buf, .len = sizeof(buf) }; | ||
494 | int i; | ||
495 | int result; | ||
496 | 549 | ||
497 | if (priv->i2c == NULL) | 550 | if (priv->i2c == NULL) |
498 | return -EINVAL; | 551 | return -EINVAL; |
499 | 552 | ||
500 | for (i = 0; i < priv->pll_desc->count; i++) { | 553 | if (priv->pll_desc->sleepdata) { |
501 | if (priv->pll_desc->entries[i].limit == 0) | 554 | struct i2c_msg msg = { .flags = 0, |
502 | break; | 555 | .addr = priv->pll_i2c_address, |
503 | } | 556 | .buf = priv->pll_desc->sleepdata + 1, |
504 | if (i == priv->pll_desc->count) | 557 | .len = priv->pll_desc->sleepdata[0] }; |
505 | return 0; | ||
506 | 558 | ||
507 | buf[0] = 0; | 559 | int result; |
508 | buf[1] = 0; | ||
509 | buf[2] = priv->pll_desc->entries[i].config; | ||
510 | buf[3] = priv->pll_desc->entries[i].cb; | ||
511 | 560 | ||
512 | if (fe->ops.i2c_gate_ctrl) | 561 | if (fe->ops.i2c_gate_ctrl) |
513 | fe->ops.i2c_gate_ctrl(fe, 1); | 562 | fe->ops.i2c_gate_ctrl(fe, 1); |
514 | if ((result = i2c_transfer(priv->i2c, &msg, 1)) != 1) { | 563 | if ((result = i2c_transfer(priv->i2c, &msg, 1)) != 1) { |
515 | return result; | 564 | return result; |
565 | } | ||
566 | return 0; | ||
516 | } | 567 | } |
517 | 568 | /* Shouldn't be called when initdata is NULL, maybe BUG()? */ | |
518 | return 0; | 569 | return -EINVAL; |
519 | } | 570 | } |
520 | 571 | ||
521 | static int dvb_pll_set_params(struct dvb_frontend *fe, | 572 | static int dvb_pll_set_params(struct dvb_frontend *fe, |
@@ -599,9 +650,35 @@ static int dvb_pll_get_bandwidth(struct dvb_frontend *fe, u32 *bandwidth) | |||
599 | return 0; | 650 | return 0; |
600 | } | 651 | } |
601 | 652 | ||
653 | static int dvb_pll_init(struct dvb_frontend *fe) | ||
654 | { | ||
655 | struct dvb_pll_priv *priv = fe->tuner_priv; | ||
656 | |||
657 | if (priv->i2c == NULL) | ||
658 | return -EINVAL; | ||
659 | |||
660 | if (priv->pll_desc->initdata) { | ||
661 | struct i2c_msg msg = { .flags = 0, | ||
662 | .addr = priv->pll_i2c_address, | ||
663 | .buf = priv->pll_desc->initdata + 1, | ||
664 | .len = priv->pll_desc->initdata[0] }; | ||
665 | |||
666 | int result; | ||
667 | if (fe->ops.i2c_gate_ctrl) | ||
668 | fe->ops.i2c_gate_ctrl(fe, 1); | ||
669 | if ((result = i2c_transfer(priv->i2c, &msg, 1)) != 1) { | ||
670 | return result; | ||
671 | } | ||
672 | return 0; | ||
673 | } | ||
674 | /* Shouldn't be called when initdata is NULL, maybe BUG()? */ | ||
675 | return -EINVAL; | ||
676 | } | ||
677 | |||
602 | static struct dvb_tuner_ops dvb_pll_tuner_ops = { | 678 | static struct dvb_tuner_ops dvb_pll_tuner_ops = { |
603 | .release = dvb_pll_release, | 679 | .release = dvb_pll_release, |
604 | .sleep = dvb_pll_sleep, | 680 | .sleep = dvb_pll_sleep, |
681 | .init = dvb_pll_init, | ||
605 | .set_params = dvb_pll_set_params, | 682 | .set_params = dvb_pll_set_params, |
606 | .calc_regs = dvb_pll_calc_regs, | 683 | .calc_regs = dvb_pll_calc_regs, |
607 | .get_frequency = dvb_pll_get_frequency, | 684 | .get_frequency = dvb_pll_get_frequency, |
@@ -640,9 +717,14 @@ struct dvb_frontend *dvb_pll_attach(struct dvb_frontend *fe, int pll_addr, | |||
640 | memcpy(&fe->ops.tuner_ops, &dvb_pll_tuner_ops, | 717 | memcpy(&fe->ops.tuner_ops, &dvb_pll_tuner_ops, |
641 | sizeof(struct dvb_tuner_ops)); | 718 | sizeof(struct dvb_tuner_ops)); |
642 | 719 | ||
643 | strncpy(fe->ops.tuner_ops.info.name, desc->name, 128); | 720 | strncpy(fe->ops.tuner_ops.info.name, desc->name, |
721 | sizeof(fe->ops.tuner_ops.info.name)); | ||
644 | fe->ops.tuner_ops.info.frequency_min = desc->min; | 722 | fe->ops.tuner_ops.info.frequency_min = desc->min; |
645 | fe->ops.tuner_ops.info.frequency_min = desc->max; | 723 | fe->ops.tuner_ops.info.frequency_min = desc->max; |
724 | if (!desc->initdata) | ||
725 | fe->ops.tuner_ops.init = NULL; | ||
726 | if (!desc->sleepdata) | ||
727 | fe->ops.tuner_ops.sleep = NULL; | ||
646 | 728 | ||
647 | fe->tuner_priv = priv; | 729 | fe->tuner_priv = priv; |
648 | return fe; | 730 | return fe; |
diff --git a/drivers/media/dvb/frontends/dvb-pll.h b/drivers/media/dvb/frontends/dvb-pll.h index 681186a5e5eb..5209f46f0893 100644 --- a/drivers/media/dvb/frontends/dvb-pll.h +++ b/drivers/media/dvb/frontends/dvb-pll.h | |||
@@ -12,11 +12,13 @@ struct dvb_pll_desc { | |||
12 | char *name; | 12 | char *name; |
13 | u32 min; | 13 | u32 min; |
14 | u32 max; | 14 | u32 max; |
15 | u32 iffreq; | ||
15 | void (*setbw)(u8 *buf, u32 freq, int bandwidth); | 16 | void (*setbw)(u8 *buf, u32 freq, int bandwidth); |
17 | u8 *initdata; | ||
18 | u8 *sleepdata; | ||
16 | int count; | 19 | int count; |
17 | struct { | 20 | struct { |
18 | u32 limit; | 21 | u32 limit; |
19 | u32 offset; | ||
20 | u32 stepsize; | 22 | u32 stepsize; |
21 | u8 config; | 23 | u8 config; |
22 | u8 cb; | 24 | u8 cb; |
@@ -46,6 +48,7 @@ extern struct dvb_pll_desc dvb_pll_philips_sd1878_tda8261; | |||
46 | extern struct dvb_pll_desc dvb_pll_philips_td1316; | 48 | extern struct dvb_pll_desc dvb_pll_philips_td1316; |
47 | 49 | ||
48 | extern struct dvb_pll_desc dvb_pll_thomson_fe6600; | 50 | extern struct dvb_pll_desc dvb_pll_thomson_fe6600; |
51 | extern struct dvb_pll_desc dvb_pll_opera1; | ||
49 | 52 | ||
50 | extern int dvb_pll_configure(struct dvb_pll_desc *desc, u8 *buf, | 53 | extern int dvb_pll_configure(struct dvb_pll_desc *desc, u8 *buf, |
51 | u32 freq, int bandwidth); | 54 | u32 freq, int bandwidth); |
@@ -59,9 +62,20 @@ extern int dvb_pll_configure(struct dvb_pll_desc *desc, u8 *buf, | |||
59 | * @param desc dvb_pll_desc to use. | 62 | * @param desc dvb_pll_desc to use. |
60 | * @return Frontend pointer on success, NULL on failure | 63 | * @return Frontend pointer on success, NULL on failure |
61 | */ | 64 | */ |
65 | #if defined(CONFIG_DVB_PLL) || (defined(CONFIG_DVB_PLL_MODULE) && defined(MODULE)) | ||
62 | extern struct dvb_frontend *dvb_pll_attach(struct dvb_frontend *fe, | 66 | extern struct dvb_frontend *dvb_pll_attach(struct dvb_frontend *fe, |
63 | int pll_addr, | 67 | int pll_addr, |
64 | struct i2c_adapter *i2c, | 68 | struct i2c_adapter *i2c, |
65 | struct dvb_pll_desc *desc); | 69 | struct dvb_pll_desc *desc); |
70 | #else | ||
71 | static inline struct dvb_frontend *dvb_pll_attach(struct dvb_frontend *fe, | ||
72 | int pll_addr, | ||
73 | struct i2c_adapter *i2c, | ||
74 | struct dvb_pll_desc *desc) | ||
75 | { | ||
76 | printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __FUNCTION__); | ||
77 | return NULL; | ||
78 | } | ||
79 | #endif | ||
66 | 80 | ||
67 | #endif | 81 | #endif |
diff --git a/drivers/media/dvb/frontends/lgdt330x.c b/drivers/media/dvb/frontends/lgdt330x.c index 68aad0f6519f..e25286e2d431 100644 --- a/drivers/media/dvb/frontends/lgdt330x.c +++ b/drivers/media/dvb/frontends/lgdt330x.c | |||
@@ -475,7 +475,7 @@ static int lgdt3302_read_status(struct dvb_frontend* fe, fe_status_t* status) | |||
475 | *status |= FE_HAS_CARRIER; | 475 | *status |= FE_HAS_CARRIER; |
476 | break; | 476 | break; |
477 | default: | 477 | default: |
478 | printk("KERN_WARNING lgdt330x: %s: Modulation set to unsupported value\n", __FUNCTION__); | 478 | printk(KERN_WARNING "lgdt330x: %s: Modulation set to unsupported value\n", __FUNCTION__); |
479 | } | 479 | } |
480 | 480 | ||
481 | return 0; | 481 | return 0; |
@@ -534,7 +534,7 @@ static int lgdt3303_read_status(struct dvb_frontend* fe, fe_status_t* status) | |||
534 | } | 534 | } |
535 | break; | 535 | break; |
536 | default: | 536 | default: |
537 | printk("KERN_WARNING lgdt330x: %s: Modulation set to unsupported value\n", __FUNCTION__); | 537 | printk(KERN_WARNING "lgdt330x: %s: Modulation set to unsupported value\n", __FUNCTION__); |
538 | } | 538 | } |
539 | return 0; | 539 | return 0; |
540 | } | 540 | } |
diff --git a/drivers/media/dvb/frontends/lgh06xf.c b/drivers/media/dvb/frontends/lgh06xf.c deleted file mode 100644 index 2202d0cc878b..000000000000 --- a/drivers/media/dvb/frontends/lgh06xf.c +++ /dev/null | |||
@@ -1,134 +0,0 @@ | |||
1 | /* | ||
2 | * lgh06xf.c - ATSC Tuner support for LG TDVS-H06xF | ||
3 | * | ||
4 | * This program is free software; you can redistribute it and/or modify | ||
5 | * it under the terms of the GNU General Public License as published by | ||
6 | * the Free Software Foundation; either version 2 of the License, or | ||
7 | * (at your option) any later version. | ||
8 | * | ||
9 | * This program is distributed in the hope that it will be useful, | ||
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
12 | * GNU General Public License for more details. | ||
13 | * | ||
14 | * You should have received a copy of the GNU General Public License | ||
15 | * along with this program; if not, write to the Free Software | ||
16 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
17 | */ | ||
18 | |||
19 | #include "dvb-pll.h" | ||
20 | #include "lgh06xf.h" | ||
21 | |||
22 | #define LG_H06XF_PLL_I2C_ADDR 0x61 | ||
23 | |||
24 | struct lgh06xf_priv { | ||
25 | struct i2c_adapter *i2c; | ||
26 | u32 frequency; | ||
27 | }; | ||
28 | |||
29 | static int lgh06xf_release(struct dvb_frontend *fe) | ||
30 | { | ||
31 | kfree(fe->tuner_priv); | ||
32 | fe->tuner_priv = NULL; | ||
33 | return 0; | ||
34 | } | ||
35 | |||
36 | static int lgh06xf_set_params(struct dvb_frontend* fe, | ||
37 | struct dvb_frontend_parameters* params) | ||
38 | { | ||
39 | struct lgh06xf_priv *priv = fe->tuner_priv; | ||
40 | u8 buf[4]; | ||
41 | struct i2c_msg msg = { .addr = LG_H06XF_PLL_I2C_ADDR, .flags = 0, | ||
42 | .buf = buf, .len = sizeof(buf) }; | ||
43 | u32 frequency; | ||
44 | int result; | ||
45 | |||
46 | if ((result = dvb_pll_configure(&dvb_pll_lg_tdvs_h06xf, buf, | ||
47 | params->frequency, 0)) < 0) | ||
48 | return result; | ||
49 | else | ||
50 | frequency = result; | ||
51 | |||
52 | if (fe->ops.i2c_gate_ctrl) | ||
53 | fe->ops.i2c_gate_ctrl(fe, 1); | ||
54 | if ((result = i2c_transfer(priv->i2c, &msg, 1)) != 1) { | ||
55 | printk(KERN_WARNING "lgh06xf: %s error " | ||
56 | "(addr %02x <- %02x, result = %i)\n", | ||
57 | __FUNCTION__, buf[0], buf[1], result); | ||
58 | if (result < 0) | ||
59 | return result; | ||
60 | else | ||
61 | return -EREMOTEIO; | ||
62 | } | ||
63 | |||
64 | /* Set the Auxiliary Byte. */ | ||
65 | buf[0] = buf[2]; | ||
66 | buf[0] &= ~0x20; | ||
67 | buf[0] |= 0x18; | ||
68 | buf[1] = 0x50; | ||
69 | msg.len = 2; | ||
70 | if (fe->ops.i2c_gate_ctrl) | ||
71 | fe->ops.i2c_gate_ctrl(fe, 1); | ||
72 | if ((result = i2c_transfer(priv->i2c, &msg, 1)) != 1) { | ||
73 | printk(KERN_WARNING "lgh06xf: %s error " | ||
74 | "(addr %02x <- %02x, result = %i)\n", | ||
75 | __FUNCTION__, buf[0], buf[1], result); | ||
76 | if (result < 0) | ||
77 | return result; | ||
78 | else | ||
79 | return -EREMOTEIO; | ||
80 | } | ||
81 | |||
82 | priv->frequency = frequency; | ||
83 | |||
84 | return 0; | ||
85 | } | ||
86 | |||
87 | static int lgh06xf_get_frequency(struct dvb_frontend *fe, u32 *frequency) | ||
88 | { | ||
89 | struct lgh06xf_priv *priv = fe->tuner_priv; | ||
90 | *frequency = priv->frequency; | ||
91 | return 0; | ||
92 | } | ||
93 | |||
94 | static struct dvb_tuner_ops lgh06xf_tuner_ops = { | ||
95 | .release = lgh06xf_release, | ||
96 | .set_params = lgh06xf_set_params, | ||
97 | .get_frequency = lgh06xf_get_frequency, | ||
98 | }; | ||
99 | |||
100 | struct dvb_frontend* lgh06xf_attach(struct dvb_frontend *fe, | ||
101 | struct i2c_adapter *i2c) | ||
102 | { | ||
103 | struct lgh06xf_priv *priv = NULL; | ||
104 | |||
105 | priv = kzalloc(sizeof(struct lgh06xf_priv), GFP_KERNEL); | ||
106 | if (priv == NULL) | ||
107 | return NULL; | ||
108 | |||
109 | priv->i2c = i2c; | ||
110 | |||
111 | memcpy(&fe->ops.tuner_ops, &lgh06xf_tuner_ops, | ||
112 | sizeof(struct dvb_tuner_ops)); | ||
113 | |||
114 | strlcpy(fe->ops.tuner_ops.info.name, dvb_pll_lg_tdvs_h06xf.name, | ||
115 | sizeof(fe->ops.tuner_ops.info.name)); | ||
116 | |||
117 | fe->ops.tuner_ops.info.frequency_min = dvb_pll_lg_tdvs_h06xf.min; | ||
118 | fe->ops.tuner_ops.info.frequency_max = dvb_pll_lg_tdvs_h06xf.max; | ||
119 | |||
120 | fe->tuner_priv = priv; | ||
121 | return fe; | ||
122 | } | ||
123 | |||
124 | EXPORT_SYMBOL(lgh06xf_attach); | ||
125 | |||
126 | MODULE_DESCRIPTION("LG TDVS-H06xF ATSC Tuner support"); | ||
127 | MODULE_AUTHOR("Michael Krufky"); | ||
128 | MODULE_LICENSE("GPL"); | ||
129 | |||
130 | /* | ||
131 | * Local variables: | ||
132 | * c-basic-offset: 8 | ||
133 | * End: | ||
134 | */ | ||
diff --git a/drivers/media/dvb/frontends/lgh06xf.h b/drivers/media/dvb/frontends/lgh06xf.h deleted file mode 100644 index 510b4bedfb24..000000000000 --- a/drivers/media/dvb/frontends/lgh06xf.h +++ /dev/null | |||
@@ -1,35 +0,0 @@ | |||
1 | /* | ||
2 | * lgh06xf.h - ATSC Tuner support for LG TDVS-H06xF | ||
3 | * | ||
4 | * This program is free software; you can redistribute it and/or modify | ||
5 | * it under the terms of the GNU General Public License as published by | ||
6 | * the Free Software Foundation; either version 2 of the License, or | ||
7 | * (at your option) any later version. | ||
8 | * | ||
9 | * This program is distributed in the hope that it will be useful, | ||
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
12 | * GNU General Public License for more details. | ||
13 | * | ||
14 | * You should have received a copy of the GNU General Public License | ||
15 | * along with this program; if not, write to the Free Software | ||
16 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
17 | */ | ||
18 | |||
19 | #ifndef _LGH06XF_H_ | ||
20 | #define _LGH06XF_H_ | ||
21 | #include "dvb_frontend.h" | ||
22 | |||
23 | #if defined(CONFIG_DVB_TUNER_LGH06XF) || (defined(CONFIG_DVB_TUNER_LGH06XF_MODULE) && defined(MODULE)) | ||
24 | extern struct dvb_frontend* lgh06xf_attach(struct dvb_frontend* fe, | ||
25 | struct i2c_adapter *i2c); | ||
26 | #else | ||
27 | static inline struct dvb_frontend* lgh06xf_attach(struct dvb_frontend* fe, | ||
28 | struct i2c_adapter *i2c) | ||
29 | { | ||
30 | printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __FUNCTION__); | ||
31 | return NULL; | ||
32 | } | ||
33 | #endif /* CONFIG_DVB_TUNER_LGH06XF */ | ||
34 | |||
35 | #endif /* _LGH06XF_H_ */ | ||
diff --git a/drivers/media/dvb/frontends/or51132.c b/drivers/media/dvb/frontends/or51132.c index 5a3a6e53cda2..4e0aca7c67aa 100644 --- a/drivers/media/dvb/frontends/or51132.c +++ b/drivers/media/dvb/frontends/or51132.c | |||
@@ -1,6 +1,9 @@ | |||
1 | /* | 1 | /* |
2 | * Support for OR51132 (pcHDTV HD-3000) - VSB/QAM | 2 | * Support for OR51132 (pcHDTV HD-3000) - VSB/QAM |
3 | * | 3 | * |
4 | * | ||
5 | * Copyright (C) 2007 Trent Piepho <xyzzy@speakeasy.org> | ||
6 | * | ||
4 | * Copyright (C) 2005 Kirk Lapray <kirk_lapray@bigfoot.com> | 7 | * Copyright (C) 2005 Kirk Lapray <kirk_lapray@bigfoot.com> |
5 | * | 8 | * |
6 | * Based on code from Jack Kelliher (kelliher@xmission.com) | 9 | * Based on code from Jack Kelliher (kelliher@xmission.com) |
@@ -69,46 +72,70 @@ struct or51132_state | |||
69 | u32 current_frequency; | 72 | u32 current_frequency; |
70 | }; | 73 | }; |
71 | 74 | ||
72 | static int i2c_writebytes (struct or51132_state* state, u8 reg, u8 *buf, int len) | 75 | |
76 | /* Write buffer to demod */ | ||
77 | static int or51132_writebuf(struct or51132_state *state, const u8 *buf, int len) | ||
73 | { | 78 | { |
74 | int err; | 79 | int err; |
75 | struct i2c_msg msg; | 80 | struct i2c_msg msg = { .addr = state->config->demod_address, |
76 | msg.addr = reg; | 81 | .flags = 0, .buf = (u8*)buf, .len = len }; |
77 | msg.flags = 0; | ||
78 | msg.len = len; | ||
79 | msg.buf = buf; | ||
80 | 82 | ||
83 | /* msleep(20); */ /* doesn't appear to be necessary */ | ||
81 | if ((err = i2c_transfer(state->i2c, &msg, 1)) != 1) { | 84 | if ((err = i2c_transfer(state->i2c, &msg, 1)) != 1) { |
82 | printk(KERN_WARNING "or51132: i2c_writebytes error (addr %02x, err == %i)\n", reg, err); | 85 | printk(KERN_WARNING "or51132: I2C write (addr 0x%02x len %d) error: %d\n", |
86 | msg.addr, msg.len, err); | ||
83 | return -EREMOTEIO; | 87 | return -EREMOTEIO; |
84 | } | 88 | } |
85 | |||
86 | return 0; | 89 | return 0; |
87 | } | 90 | } |
88 | 91 | ||
89 | static u8 i2c_readbytes (struct or51132_state* state, u8 reg, u8* buf, int len) | 92 | /* Write constant bytes, e.g. or51132_writebytes(state, 0x04, 0x42, 0x00); |
93 | Less code and more efficient that loading a buffer on the stack with | ||
94 | the bytes to send and then calling or51132_writebuf() on that. */ | ||
95 | #define or51132_writebytes(state, data...) \ | ||
96 | ({ const static u8 _data[] = {data}; \ | ||
97 | or51132_writebuf(state, _data, sizeof(_data)); }) | ||
98 | |||
99 | /* Read data from demod into buffer. Returns 0 on success. */ | ||
100 | static int or51132_readbuf(struct or51132_state *state, u8 *buf, int len) | ||
90 | { | 101 | { |
91 | int err; | 102 | int err; |
92 | struct i2c_msg msg; | 103 | struct i2c_msg msg = { .addr = state->config->demod_address, |
93 | msg.addr = reg; | 104 | .flags = I2C_M_RD, .buf = buf, .len = len }; |
94 | msg.flags = I2C_M_RD; | ||
95 | msg.len = len; | ||
96 | msg.buf = buf; | ||
97 | 105 | ||
106 | /* msleep(20); */ /* doesn't appear to be necessary */ | ||
98 | if ((err = i2c_transfer(state->i2c, &msg, 1)) != 1) { | 107 | if ((err = i2c_transfer(state->i2c, &msg, 1)) != 1) { |
99 | printk(KERN_WARNING "or51132: i2c_readbytes error (addr %02x, err == %i)\n", reg, err); | 108 | printk(KERN_WARNING "or51132: I2C read (addr 0x%02x len %d) error: %d\n", |
109 | msg.addr, msg.len, err); | ||
100 | return -EREMOTEIO; | 110 | return -EREMOTEIO; |
101 | } | 111 | } |
102 | |||
103 | return 0; | 112 | return 0; |
104 | } | 113 | } |
105 | 114 | ||
115 | /* Reads a 16-bit demod register. Returns <0 on error. */ | ||
116 | static int or51132_readreg(struct or51132_state *state, u8 reg) | ||
117 | { | ||
118 | u8 buf[2] = { 0x04, reg }; | ||
119 | struct i2c_msg msg[2] = { | ||
120 | {.addr = state->config->demod_address, .flags = 0, | ||
121 | .buf = buf, .len = 2 }, | ||
122 | {.addr = state->config->demod_address, .flags = I2C_M_RD, | ||
123 | .buf = buf, .len = 2 }}; | ||
124 | int err; | ||
125 | |||
126 | if ((err = i2c_transfer(state->i2c, msg, 2)) != 2) { | ||
127 | printk(KERN_WARNING "or51132: I2C error reading register %d: %d\n", | ||
128 | reg, err); | ||
129 | return -EREMOTEIO; | ||
130 | } | ||
131 | return le16_to_cpup((u16*)buf); | ||
132 | } | ||
133 | |||
106 | static int or51132_load_firmware (struct dvb_frontend* fe, const struct firmware *fw) | 134 | static int or51132_load_firmware (struct dvb_frontend* fe, const struct firmware *fw) |
107 | { | 135 | { |
108 | struct or51132_state* state = fe->demodulator_priv; | 136 | struct or51132_state* state = fe->demodulator_priv; |
109 | static u8 run_buf[] = {0x7F,0x01}; | 137 | const static u8 run_buf[] = {0x7F,0x01}; |
110 | u8 rec_buf[8]; | 138 | u8 rec_buf[8]; |
111 | u8 cmd_buf[3]; | ||
112 | u32 firmwareAsize, firmwareBsize; | 139 | u32 firmwareAsize, firmwareBsize; |
113 | int i,ret; | 140 | int i,ret; |
114 | 141 | ||
@@ -121,30 +148,21 @@ static int or51132_load_firmware (struct dvb_frontend* fe, const struct firmware | |||
121 | dprintk("FirmwareB is %i bytes\n",firmwareBsize); | 148 | dprintk("FirmwareB is %i bytes\n",firmwareBsize); |
122 | 149 | ||
123 | /* Upload firmware */ | 150 | /* Upload firmware */ |
124 | if ((ret = i2c_writebytes(state,state->config->demod_address, | 151 | if ((ret = or51132_writebuf(state, &fw->data[8], firmwareAsize))) { |
125 | &fw->data[8],firmwareAsize))) { | ||
126 | printk(KERN_WARNING "or51132: load_firmware error 1\n"); | 152 | printk(KERN_WARNING "or51132: load_firmware error 1\n"); |
127 | return ret; | 153 | return ret; |
128 | } | 154 | } |
129 | msleep(1); /* 1ms */ | 155 | if ((ret = or51132_writebuf(state, &fw->data[8+firmwareAsize], |
130 | if ((ret = i2c_writebytes(state,state->config->demod_address, | 156 | firmwareBsize))) { |
131 | &fw->data[8+firmwareAsize],firmwareBsize))) { | ||
132 | printk(KERN_WARNING "or51132: load_firmware error 2\n"); | 157 | printk(KERN_WARNING "or51132: load_firmware error 2\n"); |
133 | return ret; | 158 | return ret; |
134 | } | 159 | } |
135 | msleep(1); /* 1ms */ | ||
136 | 160 | ||
137 | if ((ret = i2c_writebytes(state,state->config->demod_address, | 161 | if ((ret = or51132_writebuf(state, run_buf, 2))) { |
138 | run_buf,2))) { | ||
139 | printk(KERN_WARNING "or51132: load_firmware error 3\n"); | 162 | printk(KERN_WARNING "or51132: load_firmware error 3\n"); |
140 | return ret; | 163 | return ret; |
141 | } | 164 | } |
142 | 165 | if ((ret = or51132_writebuf(state, run_buf, 2))) { | |
143 | /* Wait at least 5 msec */ | ||
144 | msleep(20); /* 10ms */ | ||
145 | |||
146 | if ((ret = i2c_writebytes(state,state->config->demod_address, | ||
147 | run_buf,2))) { | ||
148 | printk(KERN_WARNING "or51132: load_firmware error 4\n"); | 166 | printk(KERN_WARNING "or51132: load_firmware error 4\n"); |
149 | return ret; | 167 | return ret; |
150 | } | 168 | } |
@@ -154,43 +172,25 @@ static int or51132_load_firmware (struct dvb_frontend* fe, const struct firmware | |||
154 | 172 | ||
155 | /* Read back ucode version to besure we loaded correctly and are really up and running */ | 173 | /* Read back ucode version to besure we loaded correctly and are really up and running */ |
156 | /* Get uCode version */ | 174 | /* Get uCode version */ |
157 | cmd_buf[0] = 0x10; | 175 | if ((ret = or51132_writebytes(state, 0x10, 0x10, 0x00))) { |
158 | cmd_buf[1] = 0x10; | ||
159 | cmd_buf[2] = 0x00; | ||
160 | msleep(20); /* 20ms */ | ||
161 | if ((ret = i2c_writebytes(state,state->config->demod_address, | ||
162 | cmd_buf,3))) { | ||
163 | printk(KERN_WARNING "or51132: load_firmware error a\n"); | 176 | printk(KERN_WARNING "or51132: load_firmware error a\n"); |
164 | return ret; | 177 | return ret; |
165 | } | 178 | } |
166 | 179 | if ((ret = or51132_writebytes(state, 0x04, 0x17))) { | |
167 | cmd_buf[0] = 0x04; | ||
168 | cmd_buf[1] = 0x17; | ||
169 | msleep(20); /* 20ms */ | ||
170 | if ((ret = i2c_writebytes(state,state->config->demod_address, | ||
171 | cmd_buf,2))) { | ||
172 | printk(KERN_WARNING "or51132: load_firmware error b\n"); | 180 | printk(KERN_WARNING "or51132: load_firmware error b\n"); |
173 | return ret; | 181 | return ret; |
174 | } | 182 | } |
175 | 183 | if ((ret = or51132_writebytes(state, 0x00, 0x00))) { | |
176 | cmd_buf[0] = 0x00; | ||
177 | cmd_buf[1] = 0x00; | ||
178 | msleep(20); /* 20ms */ | ||
179 | if ((ret = i2c_writebytes(state,state->config->demod_address, | ||
180 | cmd_buf,2))) { | ||
181 | printk(KERN_WARNING "or51132: load_firmware error c\n"); | 184 | printk(KERN_WARNING "or51132: load_firmware error c\n"); |
182 | return ret; | 185 | return ret; |
183 | } | 186 | } |
184 | 187 | for (i=0;i<4;i++) { | |
185 | for(i=0;i<4;i++) { | ||
186 | msleep(20); /* 20ms */ | ||
187 | /* Once upon a time, this command might have had something | 188 | /* Once upon a time, this command might have had something |
188 | to do with getting the firmware version, but it's | 189 | to do with getting the firmware version, but it's |
189 | not used anymore: | 190 | not used anymore: |
190 | {0x04,0x00,0x30,0x00,i+1} */ | 191 | {0x04,0x00,0x30,0x00,i+1} */ |
191 | /* Read 8 bytes, two bytes at a time */ | 192 | /* Read 8 bytes, two bytes at a time */ |
192 | if ((ret = i2c_readbytes(state,state->config->demod_address, | 193 | if ((ret = or51132_readbuf(state, &rec_buf[i*2], 2))) { |
193 | &rec_buf[i*2],2))) { | ||
194 | printk(KERN_WARNING | 194 | printk(KERN_WARNING |
195 | "or51132: load_firmware error d - %d\n",i); | 195 | "or51132: load_firmware error d - %d\n",i); |
196 | return ret; | 196 | return ret; |
@@ -204,12 +204,7 @@ static int or51132_load_firmware (struct dvb_frontend* fe, const struct firmware | |||
204 | rec_buf[3],rec_buf[2]>>4,rec_buf[2]&0x0f, | 204 | rec_buf[3],rec_buf[2]>>4,rec_buf[2]&0x0f, |
205 | rec_buf[5],rec_buf[4]>>4,rec_buf[4]&0x0f); | 205 | rec_buf[5],rec_buf[4]>>4,rec_buf[4]&0x0f); |
206 | 206 | ||
207 | cmd_buf[0] = 0x10; | 207 | if ((ret = or51132_writebytes(state, 0x10, 0x00, 0x00))) { |
208 | cmd_buf[1] = 0x00; | ||
209 | cmd_buf[2] = 0x00; | ||
210 | msleep(20); /* 20ms */ | ||
211 | if ((ret = i2c_writebytes(state,state->config->demod_address, | ||
212 | cmd_buf,3))) { | ||
213 | printk(KERN_WARNING "or51132: load_firmware error e\n"); | 208 | printk(KERN_WARNING "or51132: load_firmware error e\n"); |
214 | return ret; | 209 | return ret; |
215 | } | 210 | } |
@@ -241,70 +236,55 @@ static int or51132_sleep(struct dvb_frontend* fe) | |||
241 | static int or51132_setmode(struct dvb_frontend* fe) | 236 | static int or51132_setmode(struct dvb_frontend* fe) |
242 | { | 237 | { |
243 | struct or51132_state* state = fe->demodulator_priv; | 238 | struct or51132_state* state = fe->demodulator_priv; |
244 | unsigned char cmd_buf[3]; | 239 | u8 cmd_buf1[3] = {0x04, 0x01, 0x5f}; |
240 | u8 cmd_buf2[3] = {0x1c, 0x00, 0 }; | ||
245 | 241 | ||
246 | dprintk("setmode %d\n",(int)state->current_modulation); | 242 | dprintk("setmode %d\n",(int)state->current_modulation); |
247 | /* set operation mode in Receiver 1 register; */ | 243 | |
248 | cmd_buf[0] = 0x04; | ||
249 | cmd_buf[1] = 0x01; | ||
250 | switch (state->current_modulation) { | 244 | switch (state->current_modulation) { |
251 | case QAM_256: | ||
252 | case QAM_64: | ||
253 | case QAM_AUTO: | ||
254 | /* Auto-deinterleave; MPEG ser, MPEG2tr, phase noise-high*/ | ||
255 | cmd_buf[2] = 0x5F; | ||
256 | break; | ||
257 | case VSB_8: | 245 | case VSB_8: |
258 | /* Auto CH, Auto NTSC rej, MPEGser, MPEG2tr, phase noise-high*/ | 246 | /* Auto CH, Auto NTSC rej, MPEGser, MPEG2tr, phase noise-high */ |
259 | cmd_buf[2] = 0x50; | 247 | cmd_buf1[2] = 0x50; |
248 | /* REC MODE inv IF spectrum, Normal */ | ||
249 | cmd_buf2[1] = 0x03; | ||
250 | /* Channel MODE ATSC/VSB8 */ | ||
251 | cmd_buf2[2] = 0x06; | ||
260 | break; | 252 | break; |
261 | default: | 253 | /* All QAM modes are: |
262 | printk("setmode:Modulation set to unsupported value\n"); | 254 | Auto-deinterleave; MPEGser, MPEG2tr, phase noise-high |
263 | }; | 255 | REC MODE Normal Carrier Lock */ |
264 | if (i2c_writebytes(state,state->config->demod_address, | ||
265 | cmd_buf,3)) { | ||
266 | printk(KERN_WARNING "or51132: set_mode error 1\n"); | ||
267 | return -1; | ||
268 | } | ||
269 | dprintk("or51132: set #1 to %02x\n", cmd_buf[2]); | ||
270 | |||
271 | /* Set operation mode in Receiver 6 register */ | ||
272 | cmd_buf[0] = 0x1C; | ||
273 | switch (state->current_modulation) { | ||
274 | case QAM_AUTO: | 256 | case QAM_AUTO: |
275 | /* REC MODE Normal Carrier Lock */ | ||
276 | cmd_buf[1] = 0x00; | ||
277 | /* Channel MODE Auto QAM64/256 */ | 257 | /* Channel MODE Auto QAM64/256 */ |
278 | cmd_buf[2] = 0x4f; | 258 | cmd_buf2[2] = 0x4f; |
279 | break; | 259 | break; |
280 | case QAM_256: | 260 | case QAM_256: |
281 | /* REC MODE Normal Carrier Lock */ | ||
282 | cmd_buf[1] = 0x00; | ||
283 | /* Channel MODE QAM256 */ | 261 | /* Channel MODE QAM256 */ |
284 | cmd_buf[2] = 0x45; | 262 | cmd_buf2[2] = 0x45; |
285 | break; | 263 | break; |
286 | case QAM_64: | 264 | case QAM_64: |
287 | /* REC MODE Normal Carrier Lock */ | ||
288 | cmd_buf[1] = 0x00; | ||
289 | /* Channel MODE QAM64 */ | 265 | /* Channel MODE QAM64 */ |
290 | cmd_buf[2] = 0x43; | 266 | cmd_buf2[2] = 0x43; |
291 | break; | ||
292 | case VSB_8: | ||
293 | /* REC MODE inv IF spectrum, Normal */ | ||
294 | cmd_buf[1] = 0x03; | ||
295 | /* Channel MODE ATSC/VSB8 */ | ||
296 | cmd_buf[2] = 0x06; | ||
297 | break; | 267 | break; |
298 | default: | 268 | default: |
299 | printk("setmode: Modulation set to unsupported value\n"); | 269 | printk(KERN_WARNING |
300 | }; | 270 | "or51132: setmode: Modulation set to unsupported value (%d)\n", |
301 | msleep(20); /* 20ms */ | 271 | state->current_modulation); |
302 | if (i2c_writebytes(state,state->config->demod_address, | 272 | return -EINVAL; |
303 | cmd_buf,3)) { | 273 | } |
274 | |||
275 | /* Set Receiver 1 register */ | ||
276 | if (or51132_writebuf(state, cmd_buf1, 3)) { | ||
277 | printk(KERN_WARNING "or51132: set_mode error 1\n"); | ||
278 | return -EREMOTEIO; | ||
279 | } | ||
280 | dprintk("set #1 to %02x\n", cmd_buf1[2]); | ||
281 | |||
282 | /* Set operation mode in Receiver 6 register */ | ||
283 | if (or51132_writebuf(state, cmd_buf2, 3)) { | ||
304 | printk(KERN_WARNING "or51132: set_mode error 2\n"); | 284 | printk(KERN_WARNING "or51132: set_mode error 2\n"); |
305 | return -1; | 285 | return -EREMOTEIO; |
306 | } | 286 | } |
307 | dprintk("or51132: set #6 to 0x%02x%02x\n", cmd_buf[1], cmd_buf[2]); | 287 | dprintk("set #6 to 0x%02x%02x\n", cmd_buf2[1], cmd_buf2[2]); |
308 | 288 | ||
309 | return 0; | 289 | return 0; |
310 | } | 290 | } |
@@ -401,28 +381,23 @@ static int or51132_get_parameters(struct dvb_frontend* fe, | |||
401 | struct dvb_frontend_parameters *param) | 381 | struct dvb_frontend_parameters *param) |
402 | { | 382 | { |
403 | struct or51132_state* state = fe->demodulator_priv; | 383 | struct or51132_state* state = fe->demodulator_priv; |
404 | u8 buf[2]; | 384 | int status; |
385 | int retry = 1; | ||
405 | 386 | ||
387 | start: | ||
406 | /* Receiver Status */ | 388 | /* Receiver Status */ |
407 | buf[0]=0x04; | 389 | if ((status = or51132_readreg(state, 0x00)) < 0) { |
408 | buf[1]=0x00; | 390 | printk(KERN_WARNING "or51132: get_parameters: error reading receiver status\n"); |
409 | msleep(30); /* 30ms */ | ||
410 | if (i2c_writebytes(state,state->config->demod_address,buf,2)) { | ||
411 | printk(KERN_WARNING "or51132: get_parameters write error\n"); | ||
412 | return -EREMOTEIO; | ||
413 | } | ||
414 | msleep(30); /* 30ms */ | ||
415 | if (i2c_readbytes(state,state->config->demod_address,buf,2)) { | ||
416 | printk(KERN_WARNING "or51132: get_parameters read error\n"); | ||
417 | return -EREMOTEIO; | 391 | return -EREMOTEIO; |
418 | } | 392 | } |
419 | switch(buf[0]) { | 393 | switch(status&0xff) { |
420 | case 0x06: param->u.vsb.modulation = VSB_8; break; | 394 | case 0x06: param->u.vsb.modulation = VSB_8; break; |
421 | case 0x43: param->u.vsb.modulation = QAM_64; break; | 395 | case 0x43: param->u.vsb.modulation = QAM_64; break; |
422 | case 0x45: param->u.vsb.modulation = QAM_256; break; | 396 | case 0x45: param->u.vsb.modulation = QAM_256; break; |
423 | default: | 397 | default: |
398 | if (retry--) goto start; | ||
424 | printk(KERN_WARNING "or51132: unknown status 0x%02x\n", | 399 | printk(KERN_WARNING "or51132: unknown status 0x%02x\n", |
425 | buf[0]); | 400 | status&0xff); |
426 | return -EREMOTEIO; | 401 | return -EREMOTEIO; |
427 | } | 402 | } |
428 | 403 | ||
@@ -438,32 +413,21 @@ static int or51132_get_parameters(struct dvb_frontend* fe, | |||
438 | static int or51132_read_status(struct dvb_frontend* fe, fe_status_t* status) | 413 | static int or51132_read_status(struct dvb_frontend* fe, fe_status_t* status) |
439 | { | 414 | { |
440 | struct or51132_state* state = fe->demodulator_priv; | 415 | struct or51132_state* state = fe->demodulator_priv; |
441 | unsigned char rec_buf[2]; | 416 | int reg; |
442 | unsigned char snd_buf[2]; | ||
443 | *status = 0; | ||
444 | 417 | ||
445 | /* Receiver Status */ | 418 | /* Receiver Status */ |
446 | snd_buf[0]=0x04; | 419 | if ((reg = or51132_readreg(state, 0x00)) < 0) { |
447 | snd_buf[1]=0x00; | 420 | printk(KERN_WARNING "or51132: read_status: error reading receiver status: %d\n", reg); |
448 | msleep(30); /* 30ms */ | 421 | *status = 0; |
449 | if (i2c_writebytes(state,state->config->demod_address,snd_buf,2)) { | 422 | return -EREMOTEIO; |
450 | printk(KERN_WARNING "or51132: read_status write error\n"); | ||
451 | return -1; | ||
452 | } | ||
453 | msleep(30); /* 30ms */ | ||
454 | if (i2c_readbytes(state,state->config->demod_address,rec_buf,2)) { | ||
455 | printk(KERN_WARNING "or51132: read_status read error\n"); | ||
456 | return -1; | ||
457 | } | ||
458 | dprintk("read_status %x %x\n",rec_buf[0],rec_buf[1]); | ||
459 | |||
460 | if (rec_buf[1] & 0x01) { /* Receiver Lock */ | ||
461 | *status |= FE_HAS_SIGNAL; | ||
462 | *status |= FE_HAS_CARRIER; | ||
463 | *status |= FE_HAS_VITERBI; | ||
464 | *status |= FE_HAS_SYNC; | ||
465 | *status |= FE_HAS_LOCK; | ||
466 | } | 423 | } |
424 | dprintk("%s: read_status %04x\n", __FUNCTION__, reg); | ||
425 | |||
426 | if (reg & 0x0100) /* Receiver Lock */ | ||
427 | *status = FE_HAS_SIGNAL|FE_HAS_CARRIER|FE_HAS_VITERBI| | ||
428 | FE_HAS_SYNC|FE_HAS_LOCK; | ||
429 | else | ||
430 | *status = 0; | ||
467 | return 0; | 431 | return 0; |
468 | } | 432 | } |
469 | 433 | ||
@@ -506,47 +470,30 @@ static u32 calculate_snr(u32 mse, u32 c) | |||
506 | static int or51132_read_snr(struct dvb_frontend* fe, u16* snr) | 470 | static int or51132_read_snr(struct dvb_frontend* fe, u16* snr) |
507 | { | 471 | { |
508 | struct or51132_state* state = fe->demodulator_priv; | 472 | struct or51132_state* state = fe->demodulator_priv; |
509 | u8 rec_buf[2]; | 473 | int noise, reg; |
510 | u8 snd_buf[2]; | 474 | u32 c, usK = 0; |
511 | u32 noise; | 475 | int retry = 1; |
512 | u32 c; | 476 | |
513 | u32 usK; | 477 | start: |
514 | 478 | /* SNR after Equalizer */ | |
515 | /* Register is same for VSB or QAM firmware */ | 479 | noise = or51132_readreg(state, 0x02); |
516 | snd_buf[0]=0x04; | 480 | if (noise < 0) { |
517 | snd_buf[1]=0x02; /* SNR after Equalizer */ | 481 | printk(KERN_WARNING "or51132: read_snr: error reading equalizer\n"); |
518 | msleep(30); /* 30ms */ | ||
519 | if (i2c_writebytes(state,state->config->demod_address,snd_buf,2)) { | ||
520 | printk(KERN_WARNING "or51132: snr write error\n"); | ||
521 | return -EREMOTEIO; | ||
522 | } | ||
523 | msleep(30); /* 30ms */ | ||
524 | if (i2c_readbytes(state,state->config->demod_address,rec_buf,2)) { | ||
525 | printk(KERN_WARNING "or51132: snr read error\n"); | ||
526 | return -EREMOTEIO; | 482 | return -EREMOTEIO; |
527 | } | 483 | } |
528 | noise = rec_buf[0] | (rec_buf[1] << 8); | 484 | dprintk("read_snr noise (%d)\n", noise); |
529 | dprintk("read_snr noise %x %x (%i)\n",rec_buf[0],rec_buf[1],noise); | ||
530 | 485 | ||
531 | /* Read status, contains modulation type for QAM_AUTO and | 486 | /* Read status, contains modulation type for QAM_AUTO and |
532 | NTSC filter for VSB */ | 487 | NTSC filter for VSB */ |
533 | snd_buf[0]=0x04; | 488 | reg = or51132_readreg(state, 0x00); |
534 | snd_buf[1]=0x00; /* Status register */ | 489 | if (reg < 0) { |
535 | msleep(30); /* 30ms */ | 490 | printk(KERN_WARNING "or51132: read_snr: error reading receiver status\n"); |
536 | if (i2c_writebytes(state,state->config->demod_address,snd_buf,2)) { | ||
537 | printk(KERN_WARNING "or51132: status write error\n"); | ||
538 | return -EREMOTEIO; | ||
539 | } | ||
540 | msleep(30); /* 30ms */ | ||
541 | if (i2c_readbytes(state,state->config->demod_address,rec_buf,2)) { | ||
542 | printk(KERN_WARNING "or51132: status read error\n"); | ||
543 | return -EREMOTEIO; | 491 | return -EREMOTEIO; |
544 | } | 492 | } |
545 | 493 | ||
546 | usK = 0; | 494 | switch (reg&0xff) { |
547 | switch (rec_buf[0]) { | ||
548 | case 0x06: | 495 | case 0x06: |
549 | usK = (rec_buf[1] & 0x10) ? 0x03000000 : 0; | 496 | if (reg & 0x1000) usK = 3 << 24; |
550 | /* Fall through to QAM64 case */ | 497 | /* Fall through to QAM64 case */ |
551 | case 0x43: | 498 | case 0x43: |
552 | c = 150204167; | 499 | c = 150204167; |
@@ -555,11 +502,12 @@ static int or51132_read_snr(struct dvb_frontend* fe, u16* snr) | |||
555 | c = 150290396; | 502 | c = 150290396; |
556 | break; | 503 | break; |
557 | default: | 504 | default: |
558 | printk(KERN_ERR "or51132: unknown status 0x%02x\n", rec_buf[0]); | 505 | printk(KERN_WARNING "or51132: unknown status 0x%02x\n", reg&0xff); |
506 | if (retry--) goto start; | ||
559 | return -EREMOTEIO; | 507 | return -EREMOTEIO; |
560 | } | 508 | } |
561 | dprintk("%s: modulation %02x, NTSC rej O%s\n", __FUNCTION__, | 509 | dprintk("%s: modulation %02x, NTSC rej O%s\n", __FUNCTION__, |
562 | rec_buf[0], rec_buf[1]&0x10?"n":"ff"); | 510 | reg&0xff, reg&0x1000?"n":"ff"); |
563 | 511 | ||
564 | /* Calculate SNR using noise, c, and NTSC rejection correction */ | 512 | /* Calculate SNR using noise, c, and NTSC rejection correction */ |
565 | state->snr = calculate_snr(noise, c) - usK; | 513 | state->snr = calculate_snr(noise, c) - usK; |
@@ -671,6 +619,7 @@ MODULE_PARM_DESC(debug, "Turn on/off frontend debugging (default:off)."); | |||
671 | 619 | ||
672 | MODULE_DESCRIPTION("OR51132 ATSC [pcHDTV HD-3000] (8VSB & ITU J83 AnnexB FEC QAM64/256) Demodulator Driver"); | 620 | MODULE_DESCRIPTION("OR51132 ATSC [pcHDTV HD-3000] (8VSB & ITU J83 AnnexB FEC QAM64/256) Demodulator Driver"); |
673 | MODULE_AUTHOR("Kirk Lapray"); | 621 | MODULE_AUTHOR("Kirk Lapray"); |
622 | MODULE_AUTHOR("Trent Piepho"); | ||
674 | MODULE_LICENSE("GPL"); | 623 | MODULE_LICENSE("GPL"); |
675 | 624 | ||
676 | EXPORT_SYMBOL(or51132_attach); | 625 | EXPORT_SYMBOL(or51132_attach); |
diff --git a/drivers/media/dvb/frontends/tda10021.c b/drivers/media/dvb/frontends/tda10021.c index 5b9c5bb29b23..110536843e8e 100644 --- a/drivers/media/dvb/frontends/tda10021.c +++ b/drivers/media/dvb/frontends/tda10021.c | |||
@@ -30,13 +30,13 @@ | |||
30 | #include <linux/slab.h> | 30 | #include <linux/slab.h> |
31 | 31 | ||
32 | #include "dvb_frontend.h" | 32 | #include "dvb_frontend.h" |
33 | #include "tda10021.h" | 33 | #include "tda1002x.h" |
34 | 34 | ||
35 | 35 | ||
36 | struct tda10021_state { | 36 | struct tda10021_state { |
37 | struct i2c_adapter* i2c; | 37 | struct i2c_adapter* i2c; |
38 | /* configuration settings */ | 38 | /* configuration settings */ |
39 | const struct tda10021_config* config; | 39 | const struct tda1002x_config* config; |
40 | struct dvb_frontend frontend; | 40 | struct dvb_frontend frontend; |
41 | 41 | ||
42 | u8 pwm; | 42 | u8 pwm; |
@@ -53,9 +53,6 @@ struct tda10021_state { | |||
53 | static int verbose; | 53 | static int verbose; |
54 | 54 | ||
55 | #define XIN 57840000UL | 55 | #define XIN 57840000UL |
56 | #define DISABLE_INVERSION(reg0) do { reg0 |= 0x20; } while (0) | ||
57 | #define ENABLE_INVERSION(reg0) do { reg0 &= ~0x20; } while (0) | ||
58 | #define HAS_INVERSION(reg0) (!(reg0 & 0x20)) | ||
59 | 56 | ||
60 | #define FIN (XIN >> 4) | 57 | #define FIN (XIN >> 4) |
61 | 58 | ||
@@ -64,7 +61,7 @@ static u8 tda10021_inittab[0x40]= | |||
64 | { | 61 | { |
65 | 0x73, 0x6a, 0x23, 0x0a, 0x02, 0x37, 0x77, 0x1a, | 62 | 0x73, 0x6a, 0x23, 0x0a, 0x02, 0x37, 0x77, 0x1a, |
66 | 0x37, 0x6a, 0x17, 0x8a, 0x1e, 0x86, 0x43, 0x40, | 63 | 0x37, 0x6a, 0x17, 0x8a, 0x1e, 0x86, 0x43, 0x40, |
67 | 0xb8, 0x3f, 0xa0, 0x00, 0xcd, 0x01, 0x00, 0xff, | 64 | 0xb8, 0x3f, 0xa1, 0x00, 0xcd, 0x01, 0x00, 0xff, |
68 | 0x11, 0x00, 0x7c, 0x31, 0x30, 0x20, 0x00, 0x00, | 65 | 0x11, 0x00, 0x7c, 0x31, 0x30, 0x20, 0x00, 0x00, |
69 | 0x02, 0x00, 0x00, 0x7d, 0x00, 0x00, 0x00, 0x00, | 66 | 0x02, 0x00, 0x00, 0x7d, 0x00, 0x00, 0x00, 0x00, |
70 | 0x07, 0x00, 0x33, 0x11, 0x0d, 0x95, 0x08, 0x58, | 67 | 0x07, 0x00, 0x33, 0x11, 0x0d, 0x95, 0x08, 0x58, |
@@ -97,7 +94,8 @@ static u8 tda10021_readreg (struct tda10021_state* state, u8 reg) | |||
97 | int ret; | 94 | int ret; |
98 | 95 | ||
99 | ret = i2c_transfer (state->i2c, msg, 2); | 96 | ret = i2c_transfer (state->i2c, msg, 2); |
100 | if (ret != 2) | 97 | // Don't print an error message if the id is read. |
98 | if (ret != 2 && reg != 0x1a) | ||
101 | printk("DVB: TDA10021: %s: readreg error (ret == %i)\n", | 99 | printk("DVB: TDA10021: %s: readreg error (ret == %i)\n", |
102 | __FUNCTION__, ret); | 100 | __FUNCTION__, ret); |
103 | return b1[0]; | 101 | return b1[0]; |
@@ -136,10 +134,10 @@ static int tda10021_setup_reg0 (struct tda10021_state* state, u8 reg0, | |||
136 | { | 134 | { |
137 | reg0 |= state->reg0 & 0x63; | 135 | reg0 |= state->reg0 & 0x63; |
138 | 136 | ||
139 | if (INVERSION_ON == inversion) | 137 | if ((INVERSION_ON == inversion) ^ (state->config->invert == 0)) |
140 | ENABLE_INVERSION(reg0); | 138 | reg0 &= ~0x20; |
141 | else if (INVERSION_OFF == inversion) | 139 | else |
142 | DISABLE_INVERSION(reg0); | 140 | reg0 |= 0x20; |
143 | 141 | ||
144 | _tda10021_writereg (state, 0x00, reg0 & 0xfe); | 142 | _tda10021_writereg (state, 0x00, reg0 & 0xfe); |
145 | _tda10021_writereg (state, 0x00, reg0 | 0x01); | 143 | _tda10021_writereg (state, 0x00, reg0 | 0x01); |
@@ -201,16 +199,6 @@ static int tda10021_set_symbolrate (struct tda10021_state* state, u32 symbolrate | |||
201 | return 0; | 199 | return 0; |
202 | } | 200 | } |
203 | 201 | ||
204 | static int tda10021_write(struct dvb_frontend* fe, u8 *buf, int len) | ||
205 | { | ||
206 | struct tda10021_state* state = fe->demodulator_priv; | ||
207 | |||
208 | if (len != 2) | ||
209 | return -EINVAL; | ||
210 | |||
211 | return _tda10021_writereg(state, buf[0], buf[1]); | ||
212 | } | ||
213 | |||
214 | static int tda10021_init (struct dvb_frontend *fe) | 202 | static int tda10021_init (struct dvb_frontend *fe) |
215 | { | 203 | { |
216 | struct tda10021_state* state = fe->demodulator_priv; | 204 | struct tda10021_state* state = fe->demodulator_priv; |
@@ -258,6 +246,9 @@ static int tda10021_set_parameters (struct dvb_frontend *fe, | |||
258 | if (qam < 0 || qam > 5) | 246 | if (qam < 0 || qam > 5) |
259 | return -EINVAL; | 247 | return -EINVAL; |
260 | 248 | ||
249 | if (p->inversion != INVERSION_ON && p->inversion != INVERSION_OFF) | ||
250 | return -EINVAL; | ||
251 | |||
261 | //printk("tda10021: set frequency to %d qam=%d symrate=%d\n", p->frequency,qam,p->u.qam.symbol_rate); | 252 | //printk("tda10021: set frequency to %d qam=%d symrate=%d\n", p->frequency,qam,p->u.qam.symbol_rate); |
262 | 253 | ||
263 | if (fe->ops.tuner_ops.set_params) { | 254 | if (fe->ops.tuner_ops.set_params) { |
@@ -366,7 +357,7 @@ static int tda10021_get_frontend(struct dvb_frontend* fe, struct dvb_frontend_pa | |||
366 | -((s32)p->u.qam.symbol_rate * afc) >> 10); | 357 | -((s32)p->u.qam.symbol_rate * afc) >> 10); |
367 | } | 358 | } |
368 | 359 | ||
369 | p->inversion = HAS_INVERSION(state->reg0) ? INVERSION_ON : INVERSION_OFF; | 360 | p->inversion = ((state->reg0 & 0x20) == 0x20) ^ (state->config->invert != 0) ? INVERSION_ON : INVERSION_OFF; |
370 | p->u.qam.modulation = ((state->reg0 >> 2) & 7) + QAM_16; | 361 | p->u.qam.modulation = ((state->reg0 >> 2) & 7) + QAM_16; |
371 | 362 | ||
372 | p->u.qam.fec_inner = FEC_NONE; | 363 | p->u.qam.fec_inner = FEC_NONE; |
@@ -408,11 +399,12 @@ static void tda10021_release(struct dvb_frontend* fe) | |||
408 | 399 | ||
409 | static struct dvb_frontend_ops tda10021_ops; | 400 | static struct dvb_frontend_ops tda10021_ops; |
410 | 401 | ||
411 | struct dvb_frontend* tda10021_attach(const struct tda10021_config* config, | 402 | struct dvb_frontend* tda10021_attach(const struct tda1002x_config* config, |
412 | struct i2c_adapter* i2c, | 403 | struct i2c_adapter* i2c, |
413 | u8 pwm) | 404 | u8 pwm) |
414 | { | 405 | { |
415 | struct tda10021_state* state = NULL; | 406 | struct tda10021_state* state = NULL; |
407 | u8 id; | ||
416 | 408 | ||
417 | /* allocate memory for the internal state */ | 409 | /* allocate memory for the internal state */ |
418 | state = kmalloc(sizeof(struct tda10021_state), GFP_KERNEL); | 410 | state = kmalloc(sizeof(struct tda10021_state), GFP_KERNEL); |
@@ -425,7 +417,11 @@ struct dvb_frontend* tda10021_attach(const struct tda10021_config* config, | |||
425 | state->reg0 = tda10021_inittab[0]; | 417 | state->reg0 = tda10021_inittab[0]; |
426 | 418 | ||
427 | /* check if the demod is there */ | 419 | /* check if the demod is there */ |
428 | if ((tda10021_readreg(state, 0x1a) & 0xf0) != 0x70) goto error; | 420 | id = tda10021_readreg(state, 0x1a); |
421 | if ((id & 0xf0) != 0x70) goto error; | ||
422 | |||
423 | printk("TDA10021: i2c-addr = 0x%02x, id = 0x%02x\n", | ||
424 | state->config->demod_address, id); | ||
429 | 425 | ||
430 | /* create dvb_frontend */ | 426 | /* create dvb_frontend */ |
431 | memcpy(&state->frontend.ops, &tda10021_ops, sizeof(struct dvb_frontend_ops)); | 427 | memcpy(&state->frontend.ops, &tda10021_ops, sizeof(struct dvb_frontend_ops)); |
@@ -447,7 +443,7 @@ static struct dvb_frontend_ops tda10021_ops = { | |||
447 | .frequency_max = 858000000, | 443 | .frequency_max = 858000000, |
448 | .symbol_rate_min = (XIN/2)/64, /* SACLK/64 == (XIN/2)/64 */ | 444 | .symbol_rate_min = (XIN/2)/64, /* SACLK/64 == (XIN/2)/64 */ |
449 | .symbol_rate_max = (XIN/2)/4, /* SACLK/4 */ | 445 | .symbol_rate_max = (XIN/2)/4, /* SACLK/4 */ |
450 | #if 0 | 446 | #if 0 |
451 | .frequency_tolerance = ???, | 447 | .frequency_tolerance = ???, |
452 | .symbol_rate_tolerance = ???, /* ppm */ /* == 8% (spec p. 5) */ | 448 | .symbol_rate_tolerance = ???, /* ppm */ /* == 8% (spec p. 5) */ |
453 | #endif | 449 | #endif |
@@ -461,7 +457,6 @@ static struct dvb_frontend_ops tda10021_ops = { | |||
461 | 457 | ||
462 | .init = tda10021_init, | 458 | .init = tda10021_init, |
463 | .sleep = tda10021_sleep, | 459 | .sleep = tda10021_sleep, |
464 | .write = tda10021_write, | ||
465 | .i2c_gate_ctrl = tda10021_i2c_gate_ctrl, | 460 | .i2c_gate_ctrl = tda10021_i2c_gate_ctrl, |
466 | 461 | ||
467 | .set_frontend = tda10021_set_parameters, | 462 | .set_frontend = tda10021_set_parameters, |
diff --git a/drivers/media/dvb/frontends/tda10023.c b/drivers/media/dvb/frontends/tda10023.c new file mode 100644 index 000000000000..da796e784be3 --- /dev/null +++ b/drivers/media/dvb/frontends/tda10023.c | |||
@@ -0,0 +1,540 @@ | |||
1 | /* | ||
2 | TDA10023 - DVB-C decoder | ||
3 | (as used in Philips CU1216-3 NIM and the Reelbox DVB-C tuner card) | ||
4 | |||
5 | Copyright (C) 2005 Georg Acher, BayCom GmbH (acher at baycom dot de) | ||
6 | Copyright (c) 2006 Hartmut Birr (e9hack at gmail dot com) | ||
7 | |||
8 | Remotely based on tda10021.c | ||
9 | Copyright (C) 1999 Convergence Integrated Media GmbH <ralph@convergence.de> | ||
10 | Copyright (C) 2004 Markus Schulz <msc@antzsystem.de> | ||
11 | Support for TDA10021 | ||
12 | |||
13 | This program is free software; you can redistribute it and/or modify | ||
14 | it under the terms of the GNU General Public License as published by | ||
15 | the Free Software Foundation; either version 2 of the License, or | ||
16 | (at your option) any later version. | ||
17 | |||
18 | This program is distributed in the hope that it will be useful, | ||
19 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
20 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
21 | GNU General Public License for more details. | ||
22 | |||
23 | You should have received a copy of the GNU General Public License | ||
24 | along with this program; if not, write to the Free Software | ||
25 | Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
26 | */ | ||
27 | |||
28 | #include <linux/delay.h> | ||
29 | #include <linux/errno.h> | ||
30 | #include <linux/init.h> | ||
31 | #include <linux/kernel.h> | ||
32 | #include <linux/module.h> | ||
33 | #include <linux/string.h> | ||
34 | #include <linux/slab.h> | ||
35 | |||
36 | #include <asm/div64.h> | ||
37 | |||
38 | #include "dvb_frontend.h" | ||
39 | #include "tda1002x.h" | ||
40 | |||
41 | |||
42 | struct tda10023_state { | ||
43 | struct i2c_adapter* i2c; | ||
44 | /* configuration settings */ | ||
45 | const struct tda1002x_config* config; | ||
46 | struct dvb_frontend frontend; | ||
47 | |||
48 | u8 pwm; | ||
49 | u8 reg0; | ||
50 | }; | ||
51 | |||
52 | |||
53 | #define dprintk(x...) | ||
54 | |||
55 | static int verbose; | ||
56 | |||
57 | #define XTAL 28920000UL | ||
58 | #define PLL_M 8UL | ||
59 | #define PLL_P 4UL | ||
60 | #define PLL_N 1UL | ||
61 | #define SYSCLK (XTAL*PLL_M/(PLL_N*PLL_P)) // -> 57840000 | ||
62 | |||
63 | static u8 tda10023_inittab[]={ | ||
64 | // reg mask val | ||
65 | 0x2a,0xff,0x02, // PLL3, Bypass, Power Down | ||
66 | 0xff,0x64,0x00, // Sleep 100ms | ||
67 | 0x2a,0xff,0x03, // PLL3, Bypass, Power Down | ||
68 | 0xff,0x64,0x00, // Sleep 100ms | ||
69 | 0x28,0xff,PLL_M-1, // PLL1 M=8 | ||
70 | 0x29,0xff,((PLL_P-1)<<6)|(PLL_N-1), // PLL2 | ||
71 | 0x00,0xff,0x23, // GPR FSAMPLING=1 | ||
72 | 0x2a,0xff,0x08, // PLL3 PSACLK=1 | ||
73 | 0xff,0x64,0x00, // Sleep 100ms | ||
74 | 0x1f,0xff,0x00, // RESET | ||
75 | 0xff,0x64,0x00, // Sleep 100ms | ||
76 | 0xe6,0x0c,0x04, // RSCFG_IND | ||
77 | 0x10,0xc0,0x80, // DECDVBCFG1 PBER=1 | ||
78 | |||
79 | 0x0e,0xff,0x82, // GAIN1 | ||
80 | 0x03,0x08,0x08, // CLKCONF DYN=1 | ||
81 | 0x2e,0xbf,0x30, // AGCCONF2 TRIAGC=0,POSAGC=ENAGCIF=1 PPWMTUN=0 PPWMIF=0 | ||
82 | 0x01,0xff,0x30, // AGCREF | ||
83 | 0x1e,0x84,0x84, // CONTROL SACLK_ON=1 | ||
84 | 0x1b,0xff,0xc8, // ADC TWOS=1 | ||
85 | 0x3b,0xff,0xff, // IFMAX | ||
86 | 0x3c,0xff,0x00, // IFMIN | ||
87 | 0x34,0xff,0x00, // PWMREF | ||
88 | 0x35,0xff,0xff, // TUNMAX | ||
89 | 0x36,0xff,0x00, // TUNMIN | ||
90 | 0x06,0xff,0x7f, // EQCONF1 POSI=7 ENADAPT=ENEQUAL=DFE=1 // 0x77 | ||
91 | 0x1c,0x30,0x30, // EQCONF2 STEPALGO=SGNALGO=1 | ||
92 | 0x37,0xff,0xf6, // DELTAF_LSB | ||
93 | 0x38,0xff,0xff, // DELTAF_MSB | ||
94 | 0x02,0xff,0x93, // AGCCONF1 IFS=1 KAGCIF=2 KAGCTUN=3 | ||
95 | 0x2d,0xff,0xf6, // SWEEP SWPOS=1 SWDYN=7 SWSTEP=1 SWLEN=2 | ||
96 | 0x04,0x10,0x00, // SWRAMP=1 | ||
97 | 0x12,0xff,0xa1, // INTP1 POCLKP=1 FEL=1 MFS=0 | ||
98 | 0x2b,0x01,0xa1, // INTS1 | ||
99 | 0x20,0xff,0x04, // INTP2 SWAPP=? MSBFIRSTP=? INTPSEL=? | ||
100 | 0x2c,0xff,0x0d, // INTP/S TRIP=0 TRIS=0 | ||
101 | 0xc4,0xff,0x00, | ||
102 | 0xc3,0x30,0x00, | ||
103 | 0xb5,0xff,0x19, // ERAGC_THD | ||
104 | 0x00,0x03,0x01, // GPR, CLBS soft reset | ||
105 | 0x00,0x03,0x03, // GPR, CLBS soft reset | ||
106 | 0xff,0x64,0x00, // Sleep 100ms | ||
107 | 0xff,0xff,0xff | ||
108 | }; | ||
109 | |||
110 | static u8 tda10023_readreg (struct tda10023_state* state, u8 reg) | ||
111 | { | ||
112 | u8 b0 [] = { reg }; | ||
113 | u8 b1 [] = { 0 }; | ||
114 | struct i2c_msg msg [] = { { .addr = state->config->demod_address, .flags = 0, .buf = b0, .len = 1 }, | ||
115 | { .addr = state->config->demod_address, .flags = I2C_M_RD, .buf = b1, .len = 1 } }; | ||
116 | int ret; | ||
117 | |||
118 | ret = i2c_transfer (state->i2c, msg, 2); | ||
119 | if (ret != 2) | ||
120 | printk("DVB: TDA10023: %s: readreg error (ret == %i)\n", | ||
121 | __FUNCTION__, ret); | ||
122 | return b1[0]; | ||
123 | } | ||
124 | |||
125 | static int tda10023_writereg (struct tda10023_state* state, u8 reg, u8 data) | ||
126 | { | ||
127 | u8 buf[] = { reg, data }; | ||
128 | struct i2c_msg msg = { .addr = state->config->demod_address, .flags = 0, .buf = buf, .len = 2 }; | ||
129 | int ret; | ||
130 | |||
131 | ret = i2c_transfer (state->i2c, &msg, 1); | ||
132 | if (ret != 1) | ||
133 | printk("DVB: TDA10023(%d): %s, writereg error " | ||
134 | "(reg == 0x%02x, val == 0x%02x, ret == %i)\n", | ||
135 | state->frontend.dvb->num, __FUNCTION__, reg, data, ret); | ||
136 | |||
137 | return (ret != 1) ? -EREMOTEIO : 0; | ||
138 | } | ||
139 | |||
140 | |||
141 | static int tda10023_writebit (struct tda10023_state* state, u8 reg, u8 mask,u8 data) | ||
142 | { | ||
143 | if (mask==0xff) | ||
144 | return tda10023_writereg(state, reg, data); | ||
145 | else { | ||
146 | u8 val; | ||
147 | val=tda10023_readreg(state,reg); | ||
148 | val&=~mask; | ||
149 | val|=(data&mask); | ||
150 | return tda10023_writereg(state, reg, val); | ||
151 | } | ||
152 | } | ||
153 | |||
154 | static void tda10023_writetab(struct tda10023_state* state, u8* tab) | ||
155 | { | ||
156 | u8 r,m,v; | ||
157 | while (1) { | ||
158 | r=*tab++; | ||
159 | m=*tab++; | ||
160 | v=*tab++; | ||
161 | if (r==0xff) { | ||
162 | if (m==0xff) | ||
163 | break; | ||
164 | else | ||
165 | msleep(m); | ||
166 | } | ||
167 | else | ||
168 | tda10023_writebit(state,r,m,v); | ||
169 | } | ||
170 | } | ||
171 | |||
172 | //get access to tuner | ||
173 | static int lock_tuner(struct tda10023_state* state) | ||
174 | { | ||
175 | u8 buf[2] = { 0x0f, 0xc0 }; | ||
176 | struct i2c_msg msg = {.addr=state->config->demod_address, .flags=0, .buf=buf, .len=2}; | ||
177 | |||
178 | if(i2c_transfer(state->i2c, &msg, 1) != 1) | ||
179 | { | ||
180 | printk("tda10023: lock tuner fails\n"); | ||
181 | return -EREMOTEIO; | ||
182 | } | ||
183 | return 0; | ||
184 | } | ||
185 | |||
186 | //release access from tuner | ||
187 | static int unlock_tuner(struct tda10023_state* state) | ||
188 | { | ||
189 | u8 buf[2] = { 0x0f, 0x40 }; | ||
190 | struct i2c_msg msg_post={.addr=state->config->demod_address, .flags=0, .buf=buf, .len=2}; | ||
191 | |||
192 | if(i2c_transfer(state->i2c, &msg_post, 1) != 1) | ||
193 | { | ||
194 | printk("tda10023: unlock tuner fails\n"); | ||
195 | return -EREMOTEIO; | ||
196 | } | ||
197 | return 0; | ||
198 | } | ||
199 | |||
200 | static int tda10023_setup_reg0 (struct tda10023_state* state, u8 reg0) | ||
201 | { | ||
202 | reg0 |= state->reg0 & 0x63; | ||
203 | |||
204 | tda10023_writereg (state, 0x00, reg0 & 0xfe); | ||
205 | tda10023_writereg (state, 0x00, reg0 | 0x01); | ||
206 | |||
207 | state->reg0 = reg0; | ||
208 | return 0; | ||
209 | } | ||
210 | |||
211 | static int tda10023_set_symbolrate (struct tda10023_state* state, u32 sr) | ||
212 | { | ||
213 | s32 BDR; | ||
214 | s32 BDRI; | ||
215 | s16 SFIL=0; | ||
216 | u16 NDEC = 0; | ||
217 | |||
218 | if (sr > (SYSCLK/(2*4))) | ||
219 | sr=SYSCLK/(2*4); | ||
220 | |||
221 | if (sr<870000) | ||
222 | sr=870000; | ||
223 | |||
224 | if (sr < (u32)(SYSCLK/98.40)) { | ||
225 | NDEC=3; | ||
226 | SFIL=1; | ||
227 | } else if (sr<(u32)(SYSCLK/64.0)) { | ||
228 | NDEC=3; | ||
229 | SFIL=0; | ||
230 | } else if (sr<(u32)(SYSCLK/49.2)) { | ||
231 | NDEC=2; | ||
232 | SFIL=1; | ||
233 | } else if (sr<(u32)(SYSCLK/32.0)) { | ||
234 | NDEC=2; | ||
235 | SFIL=0; | ||
236 | } else if (sr<(u32)(SYSCLK/24.6)) { | ||
237 | NDEC=1; | ||
238 | SFIL=1; | ||
239 | } else if (sr<(u32)(SYSCLK/16.0)) { | ||
240 | NDEC=1; | ||
241 | SFIL=0; | ||
242 | } else if (sr<(u32)(SYSCLK/12.3)) { | ||
243 | NDEC=0; | ||
244 | SFIL=1; | ||
245 | } | ||
246 | |||
247 | BDRI=SYSCLK*16; | ||
248 | BDRI>>=NDEC; | ||
249 | BDRI +=sr/2; | ||
250 | BDRI /=sr; | ||
251 | |||
252 | if (BDRI>255) | ||
253 | BDRI=255; | ||
254 | |||
255 | { | ||
256 | u64 BDRX; | ||
257 | |||
258 | BDRX=1<<(24+NDEC); | ||
259 | BDRX*=sr; | ||
260 | do_div(BDRX,SYSCLK); // BDRX/=SYSCLK; | ||
261 | |||
262 | BDR=(s32)BDRX; | ||
263 | } | ||
264 | // printk("Symbolrate %i, BDR %i BDRI %i, NDEC %i\n",sr,BDR,BDRI,NDEC); | ||
265 | tda10023_writebit (state, 0x03, 0xc0, NDEC<<6); | ||
266 | tda10023_writereg (state, 0x0a, BDR&255); | ||
267 | tda10023_writereg (state, 0x0b, (BDR>>8)&255); | ||
268 | tda10023_writereg (state, 0x0c, (BDR>>16)&31); | ||
269 | tda10023_writereg (state, 0x0d, BDRI); | ||
270 | tda10023_writereg (state, 0x3d, (SFIL<<7)); | ||
271 | return 0; | ||
272 | } | ||
273 | |||
274 | static int tda10023_init (struct dvb_frontend *fe) | ||
275 | { | ||
276 | struct tda10023_state* state = fe->demodulator_priv; | ||
277 | |||
278 | dprintk("DVB: TDA10023(%d): init chip\n", fe->adapter->num); | ||
279 | |||
280 | tda10023_writetab(state, tda10023_inittab); | ||
281 | |||
282 | return 0; | ||
283 | } | ||
284 | |||
285 | static int tda10023_set_parameters (struct dvb_frontend *fe, | ||
286 | struct dvb_frontend_parameters *p) | ||
287 | { | ||
288 | struct tda10023_state* state = fe->demodulator_priv; | ||
289 | |||
290 | static int qamvals[6][6] = { | ||
291 | // QAM LOCKTHR MSETH AREF AGCREFNYQ ERAGCNYQ_THD | ||
292 | { (5<<2), 0x78, 0x8c, 0x96, 0x78, 0x4c }, // 4 QAM | ||
293 | { (0<<2), 0x87, 0xa2, 0x91, 0x8c, 0x57 }, // 16 QAM | ||
294 | { (1<<2), 0x64, 0x74, 0x96, 0x8c, 0x57 }, // 32 QAM | ||
295 | { (2<<2), 0x46, 0x43, 0x6a, 0x6a, 0x44 }, // 64 QAM | ||
296 | { (3<<2), 0x36, 0x34, 0x7e, 0x78, 0x4c }, // 128 QAM | ||
297 | { (4<<2), 0x26, 0x23, 0x6c, 0x5c, 0x3c }, // 256 QAM | ||
298 | }; | ||
299 | |||
300 | int qam = p->u.qam.modulation; | ||
301 | |||
302 | if (qam < 0 || qam > 5) | ||
303 | return -EINVAL; | ||
304 | |||
305 | if (fe->ops.tuner_ops.set_params) { | ||
306 | fe->ops.tuner_ops.set_params(fe, p); | ||
307 | if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0); | ||
308 | } | ||
309 | |||
310 | tda10023_set_symbolrate (state, p->u.qam.symbol_rate); | ||
311 | tda10023_writereg (state, 0x05, qamvals[qam][1]); | ||
312 | tda10023_writereg (state, 0x08, qamvals[qam][2]); | ||
313 | tda10023_writereg (state, 0x09, qamvals[qam][3]); | ||
314 | tda10023_writereg (state, 0xb4, qamvals[qam][4]); | ||
315 | tda10023_writereg (state, 0xb6, qamvals[qam][5]); | ||
316 | |||
317 | // tda10023_writereg (state, 0x04, (p->inversion?0x12:0x32)); | ||
318 | // tda10023_writebit (state, 0x04, 0x60, (p->inversion?0:0x20)); | ||
319 | tda10023_writebit (state, 0x04, 0x40, 0x40); | ||
320 | tda10023_setup_reg0 (state, qamvals[qam][0]); | ||
321 | |||
322 | return 0; | ||
323 | } | ||
324 | |||
325 | static int tda10023_read_status(struct dvb_frontend* fe, fe_status_t* status) | ||
326 | { | ||
327 | struct tda10023_state* state = fe->demodulator_priv; | ||
328 | int sync; | ||
329 | |||
330 | *status = 0; | ||
331 | |||
332 | //0x11[1] == CARLOCK -> Carrier locked | ||
333 | //0x11[2] == FSYNC -> Frame synchronisation | ||
334 | //0x11[3] == FEL -> Front End locked | ||
335 | //0x11[6] == NODVB -> DVB Mode Information | ||
336 | sync = tda10023_readreg (state, 0x11); | ||
337 | |||
338 | if (sync & 2) | ||
339 | *status |= FE_HAS_SIGNAL|FE_HAS_CARRIER; | ||
340 | |||
341 | if (sync & 4) | ||
342 | *status |= FE_HAS_SYNC|FE_HAS_VITERBI; | ||
343 | |||
344 | if (sync & 8) | ||
345 | *status |= FE_HAS_LOCK; | ||
346 | |||
347 | return 0; | ||
348 | } | ||
349 | |||
350 | static int tda10023_read_ber(struct dvb_frontend* fe, u32* ber) | ||
351 | { | ||
352 | struct tda10023_state* state = fe->demodulator_priv; | ||
353 | u8 a,b,c; | ||
354 | a=tda10023_readreg(state, 0x14); | ||
355 | b=tda10023_readreg(state, 0x15); | ||
356 | c=tda10023_readreg(state, 0x16)&0xf; | ||
357 | tda10023_writebit (state, 0x10, 0xc0, 0x00); | ||
358 | |||
359 | *ber = a | (b<<8)| (c<<16); | ||
360 | return 0; | ||
361 | } | ||
362 | |||
363 | static int tda10023_read_signal_strength(struct dvb_frontend* fe, u16* strength) | ||
364 | { | ||
365 | struct tda10023_state* state = fe->demodulator_priv; | ||
366 | u8 ifgain=tda10023_readreg(state, 0x2f); | ||
367 | |||
368 | u16 gain = ((255-tda10023_readreg(state, 0x17))) + (255-ifgain)/16; | ||
369 | // Max raw value is about 0xb0 -> Normalize to >0xf0 after 0x90 | ||
370 | if (gain>0x90) | ||
371 | gain=gain+2*(gain-0x90); | ||
372 | if (gain>255) | ||
373 | gain=255; | ||
374 | |||
375 | *strength = (gain<<8)|gain; | ||
376 | return 0; | ||
377 | } | ||
378 | |||
379 | static int tda10023_read_snr(struct dvb_frontend* fe, u16* snr) | ||
380 | { | ||
381 | struct tda10023_state* state = fe->demodulator_priv; | ||
382 | |||
383 | u8 quality = ~tda10023_readreg(state, 0x18); | ||
384 | *snr = (quality << 8) | quality; | ||
385 | return 0; | ||
386 | } | ||
387 | |||
388 | static int tda10023_read_ucblocks(struct dvb_frontend* fe, u32* ucblocks) | ||
389 | { | ||
390 | struct tda10023_state* state = fe->demodulator_priv; | ||
391 | u8 a,b,c,d; | ||
392 | a= tda10023_readreg (state, 0x74); | ||
393 | b= tda10023_readreg (state, 0x75); | ||
394 | c= tda10023_readreg (state, 0x76); | ||
395 | d= tda10023_readreg (state, 0x77); | ||
396 | *ucblocks = a | (b<<8)|(c<<16)|(d<<24); | ||
397 | |||
398 | tda10023_writebit (state, 0x10, 0x20,0x00); | ||
399 | tda10023_writebit (state, 0x10, 0x20,0x20); | ||
400 | tda10023_writebit (state, 0x13, 0x01, 0x00); | ||
401 | |||
402 | return 0; | ||
403 | } | ||
404 | |||
405 | static int tda10023_get_frontend(struct dvb_frontend* fe, struct dvb_frontend_parameters *p) | ||
406 | { | ||
407 | struct tda10023_state* state = fe->demodulator_priv; | ||
408 | int sync,inv; | ||
409 | s8 afc = 0; | ||
410 | |||
411 | sync = tda10023_readreg(state, 0x11); | ||
412 | afc = tda10023_readreg(state, 0x19); | ||
413 | inv = tda10023_readreg(state, 0x04); | ||
414 | |||
415 | if (verbose) { | ||
416 | /* AFC only valid when carrier has been recovered */ | ||
417 | printk(sync & 2 ? "DVB: TDA10023(%d): AFC (%d) %dHz\n" : | ||
418 | "DVB: TDA10023(%d): [AFC (%d) %dHz]\n", | ||
419 | state->frontend.dvb->num, afc, | ||
420 | -((s32)p->u.qam.symbol_rate * afc) >> 10); | ||
421 | } | ||
422 | |||
423 | p->inversion = (inv&0x20?0:1); | ||
424 | p->u.qam.modulation = ((state->reg0 >> 2) & 7) + QAM_16; | ||
425 | |||
426 | p->u.qam.fec_inner = FEC_NONE; | ||
427 | p->frequency = ((p->frequency + 31250) / 62500) * 62500; | ||
428 | |||
429 | if (sync & 2) | ||
430 | p->frequency -= ((s32)p->u.qam.symbol_rate * afc) >> 10; | ||
431 | |||
432 | return 0; | ||
433 | } | ||
434 | |||
435 | static int tda10023_sleep(struct dvb_frontend* fe) | ||
436 | { | ||
437 | struct tda10023_state* state = fe->demodulator_priv; | ||
438 | |||
439 | tda10023_writereg (state, 0x1b, 0x02); /* pdown ADC */ | ||
440 | tda10023_writereg (state, 0x00, 0x80); /* standby */ | ||
441 | |||
442 | return 0; | ||
443 | } | ||
444 | |||
445 | static int tda10023_i2c_gate_ctrl(struct dvb_frontend* fe, int enable) | ||
446 | { | ||
447 | struct tda10023_state* state = fe->demodulator_priv; | ||
448 | |||
449 | if (enable) { | ||
450 | lock_tuner(state); | ||
451 | } else { | ||
452 | unlock_tuner(state); | ||
453 | } | ||
454 | return 0; | ||
455 | } | ||
456 | |||
457 | static void tda10023_release(struct dvb_frontend* fe) | ||
458 | { | ||
459 | struct tda10023_state* state = fe->demodulator_priv; | ||
460 | kfree(state); | ||
461 | } | ||
462 | |||
463 | static struct dvb_frontend_ops tda10023_ops; | ||
464 | |||
465 | struct dvb_frontend* tda10023_attach(const struct tda1002x_config* config, | ||
466 | struct i2c_adapter* i2c, | ||
467 | u8 pwm) | ||
468 | { | ||
469 | struct tda10023_state* state = NULL; | ||
470 | int i; | ||
471 | |||
472 | /* allocate memory for the internal state */ | ||
473 | state = kmalloc(sizeof(struct tda10023_state), GFP_KERNEL); | ||
474 | if (state == NULL) goto error; | ||
475 | |||
476 | /* setup the state */ | ||
477 | state->config = config; | ||
478 | state->i2c = i2c; | ||
479 | memcpy(&state->frontend.ops, &tda10023_ops, sizeof(struct dvb_frontend_ops)); | ||
480 | state->pwm = pwm; | ||
481 | for (i=0; i < sizeof(tda10023_inittab)/sizeof(*tda10023_inittab);i+=3) { | ||
482 | if (tda10023_inittab[i] == 0x00) { | ||
483 | state->reg0 = tda10023_inittab[i+2]; | ||
484 | break; | ||
485 | } | ||
486 | } | ||
487 | |||
488 | // Wakeup if in standby | ||
489 | tda10023_writereg (state, 0x00, 0x33); | ||
490 | /* check if the demod is there */ | ||
491 | if ((tda10023_readreg(state, 0x1a) & 0xf0) != 0x70) goto error; | ||
492 | |||
493 | /* create dvb_frontend */ | ||
494 | memcpy(&state->frontend.ops, &tda10023_ops, sizeof(struct dvb_frontend_ops)); | ||
495 | state->frontend.demodulator_priv = state; | ||
496 | return &state->frontend; | ||
497 | |||
498 | error: | ||
499 | kfree(state); | ||
500 | return NULL; | ||
501 | } | ||
502 | |||
503 | static struct dvb_frontend_ops tda10023_ops = { | ||
504 | |||
505 | .info = { | ||
506 | .name = "Philips TDA10023 DVB-C", | ||
507 | .type = FE_QAM, | ||
508 | .frequency_stepsize = 62500, | ||
509 | .frequency_min = 51000000, | ||
510 | .frequency_max = 858000000, | ||
511 | .symbol_rate_min = (SYSCLK/2)/64, /* SACLK/64 == (SYSCLK/2)/64 */ | ||
512 | .symbol_rate_max = (SYSCLK/2)/4, /* SACLK/4 */ | ||
513 | .caps = 0x400 | //FE_CAN_QAM_4 | ||
514 | FE_CAN_QAM_16 | FE_CAN_QAM_32 | FE_CAN_QAM_64 | | ||
515 | FE_CAN_QAM_128 | FE_CAN_QAM_256 | | ||
516 | FE_CAN_FEC_AUTO | ||
517 | }, | ||
518 | |||
519 | .release = tda10023_release, | ||
520 | |||
521 | .init = tda10023_init, | ||
522 | .sleep = tda10023_sleep, | ||
523 | .i2c_gate_ctrl = tda10023_i2c_gate_ctrl, | ||
524 | |||
525 | .set_frontend = tda10023_set_parameters, | ||
526 | .get_frontend = tda10023_get_frontend, | ||
527 | |||
528 | .read_status = tda10023_read_status, | ||
529 | .read_ber = tda10023_read_ber, | ||
530 | .read_signal_strength = tda10023_read_signal_strength, | ||
531 | .read_snr = tda10023_read_snr, | ||
532 | .read_ucblocks = tda10023_read_ucblocks, | ||
533 | }; | ||
534 | |||
535 | |||
536 | MODULE_DESCRIPTION("Philips TDA10023 DVB-C demodulator driver"); | ||
537 | MODULE_AUTHOR("Georg Acher, Hartmut Birr"); | ||
538 | MODULE_LICENSE("GPL"); | ||
539 | |||
540 | EXPORT_SYMBOL(tda10023_attach); | ||
diff --git a/drivers/media/dvb/frontends/tda10021.h b/drivers/media/dvb/frontends/tda1002x.h index e3da780108f6..e9094d8123f6 100644 --- a/drivers/media/dvb/frontends/tda10021.h +++ b/drivers/media/dvb/frontends/tda1002x.h | |||
@@ -1,6 +1,6 @@ | |||
1 | /* | 1 | /* |
2 | TDA10021 - Single Chip Cable Channel Receiver driver module | 2 | TDA10021/TDA10023 - Single Chip Cable Channel Receiver driver module |
3 | used on the the Siemens DVB-C cards | 3 | used on the the Siemens DVB-C cards |
4 | 4 | ||
5 | Copyright (C) 1999 Convergence Integrated Media GmbH <ralph@convergence.de> | 5 | Copyright (C) 1999 Convergence Integrated Media GmbH <ralph@convergence.de> |
6 | Copyright (C) 2004 Markus Schulz <msc@antzsystem.de> | 6 | Copyright (C) 2004 Markus Schulz <msc@antzsystem.de> |
@@ -21,22 +21,23 @@ | |||
21 | Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | 21 | Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. |
22 | */ | 22 | */ |
23 | 23 | ||
24 | #ifndef TDA10021_H | 24 | #ifndef TDA1002x_H |
25 | #define TDA10021_H | 25 | #define TDA1002x_H |
26 | 26 | ||
27 | #include <linux/dvb/frontend.h> | 27 | #include <linux/dvb/frontend.h> |
28 | 28 | ||
29 | struct tda10021_config | 29 | struct tda1002x_config |
30 | { | 30 | { |
31 | /* the demodulator's i2c address */ | 31 | /* the demodulator's i2c address */ |
32 | u8 demod_address; | 32 | u8 demod_address; |
33 | u8 invert; | ||
33 | }; | 34 | }; |
34 | 35 | ||
35 | #if defined(CONFIG_DVB_TDA10021) || (defined(CONFIG_DVB_TDA10021_MODULE) && defined(MODULE)) | 36 | #if defined(CONFIG_DVB_TDA10021) || (defined(CONFIG_DVB_TDA10021_MODULE) && defined(MODULE)) |
36 | extern struct dvb_frontend* tda10021_attach(const struct tda10021_config* config, | 37 | extern struct dvb_frontend* tda10021_attach(const struct tda1002x_config* config, |
37 | struct i2c_adapter* i2c, u8 pwm); | 38 | struct i2c_adapter* i2c, u8 pwm); |
38 | #else | 39 | #else |
39 | static inline struct dvb_frontend* tda10021_attach(const struct tda10021_config* config, | 40 | static inline struct dvb_frontend* tda10021_attach(const struct tda1002x_config* config, |
40 | struct i2c_adapter* i2c, u8 pwm) | 41 | struct i2c_adapter* i2c, u8 pwm) |
41 | { | 42 | { |
42 | printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __FUNCTION__); | 43 | printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __FUNCTION__); |
@@ -44,12 +45,16 @@ static inline struct dvb_frontend* tda10021_attach(const struct tda10021_config* | |||
44 | } | 45 | } |
45 | #endif // CONFIG_DVB_TDA10021 | 46 | #endif // CONFIG_DVB_TDA10021 |
46 | 47 | ||
47 | static inline int tda10021_writereg(struct dvb_frontend *fe, u8 reg, u8 val) { | 48 | #if defined(CONFIG_DVB_TDA10023) || (defined(CONFIG_DVB_TDA10023_MODULE) && defined(MODULE)) |
48 | int r = 0; | 49 | extern struct dvb_frontend* tda10023_attach(const struct tda1002x_config* config, |
49 | u8 buf[] = {reg, val}; | 50 | struct i2c_adapter* i2c, u8 pwm); |
50 | if (fe->ops.write) | 51 | #else |
51 | r = fe->ops.write(fe, buf, 2); | 52 | static inline struct dvb_frontend* tda10023_attach(const struct tda1002x_config* config, |
52 | return r; | 53 | struct i2c_adapter* i2c, u8 pwm) |
54 | { | ||
55 | printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __FUNCTION__); | ||
56 | return NULL; | ||
53 | } | 57 | } |
58 | #endif // CONFIG_DVB_TDA10023 | ||
54 | 59 | ||
55 | #endif // TDA10021_H | 60 | #endif // TDA1002x_H |
diff --git a/drivers/media/dvb/frontends/tda1004x.c b/drivers/media/dvb/frontends/tda1004x.c index f4a9cf9d26d0..33a84372c9e6 100644 --- a/drivers/media/dvb/frontends/tda1004x.c +++ b/drivers/media/dvb/frontends/tda1004x.c | |||
@@ -40,20 +40,6 @@ | |||
40 | #include "dvb_frontend.h" | 40 | #include "dvb_frontend.h" |
41 | #include "tda1004x.h" | 41 | #include "tda1004x.h" |
42 | 42 | ||
43 | enum tda1004x_demod { | ||
44 | TDA1004X_DEMOD_TDA10045, | ||
45 | TDA1004X_DEMOD_TDA10046, | ||
46 | }; | ||
47 | |||
48 | struct tda1004x_state { | ||
49 | struct i2c_adapter* i2c; | ||
50 | const struct tda1004x_config* config; | ||
51 | struct dvb_frontend frontend; | ||
52 | |||
53 | /* private demod data */ | ||
54 | enum tda1004x_demod demod_type; | ||
55 | }; | ||
56 | |||
57 | static int debug; | 43 | static int debug; |
58 | #define dprintk(args...) \ | 44 | #define dprintk(args...) \ |
59 | do { \ | 45 | do { \ |
@@ -507,35 +493,51 @@ static int tda10046_fwupload(struct dvb_frontend* fe) | |||
507 | tda1004x_write_byteI(state, TDA1004X_CONFC4, 0x80); | 493 | tda1004x_write_byteI(state, TDA1004X_CONFC4, 0x80); |
508 | } | 494 | } |
509 | tda1004x_write_mask(state, TDA10046H_CONF_TRISTATE1, 1, 0); | 495 | tda1004x_write_mask(state, TDA10046H_CONF_TRISTATE1, 1, 0); |
496 | /* set GPIO 1 and 3 */ | ||
497 | if (state->config->gpio_config != TDA10046_GPTRI) { | ||
498 | tda1004x_write_byteI(state, TDA10046H_CONF_TRISTATE2, 0x33); | ||
499 | tda1004x_write_mask(state, TDA10046H_CONF_POLARITY, 0x0f, state->config->gpio_config &0x0f); | ||
500 | } | ||
510 | /* let the clocks recover from sleep */ | 501 | /* let the clocks recover from sleep */ |
511 | msleep(5); | 502 | msleep(10); |
512 | 503 | ||
513 | /* The PLLs need to be reprogrammed after sleep */ | 504 | /* The PLLs need to be reprogrammed after sleep */ |
514 | tda10046_init_plls(fe); | 505 | tda10046_init_plls(fe); |
506 | tda1004x_write_mask(state, TDA1004X_CONFADC2, 0xc0, 0); | ||
515 | 507 | ||
516 | /* don't re-upload unless necessary */ | 508 | /* don't re-upload unless necessary */ |
517 | if (tda1004x_check_upload_ok(state) == 0) | 509 | if (tda1004x_check_upload_ok(state) == 0) |
518 | return 0; | 510 | return 0; |
519 | 511 | ||
512 | printk(KERN_INFO "tda1004x: trying to boot from eeprom\n"); | ||
513 | tda1004x_write_mask(state, TDA1004X_CONFC4, 4, 4); | ||
514 | msleep(300); | ||
515 | /* don't re-upload unless necessary */ | ||
516 | if (tda1004x_check_upload_ok(state) == 0) | ||
517 | return 0; | ||
518 | |||
520 | if (state->config->request_firmware != NULL) { | 519 | if (state->config->request_firmware != NULL) { |
521 | /* request the firmware, this will block until someone uploads it */ | 520 | /* request the firmware, this will block until someone uploads it */ |
522 | printk(KERN_INFO "tda1004x: waiting for firmware upload...\n"); | 521 | printk(KERN_INFO "tda1004x: waiting for firmware upload...\n"); |
523 | ret = state->config->request_firmware(fe, &fw, TDA10046_DEFAULT_FIRMWARE); | 522 | ret = state->config->request_firmware(fe, &fw, TDA10046_DEFAULT_FIRMWARE); |
524 | if (ret) { | 523 | if (ret) { |
525 | printk(KERN_ERR "tda1004x: no firmware upload (timeout or file not found?)\n"); | 524 | /* remain compatible to old bug: try to load with tda10045 image name */ |
526 | return ret; | 525 | ret = state->config->request_firmware(fe, &fw, TDA10045_DEFAULT_FIRMWARE); |
526 | if (ret) { | ||
527 | printk(KERN_ERR "tda1004x: no firmware upload (timeout or file not found?)\n"); | ||
528 | return ret; | ||
529 | } else { | ||
530 | printk(KERN_INFO "tda1004x: please rename the firmware file to %s\n", | ||
531 | TDA10046_DEFAULT_FIRMWARE); | ||
532 | } | ||
527 | } | 533 | } |
528 | tda1004x_write_mask(state, TDA1004X_CONFC4, 8, 8); // going to boot from HOST | ||
529 | ret = tda1004x_do_upload(state, fw->data, fw->size, TDA10046H_CODE_CPT, TDA10046H_CODE_IN); | ||
530 | release_firmware(fw); | ||
531 | if (ret) | ||
532 | return ret; | ||
533 | } else { | 534 | } else { |
534 | /* boot from firmware eeprom */ | 535 | printk(KERN_ERR "tda1004x: no request function defined, can't upload from file\n"); |
535 | printk(KERN_INFO "tda1004x: booting from eeprom\n"); | 536 | return -EIO; |
536 | tda1004x_write_mask(state, TDA1004X_CONFC4, 4, 4); | ||
537 | msleep(300); | ||
538 | } | 537 | } |
538 | tda1004x_write_mask(state, TDA1004X_CONFC4, 8, 8); // going to boot from HOST | ||
539 | ret = tda1004x_do_upload(state, fw->data, fw->size, TDA10046H_CODE_CPT, TDA10046H_CODE_IN); | ||
540 | release_firmware(fw); | ||
539 | return tda1004x_check_upload_ok(state); | 541 | return tda1004x_check_upload_ok(state); |
540 | } | 542 | } |
541 | 543 | ||
@@ -638,37 +640,33 @@ static int tda10046_init(struct dvb_frontend* fe) | |||
638 | switch (state->config->agc_config) { | 640 | switch (state->config->agc_config) { |
639 | case TDA10046_AGC_DEFAULT: | 641 | case TDA10046_AGC_DEFAULT: |
640 | tda1004x_write_byteI(state, TDA10046H_AGC_CONF, 0x00); // AGC setup | 642 | tda1004x_write_byteI(state, TDA10046H_AGC_CONF, 0x00); // AGC setup |
641 | tda1004x_write_byteI(state, TDA10046H_CONF_POLARITY, 0x60); // set AGC polarities | 643 | tda1004x_write_mask(state, TDA10046H_CONF_POLARITY, 0xf0, 0x60); // set AGC polarities |
642 | break; | 644 | break; |
643 | case TDA10046_AGC_IFO_AUTO_NEG: | 645 | case TDA10046_AGC_IFO_AUTO_NEG: |
644 | tda1004x_write_byteI(state, TDA10046H_AGC_CONF, 0x0a); // AGC setup | 646 | tda1004x_write_byteI(state, TDA10046H_AGC_CONF, 0x0a); // AGC setup |
645 | tda1004x_write_byteI(state, TDA10046H_CONF_POLARITY, 0x60); // set AGC polarities | 647 | tda1004x_write_mask(state, TDA10046H_CONF_POLARITY, 0xf0, 0x60); // set AGC polarities |
646 | break; | 648 | break; |
647 | case TDA10046_AGC_IFO_AUTO_POS: | 649 | case TDA10046_AGC_IFO_AUTO_POS: |
648 | tda1004x_write_byteI(state, TDA10046H_AGC_CONF, 0x0a); // AGC setup | 650 | tda1004x_write_byteI(state, TDA10046H_AGC_CONF, 0x0a); // AGC setup |
649 | tda1004x_write_byteI(state, TDA10046H_CONF_POLARITY, 0x00); // set AGC polarities | 651 | tda1004x_write_mask(state, TDA10046H_CONF_POLARITY, 0xf0, 0x00); // set AGC polarities |
650 | break; | ||
651 | case TDA10046_AGC_TDA827X_GP11: | ||
652 | tda1004x_write_byteI(state, TDA10046H_AGC_CONF, 0x02); // AGC setup | ||
653 | tda1004x_write_byteI(state, TDA10046H_AGC_THR, 0x70); // AGC Threshold | ||
654 | tda1004x_write_byteI(state, TDA10046H_AGC_RENORM, 0x08); // Gain Renormalize | ||
655 | tda1004x_write_byteI(state, TDA10046H_CONF_POLARITY, 0x6a); // set AGC polarities | ||
656 | break; | ||
657 | case TDA10046_AGC_TDA827X_GP00: | ||
658 | tda1004x_write_byteI(state, TDA10046H_AGC_CONF, 0x02); // AGC setup | ||
659 | tda1004x_write_byteI(state, TDA10046H_AGC_THR, 0x70); // AGC Threshold | ||
660 | tda1004x_write_byteI(state, TDA10046H_AGC_RENORM, 0x08); // Gain Renormalize | ||
661 | tda1004x_write_byteI(state, TDA10046H_CONF_POLARITY, 0x60); // set AGC polarities | ||
662 | break; | 652 | break; |
663 | case TDA10046_AGC_TDA827X_GP01: | 653 | case TDA10046_AGC_TDA827X: |
664 | tda1004x_write_byteI(state, TDA10046H_AGC_CONF, 0x02); // AGC setup | 654 | tda1004x_write_byteI(state, TDA10046H_AGC_CONF, 0x02); // AGC setup |
665 | tda1004x_write_byteI(state, TDA10046H_AGC_THR, 0x70); // AGC Threshold | 655 | tda1004x_write_byteI(state, TDA10046H_AGC_THR, 0x70); // AGC Threshold |
666 | tda1004x_write_byteI(state, TDA10046H_AGC_RENORM, 0x08); // Gain Renormalize | 656 | tda1004x_write_byteI(state, TDA10046H_AGC_RENORM, 0x08); // Gain Renormalize |
667 | tda1004x_write_byteI(state, TDA10046H_CONF_POLARITY, 0x62); // set AGC polarities | 657 | tda1004x_write_mask(state, TDA10046H_CONF_POLARITY, 0xf0, 0x60); // set AGC polarities |
668 | break; | 658 | break; |
669 | } | 659 | } |
660 | if (state->config->ts_mode == 0) { | ||
661 | tda1004x_write_mask(state, TDA10046H_CONF_TRISTATE1, 0xc0, 0x40); | ||
662 | tda1004x_write_mask(state, 0x3a, 0x80, state->config->invert_oclk << 7); | ||
663 | } else { | ||
664 | tda1004x_write_mask(state, TDA10046H_CONF_TRISTATE1, 0xc0, 0x80); | ||
665 | tda1004x_write_mask(state, TDA10046H_CONF_POLARITY, 0x10, | ||
666 | state->config->invert_oclk << 4); | ||
667 | } | ||
670 | tda1004x_write_byteI(state, TDA1004X_CONFADC2, 0x38); | 668 | tda1004x_write_byteI(state, TDA1004X_CONFADC2, 0x38); |
671 | tda1004x_write_byteI(state, TDA10046H_CONF_TRISTATE1, 0x61); // Turn both AGC outputs on | 669 | tda1004x_write_mask (state, TDA10046H_CONF_TRISTATE1, 0x3e, 0x38); // Turn IF AGC output on |
672 | tda1004x_write_byteI(state, TDA10046H_AGC_TUN_MIN, 0); // } | 670 | tda1004x_write_byteI(state, TDA10046H_AGC_TUN_MIN, 0); // } |
673 | tda1004x_write_byteI(state, TDA10046H_AGC_TUN_MAX, 0xff); // } AGC min/max values | 671 | tda1004x_write_byteI(state, TDA10046H_AGC_TUN_MAX, 0xff); // } AGC min/max values |
674 | tda1004x_write_byteI(state, TDA10046H_AGC_IF_MIN, 0); // } | 672 | tda1004x_write_byteI(state, TDA10046H_AGC_IF_MIN, 0); // } |
@@ -678,7 +676,6 @@ static int tda10046_init(struct dvb_frontend* fe) | |||
678 | tda1004x_write_byteI(state, TDA1004X_CONF_TS1, 7); // MPEG2 interface config | 676 | tda1004x_write_byteI(state, TDA1004X_CONF_TS1, 7); // MPEG2 interface config |
679 | tda1004x_write_byteI(state, TDA1004X_CONF_TS2, 0xc0); // MPEG2 interface config | 677 | tda1004x_write_byteI(state, TDA1004X_CONF_TS2, 0xc0); // MPEG2 interface config |
680 | // tda1004x_write_mask(state, 0x50, 0x80, 0x80); // handle out of guard echoes | 678 | // tda1004x_write_mask(state, 0x50, 0x80, 0x80); // handle out of guard echoes |
681 | tda1004x_write_mask(state, 0x3a, 0x80, state->config->invert_oclk << 7); | ||
682 | 679 | ||
683 | return 0; | 680 | return 0; |
684 | } | 681 | } |
@@ -705,7 +702,8 @@ static int tda1004x_set_fe(struct dvb_frontend* fe, | |||
705 | // set frequency | 702 | // set frequency |
706 | if (fe->ops.tuner_ops.set_params) { | 703 | if (fe->ops.tuner_ops.set_params) { |
707 | fe->ops.tuner_ops.set_params(fe, fe_params); | 704 | fe->ops.tuner_ops.set_params(fe, fe_params); |
708 | if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0); | 705 | if (fe->ops.i2c_gate_ctrl) |
706 | fe->ops.i2c_gate_ctrl(fe, 0); | ||
709 | } | 707 | } |
710 | 708 | ||
711 | // Hardcoded to use auto as much as possible on the TDA10045 as it | 709 | // Hardcoded to use auto as much as possible on the TDA10045 as it |
@@ -1165,6 +1163,7 @@ static int tda1004x_read_ber(struct dvb_frontend* fe, u32* ber) | |||
1165 | static int tda1004x_sleep(struct dvb_frontend* fe) | 1163 | static int tda1004x_sleep(struct dvb_frontend* fe) |
1166 | { | 1164 | { |
1167 | struct tda1004x_state* state = fe->demodulator_priv; | 1165 | struct tda1004x_state* state = fe->demodulator_priv; |
1166 | int gpio_conf; | ||
1168 | 1167 | ||
1169 | switch (state->demod_type) { | 1168 | switch (state->demod_type) { |
1170 | case TDA1004X_DEMOD_TDA10045: | 1169 | case TDA1004X_DEMOD_TDA10045: |
@@ -1174,6 +1173,13 @@ static int tda1004x_sleep(struct dvb_frontend* fe) | |||
1174 | case TDA1004X_DEMOD_TDA10046: | 1173 | case TDA1004X_DEMOD_TDA10046: |
1175 | /* set outputs to tristate */ | 1174 | /* set outputs to tristate */ |
1176 | tda1004x_write_byteI(state, TDA10046H_CONF_TRISTATE1, 0xff); | 1175 | tda1004x_write_byteI(state, TDA10046H_CONF_TRISTATE1, 0xff); |
1176 | /* invert GPIO 1 and 3 if desired*/ | ||
1177 | gpio_conf = state->config->gpio_config; | ||
1178 | if (gpio_conf >= TDA10046_GP00_I) | ||
1179 | tda1004x_write_mask(state, TDA10046H_CONF_POLARITY, 0x0f, | ||
1180 | (gpio_conf & 0x0f) ^ 0x0a); | ||
1181 | |||
1182 | tda1004x_write_mask(state, TDA1004X_CONFADC2, 0xc0, 0xc0); | ||
1177 | tda1004x_write_mask(state, TDA1004X_CONFC4, 1, 1); | 1183 | tda1004x_write_mask(state, TDA1004X_CONFC4, 1, 1); |
1178 | break; | 1184 | break; |
1179 | } | 1185 | } |
diff --git a/drivers/media/dvb/frontends/tda1004x.h b/drivers/media/dvb/frontends/tda1004x.h index ec502d71b83c..abae84350142 100644 --- a/drivers/media/dvb/frontends/tda1004x.h +++ b/drivers/media/dvb/frontends/tda1004x.h | |||
@@ -35,9 +35,23 @@ enum tda10046_agc { | |||
35 | TDA10046_AGC_DEFAULT, /* original configuration */ | 35 | TDA10046_AGC_DEFAULT, /* original configuration */ |
36 | TDA10046_AGC_IFO_AUTO_NEG, /* IF AGC only, automatic, negtive */ | 36 | TDA10046_AGC_IFO_AUTO_NEG, /* IF AGC only, automatic, negtive */ |
37 | TDA10046_AGC_IFO_AUTO_POS, /* IF AGC only, automatic, positive */ | 37 | TDA10046_AGC_IFO_AUTO_POS, /* IF AGC only, automatic, positive */ |
38 | TDA10046_AGC_TDA827X_GP11, /* IF AGC only, special setup for tda827x */ | 38 | TDA10046_AGC_TDA827X, /* IF AGC only, special setup for tda827x */ |
39 | TDA10046_AGC_TDA827X_GP00, /* same as above, but GPIOs 0 */ | 39 | }; |
40 | TDA10046_AGC_TDA827X_GP01, /* same as above, but GPIO3=0 GPIO1=1*/ | 40 | |
41 | /* Many (hybrid) boards use GPIO 1 and 3 | ||
42 | GPIO1 analog - dvb switch | ||
43 | GPIO3 firmware eeprom address switch | ||
44 | */ | ||
45 | enum tda10046_gpio { | ||
46 | TDA10046_GPTRI = 0x00, /* All GPIOs tristate */ | ||
47 | TDA10046_GP00 = 0x40, /* GPIO3=0, GPIO1=0 */ | ||
48 | TDA10046_GP01 = 0x42, /* GPIO3=0, GPIO1=1 */ | ||
49 | TDA10046_GP10 = 0x48, /* GPIO3=1, GPIO1=0 */ | ||
50 | TDA10046_GP11 = 0x4a, /* GPIO3=1, GPIO1=1 */ | ||
51 | TDA10046_GP00_I = 0x80, /* GPIO3=0, GPIO1=0, invert in sleep mode*/ | ||
52 | TDA10046_GP01_I = 0x82, /* GPIO3=0, GPIO1=1, invert in sleep mode */ | ||
53 | TDA10046_GP10_I = 0x88, /* GPIO3=1, GPIO1=0, invert in sleep mode */ | ||
54 | TDA10046_GP11_I = 0x8a, /* GPIO3=1, GPIO1=1, invert in sleep mode */ | ||
41 | }; | 55 | }; |
42 | 56 | ||
43 | enum tda10046_if { | 57 | enum tda10046_if { |
@@ -47,6 +61,11 @@ enum tda10046_if { | |||
47 | TDA10046_FREQ_052, /* low IF, 5.1667 MHZ for tda9889 */ | 61 | TDA10046_FREQ_052, /* low IF, 5.1667 MHZ for tda9889 */ |
48 | }; | 62 | }; |
49 | 63 | ||
64 | enum tda10046_tsout { | ||
65 | TDA10046_TS_PARALLEL = 0x00, /* parallel transport stream, default */ | ||
66 | TDA10046_TS_SERIAL = 0x01, /* serial transport stream */ | ||
67 | }; | ||
68 | |||
50 | struct tda1004x_config | 69 | struct tda1004x_config |
51 | { | 70 | { |
52 | /* the demodulator's i2c address */ | 71 | /* the demodulator's i2c address */ |
@@ -58,6 +77,9 @@ struct tda1004x_config | |||
58 | /* Does the OCLK signal need inverted? */ | 77 | /* Does the OCLK signal need inverted? */ |
59 | u8 invert_oclk; | 78 | u8 invert_oclk; |
60 | 79 | ||
80 | /* parallel or serial transport stream */ | ||
81 | enum tda10046_tsout ts_mode; | ||
82 | |||
61 | /* Xtal frequency, 4 or 16MHz*/ | 83 | /* Xtal frequency, 4 or 16MHz*/ |
62 | enum tda10046_xtal xtal_freq; | 84 | enum tda10046_xtal xtal_freq; |
63 | 85 | ||
@@ -67,11 +89,35 @@ struct tda1004x_config | |||
67 | /* AGC configuration */ | 89 | /* AGC configuration */ |
68 | enum tda10046_agc agc_config; | 90 | enum tda10046_agc agc_config; |
69 | 91 | ||
92 | /* setting of GPIO1 and 3 */ | ||
93 | enum tda10046_gpio gpio_config; | ||
94 | |||
95 | /* slave address and configuration of the tuner */ | ||
96 | u8 tuner_address; | ||
97 | u8 tuner_config; | ||
98 | u8 antenna_switch; | ||
99 | |||
100 | /* if the board uses another I2c Bridge (tda8290), its address */ | ||
101 | u8 i2c_gate; | ||
102 | |||
70 | /* request firmware for device */ | 103 | /* request firmware for device */ |
71 | /* set this to NULL if the card has a firmware EEPROM */ | ||
72 | int (*request_firmware)(struct dvb_frontend* fe, const struct firmware **fw, char* name); | 104 | int (*request_firmware)(struct dvb_frontend* fe, const struct firmware **fw, char* name); |
73 | }; | 105 | }; |
74 | 106 | ||
107 | enum tda1004x_demod { | ||
108 | TDA1004X_DEMOD_TDA10045, | ||
109 | TDA1004X_DEMOD_TDA10046, | ||
110 | }; | ||
111 | |||
112 | struct tda1004x_state { | ||
113 | struct i2c_adapter* i2c; | ||
114 | const struct tda1004x_config* config; | ||
115 | struct dvb_frontend frontend; | ||
116 | |||
117 | /* private demod data */ | ||
118 | enum tda1004x_demod demod_type; | ||
119 | }; | ||
120 | |||
75 | #if defined(CONFIG_DVB_TDA1004X) || (defined(CONFIG_DVB_TDA1004X_MODULE) && defined(MODULE)) | 121 | #if defined(CONFIG_DVB_TDA1004X) || (defined(CONFIG_DVB_TDA1004X_MODULE) && defined(MODULE)) |
76 | extern struct dvb_frontend* tda10045_attach(const struct tda1004x_config* config, | 122 | extern struct dvb_frontend* tda10045_attach(const struct tda1004x_config* config, |
77 | struct i2c_adapter* i2c); | 123 | struct i2c_adapter* i2c); |
diff --git a/drivers/media/dvb/frontends/tda827x.c b/drivers/media/dvb/frontends/tda827x.c new file mode 100644 index 000000000000..256fc4bf500b --- /dev/null +++ b/drivers/media/dvb/frontends/tda827x.c | |||
@@ -0,0 +1,512 @@ | |||
1 | /* | ||
2 | * | ||
3 | * (c) 2005 Hartmut Hackmann | ||
4 | * (c) 2007 Michael Krufky | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify | ||
7 | * it under the terms of the GNU General Public License as published by | ||
8 | * the Free Software Foundation; either version 2 of the License, or | ||
9 | * (at your option) any later version. | ||
10 | * | ||
11 | * This program is distributed in the hope that it will be useful, | ||
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
14 | * GNU General Public License for more details. | ||
15 | * | ||
16 | * You should have received a copy of the GNU General Public License | ||
17 | * along with this program; if not, write to the Free Software | ||
18 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
19 | */ | ||
20 | |||
21 | #include <linux/module.h> | ||
22 | #include <linux/dvb/frontend.h> | ||
23 | #include <asm/types.h> | ||
24 | |||
25 | #include "tda827x.h" | ||
26 | |||
27 | static int debug = 0; | ||
28 | #define dprintk(args...) \ | ||
29 | do { \ | ||
30 | if (debug) printk(KERN_DEBUG "tda827x: " args); \ | ||
31 | } while (0) | ||
32 | |||
33 | struct tda827x_priv { | ||
34 | int i2c_addr; | ||
35 | struct i2c_adapter *i2c_adap; | ||
36 | struct tda827x_config *cfg; | ||
37 | u32 frequency; | ||
38 | u32 bandwidth; | ||
39 | }; | ||
40 | |||
41 | struct tda827x_data { | ||
42 | u32 lomax; | ||
43 | u8 spd; | ||
44 | u8 bs; | ||
45 | u8 bp; | ||
46 | u8 cp; | ||
47 | u8 gc3; | ||
48 | u8 div1p5; | ||
49 | }; | ||
50 | |||
51 | static const struct tda827x_data tda827x_dvbt[] = { | ||
52 | { .lomax = 62000000, .spd = 3, .bs = 2, .bp = 0, .cp = 0, .gc3 = 3, .div1p5 = 1}, | ||
53 | { .lomax = 66000000, .spd = 3, .bs = 3, .bp = 0, .cp = 0, .gc3 = 3, .div1p5 = 1}, | ||
54 | { .lomax = 76000000, .spd = 3, .bs = 1, .bp = 0, .cp = 0, .gc3 = 3, .div1p5 = 0}, | ||
55 | { .lomax = 84000000, .spd = 3, .bs = 2, .bp = 0, .cp = 0, .gc3 = 3, .div1p5 = 0}, | ||
56 | { .lomax = 93000000, .spd = 3, .bs = 2, .bp = 0, .cp = 0, .gc3 = 1, .div1p5 = 0}, | ||
57 | { .lomax = 98000000, .spd = 3, .bs = 3, .bp = 0, .cp = 0, .gc3 = 1, .div1p5 = 0}, | ||
58 | { .lomax = 109000000, .spd = 3, .bs = 3, .bp = 1, .cp = 0, .gc3 = 1, .div1p5 = 0}, | ||
59 | { .lomax = 123000000, .spd = 2, .bs = 2, .bp = 1, .cp = 0, .gc3 = 1, .div1p5 = 1}, | ||
60 | { .lomax = 133000000, .spd = 2, .bs = 3, .bp = 1, .cp = 0, .gc3 = 1, .div1p5 = 1}, | ||
61 | { .lomax = 151000000, .spd = 2, .bs = 1, .bp = 1, .cp = 0, .gc3 = 1, .div1p5 = 0}, | ||
62 | { .lomax = 154000000, .spd = 2, .bs = 2, .bp = 1, .cp = 0, .gc3 = 1, .div1p5 = 0}, | ||
63 | { .lomax = 181000000, .spd = 2, .bs = 2, .bp = 1, .cp = 0, .gc3 = 0, .div1p5 = 0}, | ||
64 | { .lomax = 185000000, .spd = 2, .bs = 2, .bp = 2, .cp = 0, .gc3 = 1, .div1p5 = 0}, | ||
65 | { .lomax = 217000000, .spd = 2, .bs = 3, .bp = 2, .cp = 0, .gc3 = 1, .div1p5 = 0}, | ||
66 | { .lomax = 244000000, .spd = 1, .bs = 2, .bp = 2, .cp = 0, .gc3 = 1, .div1p5 = 1}, | ||
67 | { .lomax = 265000000, .spd = 1, .bs = 3, .bp = 2, .cp = 0, .gc3 = 1, .div1p5 = 1}, | ||
68 | { .lomax = 302000000, .spd = 1, .bs = 1, .bp = 2, .cp = 0, .gc3 = 1, .div1p5 = 0}, | ||
69 | { .lomax = 324000000, .spd = 1, .bs = 2, .bp = 2, .cp = 0, .gc3 = 1, .div1p5 = 0}, | ||
70 | { .lomax = 370000000, .spd = 1, .bs = 2, .bp = 3, .cp = 0, .gc3 = 1, .div1p5 = 0}, | ||
71 | { .lomax = 454000000, .spd = 1, .bs = 3, .bp = 3, .cp = 0, .gc3 = 1, .div1p5 = 0}, | ||
72 | { .lomax = 493000000, .spd = 0, .bs = 2, .bp = 3, .cp = 0, .gc3 = 1, .div1p5 = 1}, | ||
73 | { .lomax = 530000000, .spd = 0, .bs = 3, .bp = 3, .cp = 0, .gc3 = 1, .div1p5 = 1}, | ||
74 | { .lomax = 554000000, .spd = 0, .bs = 1, .bp = 3, .cp = 0, .gc3 = 1, .div1p5 = 0}, | ||
75 | { .lomax = 604000000, .spd = 0, .bs = 1, .bp = 4, .cp = 0, .gc3 = 0, .div1p5 = 0}, | ||
76 | { .lomax = 696000000, .spd = 0, .bs = 2, .bp = 4, .cp = 0, .gc3 = 0, .div1p5 = 0}, | ||
77 | { .lomax = 740000000, .spd = 0, .bs = 2, .bp = 4, .cp = 1, .gc3 = 0, .div1p5 = 0}, | ||
78 | { .lomax = 820000000, .spd = 0, .bs = 3, .bp = 4, .cp = 0, .gc3 = 0, .div1p5 = 0}, | ||
79 | { .lomax = 865000000, .spd = 0, .bs = 3, .bp = 4, .cp = 1, .gc3 = 0, .div1p5 = 0}, | ||
80 | { .lomax = 0, .spd = 0, .bs = 0, .bp = 0, .cp = 0, .gc3 = 0, .div1p5 = 0} | ||
81 | }; | ||
82 | |||
83 | static int tda827xo_set_params(struct dvb_frontend *fe, | ||
84 | struct dvb_frontend_parameters *params) | ||
85 | { | ||
86 | struct tda827x_priv *priv = fe->tuner_priv; | ||
87 | u8 buf[14]; | ||
88 | |||
89 | struct i2c_msg msg = { .addr = priv->i2c_addr, .flags = 0, | ||
90 | .buf = buf, .len = sizeof(buf) }; | ||
91 | int i, tuner_freq, if_freq; | ||
92 | u32 N; | ||
93 | |||
94 | dprintk("%s:\n", __FUNCTION__); | ||
95 | switch (params->u.ofdm.bandwidth) { | ||
96 | case BANDWIDTH_6_MHZ: | ||
97 | if_freq = 4000000; | ||
98 | break; | ||
99 | case BANDWIDTH_7_MHZ: | ||
100 | if_freq = 4500000; | ||
101 | break; | ||
102 | default: /* 8 MHz or Auto */ | ||
103 | if_freq = 5000000; | ||
104 | break; | ||
105 | } | ||
106 | tuner_freq = params->frequency + if_freq; | ||
107 | |||
108 | i = 0; | ||
109 | while (tda827x_dvbt[i].lomax < tuner_freq) { | ||
110 | if(tda827x_dvbt[i + 1].lomax == 0) | ||
111 | break; | ||
112 | i++; | ||
113 | } | ||
114 | |||
115 | N = ((tuner_freq + 125000) / 250000) << (tda827x_dvbt[i].spd + 2); | ||
116 | buf[0] = 0; | ||
117 | buf[1] = (N>>8) | 0x40; | ||
118 | buf[2] = N & 0xff; | ||
119 | buf[3] = 0; | ||
120 | buf[4] = 0x52; | ||
121 | buf[5] = (tda827x_dvbt[i].spd << 6) + (tda827x_dvbt[i].div1p5 << 5) + | ||
122 | (tda827x_dvbt[i].bs << 3) + tda827x_dvbt[i].bp; | ||
123 | buf[6] = (tda827x_dvbt[i].gc3 << 4) + 0x8f; | ||
124 | buf[7] = 0xbf; | ||
125 | buf[8] = 0x2a; | ||
126 | buf[9] = 0x05; | ||
127 | buf[10] = 0xff; | ||
128 | buf[11] = 0x00; | ||
129 | buf[12] = 0x00; | ||
130 | buf[13] = 0x40; | ||
131 | |||
132 | msg.len = 14; | ||
133 | if (fe->ops.i2c_gate_ctrl) | ||
134 | fe->ops.i2c_gate_ctrl(fe, 1); | ||
135 | if (i2c_transfer(priv->i2c_adap, &msg, 1) != 1) { | ||
136 | printk("%s: could not write to tuner at addr: 0x%02x\n", | ||
137 | __FUNCTION__, priv->i2c_addr << 1); | ||
138 | return -EIO; | ||
139 | } | ||
140 | msleep(500); | ||
141 | /* correct CP value */ | ||
142 | buf[0] = 0x30; | ||
143 | buf[1] = 0x50 + tda827x_dvbt[i].cp; | ||
144 | msg.len = 2; | ||
145 | |||
146 | if (fe->ops.i2c_gate_ctrl) | ||
147 | fe->ops.i2c_gate_ctrl(fe, 1); | ||
148 | i2c_transfer(priv->i2c_adap, &msg, 1); | ||
149 | |||
150 | priv->frequency = tuner_freq - if_freq; // FIXME | ||
151 | priv->bandwidth = (fe->ops.info.type == FE_OFDM) ? params->u.ofdm.bandwidth : 0; | ||
152 | |||
153 | return 0; | ||
154 | } | ||
155 | |||
156 | static int tda827xo_sleep(struct dvb_frontend *fe) | ||
157 | { | ||
158 | struct tda827x_priv *priv = fe->tuner_priv; | ||
159 | static u8 buf[] = { 0x30, 0xd0 }; | ||
160 | struct i2c_msg msg = { .addr = priv->i2c_addr, .flags = 0, | ||
161 | .buf = buf, .len = sizeof(buf) }; | ||
162 | |||
163 | dprintk("%s:\n", __FUNCTION__); | ||
164 | if (fe->ops.i2c_gate_ctrl) | ||
165 | fe->ops.i2c_gate_ctrl(fe, 1); | ||
166 | i2c_transfer(priv->i2c_adap, &msg, 1); | ||
167 | |||
168 | if (priv->cfg && priv->cfg->sleep) | ||
169 | priv->cfg->sleep(fe); | ||
170 | |||
171 | return 0; | ||
172 | } | ||
173 | |||
174 | /* ------------------------------------------------------------------ */ | ||
175 | |||
176 | struct tda827xa_data { | ||
177 | u32 lomax; | ||
178 | u8 svco; | ||
179 | u8 spd; | ||
180 | u8 scr; | ||
181 | u8 sbs; | ||
182 | u8 gc3; | ||
183 | }; | ||
184 | |||
185 | static const struct tda827xa_data tda827xa_dvbt[] = { | ||
186 | { .lomax = 56875000, .svco = 3, .spd = 4, .scr = 0, .sbs = 0, .gc3 = 1}, | ||
187 | { .lomax = 67250000, .svco = 0, .spd = 3, .scr = 0, .sbs = 0, .gc3 = 1}, | ||
188 | { .lomax = 81250000, .svco = 1, .spd = 3, .scr = 0, .sbs = 0, .gc3 = 1}, | ||
189 | { .lomax = 97500000, .svco = 2, .spd = 3, .scr = 0, .sbs = 0, .gc3 = 1}, | ||
190 | { .lomax = 113750000, .svco = 3, .spd = 3, .scr = 0, .sbs = 1, .gc3 = 1}, | ||
191 | { .lomax = 134500000, .svco = 0, .spd = 2, .scr = 0, .sbs = 1, .gc3 = 1}, | ||
192 | { .lomax = 154000000, .svco = 1, .spd = 2, .scr = 0, .sbs = 1, .gc3 = 1}, | ||
193 | { .lomax = 162500000, .svco = 1, .spd = 2, .scr = 0, .sbs = 1, .gc3 = 1}, | ||
194 | { .lomax = 183000000, .svco = 2, .spd = 2, .scr = 0, .sbs = 1, .gc3 = 1}, | ||
195 | { .lomax = 195000000, .svco = 2, .spd = 2, .scr = 0, .sbs = 2, .gc3 = 1}, | ||
196 | { .lomax = 227500000, .svco = 3, .spd = 2, .scr = 0, .sbs = 2, .gc3 = 1}, | ||
197 | { .lomax = 269000000, .svco = 0, .spd = 1, .scr = 0, .sbs = 2, .gc3 = 1}, | ||
198 | { .lomax = 290000000, .svco = 1, .spd = 1, .scr = 0, .sbs = 2, .gc3 = 1}, | ||
199 | { .lomax = 325000000, .svco = 1, .spd = 1, .scr = 0, .sbs = 3, .gc3 = 1}, | ||
200 | { .lomax = 390000000, .svco = 2, .spd = 1, .scr = 0, .sbs = 3, .gc3 = 1}, | ||
201 | { .lomax = 455000000, .svco = 3, .spd = 1, .scr = 0, .sbs = 3, .gc3 = 1}, | ||
202 | { .lomax = 520000000, .svco = 0, .spd = 0, .scr = 0, .sbs = 3, .gc3 = 1}, | ||
203 | { .lomax = 538000000, .svco = 0, .spd = 0, .scr = 1, .sbs = 3, .gc3 = 1}, | ||
204 | { .lomax = 550000000, .svco = 1, .spd = 0, .scr = 0, .sbs = 3, .gc3 = 1}, | ||
205 | { .lomax = 620000000, .svco = 1, .spd = 0, .scr = 0, .sbs = 4, .gc3 = 0}, | ||
206 | { .lomax = 650000000, .svco = 1, .spd = 0, .scr = 1, .sbs = 4, .gc3 = 0}, | ||
207 | { .lomax = 700000000, .svco = 2, .spd = 0, .scr = 0, .sbs = 4, .gc3 = 0}, | ||
208 | { .lomax = 780000000, .svco = 2, .spd = 0, .scr = 1, .sbs = 4, .gc3 = 0}, | ||
209 | { .lomax = 820000000, .svco = 3, .spd = 0, .scr = 0, .sbs = 4, .gc3 = 0}, | ||
210 | { .lomax = 870000000, .svco = 3, .spd = 0, .scr = 1, .sbs = 4, .gc3 = 0}, | ||
211 | { .lomax = 911000000, .svco = 3, .spd = 0, .scr = 2, .sbs = 4, .gc3 = 0}, | ||
212 | { .lomax = 0, .svco = 0, .spd = 0, .scr = 0, .sbs = 0, .gc3 = 0} | ||
213 | }; | ||
214 | |||
215 | static int tda827xa_set_params(struct dvb_frontend *fe, | ||
216 | struct dvb_frontend_parameters *params) | ||
217 | { | ||
218 | struct tda827x_priv *priv = fe->tuner_priv; | ||
219 | u8 buf[11]; | ||
220 | |||
221 | struct i2c_msg msg = { .addr = priv->i2c_addr, .flags = 0, | ||
222 | .buf = buf, .len = sizeof(buf) }; | ||
223 | |||
224 | int i, tuner_freq, if_freq; | ||
225 | u32 N; | ||
226 | |||
227 | dprintk("%s:\n", __FUNCTION__); | ||
228 | if (priv->cfg && priv->cfg->lna_gain) | ||
229 | priv->cfg->lna_gain(fe, 1); | ||
230 | msleep(20); | ||
231 | |||
232 | switch (params->u.ofdm.bandwidth) { | ||
233 | case BANDWIDTH_6_MHZ: | ||
234 | if_freq = 4000000; | ||
235 | break; | ||
236 | case BANDWIDTH_7_MHZ: | ||
237 | if_freq = 4500000; | ||
238 | break; | ||
239 | default: /* 8 MHz or Auto */ | ||
240 | if_freq = 5000000; | ||
241 | break; | ||
242 | } | ||
243 | tuner_freq = params->frequency + if_freq; | ||
244 | |||
245 | i = 0; | ||
246 | while (tda827xa_dvbt[i].lomax < tuner_freq) { | ||
247 | if(tda827xa_dvbt[i + 1].lomax == 0) | ||
248 | break; | ||
249 | i++; | ||
250 | } | ||
251 | |||
252 | N = ((tuner_freq + 31250) / 62500) << tda827xa_dvbt[i].spd; | ||
253 | buf[0] = 0; // subaddress | ||
254 | buf[1] = N >> 8; | ||
255 | buf[2] = N & 0xff; | ||
256 | buf[3] = 0; | ||
257 | buf[4] = 0x16; | ||
258 | buf[5] = (tda827xa_dvbt[i].spd << 5) + (tda827xa_dvbt[i].svco << 3) + | ||
259 | tda827xa_dvbt[i].sbs; | ||
260 | buf[6] = 0x4b + (tda827xa_dvbt[i].gc3 << 4); | ||
261 | buf[7] = 0x1c; | ||
262 | buf[8] = 0x06; | ||
263 | buf[9] = 0x24; | ||
264 | buf[10] = 0x00; | ||
265 | msg.len = 11; | ||
266 | if (fe->ops.i2c_gate_ctrl) | ||
267 | fe->ops.i2c_gate_ctrl(fe, 1); | ||
268 | if (i2c_transfer(priv->i2c_adap, &msg, 1) != 1) { | ||
269 | printk("%s: could not write to tuner at addr: 0x%02x\n", | ||
270 | __FUNCTION__, priv->i2c_addr << 1); | ||
271 | return -EIO; | ||
272 | } | ||
273 | buf[0] = 0x90; | ||
274 | buf[1] = 0xff; | ||
275 | buf[2] = 0x60; | ||
276 | buf[3] = 0x00; | ||
277 | buf[4] = 0x59; // lpsel, for 6MHz + 2 | ||
278 | msg.len = 5; | ||
279 | if (fe->ops.i2c_gate_ctrl) | ||
280 | fe->ops.i2c_gate_ctrl(fe, 1); | ||
281 | i2c_transfer(priv->i2c_adap, &msg, 1); | ||
282 | |||
283 | buf[0] = 0xa0; | ||
284 | buf[1] = 0x40; | ||
285 | msg.len = 2; | ||
286 | if (fe->ops.i2c_gate_ctrl) | ||
287 | fe->ops.i2c_gate_ctrl(fe, 1); | ||
288 | i2c_transfer(priv->i2c_adap, &msg, 1); | ||
289 | |||
290 | msleep(11); | ||
291 | msg.flags = I2C_M_RD; | ||
292 | if (fe->ops.i2c_gate_ctrl) | ||
293 | fe->ops.i2c_gate_ctrl(fe, 1); | ||
294 | i2c_transfer(priv->i2c_adap, &msg, 1); | ||
295 | msg.flags = 0; | ||
296 | |||
297 | buf[1] >>= 4; | ||
298 | dprintk("tda8275a AGC2 gain is: %d\n", buf[1]); | ||
299 | if ((buf[1]) < 2) { | ||
300 | if (priv->cfg && priv->cfg->lna_gain) | ||
301 | priv->cfg->lna_gain(fe, 0); | ||
302 | buf[0] = 0x60; | ||
303 | buf[1] = 0x0c; | ||
304 | if (fe->ops.i2c_gate_ctrl) | ||
305 | fe->ops.i2c_gate_ctrl(fe, 1); | ||
306 | i2c_transfer(priv->i2c_adap, &msg, 1); | ||
307 | } | ||
308 | |||
309 | buf[0] = 0xc0; | ||
310 | buf[1] = 0x99; // lpsel, for 6MHz + 2 | ||
311 | if (fe->ops.i2c_gate_ctrl) | ||
312 | fe->ops.i2c_gate_ctrl(fe, 1); | ||
313 | i2c_transfer(priv->i2c_adap, &msg, 1); | ||
314 | |||
315 | buf[0] = 0x60; | ||
316 | buf[1] = 0x3c; | ||
317 | if (fe->ops.i2c_gate_ctrl) | ||
318 | fe->ops.i2c_gate_ctrl(fe, 1); | ||
319 | i2c_transfer(priv->i2c_adap, &msg, 1); | ||
320 | |||
321 | /* correct CP value */ | ||
322 | buf[0] = 0x30; | ||
323 | buf[1] = 0x10 + tda827xa_dvbt[i].scr; | ||
324 | if (fe->ops.i2c_gate_ctrl) | ||
325 | fe->ops.i2c_gate_ctrl(fe, 1); | ||
326 | i2c_transfer(priv->i2c_adap, &msg, 1); | ||
327 | |||
328 | msleep(163); | ||
329 | buf[0] = 0xc0; | ||
330 | buf[1] = 0x39; // lpsel, for 6MHz + 2 | ||
331 | if (fe->ops.i2c_gate_ctrl) | ||
332 | fe->ops.i2c_gate_ctrl(fe, 1); | ||
333 | i2c_transfer(priv->i2c_adap, &msg, 1); | ||
334 | |||
335 | msleep(3); | ||
336 | /* freeze AGC1 */ | ||
337 | buf[0] = 0x50; | ||
338 | buf[1] = 0x4f + (tda827xa_dvbt[i].gc3 << 4); | ||
339 | if (fe->ops.i2c_gate_ctrl) | ||
340 | fe->ops.i2c_gate_ctrl(fe, 1); | ||
341 | i2c_transfer(priv->i2c_adap, &msg, 1); | ||
342 | |||
343 | priv->frequency = tuner_freq - if_freq; // FIXME | ||
344 | priv->bandwidth = (fe->ops.info.type == FE_OFDM) ? params->u.ofdm.bandwidth : 0; | ||
345 | |||
346 | return 0; | ||
347 | } | ||
348 | |||
349 | static int tda827xa_sleep(struct dvb_frontend *fe) | ||
350 | { | ||
351 | struct tda827x_priv *priv = fe->tuner_priv; | ||
352 | static u8 buf[] = { 0x30, 0x90 }; | ||
353 | struct i2c_msg msg = { .addr = priv->i2c_addr, .flags = 0, | ||
354 | .buf = buf, .len = sizeof(buf) }; | ||
355 | |||
356 | dprintk("%s:\n", __FUNCTION__); | ||
357 | if (fe->ops.i2c_gate_ctrl) | ||
358 | fe->ops.i2c_gate_ctrl(fe, 1); | ||
359 | |||
360 | i2c_transfer(priv->i2c_adap, &msg, 1); | ||
361 | |||
362 | if (fe->ops.i2c_gate_ctrl) | ||
363 | fe->ops.i2c_gate_ctrl(fe, 0); | ||
364 | |||
365 | if (priv->cfg && priv->cfg->sleep) | ||
366 | priv->cfg->sleep(fe); | ||
367 | |||
368 | return 0; | ||
369 | } | ||
370 | |||
371 | static int tda827x_release(struct dvb_frontend *fe) | ||
372 | { | ||
373 | kfree(fe->tuner_priv); | ||
374 | fe->tuner_priv = NULL; | ||
375 | return 0; | ||
376 | } | ||
377 | |||
378 | static int tda827x_get_frequency(struct dvb_frontend *fe, u32 *frequency) | ||
379 | { | ||
380 | struct tda827x_priv *priv = fe->tuner_priv; | ||
381 | *frequency = priv->frequency; | ||
382 | return 0; | ||
383 | } | ||
384 | |||
385 | static int tda827x_get_bandwidth(struct dvb_frontend *fe, u32 *bandwidth) | ||
386 | { | ||
387 | struct tda827x_priv *priv = fe->tuner_priv; | ||
388 | *bandwidth = priv->bandwidth; | ||
389 | return 0; | ||
390 | } | ||
391 | |||
392 | static int tda827x_init(struct dvb_frontend *fe) | ||
393 | { | ||
394 | struct tda827x_priv *priv = fe->tuner_priv; | ||
395 | dprintk("%s:\n", __FUNCTION__); | ||
396 | if (priv->cfg && priv->cfg->init) | ||
397 | priv->cfg->init(fe); | ||
398 | |||
399 | return 0; | ||
400 | } | ||
401 | |||
402 | static int tda827x_probe_version(struct dvb_frontend *fe); | ||
403 | |||
404 | static int tda827x_initial_init(struct dvb_frontend *fe) | ||
405 | { | ||
406 | int ret; | ||
407 | ret = tda827x_probe_version(fe); | ||
408 | if (ret) | ||
409 | return ret; | ||
410 | return fe->ops.tuner_ops.init(fe); | ||
411 | } | ||
412 | |||
413 | static int tda827x_initial_sleep(struct dvb_frontend *fe) | ||
414 | { | ||
415 | int ret; | ||
416 | ret = tda827x_probe_version(fe); | ||
417 | if (ret) | ||
418 | return ret; | ||
419 | return fe->ops.tuner_ops.sleep(fe); | ||
420 | } | ||
421 | |||
422 | static struct dvb_tuner_ops tda827xo_tuner_ops = { | ||
423 | .info = { | ||
424 | .name = "Philips TDA827X", | ||
425 | .frequency_min = 55000000, | ||
426 | .frequency_max = 860000000, | ||
427 | .frequency_step = 250000 | ||
428 | }, | ||
429 | .release = tda827x_release, | ||
430 | .init = tda827x_initial_init, | ||
431 | .sleep = tda827x_initial_sleep, | ||
432 | .set_params = tda827xo_set_params, | ||
433 | .get_frequency = tda827x_get_frequency, | ||
434 | .get_bandwidth = tda827x_get_bandwidth, | ||
435 | }; | ||
436 | |||
437 | static struct dvb_tuner_ops tda827xa_tuner_ops = { | ||
438 | .info = { | ||
439 | .name = "Philips TDA827XA", | ||
440 | .frequency_min = 44000000, | ||
441 | .frequency_max = 906000000, | ||
442 | .frequency_step = 62500 | ||
443 | }, | ||
444 | .release = tda827x_release, | ||
445 | .init = tda827x_init, | ||
446 | .sleep = tda827xa_sleep, | ||
447 | .set_params = tda827xa_set_params, | ||
448 | .get_frequency = tda827x_get_frequency, | ||
449 | .get_bandwidth = tda827x_get_bandwidth, | ||
450 | }; | ||
451 | |||
452 | static int tda827x_probe_version(struct dvb_frontend *fe) | ||
453 | { u8 data; | ||
454 | struct tda827x_priv *priv = fe->tuner_priv; | ||
455 | struct i2c_msg msg = { .addr = priv->i2c_addr, .flags = I2C_M_RD, | ||
456 | .buf = &data, .len = 1 }; | ||
457 | if (fe->ops.i2c_gate_ctrl) | ||
458 | fe->ops.i2c_gate_ctrl(fe, 1); | ||
459 | if (i2c_transfer(priv->i2c_adap, &msg, 1) != 1) { | ||
460 | printk("%s: could not read from tuner at addr: 0x%02x\n", | ||
461 | __FUNCTION__, msg.addr << 1); | ||
462 | return -EIO; | ||
463 | } | ||
464 | if ((data & 0x3c) == 0) { | ||
465 | dprintk("tda827x tuner found\n"); | ||
466 | fe->ops.tuner_ops.init = tda827x_init; | ||
467 | fe->ops.tuner_ops.sleep = tda827xo_sleep; | ||
468 | } else { | ||
469 | dprintk("tda827xa tuner found\n"); | ||
470 | memcpy(&fe->ops.tuner_ops, &tda827xa_tuner_ops, sizeof(struct dvb_tuner_ops)); | ||
471 | } | ||
472 | return 0; | ||
473 | } | ||
474 | |||
475 | struct dvb_frontend *tda827x_attach(struct dvb_frontend *fe, int addr, | ||
476 | struct i2c_adapter *i2c, | ||
477 | struct tda827x_config *cfg) | ||
478 | { | ||
479 | struct tda827x_priv *priv = NULL; | ||
480 | |||
481 | dprintk("%s:\n", __FUNCTION__); | ||
482 | priv = kzalloc(sizeof(struct tda827x_priv), GFP_KERNEL); | ||
483 | if (priv == NULL) | ||
484 | return NULL; | ||
485 | |||
486 | priv->i2c_addr = addr; | ||
487 | priv->i2c_adap = i2c; | ||
488 | priv->cfg = cfg; | ||
489 | memcpy(&fe->ops.tuner_ops, &tda827xo_tuner_ops, sizeof(struct dvb_tuner_ops)); | ||
490 | |||
491 | fe->tuner_priv = priv; | ||
492 | |||
493 | return fe; | ||
494 | } | ||
495 | |||
496 | EXPORT_SYMBOL(tda827x_attach); | ||
497 | |||
498 | module_param(debug, int, 0644); | ||
499 | MODULE_PARM_DESC(debug, "Turn on/off frontend debugging (default:off)."); | ||
500 | |||
501 | MODULE_DESCRIPTION("DVB TDA827x driver"); | ||
502 | MODULE_AUTHOR("Hartmut Hackmann <hartmut.hackmann@t-online.de>"); | ||
503 | MODULE_AUTHOR("Michael Krufky <mkrufky@linuxtv.org>"); | ||
504 | MODULE_LICENSE("GPL"); | ||
505 | |||
506 | /* | ||
507 | * Overrides for Emacs so that we follow Linus's tabbing style. | ||
508 | * --------------------------------------------------------------------------- | ||
509 | * Local variables: | ||
510 | * c-basic-offset: 8 | ||
511 | * End: | ||
512 | */ | ||
diff --git a/drivers/media/dvb/frontends/tda827x.h b/drivers/media/dvb/frontends/tda827x.h new file mode 100644 index 000000000000..69e8263d6d59 --- /dev/null +++ b/drivers/media/dvb/frontends/tda827x.h | |||
@@ -0,0 +1,62 @@ | |||
1 | /* | ||
2 | DVB Driver for Philips tda827x / tda827xa Silicon tuners | ||
3 | |||
4 | (c) 2005 Hartmut Hackmann | ||
5 | (c) 2007 Michael Krufky | ||
6 | |||
7 | This program is free software; you can redistribute it and/or modify | ||
8 | it under the terms of the GNU General Public License as published by | ||
9 | the Free Software Foundation; either version 2 of the License, or | ||
10 | (at your option) any later version. | ||
11 | |||
12 | This program is distributed in the hope that it will be useful, | ||
13 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
15 | |||
16 | GNU General Public License for more details. | ||
17 | |||
18 | You should have received a copy of the GNU General Public License | ||
19 | along with this program; if not, write to the Free Software | ||
20 | Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
21 | |||
22 | */ | ||
23 | |||
24 | #ifndef __DVB_TDA827X_H__ | ||
25 | #define __DVB_TDA827X_H__ | ||
26 | |||
27 | #include <linux/i2c.h> | ||
28 | #include "dvb_frontend.h" | ||
29 | |||
30 | struct tda827x_config | ||
31 | { | ||
32 | void (*lna_gain) (struct dvb_frontend *fe, int high); | ||
33 | int (*init) (struct dvb_frontend *fe); | ||
34 | int (*sleep) (struct dvb_frontend *fe); | ||
35 | }; | ||
36 | |||
37 | |||
38 | /** | ||
39 | * Attach a tda827x tuner to the supplied frontend structure. | ||
40 | * | ||
41 | * @param fe Frontend to attach to. | ||
42 | * @param addr i2c address of the tuner. | ||
43 | * @param i2c i2c adapter to use. | ||
44 | * @param cfg optional callback function pointers. | ||
45 | * @return FE pointer on success, NULL on failure. | ||
46 | */ | ||
47 | #if defined(CONFIG_DVB_TDA827X) || (defined(CONFIG_DVB_TDA827X_MODULE) && defined(MODULE)) | ||
48 | extern struct dvb_frontend* tda827x_attach(struct dvb_frontend *fe, int addr, | ||
49 | struct i2c_adapter *i2c, | ||
50 | struct tda827x_config *cfg); | ||
51 | #else | ||
52 | static inline struct dvb_frontend* tda827x_attach(struct dvb_frontend *fe, | ||
53 | int addr, | ||
54 | struct i2c_adapter *i2c, | ||
55 | struct tda827x_config *cfg) | ||
56 | { | ||
57 | printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __FUNCTION__); | ||
58 | return NULL; | ||
59 | } | ||
60 | #endif // CONFIG_DVB_TDA827X | ||
61 | |||
62 | #endif // __DVB_TDA827X_H__ | ||
diff --git a/drivers/media/dvb/pluto2/Kconfig b/drivers/media/dvb/pluto2/Kconfig index 9b84b1bdc313..7d8e6e87bdbb 100644 --- a/drivers/media/dvb/pluto2/Kconfig +++ b/drivers/media/dvb/pluto2/Kconfig | |||
@@ -2,7 +2,6 @@ config DVB_PLUTO2 | |||
2 | tristate "Pluto2 cards" | 2 | tristate "Pluto2 cards" |
3 | depends on DVB_CORE && PCI && I2C | 3 | depends on DVB_CORE && PCI && I2C |
4 | select I2C_ALGOBIT | 4 | select I2C_ALGOBIT |
5 | select DVB_PLL | ||
6 | select DVB_TDA1004X | 5 | select DVB_TDA1004X |
7 | help | 6 | help |
8 | Support for PCI cards based on the Pluto2 FPGA like the Satelco | 7 | Support for PCI cards based on the Pluto2 FPGA like the Satelco |
diff --git a/drivers/media/dvb/ttpci/Kconfig b/drivers/media/dvb/ttpci/Kconfig index eec7ccf41f8b..7751628e1415 100644 --- a/drivers/media/dvb/ttpci/Kconfig +++ b/drivers/media/dvb/ttpci/Kconfig | |||
@@ -3,7 +3,6 @@ config DVB_AV7110 | |||
3 | depends on DVB_CORE && PCI && I2C && VIDEO_V4L1 | 3 | depends on DVB_CORE && PCI && I2C && VIDEO_V4L1 |
4 | select FW_LOADER if !DVB_AV7110_FIRMWARE | 4 | select FW_LOADER if !DVB_AV7110_FIRMWARE |
5 | select VIDEO_SAA7146_VV | 5 | select VIDEO_SAA7146_VV |
6 | select DVB_PLL | ||
7 | select DVB_VES1820 if !DVB_FE_CUSTOMISE | 6 | select DVB_VES1820 if !DVB_FE_CUSTOMISE |
8 | select DVB_VES1X93 if !DVB_FE_CUSTOMISE | 7 | select DVB_VES1X93 if !DVB_FE_CUSTOMISE |
9 | select DVB_STV0299 if !DVB_FE_CUSTOMISE | 8 | select DVB_STV0299 if !DVB_FE_CUSTOMISE |
@@ -62,13 +61,13 @@ config DVB_BUDGET | |||
62 | tristate "Budget cards" | 61 | tristate "Budget cards" |
63 | depends on DVB_CORE && PCI && I2C && VIDEO_V4L1 | 62 | depends on DVB_CORE && PCI && I2C && VIDEO_V4L1 |
64 | select VIDEO_SAA7146 | 63 | select VIDEO_SAA7146 |
65 | select DVB_PLL | ||
66 | select DVB_STV0299 if !DVB_FE_CUSTOMISE | 64 | select DVB_STV0299 if !DVB_FE_CUSTOMISE |
67 | select DVB_VES1X93 if !DVB_FE_CUSTOMISE | 65 | select DVB_VES1X93 if !DVB_FE_CUSTOMISE |
68 | select DVB_VES1820 if !DVB_FE_CUSTOMISE | 66 | select DVB_VES1820 if !DVB_FE_CUSTOMISE |
69 | select DVB_L64781 if !DVB_FE_CUSTOMISE | 67 | select DVB_L64781 if !DVB_FE_CUSTOMISE |
70 | select DVB_TDA8083 if !DVB_FE_CUSTOMISE | 68 | select DVB_TDA8083 if !DVB_FE_CUSTOMISE |
71 | select DVB_TDA10021 if !DVB_FE_CUSTOMISE | 69 | select DVB_TDA10021 if !DVB_FE_CUSTOMISE |
70 | select DVB_TDA10023 if !DVB_FE_CUSTOMISE | ||
72 | select DVB_S5H1420 if !DVB_FE_CUSTOMISE | 71 | select DVB_S5H1420 if !DVB_FE_CUSTOMISE |
73 | select DVB_TDA10086 if !DVB_FE_CUSTOMISE | 72 | select DVB_TDA10086 if !DVB_FE_CUSTOMISE |
74 | select DVB_TDA826X if !DVB_FE_CUSTOMISE | 73 | select DVB_TDA826X if !DVB_FE_CUSTOMISE |
@@ -87,7 +86,6 @@ config DVB_BUDGET_CI | |||
87 | tristate "Budget cards with onboard CI connector" | 86 | tristate "Budget cards with onboard CI connector" |
88 | depends on DVB_CORE && PCI && I2C && VIDEO_V4L1 | 87 | depends on DVB_CORE && PCI && I2C && VIDEO_V4L1 |
89 | select VIDEO_SAA7146 | 88 | select VIDEO_SAA7146 |
90 | select DVB_PLL | ||
91 | select DVB_STV0297 if !DVB_FE_CUSTOMISE | 89 | select DVB_STV0297 if !DVB_FE_CUSTOMISE |
92 | select DVB_STV0299 if !DVB_FE_CUSTOMISE | 90 | select DVB_STV0299 if !DVB_FE_CUSTOMISE |
93 | select DVB_TDA1004X if !DVB_FE_CUSTOMISE | 91 | select DVB_TDA1004X if !DVB_FE_CUSTOMISE |
@@ -114,6 +112,7 @@ config DVB_BUDGET_AV | |||
114 | select DVB_STV0299 if !DVB_FE_CUSTOMISE | 112 | select DVB_STV0299 if !DVB_FE_CUSTOMISE |
115 | select DVB_TDA1004X if !DVB_FE_CUSTOMISE | 113 | select DVB_TDA1004X if !DVB_FE_CUSTOMISE |
116 | select DVB_TDA10021 if !DVB_FE_CUSTOMISE | 114 | select DVB_TDA10021 if !DVB_FE_CUSTOMISE |
115 | select DVB_TDA10023 if !DVB_FE_CUSTOMISE | ||
117 | select DVB_TUA6100 if !DVB_FE_CUSTOMISE | 116 | select DVB_TUA6100 if !DVB_FE_CUSTOMISE |
118 | select FW_LOADER | 117 | select FW_LOADER |
119 | help | 118 | help |
@@ -130,7 +129,6 @@ config DVB_BUDGET_PATCH | |||
130 | tristate "AV7110 cards with Budget Patch" | 129 | tristate "AV7110 cards with Budget Patch" |
131 | depends on DVB_CORE && DVB_BUDGET && VIDEO_V4L1 | 130 | depends on DVB_CORE && DVB_BUDGET && VIDEO_V4L1 |
132 | select DVB_AV7110 | 131 | select DVB_AV7110 |
133 | select DVB_PLL | ||
134 | select DVB_STV0299 if !DVB_FE_CUSTOMISE | 132 | select DVB_STV0299 if !DVB_FE_CUSTOMISE |
135 | select DVB_VES1X93 if !DVB_FE_CUSTOMISE | 133 | select DVB_VES1X93 if !DVB_FE_CUSTOMISE |
136 | select DVB_TDA8083 if !DVB_FE_CUSTOMISE | 134 | select DVB_TDA8083 if !DVB_FE_CUSTOMISE |
diff --git a/drivers/media/dvb/ttpci/av7110.c b/drivers/media/dvb/ttpci/av7110.c index 29ed532ba966..67becdd4db60 100644 --- a/drivers/media/dvb/ttpci/av7110.c +++ b/drivers/media/dvb/ttpci/av7110.c | |||
@@ -219,7 +219,10 @@ static void recover_arm(struct av7110 *av7110) | |||
219 | av7110->recover(av7110); | 219 | av7110->recover(av7110); |
220 | 220 | ||
221 | restart_feeds(av7110); | 221 | restart_feeds(av7110); |
222 | av7110_fw_cmd(av7110, COMTYPE_PIDFILTER, SetIR, 1, av7110->ir_config); | 222 | |
223 | #if defined(CONFIG_INPUT_EVDEV) || defined(CONFIG_INPUT_EVDEV_MODULE) | ||
224 | av7110_check_ir_config(av7110, true); | ||
225 | #endif | ||
223 | } | 226 | } |
224 | 227 | ||
225 | static void av7110_arm_sync(struct av7110 *av7110) | 228 | static void av7110_arm_sync(struct av7110 *av7110) |
@@ -250,6 +253,10 @@ static int arm_thread(void *data) | |||
250 | if (!av7110->arm_ready) | 253 | if (!av7110->arm_ready) |
251 | continue; | 254 | continue; |
252 | 255 | ||
256 | #if defined(CONFIG_INPUT_EVDEV) || defined(CONFIG_INPUT_EVDEV_MODULE) | ||
257 | av7110_check_ir_config(av7110, false); | ||
258 | #endif | ||
259 | |||
253 | if (mutex_lock_interruptible(&av7110->dcomlock)) | 260 | if (mutex_lock_interruptible(&av7110->dcomlock)) |
254 | break; | 261 | break; |
255 | newloops = rdebi(av7110, DEBINOSWAP, STATUS_LOOPS, 0, 2); | 262 | newloops = rdebi(av7110, DEBINOSWAP, STATUS_LOOPS, 0, 2); |
@@ -667,8 +674,8 @@ static void gpioirq(unsigned long data) | |||
667 | return; | 674 | return; |
668 | 675 | ||
669 | case DATA_IRCOMMAND: | 676 | case DATA_IRCOMMAND: |
670 | if (av7110->ir_handler) | 677 | if (av7110->ir.ir_handler) |
671 | av7110->ir_handler(av7110, | 678 | av7110->ir.ir_handler(av7110, |
672 | swahw32(irdebi(av7110, DEBINOSWAP, Reserved, 0, 4))); | 679 | swahw32(irdebi(av7110, DEBINOSWAP, Reserved, 0, 4))); |
673 | iwdebi(av7110, DEBINOSWAP, RX_BUFF, 0, 2); | 680 | iwdebi(av7110, DEBINOSWAP, RX_BUFF, 0, 2); |
674 | break; | 681 | break; |
@@ -1907,8 +1914,10 @@ static int av7110_fe_lock_fix(struct av7110* av7110, fe_status_t status) | |||
1907 | if (av7110->fe_synced == synced) | 1914 | if (av7110->fe_synced == synced) |
1908 | return 0; | 1915 | return 0; |
1909 | 1916 | ||
1910 | if (av7110->playing) | 1917 | if (av7110->playing) { |
1918 | av7110->fe_synced = synced; | ||
1911 | return 0; | 1919 | return 0; |
1920 | } | ||
1912 | 1921 | ||
1913 | if (mutex_lock_interruptible(&av7110->pid_mutex)) | 1922 | if (mutex_lock_interruptible(&av7110->pid_mutex)) |
1914 | return -ERESTARTSYS; | 1923 | return -ERESTARTSYS; |
diff --git a/drivers/media/dvb/ttpci/av7110.h b/drivers/media/dvb/ttpci/av7110.h index b98bd453cade..115002b0390c 100644 --- a/drivers/media/dvb/ttpci/av7110.h +++ b/drivers/media/dvb/ttpci/av7110.h | |||
@@ -5,6 +5,7 @@ | |||
5 | #include <linux/socket.h> | 5 | #include <linux/socket.h> |
6 | #include <linux/netdevice.h> | 6 | #include <linux/netdevice.h> |
7 | #include <linux/i2c.h> | 7 | #include <linux/i2c.h> |
8 | #include <linux/input.h> | ||
8 | 9 | ||
9 | #include <linux/dvb/video.h> | 10 | #include <linux/dvb/video.h> |
10 | #include <linux/dvb/audio.h> | 11 | #include <linux/dvb/audio.h> |
@@ -66,6 +67,27 @@ struct dvb_video_events { | |||
66 | }; | 67 | }; |
67 | 68 | ||
68 | 69 | ||
70 | struct av7110; | ||
71 | |||
72 | /* infrared remote control */ | ||
73 | struct infrared { | ||
74 | u16 key_map[256]; | ||
75 | struct input_dev *input_dev; | ||
76 | char input_phys[32]; | ||
77 | struct timer_list keyup_timer; | ||
78 | struct tasklet_struct ir_tasklet; | ||
79 | void (*ir_handler)(struct av7110 *av7110, u32 ircom); | ||
80 | u32 ir_command; | ||
81 | u32 ir_config; | ||
82 | u32 device_mask; | ||
83 | u8 protocol; | ||
84 | u8 inversion; | ||
85 | u16 last_key; | ||
86 | u16 last_toggle; | ||
87 | u8 delay_timer_finished; | ||
88 | }; | ||
89 | |||
90 | |||
69 | /* place to store all the necessary device information */ | 91 | /* place to store all the necessary device information */ |
70 | struct av7110 { | 92 | struct av7110 { |
71 | 93 | ||
@@ -227,10 +249,7 @@ struct av7110 { | |||
227 | u16 wssMode; | 249 | u16 wssMode; |
228 | u16 wssData; | 250 | u16 wssData; |
229 | 251 | ||
230 | u32 ir_config; | 252 | struct infrared ir; |
231 | u32 ir_command; | ||
232 | void (*ir_handler)(struct av7110 *av7110, u32 ircom); | ||
233 | struct tasklet_struct ir_tasklet; | ||
234 | 253 | ||
235 | /* firmware stuff */ | 254 | /* firmware stuff */ |
236 | unsigned char *bin_fw; | 255 | unsigned char *bin_fw; |
@@ -268,6 +287,7 @@ struct av7110 { | |||
268 | extern int ChangePIDs(struct av7110 *av7110, u16 vpid, u16 apid, u16 ttpid, | 287 | extern int ChangePIDs(struct av7110 *av7110, u16 vpid, u16 apid, u16 ttpid, |
269 | u16 subpid, u16 pcrpid); | 288 | u16 subpid, u16 pcrpid); |
270 | 289 | ||
290 | extern int av7110_check_ir_config(struct av7110 *av7110, int force); | ||
271 | extern int av7110_ir_init(struct av7110 *av7110); | 291 | extern int av7110_ir_init(struct av7110 *av7110); |
272 | extern void av7110_ir_exit(struct av7110 *av7110); | 292 | extern void av7110_ir_exit(struct av7110 *av7110); |
273 | 293 | ||
diff --git a/drivers/media/dvb/ttpci/av7110_av.c b/drivers/media/dvb/ttpci/av7110_av.c index e719af807685..654c9e919e04 100644 --- a/drivers/media/dvb/ttpci/av7110_av.c +++ b/drivers/media/dvb/ttpci/av7110_av.c | |||
@@ -1009,7 +1009,7 @@ static int dvb_video_ioctl(struct inode *inode, struct file *file, | |||
1009 | if (av7110->videostate.stream_source == VIDEO_SOURCE_MEMORY) | 1009 | if (av7110->videostate.stream_source == VIDEO_SOURCE_MEMORY) |
1010 | ret = av7110_av_stop(av7110, RP_VIDEO); | 1010 | ret = av7110_av_stop(av7110, RP_VIDEO); |
1011 | else | 1011 | else |
1012 | ret = vidcom(av7110, VIDEO_CMD_STOP, | 1012 | ret = vidcom(av7110, AV_VIDEO_CMD_STOP, |
1013 | av7110->videostate.video_blank ? 0 : 1); | 1013 | av7110->videostate.video_blank ? 0 : 1); |
1014 | if (!ret) | 1014 | if (!ret) |
1015 | av7110->trickmode = TRICK_NONE; | 1015 | av7110->trickmode = TRICK_NONE; |
@@ -1019,7 +1019,7 @@ static int dvb_video_ioctl(struct inode *inode, struct file *file, | |||
1019 | av7110->trickmode = TRICK_NONE; | 1019 | av7110->trickmode = TRICK_NONE; |
1020 | if (av7110->videostate.play_state == VIDEO_FREEZED) { | 1020 | if (av7110->videostate.play_state == VIDEO_FREEZED) { |
1021 | av7110->videostate.play_state = VIDEO_PLAYING; | 1021 | av7110->videostate.play_state = VIDEO_PLAYING; |
1022 | ret = vidcom(av7110, VIDEO_CMD_PLAY, 0); | 1022 | ret = vidcom(av7110, AV_VIDEO_CMD_PLAY, 0); |
1023 | if (ret) | 1023 | if (ret) |
1024 | break; | 1024 | break; |
1025 | } | 1025 | } |
@@ -1034,7 +1034,7 @@ static int dvb_video_ioctl(struct inode *inode, struct file *file, | |||
1034 | ret = av7110_av_start_play(av7110, RP_VIDEO); | 1034 | ret = av7110_av_start_play(av7110, RP_VIDEO); |
1035 | } | 1035 | } |
1036 | if (!ret) | 1036 | if (!ret) |
1037 | ret = vidcom(av7110, VIDEO_CMD_PLAY, 0); | 1037 | ret = vidcom(av7110, AV_VIDEO_CMD_PLAY, 0); |
1038 | if (!ret) | 1038 | if (!ret) |
1039 | av7110->videostate.play_state = VIDEO_PLAYING; | 1039 | av7110->videostate.play_state = VIDEO_PLAYING; |
1040 | break; | 1040 | break; |
@@ -1044,7 +1044,7 @@ static int dvb_video_ioctl(struct inode *inode, struct file *file, | |||
1044 | if (av7110->playing & RP_VIDEO) | 1044 | if (av7110->playing & RP_VIDEO) |
1045 | ret = av7110_fw_cmd(av7110, COMTYPE_REC_PLAY, __Pause, 0); | 1045 | ret = av7110_fw_cmd(av7110, COMTYPE_REC_PLAY, __Pause, 0); |
1046 | else | 1046 | else |
1047 | ret = vidcom(av7110, VIDEO_CMD_FREEZE, 1); | 1047 | ret = vidcom(av7110, AV_VIDEO_CMD_FREEZE, 1); |
1048 | if (!ret) | 1048 | if (!ret) |
1049 | av7110->trickmode = TRICK_FREEZE; | 1049 | av7110->trickmode = TRICK_FREEZE; |
1050 | break; | 1050 | break; |
@@ -1053,7 +1053,7 @@ static int dvb_video_ioctl(struct inode *inode, struct file *file, | |||
1053 | if (av7110->playing & RP_VIDEO) | 1053 | if (av7110->playing & RP_VIDEO) |
1054 | ret = av7110_fw_cmd(av7110, COMTYPE_REC_PLAY, __Continue, 0); | 1054 | ret = av7110_fw_cmd(av7110, COMTYPE_REC_PLAY, __Continue, 0); |
1055 | if (!ret) | 1055 | if (!ret) |
1056 | ret = vidcom(av7110, VIDEO_CMD_PLAY, 0); | 1056 | ret = vidcom(av7110, AV_VIDEO_CMD_PLAY, 0); |
1057 | if (!ret) { | 1057 | if (!ret) { |
1058 | av7110->videostate.play_state = VIDEO_PLAYING; | 1058 | av7110->videostate.play_state = VIDEO_PLAYING; |
1059 | av7110->trickmode = TRICK_NONE; | 1059 | av7110->trickmode = TRICK_NONE; |
@@ -1136,7 +1136,7 @@ static int dvb_video_ioctl(struct inode *inode, struct file *file, | |||
1136 | ret = av7110_fw_cmd(av7110, COMTYPE_REC_PLAY, | 1136 | ret = av7110_fw_cmd(av7110, COMTYPE_REC_PLAY, |
1137 | __Scan_I, 2, AV_PES, 0); | 1137 | __Scan_I, 2, AV_PES, 0); |
1138 | else | 1138 | else |
1139 | ret = vidcom(av7110, VIDEO_CMD_FFWD, arg); | 1139 | ret = vidcom(av7110, AV_VIDEO_CMD_FFWD, arg); |
1140 | if (!ret) { | 1140 | if (!ret) { |
1141 | av7110->trickmode = TRICK_FAST; | 1141 | av7110->trickmode = TRICK_FAST; |
1142 | av7110->videostate.play_state = VIDEO_PLAYING; | 1142 | av7110->videostate.play_state = VIDEO_PLAYING; |
@@ -1147,13 +1147,13 @@ static int dvb_video_ioctl(struct inode *inode, struct file *file, | |||
1147 | if (av7110->playing&RP_VIDEO) { | 1147 | if (av7110->playing&RP_VIDEO) { |
1148 | ret = av7110_fw_cmd(av7110, COMTYPE_REC_PLAY, __Slow, 2, 0, 0); | 1148 | ret = av7110_fw_cmd(av7110, COMTYPE_REC_PLAY, __Slow, 2, 0, 0); |
1149 | if (!ret) | 1149 | if (!ret) |
1150 | ret = vidcom(av7110, VIDEO_CMD_SLOW, arg); | 1150 | ret = vidcom(av7110, AV_VIDEO_CMD_SLOW, arg); |
1151 | } else { | 1151 | } else { |
1152 | ret = vidcom(av7110, VIDEO_CMD_PLAY, 0); | 1152 | ret = vidcom(av7110, AV_VIDEO_CMD_PLAY, 0); |
1153 | if (!ret) | 1153 | if (!ret) |
1154 | ret = vidcom(av7110, VIDEO_CMD_STOP, 0); | 1154 | ret = vidcom(av7110, AV_VIDEO_CMD_STOP, 0); |
1155 | if (!ret) | 1155 | if (!ret) |
1156 | ret = vidcom(av7110, VIDEO_CMD_SLOW, arg); | 1156 | ret = vidcom(av7110, AV_VIDEO_CMD_SLOW, arg); |
1157 | } | 1157 | } |
1158 | if (!ret) { | 1158 | if (!ret) { |
1159 | av7110->trickmode = TRICK_SLOW; | 1159 | av7110->trickmode = TRICK_SLOW; |
@@ -1182,10 +1182,10 @@ static int dvb_video_ioctl(struct inode *inode, struct file *file, | |||
1182 | ret = av7110_fw_cmd(av7110, COMTYPE_REC_PLAY, | 1182 | ret = av7110_fw_cmd(av7110, COMTYPE_REC_PLAY, |
1183 | __Slow, 2, 0, 0); | 1183 | __Slow, 2, 0, 0); |
1184 | if (!ret) | 1184 | if (!ret) |
1185 | ret = vidcom(av7110, VIDEO_CMD_SLOW, arg); | 1185 | ret = vidcom(av7110, AV_VIDEO_CMD_SLOW, arg); |
1186 | } | 1186 | } |
1187 | if (av7110->trickmode == TRICK_FREEZE) | 1187 | if (av7110->trickmode == TRICK_FREEZE) |
1188 | ret = vidcom(av7110, VIDEO_CMD_STOP, 1); | 1188 | ret = vidcom(av7110, AV_VIDEO_CMD_STOP, 1); |
1189 | } | 1189 | } |
1190 | break; | 1190 | break; |
1191 | 1191 | ||
diff --git a/drivers/media/dvb/ttpci/av7110_hw.h b/drivers/media/dvb/ttpci/av7110_hw.h index 4e173c67fbb2..673d9b3f064c 100644 --- a/drivers/media/dvb/ttpci/av7110_hw.h +++ b/drivers/media/dvb/ttpci/av7110_hw.h | |||
@@ -216,11 +216,11 @@ enum av7110_command_type { | |||
216 | #define VID_CENTRE_CUT_PREF 0x05 /* PanScan with zero vector */ | 216 | #define VID_CENTRE_CUT_PREF 0x05 /* PanScan with zero vector */ |
217 | 217 | ||
218 | /* MPEG video decoder commands */ | 218 | /* MPEG video decoder commands */ |
219 | #define VIDEO_CMD_STOP 0x000e | 219 | #define AV_VIDEO_CMD_STOP 0x000e |
220 | #define VIDEO_CMD_PLAY 0x000d | 220 | #define AV_VIDEO_CMD_PLAY 0x000d |
221 | #define VIDEO_CMD_FREEZE 0x0102 | 221 | #define AV_VIDEO_CMD_FREEZE 0x0102 |
222 | #define VIDEO_CMD_FFWD 0x0016 | 222 | #define AV_VIDEO_CMD_FFWD 0x0016 |
223 | #define VIDEO_CMD_SLOW 0x0022 | 223 | #define AV_VIDEO_CMD_SLOW 0x0022 |
224 | 224 | ||
225 | /* MPEG audio decoder commands */ | 225 | /* MPEG audio decoder commands */ |
226 | #define AUDIO_CMD_MUTE 0x0001 | 226 | #define AUDIO_CMD_MUTE 0x0001 |
diff --git a/drivers/media/dvb/ttpci/av7110_ir.c b/drivers/media/dvb/ttpci/av7110_ir.c index f59465bb0af3..a97f166bb523 100644 --- a/drivers/media/dvb/ttpci/av7110_ir.c +++ b/drivers/media/dvb/ttpci/av7110_ir.c | |||
@@ -1,8 +1,31 @@ | |||
1 | /* | ||
2 | * Driver for the remote control of SAA7146 based AV7110 cards | ||
3 | * | ||
4 | * Copyright (C) 1999-2003 Holger Waechtler <holger@convergence.de> | ||
5 | * Copyright (C) 2003-2007 Oliver Endriss <o.endriss@gmx.de> | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or | ||
8 | * modify it under the terms of the GNU General Public License | ||
9 | * as published by the Free Software Foundation; either version 2 | ||
10 | * of the License, or (at your option) any later version. | ||
11 | * | ||
12 | * This program is distributed in the hope that it will be useful, | ||
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
15 | * GNU General Public License for more details. | ||
16 | * | ||
17 | * You should have received a copy of the GNU General Public License | ||
18 | * along with this program; if not, write to the Free Software | ||
19 | * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | ||
20 | * Or, point your browser to http://www.gnu.org/copyleft/gpl.html | ||
21 | * | ||
22 | */ | ||
23 | |||
24 | |||
1 | #include <linux/types.h> | 25 | #include <linux/types.h> |
2 | #include <linux/init.h> | 26 | #include <linux/init.h> |
3 | #include <linux/module.h> | 27 | #include <linux/module.h> |
4 | #include <linux/moduleparam.h> | 28 | #include <linux/moduleparam.h> |
5 | #include <linux/input.h> | ||
6 | #include <linux/proc_fs.h> | 29 | #include <linux/proc_fs.h> |
7 | #include <linux/kernel.h> | 30 | #include <linux/kernel.h> |
8 | #include <asm/bitops.h> | 31 | #include <asm/bitops.h> |
@@ -10,18 +33,37 @@ | |||
10 | #include "av7110.h" | 33 | #include "av7110.h" |
11 | #include "av7110_hw.h" | 34 | #include "av7110_hw.h" |
12 | 35 | ||
13 | #define UP_TIMEOUT (HZ*7/25) | ||
14 | 36 | ||
15 | /* enable ir debugging by or'ing debug with 16 */ | 37 | #define AV_CNT 4 |
38 | |||
39 | #define IR_RC5 0 | ||
40 | #define IR_RCMM 1 | ||
41 | #define IR_RC5_EXT 2 /* internal only */ | ||
42 | |||
43 | #define IR_ALL 0xffffffff | ||
44 | |||
45 | #define UP_TIMEOUT (HZ*7/25) | ||
16 | 46 | ||
17 | static int av_cnt; | ||
18 | static struct av7110 *av_list[4]; | ||
19 | static struct input_dev *input_dev; | ||
20 | static char input_phys[32]; | ||
21 | 47 | ||
22 | static u8 delay_timer_finished; | 48 | /* Note: enable ir debugging by or'ing debug with 16 */ |
49 | |||
50 | static int ir_protocol[AV_CNT] = { IR_RCMM, IR_RCMM, IR_RCMM, IR_RCMM}; | ||
51 | module_param_array(ir_protocol, int, NULL, 0644); | ||
52 | MODULE_PARM_DESC(ir_protocol, "Infrared protocol: 0 RC5, 1 RCMM (default)"); | ||
53 | |||
54 | static int ir_inversion[AV_CNT]; | ||
55 | module_param_array(ir_inversion, int, NULL, 0644); | ||
56 | MODULE_PARM_DESC(ir_inversion, "Inversion of infrared signal: 0 not inverted (default), 1 inverted"); | ||
57 | |||
58 | static uint ir_device_mask[AV_CNT] = { IR_ALL, IR_ALL, IR_ALL, IR_ALL }; | ||
59 | module_param_array(ir_device_mask, uint, NULL, 0644); | ||
60 | MODULE_PARM_DESC(ir_device_mask, "Bitmask of infrared devices: bit 0..31 = device 0..31 (default: all)"); | ||
61 | |||
62 | |||
63 | static int av_cnt; | ||
64 | static struct av7110 *av_list[AV_CNT]; | ||
23 | 65 | ||
24 | static u16 key_map [256] = { | 66 | static u16 default_key_map [256] = { |
25 | KEY_0, KEY_1, KEY_2, KEY_3, KEY_4, KEY_5, KEY_6, KEY_7, | 67 | KEY_0, KEY_1, KEY_2, KEY_3, KEY_4, KEY_5, KEY_6, KEY_7, |
26 | KEY_8, KEY_9, KEY_BACK, 0, KEY_POWER, KEY_MUTE, 0, KEY_INFO, | 68 | KEY_8, KEY_9, KEY_BACK, 0, KEY_POWER, KEY_MUTE, 0, KEY_INFO, |
27 | KEY_VOLUMEUP, KEY_VOLUMEDOWN, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, | 69 | KEY_VOLUMEUP, KEY_VOLUMEDOWN, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, |
@@ -45,141 +87,194 @@ static u16 key_map [256] = { | |||
45 | }; | 87 | }; |
46 | 88 | ||
47 | 89 | ||
48 | static void av7110_emit_keyup(unsigned long data) | 90 | /* key-up timer */ |
91 | static void av7110_emit_keyup(unsigned long parm) | ||
49 | { | 92 | { |
50 | if (!data || !test_bit(data, input_dev->key)) | 93 | struct infrared *ir = (struct infrared *) parm; |
94 | |||
95 | if (!ir || !test_bit(ir->last_key, ir->input_dev->key)) | ||
51 | return; | 96 | return; |
52 | 97 | ||
53 | input_report_key(input_dev, data, 0); | 98 | input_report_key(ir->input_dev, ir->last_key, 0); |
54 | input_sync(input_dev); | 99 | input_sync(ir->input_dev); |
55 | } | 100 | } |
56 | 101 | ||
57 | 102 | ||
58 | static struct timer_list keyup_timer = { .function = av7110_emit_keyup }; | 103 | /* tasklet */ |
59 | |||
60 | |||
61 | static void av7110_emit_key(unsigned long parm) | 104 | static void av7110_emit_key(unsigned long parm) |
62 | { | 105 | { |
63 | struct av7110 *av7110 = (struct av7110 *) parm; | 106 | struct infrared *ir = (struct infrared *) parm; |
64 | u32 ir_config = av7110->ir_config; | 107 | u32 ircom = ir->ir_command; |
65 | u32 ircom = av7110->ir_command; | ||
66 | u8 data; | 108 | u8 data; |
67 | u8 addr; | 109 | u8 addr; |
68 | static u16 old_toggle = 0; | 110 | u16 toggle; |
69 | u16 new_toggle; | ||
70 | u16 keycode; | 111 | u16 keycode; |
71 | 112 | ||
72 | /* extract device address and data */ | 113 | /* extract device address and data */ |
73 | switch (ir_config & 0x0003) { | 114 | switch (ir->protocol) { |
74 | case 0: /* RC5: 5 bits device address, 6 bits data */ | 115 | case IR_RC5: /* RC5: 5 bits device address, 6 bits data */ |
75 | data = ircom & 0x3f; | 116 | data = ircom & 0x3f; |
76 | addr = (ircom >> 6) & 0x1f; | 117 | addr = (ircom >> 6) & 0x1f; |
118 | toggle = ircom & 0x0800; | ||
77 | break; | 119 | break; |
78 | 120 | ||
79 | case 1: /* RCMM: 8(?) bits device address, 8(?) bits data */ | 121 | case IR_RCMM: /* RCMM: ? bits device address, ? bits data */ |
80 | data = ircom & 0xff; | 122 | data = ircom & 0xff; |
81 | addr = (ircom >> 8) & 0xff; | 123 | addr = (ircom >> 8) & 0x1f; |
124 | toggle = ircom & 0x8000; | ||
82 | break; | 125 | break; |
83 | 126 | ||
84 | case 2: /* extended RC5: 5 bits device address, 7 bits data */ | 127 | case IR_RC5_EXT: /* extended RC5: 5 bits device address, 7 bits data */ |
85 | data = ircom & 0x3f; | 128 | data = ircom & 0x3f; |
86 | addr = (ircom >> 6) & 0x1f; | 129 | addr = (ircom >> 6) & 0x1f; |
87 | /* invert 7th data bit for backward compatibility with RC5 keymaps */ | 130 | /* invert 7th data bit for backward compatibility with RC5 keymaps */ |
88 | if (!(ircom & 0x1000)) | 131 | if (!(ircom & 0x1000)) |
89 | data |= 0x40; | 132 | data |= 0x40; |
133 | toggle = ircom & 0x0800; | ||
90 | break; | 134 | break; |
91 | 135 | ||
92 | default: | 136 | default: |
93 | printk("invalid ir_config %x\n", ir_config); | 137 | printk("%s invalid protocol %x\n", __FUNCTION__, ir->protocol); |
94 | return; | 138 | return; |
95 | } | 139 | } |
96 | 140 | ||
97 | keycode = key_map[data]; | 141 | input_event(ir->input_dev, EV_MSC, MSC_RAW, (addr << 16) | data); |
142 | input_event(ir->input_dev, EV_MSC, MSC_SCAN, data); | ||
98 | 143 | ||
99 | dprintk(16, "code %08x -> addr %i data 0x%02x -> keycode %i\n", | 144 | keycode = ir->key_map[data]; |
100 | ircom, addr, data, keycode); | ||
101 | 145 | ||
102 | /* check device address (if selected) */ | 146 | dprintk(16, "%s: code %08x -> addr %i data 0x%02x -> keycode %i\n", |
103 | if (ir_config & 0x4000) | 147 | __FUNCTION__, ircom, addr, data, keycode); |
104 | if (addr != ((ir_config >> 16) & 0xff)) | 148 | |
105 | return; | 149 | /* check device address */ |
150 | if (!(ir->device_mask & (1 << addr))) | ||
151 | return; | ||
106 | 152 | ||
107 | if (!keycode) { | 153 | if (!keycode) { |
108 | printk ("%s: unknown key 0x%02x!!\n", __FUNCTION__, data); | 154 | printk ("%s: code %08x -> addr %i data 0x%02x -> unknown key!\n", |
155 | __FUNCTION__, ircom, addr, data); | ||
109 | return; | 156 | return; |
110 | } | 157 | } |
111 | 158 | ||
112 | if ((ir_config & 0x0003) == 1) | 159 | if (timer_pending(&ir->keyup_timer)) { |
113 | new_toggle = 0; /* RCMM */ | 160 | del_timer(&ir->keyup_timer); |
114 | else | 161 | if (ir->last_key != keycode || toggle != ir->last_toggle) { |
115 | new_toggle = (ircom & 0x800); /* RC5, extended RC5 */ | 162 | ir->delay_timer_finished = 0; |
116 | 163 | input_event(ir->input_dev, EV_KEY, ir->last_key, 0); | |
117 | if (timer_pending(&keyup_timer)) { | 164 | input_event(ir->input_dev, EV_KEY, keycode, 1); |
118 | del_timer(&keyup_timer); | 165 | input_sync(ir->input_dev); |
119 | if (keyup_timer.data != keycode || new_toggle != old_toggle) { | 166 | } else if (ir->delay_timer_finished) { |
120 | delay_timer_finished = 0; | 167 | input_event(ir->input_dev, EV_KEY, keycode, 2); |
121 | input_event(input_dev, EV_KEY, keyup_timer.data, 0); | 168 | input_sync(ir->input_dev); |
122 | input_event(input_dev, EV_KEY, keycode, 1); | ||
123 | input_sync(input_dev); | ||
124 | } else if (delay_timer_finished) { | ||
125 | input_event(input_dev, EV_KEY, keycode, 2); | ||
126 | input_sync(input_dev); | ||
127 | } | 169 | } |
128 | } else { | 170 | } else { |
129 | delay_timer_finished = 0; | 171 | ir->delay_timer_finished = 0; |
130 | input_event(input_dev, EV_KEY, keycode, 1); | 172 | input_event(ir->input_dev, EV_KEY, keycode, 1); |
131 | input_sync(input_dev); | 173 | input_sync(ir->input_dev); |
132 | } | 174 | } |
133 | 175 | ||
134 | keyup_timer.expires = jiffies + UP_TIMEOUT; | 176 | ir->last_key = keycode; |
135 | keyup_timer.data = keycode; | 177 | ir->last_toggle = toggle; |
136 | 178 | ||
137 | add_timer(&keyup_timer); | 179 | ir->keyup_timer.expires = jiffies + UP_TIMEOUT; |
180 | add_timer(&ir->keyup_timer); | ||
138 | 181 | ||
139 | old_toggle = new_toggle; | ||
140 | } | 182 | } |
141 | 183 | ||
142 | static void input_register_keys(void) | 184 | |
185 | /* register with input layer */ | ||
186 | static void input_register_keys(struct infrared *ir) | ||
143 | { | 187 | { |
144 | int i; | 188 | int i; |
145 | 189 | ||
146 | memset(input_dev->keybit, 0, sizeof(input_dev->keybit)); | 190 | set_bit(EV_KEY, ir->input_dev->evbit); |
191 | set_bit(EV_REP, ir->input_dev->evbit); | ||
192 | set_bit(EV_MSC, ir->input_dev->evbit); | ||
147 | 193 | ||
148 | for (i = 0; i < ARRAY_SIZE(key_map); i++) { | 194 | set_bit(MSC_RAW, ir->input_dev->mscbit); |
149 | if (key_map[i] > KEY_MAX) | 195 | set_bit(MSC_SCAN, ir->input_dev->mscbit); |
150 | key_map[i] = 0; | 196 | |
151 | else if (key_map[i] > KEY_RESERVED) | 197 | memset(ir->input_dev->keybit, 0, sizeof(ir->input_dev->keybit)); |
152 | set_bit(key_map[i], input_dev->keybit); | 198 | |
199 | for (i = 0; i < ARRAY_SIZE(ir->key_map); i++) { | ||
200 | if (ir->key_map[i] > KEY_MAX) | ||
201 | ir->key_map[i] = 0; | ||
202 | else if (ir->key_map[i] > KEY_RESERVED) | ||
203 | set_bit(ir->key_map[i], ir->input_dev->keybit); | ||
153 | } | 204 | } |
205 | |||
206 | ir->input_dev->keycode = ir->key_map; | ||
207 | ir->input_dev->keycodesize = sizeof(ir->key_map[0]); | ||
208 | ir->input_dev->keycodemax = ARRAY_SIZE(ir->key_map); | ||
154 | } | 209 | } |
155 | 210 | ||
156 | 211 | ||
157 | static void input_repeat_key(unsigned long data) | 212 | /* called by the input driver after rep[REP_DELAY] ms */ |
213 | static void input_repeat_key(unsigned long parm) | ||
158 | { | 214 | { |
159 | /* called by the input driver after rep[REP_DELAY] ms */ | 215 | struct infrared *ir = (struct infrared *) parm; |
160 | delay_timer_finished = 1; | 216 | |
217 | ir->delay_timer_finished = 1; | ||
161 | } | 218 | } |
162 | 219 | ||
163 | 220 | ||
164 | static int av7110_setup_irc_config(struct av7110 *av7110, u32 ir_config) | 221 | /* check for configuration changes */ |
222 | int av7110_check_ir_config(struct av7110 *av7110, int force) | ||
165 | { | 223 | { |
166 | int ret = 0; | 224 | int i; |
225 | int modified = force; | ||
226 | int ret = -ENODEV; | ||
167 | 227 | ||
168 | dprintk(4, "%p\n", av7110); | 228 | for (i = 0; i < av_cnt; i++) |
169 | if (av7110) { | 229 | if (av7110 == av_list[i]) |
170 | ret = av7110_fw_cmd(av7110, COMTYPE_PIDFILTER, SetIR, 1, ir_config); | 230 | break; |
171 | av7110->ir_config = ir_config; | 231 | |
232 | if (i < av_cnt && av7110) { | ||
233 | if ((av7110->ir.protocol & 1) != ir_protocol[i] || | ||
234 | av7110->ir.inversion != ir_inversion[i]) | ||
235 | modified = true; | ||
236 | |||
237 | if (modified) { | ||
238 | /* protocol */ | ||
239 | if (ir_protocol[i]) { | ||
240 | ir_protocol[i] = 1; | ||
241 | av7110->ir.protocol = IR_RCMM; | ||
242 | av7110->ir.ir_config = 0x0001; | ||
243 | } else if (FW_VERSION(av7110->arm_app) >= 0x2620) { | ||
244 | av7110->ir.protocol = IR_RC5_EXT; | ||
245 | av7110->ir.ir_config = 0x0002; | ||
246 | } else { | ||
247 | av7110->ir.protocol = IR_RC5; | ||
248 | av7110->ir.ir_config = 0x0000; | ||
249 | } | ||
250 | /* inversion */ | ||
251 | if (ir_inversion[i]) { | ||
252 | ir_inversion[i] = 1; | ||
253 | av7110->ir.ir_config |= 0x8000; | ||
254 | } | ||
255 | av7110->ir.inversion = ir_inversion[i]; | ||
256 | /* update ARM */ | ||
257 | ret = av7110_fw_cmd(av7110, COMTYPE_PIDFILTER, SetIR, 1, | ||
258 | av7110->ir.ir_config); | ||
259 | } else | ||
260 | ret = 0; | ||
261 | |||
262 | /* address */ | ||
263 | if (av7110->ir.device_mask != ir_device_mask[i]) | ||
264 | av7110->ir.device_mask = ir_device_mask[i]; | ||
172 | } | 265 | } |
266 | |||
173 | return ret; | 267 | return ret; |
174 | } | 268 | } |
175 | 269 | ||
176 | 270 | ||
271 | /* /proc/av7110_ir interface */ | ||
177 | static int av7110_ir_write_proc(struct file *file, const char __user *buffer, | 272 | static int av7110_ir_write_proc(struct file *file, const char __user *buffer, |
178 | unsigned long count, void *data) | 273 | unsigned long count, void *data) |
179 | { | 274 | { |
180 | char *page; | 275 | char *page; |
181 | int size = 4 + 256 * sizeof(u16); | ||
182 | u32 ir_config; | 276 | u32 ir_config; |
277 | int size = sizeof ir_config + sizeof av_list[0]->ir.key_map; | ||
183 | int i; | 278 | int i; |
184 | 279 | ||
185 | if (count < size) | 280 | if (count < size) |
@@ -194,71 +289,86 @@ static int av7110_ir_write_proc(struct file *file, const char __user *buffer, | |||
194 | return -EFAULT; | 289 | return -EFAULT; |
195 | } | 290 | } |
196 | 291 | ||
197 | memcpy(&ir_config, page, 4); | 292 | memcpy(&ir_config, page, sizeof ir_config); |
198 | memcpy(&key_map, page + 4, 256 * sizeof(u16)); | 293 | |
294 | for (i = 0; i < av_cnt; i++) { | ||
295 | /* keymap */ | ||
296 | memcpy(av_list[i]->ir.key_map, page + sizeof ir_config, | ||
297 | sizeof(av_list[i]->ir.key_map)); | ||
298 | /* protocol, inversion, address */ | ||
299 | ir_protocol[i] = ir_config & 0x0001; | ||
300 | ir_inversion[i] = ir_config & 0x8000 ? 1 : 0; | ||
301 | if (ir_config & 0x4000) | ||
302 | ir_device_mask[i] = 1 << ((ir_config >> 16) & 0x1f); | ||
303 | else | ||
304 | ir_device_mask[i] = IR_ALL; | ||
305 | /* update configuration */ | ||
306 | av7110_check_ir_config(av_list[i], false); | ||
307 | input_register_keys(&av_list[i]->ir); | ||
308 | } | ||
199 | vfree(page); | 309 | vfree(page); |
200 | if (FW_VERSION(av_list[0]->arm_app) >= 0x2620 && !(ir_config & 0x0001)) | ||
201 | ir_config |= 0x0002; /* enable extended RC5 */ | ||
202 | for (i = 0; i < av_cnt; i++) | ||
203 | av7110_setup_irc_config(av_list[i], ir_config); | ||
204 | input_register_keys(); | ||
205 | return count; | 310 | return count; |
206 | } | 311 | } |
207 | 312 | ||
208 | 313 | ||
314 | /* interrupt handler */ | ||
209 | static void ir_handler(struct av7110 *av7110, u32 ircom) | 315 | static void ir_handler(struct av7110 *av7110, u32 ircom) |
210 | { | 316 | { |
211 | dprintk(4, "ircommand = %08x\n", ircom); | 317 | dprintk(4, "ir command = %08x\n", ircom); |
212 | av7110->ir_command = ircom; | 318 | av7110->ir.ir_command = ircom; |
213 | tasklet_schedule(&av7110->ir_tasklet); | 319 | tasklet_schedule(&av7110->ir.ir_tasklet); |
214 | } | 320 | } |
215 | 321 | ||
216 | 322 | ||
217 | int __devinit av7110_ir_init(struct av7110 *av7110) | 323 | int __devinit av7110_ir_init(struct av7110 *av7110) |
218 | { | 324 | { |
325 | struct input_dev *input_dev; | ||
219 | static struct proc_dir_entry *e; | 326 | static struct proc_dir_entry *e; |
220 | int err; | 327 | int err; |
221 | 328 | ||
222 | if (av_cnt >= ARRAY_SIZE(av_list)) | 329 | if (av_cnt >= ARRAY_SIZE(av_list)) |
223 | return -ENOSPC; | 330 | return -ENOSPC; |
224 | 331 | ||
225 | av7110_setup_irc_config(av7110, 0x0001); | ||
226 | av_list[av_cnt++] = av7110; | 332 | av_list[av_cnt++] = av7110; |
333 | av7110_check_ir_config(av7110, true); | ||
227 | 334 | ||
228 | if (av_cnt == 1) { | 335 | init_timer(&av7110->ir.keyup_timer); |
229 | init_timer(&keyup_timer); | 336 | av7110->ir.keyup_timer.function = av7110_emit_keyup; |
230 | keyup_timer.data = 0; | 337 | av7110->ir.keyup_timer.data = (unsigned long) &av7110->ir; |
231 | 338 | ||
232 | input_dev = input_allocate_device(); | 339 | input_dev = input_allocate_device(); |
233 | if (!input_dev) | 340 | if (!input_dev) |
234 | return -ENOMEM; | 341 | return -ENOMEM; |
235 | |||
236 | snprintf(input_phys, sizeof(input_phys), | ||
237 | "pci-%s/ir0", pci_name(av7110->dev->pci)); | ||
238 | |||
239 | input_dev->name = "DVB on-card IR receiver"; | ||
240 | |||
241 | input_dev->phys = input_phys; | ||
242 | input_dev->id.bustype = BUS_PCI; | ||
243 | input_dev->id.version = 1; | ||
244 | if (av7110->dev->pci->subsystem_vendor) { | ||
245 | input_dev->id.vendor = av7110->dev->pci->subsystem_vendor; | ||
246 | input_dev->id.product = av7110->dev->pci->subsystem_device; | ||
247 | } else { | ||
248 | input_dev->id.vendor = av7110->dev->pci->vendor; | ||
249 | input_dev->id.product = av7110->dev->pci->device; | ||
250 | } | ||
251 | input_dev->cdev.dev = &av7110->dev->pci->dev; | ||
252 | set_bit(EV_KEY, input_dev->evbit); | ||
253 | set_bit(EV_REP, input_dev->evbit); | ||
254 | input_register_keys(); | ||
255 | err = input_register_device(input_dev); | ||
256 | if (err) { | ||
257 | input_free_device(input_dev); | ||
258 | return err; | ||
259 | } | ||
260 | input_dev->timer.function = input_repeat_key; | ||
261 | 342 | ||
343 | av7110->ir.input_dev = input_dev; | ||
344 | snprintf(av7110->ir.input_phys, sizeof(av7110->ir.input_phys), | ||
345 | "pci-%s/ir0", pci_name(av7110->dev->pci)); | ||
346 | |||
347 | input_dev->name = "DVB on-card IR receiver"; | ||
348 | |||
349 | input_dev->phys = av7110->ir.input_phys; | ||
350 | input_dev->id.bustype = BUS_PCI; | ||
351 | input_dev->id.version = 2; | ||
352 | if (av7110->dev->pci->subsystem_vendor) { | ||
353 | input_dev->id.vendor = av7110->dev->pci->subsystem_vendor; | ||
354 | input_dev->id.product = av7110->dev->pci->subsystem_device; | ||
355 | } else { | ||
356 | input_dev->id.vendor = av7110->dev->pci->vendor; | ||
357 | input_dev->id.product = av7110->dev->pci->device; | ||
358 | } | ||
359 | input_dev->cdev.dev = &av7110->dev->pci->dev; | ||
360 | /* initial keymap */ | ||
361 | memcpy(av7110->ir.key_map, default_key_map, sizeof av7110->ir.key_map); | ||
362 | input_register_keys(&av7110->ir); | ||
363 | err = input_register_device(input_dev); | ||
364 | if (err) { | ||
365 | input_free_device(input_dev); | ||
366 | return err; | ||
367 | } | ||
368 | input_dev->timer.function = input_repeat_key; | ||
369 | input_dev->timer.data = (unsigned long) &av7110->ir; | ||
370 | |||
371 | if (av_cnt == 1) { | ||
262 | e = create_proc_entry("av7110_ir", S_IFREG | S_IRUGO | S_IWUSR, NULL); | 372 | e = create_proc_entry("av7110_ir", S_IFREG | S_IRUGO | S_IWUSR, NULL); |
263 | if (e) { | 373 | if (e) { |
264 | e->write_proc = av7110_ir_write_proc; | 374 | e->write_proc = av7110_ir_write_proc; |
@@ -266,8 +376,8 @@ int __devinit av7110_ir_init(struct av7110 *av7110) | |||
266 | } | 376 | } |
267 | } | 377 | } |
268 | 378 | ||
269 | tasklet_init(&av7110->ir_tasklet, av7110_emit_key, (unsigned long) av7110); | 379 | tasklet_init(&av7110->ir.ir_tasklet, av7110_emit_key, (unsigned long) &av7110->ir); |
270 | av7110->ir_handler = ir_handler; | 380 | av7110->ir.ir_handler = ir_handler; |
271 | 381 | ||
272 | return 0; | 382 | return 0; |
273 | } | 383 | } |
@@ -280,8 +390,10 @@ void __devexit av7110_ir_exit(struct av7110 *av7110) | |||
280 | if (av_cnt == 0) | 390 | if (av_cnt == 0) |
281 | return; | 391 | return; |
282 | 392 | ||
283 | av7110->ir_handler = NULL; | 393 | del_timer_sync(&av7110->ir.keyup_timer); |
284 | tasklet_kill(&av7110->ir_tasklet); | 394 | av7110->ir.ir_handler = NULL; |
395 | tasklet_kill(&av7110->ir.ir_tasklet); | ||
396 | |||
285 | for (i = 0; i < av_cnt; i++) | 397 | for (i = 0; i < av_cnt; i++) |
286 | if (av_list[i] == av7110) { | 398 | if (av_list[i] == av7110) { |
287 | av_list[i] = av_list[av_cnt-1]; | 399 | av_list[i] = av_list[av_cnt-1]; |
@@ -289,14 +401,13 @@ void __devexit av7110_ir_exit(struct av7110 *av7110) | |||
289 | break; | 401 | break; |
290 | } | 402 | } |
291 | 403 | ||
292 | if (av_cnt == 1) { | 404 | if (av_cnt == 1) |
293 | del_timer_sync(&keyup_timer); | ||
294 | remove_proc_entry("av7110_ir", NULL); | 405 | remove_proc_entry("av7110_ir", NULL); |
295 | input_unregister_device(input_dev); | 406 | |
296 | } | 407 | input_unregister_device(av7110->ir.input_dev); |
297 | 408 | ||
298 | av_cnt--; | 409 | av_cnt--; |
299 | } | 410 | } |
300 | 411 | ||
301 | //MODULE_AUTHOR("Holger Waechtler <holger@convergence.de>"); | 412 | //MODULE_AUTHOR("Holger Waechtler <holger@convergence.de>, Oliver Endriss <o.endriss@gmx.de>"); |
302 | //MODULE_LICENSE("GPL"); | 413 | //MODULE_LICENSE("GPL"); |
diff --git a/drivers/media/dvb/ttpci/budget-av.c b/drivers/media/dvb/ttpci/budget-av.c index 3035b224c7a3..0e817d6f1ce5 100644 --- a/drivers/media/dvb/ttpci/budget-av.c +++ b/drivers/media/dvb/ttpci/budget-av.c | |||
@@ -35,7 +35,7 @@ | |||
35 | 35 | ||
36 | #include "budget.h" | 36 | #include "budget.h" |
37 | #include "stv0299.h" | 37 | #include "stv0299.h" |
38 | #include "tda10021.h" | 38 | #include "tda1002x.h" |
39 | #include "tda1004x.h" | 39 | #include "tda1004x.h" |
40 | #include "tua6100.h" | 40 | #include "tua6100.h" |
41 | #include "dvb-pll.h" | 41 | #include "dvb-pll.h" |
@@ -66,9 +66,6 @@ struct budget_av { | |||
66 | int slot_status; | 66 | int slot_status; |
67 | struct dvb_ca_en50221 ca; | 67 | struct dvb_ca_en50221 ca; |
68 | u8 reinitialise_demod:1; | 68 | u8 reinitialise_demod:1; |
69 | u8 tda10021_poclkp:1; | ||
70 | u8 tda10021_ts_enabled; | ||
71 | int (*tda10021_set_frontend)(struct dvb_frontend *fe, struct dvb_frontend_parameters *p); | ||
72 | }; | 69 | }; |
73 | 70 | ||
74 | static int ciintf_slot_shutdown(struct dvb_ca_en50221 *ca, int slot); | 71 | static int ciintf_slot_shutdown(struct dvb_ca_en50221 *ca, int slot); |
@@ -234,12 +231,6 @@ static int ciintf_slot_reset(struct dvb_ca_en50221 *ca, int slot) | |||
234 | if (budget_av->reinitialise_demod) | 231 | if (budget_av->reinitialise_demod) |
235 | dvb_frontend_reinitialise(budget_av->budget.dvb_frontend); | 232 | dvb_frontend_reinitialise(budget_av->budget.dvb_frontend); |
236 | 233 | ||
237 | /* set tda10021 back to original clock configuration on reset */ | ||
238 | if (budget_av->tda10021_poclkp) { | ||
239 | tda10021_writereg(budget_av->budget.dvb_frontend, 0x12, 0xa0); | ||
240 | budget_av->tda10021_ts_enabled = 0; | ||
241 | } | ||
242 | |||
243 | return 0; | 234 | return 0; |
244 | } | 235 | } |
245 | 236 | ||
@@ -256,11 +247,6 @@ static int ciintf_slot_shutdown(struct dvb_ca_en50221 *ca, int slot) | |||
256 | ttpci_budget_set_video_port(saa, BUDGET_VIDEO_PORTB); | 247 | ttpci_budget_set_video_port(saa, BUDGET_VIDEO_PORTB); |
257 | budget_av->slot_status = SLOTSTATUS_NONE; | 248 | budget_av->slot_status = SLOTSTATUS_NONE; |
258 | 249 | ||
259 | /* set tda10021 back to original clock configuration when cam removed */ | ||
260 | if (budget_av->tda10021_poclkp) { | ||
261 | tda10021_writereg(budget_av->budget.dvb_frontend, 0x12, 0xa0); | ||
262 | budget_av->tda10021_ts_enabled = 0; | ||
263 | } | ||
264 | return 0; | 250 | return 0; |
265 | } | 251 | } |
266 | 252 | ||
@@ -276,12 +262,6 @@ static int ciintf_slot_ts_enable(struct dvb_ca_en50221 *ca, int slot) | |||
276 | 262 | ||
277 | ttpci_budget_set_video_port(saa, BUDGET_VIDEO_PORTA); | 263 | ttpci_budget_set_video_port(saa, BUDGET_VIDEO_PORTA); |
278 | 264 | ||
279 | /* tda10021 seems to need a different TS clock config when data is routed to the CAM */ | ||
280 | if (budget_av->tda10021_poclkp) { | ||
281 | tda10021_writereg(budget_av->budget.dvb_frontend, 0x12, 0xa1); | ||
282 | budget_av->tda10021_ts_enabled = 1; | ||
283 | } | ||
284 | |||
285 | return 0; | 265 | return 0; |
286 | } | 266 | } |
287 | 267 | ||
@@ -631,37 +611,62 @@ static struct stv0299_config cinergy_1200s_1894_0010_config = { | |||
631 | static int philips_cu1216_tuner_set_params(struct dvb_frontend *fe, struct dvb_frontend_parameters *params) | 611 | static int philips_cu1216_tuner_set_params(struct dvb_frontend *fe, struct dvb_frontend_parameters *params) |
632 | { | 612 | { |
633 | struct budget *budget = (struct budget *) fe->dvb->priv; | 613 | struct budget *budget = (struct budget *) fe->dvb->priv; |
634 | u8 buf[4]; | 614 | u8 buf[6]; |
635 | struct i2c_msg msg = {.addr = 0x60,.flags = 0,.buf = buf,.len = sizeof(buf) }; | 615 | struct i2c_msg msg = {.addr = 0x60,.flags = 0,.buf = buf,.len = sizeof(buf) }; |
616 | int i; | ||
636 | 617 | ||
618 | #define CU1216_IF 36125000 | ||
637 | #define TUNER_MUL 62500 | 619 | #define TUNER_MUL 62500 |
638 | 620 | ||
639 | u32 div = (params->frequency + 36125000 + TUNER_MUL / 2) / TUNER_MUL; | 621 | u32 div = (params->frequency + CU1216_IF + TUNER_MUL / 2) / TUNER_MUL; |
640 | 622 | ||
641 | buf[0] = (div >> 8) & 0x7f; | 623 | buf[0] = (div >> 8) & 0x7f; |
642 | buf[1] = div & 0xff; | 624 | buf[1] = div & 0xff; |
643 | buf[2] = 0x86; | 625 | buf[2] = 0xce; |
644 | buf[3] = (params->frequency < 150000000 ? 0x01 : | 626 | buf[3] = (params->frequency < 150000000 ? 0x01 : |
645 | params->frequency < 445000000 ? 0x02 : 0x04); | 627 | params->frequency < 445000000 ? 0x02 : 0x04); |
628 | buf[4] = 0xde; | ||
629 | buf[5] = 0x20; | ||
630 | |||
631 | if (fe->ops.i2c_gate_ctrl) | ||
632 | fe->ops.i2c_gate_ctrl(fe, 1); | ||
633 | if (i2c_transfer(&budget->i2c_adap, &msg, 1) != 1) | ||
634 | return -EIO; | ||
646 | 635 | ||
636 | /* wait for the pll lock */ | ||
637 | msg.flags = I2C_M_RD; | ||
638 | msg.len = 1; | ||
639 | for (i = 0; i < 20; i++) { | ||
640 | if (fe->ops.i2c_gate_ctrl) | ||
641 | fe->ops.i2c_gate_ctrl(fe, 1); | ||
642 | if (i2c_transfer(&budget->i2c_adap, &msg, 1) == 1 && (buf[0] & 0x40)) | ||
643 | break; | ||
644 | msleep(10); | ||
645 | } | ||
646 | |||
647 | /* switch the charge pump to the lower current */ | ||
648 | msg.flags = 0; | ||
649 | msg.len = 2; | ||
650 | msg.buf = &buf[2]; | ||
651 | buf[2] &= ~0x40; | ||
647 | if (fe->ops.i2c_gate_ctrl) | 652 | if (fe->ops.i2c_gate_ctrl) |
648 | fe->ops.i2c_gate_ctrl(fe, 1); | 653 | fe->ops.i2c_gate_ctrl(fe, 1); |
649 | if (i2c_transfer(&budget->i2c_adap, &msg, 1) != 1) | 654 | if (i2c_transfer(&budget->i2c_adap, &msg, 1) != 1) |
650 | return -EIO; | 655 | return -EIO; |
656 | |||
651 | return 0; | 657 | return 0; |
652 | } | 658 | } |
653 | 659 | ||
654 | static struct tda10021_config philips_cu1216_config = { | 660 | static struct tda1002x_config philips_cu1216_config = { |
655 | .demod_address = 0x0c, | 661 | .demod_address = 0x0c, |
662 | .invert = 1, | ||
656 | }; | 663 | }; |
657 | 664 | ||
658 | static struct tda10021_config philips_cu1216_config_altaddress = { | 665 | static struct tda1002x_config philips_cu1216_config_altaddress = { |
659 | .demod_address = 0x0d, | 666 | .demod_address = 0x0d, |
667 | .invert = 0, | ||
660 | }; | 668 | }; |
661 | 669 | ||
662 | |||
663 | |||
664 | |||
665 | static int philips_tu1216_tuner_init(struct dvb_frontend *fe) | 670 | static int philips_tu1216_tuner_init(struct dvb_frontend *fe) |
666 | { | 671 | { |
667 | struct budget *budget = (struct budget *) fe->dvb->priv; | 672 | struct budget *budget = (struct budget *) fe->dvb->priv; |
@@ -908,41 +913,28 @@ static u8 read_pwm(struct budget_av *budget_av) | |||
908 | return pwm; | 913 | return pwm; |
909 | } | 914 | } |
910 | 915 | ||
911 | #define SUBID_DVBS_KNC1 0x0010 | 916 | #define SUBID_DVBS_KNC1 0x0010 |
912 | #define SUBID_DVBS_KNC1_PLUS 0x0011 | 917 | #define SUBID_DVBS_KNC1_PLUS 0x0011 |
913 | #define SUBID_DVBS_TYPHOON 0x4f56 | 918 | #define SUBID_DVBS_TYPHOON 0x4f56 |
914 | #define SUBID_DVBS_CINERGY1200 0x1154 | 919 | #define SUBID_DVBS_CINERGY1200 0x1154 |
915 | #define SUBID_DVBS_CYNERGY1200N 0x1155 | 920 | #define SUBID_DVBS_CYNERGY1200N 0x1155 |
916 | 921 | #define SUBID_DVBS_TV_STAR 0x0014 | |
917 | #define SUBID_DVBS_TV_STAR 0x0014 | 922 | #define SUBID_DVBS_TV_STAR_CI 0x0016 |
918 | #define SUBID_DVBS_TV_STAR_CI 0x0016 | 923 | #define SUBID_DVBS_EASYWATCH_1 0x001a |
919 | #define SUBID_DVBS_EASYWATCH_1 0x001a | 924 | #define SUBID_DVBS_EASYWATCH 0x001e |
920 | #define SUBID_DVBS_EASYWATCH 0x001e | 925 | |
921 | #define SUBID_DVBC_EASYWATCH 0x002a | 926 | #define SUBID_DVBC_EASYWATCH 0x002a |
922 | #define SUBID_DVBC_KNC1 0x0020 | 927 | #define SUBID_DVBC_EASYWATCH_MK3 0x002c |
923 | #define SUBID_DVBC_KNC1_PLUS 0x0021 | 928 | #define SUBID_DVBC_KNC1 0x0020 |
924 | #define SUBID_DVBC_CINERGY1200 0x1156 | 929 | #define SUBID_DVBC_KNC1_PLUS 0x0021 |
925 | 930 | #define SUBID_DVBC_KNC1_MK3 0x0022 | |
926 | #define SUBID_DVBT_KNC1_PLUS 0x0031 | 931 | #define SUBID_DVBC_KNC1_PLUS_MK3 0x0023 |
927 | #define SUBID_DVBT_KNC1 0x0030 | 932 | #define SUBID_DVBC_CINERGY1200 0x1156 |
928 | #define SUBID_DVBT_CINERGY1200 0x1157 | 933 | #define SUBID_DVBC_CINERGY1200_MK3 0x1176 |
929 | 934 | ||
930 | 935 | #define SUBID_DVBT_KNC1_PLUS 0x0031 | |
931 | static int tda10021_set_frontend(struct dvb_frontend *fe, | 936 | #define SUBID_DVBT_KNC1 0x0030 |
932 | struct dvb_frontend_parameters *p) | 937 | #define SUBID_DVBT_CINERGY1200 0x1157 |
933 | { | ||
934 | struct budget_av* budget_av = fe->dvb->priv; | ||
935 | int result; | ||
936 | |||
937 | result = budget_av->tda10021_set_frontend(fe, p); | ||
938 | if (budget_av->tda10021_ts_enabled) { | ||
939 | tda10021_writereg(budget_av->budget.dvb_frontend, 0x12, 0xa1); | ||
940 | } else { | ||
941 | tda10021_writereg(budget_av->budget.dvb_frontend, 0x12, 0xa0); | ||
942 | } | ||
943 | |||
944 | return result; | ||
945 | } | ||
946 | 938 | ||
947 | static void frontend_init(struct budget_av *budget_av) | 939 | static void frontend_init(struct budget_av *budget_av) |
948 | { | 940 | { |
@@ -961,6 +953,7 @@ static void frontend_init(struct budget_av *budget_av) | |||
961 | case SUBID_DVBC_KNC1_PLUS: | 953 | case SUBID_DVBC_KNC1_PLUS: |
962 | case SUBID_DVBT_KNC1_PLUS: | 954 | case SUBID_DVBT_KNC1_PLUS: |
963 | case SUBID_DVBC_EASYWATCH: | 955 | case SUBID_DVBC_EASYWATCH: |
956 | case SUBID_DVBC_KNC1_PLUS_MK3: | ||
964 | saa7146_setgpio(saa, 3, SAA7146_GPIO_OUTHI); | 957 | saa7146_setgpio(saa, 3, SAA7146_GPIO_OUTHI); |
965 | break; | 958 | break; |
966 | } | 959 | } |
@@ -1017,6 +1010,7 @@ static void frontend_init(struct budget_av *budget_av) | |||
1017 | case SUBID_DVBC_CINERGY1200: | 1010 | case SUBID_DVBC_CINERGY1200: |
1018 | case SUBID_DVBC_EASYWATCH: | 1011 | case SUBID_DVBC_EASYWATCH: |
1019 | budget_av->reinitialise_demod = 1; | 1012 | budget_av->reinitialise_demod = 1; |
1013 | budget_av->budget.dev->i2c_bitrate = SAA7146_I2C_BUS_BIT_RATE_240; | ||
1020 | fe = dvb_attach(tda10021_attach, &philips_cu1216_config, | 1014 | fe = dvb_attach(tda10021_attach, &philips_cu1216_config, |
1021 | &budget_av->budget.i2c_adap, | 1015 | &budget_av->budget.i2c_adap, |
1022 | read_pwm(budget_av)); | 1016 | read_pwm(budget_av)); |
@@ -1025,9 +1019,20 @@ static void frontend_init(struct budget_av *budget_av) | |||
1025 | &budget_av->budget.i2c_adap, | 1019 | &budget_av->budget.i2c_adap, |
1026 | read_pwm(budget_av)); | 1020 | read_pwm(budget_av)); |
1027 | if (fe) { | 1021 | if (fe) { |
1028 | budget_av->tda10021_poclkp = 1; | 1022 | fe->ops.tuner_ops.set_params = philips_cu1216_tuner_set_params; |
1029 | budget_av->tda10021_set_frontend = fe->ops.set_frontend; | 1023 | } |
1030 | fe->ops.set_frontend = tda10021_set_frontend; | 1024 | break; |
1025 | |||
1026 | case SUBID_DVBC_EASYWATCH_MK3: | ||
1027 | case SUBID_DVBC_CINERGY1200_MK3: | ||
1028 | case SUBID_DVBC_KNC1_MK3: | ||
1029 | case SUBID_DVBC_KNC1_PLUS_MK3: | ||
1030 | budget_av->reinitialise_demod = 1; | ||
1031 | budget_av->budget.dev->i2c_bitrate = SAA7146_I2C_BUS_BIT_RATE_240; | ||
1032 | fe = dvb_attach(tda10023_attach, &philips_cu1216_config, | ||
1033 | &budget_av->budget.i2c_adap, | ||
1034 | read_pwm(budget_av)); | ||
1035 | if (fe) { | ||
1031 | fe->ops.tuner_ops.set_params = philips_cu1216_tuner_set_params; | 1036 | fe->ops.tuner_ops.set_params = philips_cu1216_tuner_set_params; |
1032 | } | 1037 | } |
1033 | break; | 1038 | break; |
@@ -1260,12 +1265,16 @@ MAKE_BUDGET_INFO(kncxs, "KNC TV STAR DVB-S", BUDGET_TVSTAR); | |||
1260 | MAKE_BUDGET_INFO(satewpls, "Satelco EasyWatch DVB-S light", BUDGET_TVSTAR); | 1265 | MAKE_BUDGET_INFO(satewpls, "Satelco EasyWatch DVB-S light", BUDGET_TVSTAR); |
1261 | MAKE_BUDGET_INFO(satewpls1, "Satelco EasyWatch DVB-S light", BUDGET_KNC1S); | 1266 | MAKE_BUDGET_INFO(satewpls1, "Satelco EasyWatch DVB-S light", BUDGET_KNC1S); |
1262 | MAKE_BUDGET_INFO(satewplc, "Satelco EasyWatch DVB-C", BUDGET_KNC1CP); | 1267 | MAKE_BUDGET_INFO(satewplc, "Satelco EasyWatch DVB-C", BUDGET_KNC1CP); |
1268 | MAKE_BUDGET_INFO(satewcmk3, "Satelco EasyWatch DVB-C MK3", BUDGET_KNC1C_MK3); | ||
1263 | MAKE_BUDGET_INFO(knc1sp, "KNC1 DVB-S Plus", BUDGET_KNC1SP); | 1269 | MAKE_BUDGET_INFO(knc1sp, "KNC1 DVB-S Plus", BUDGET_KNC1SP); |
1264 | MAKE_BUDGET_INFO(knc1cp, "KNC1 DVB-C Plus", BUDGET_KNC1CP); | 1270 | MAKE_BUDGET_INFO(knc1cp, "KNC1 DVB-C Plus", BUDGET_KNC1CP); |
1271 | MAKE_BUDGET_INFO(knc1cmk3, "KNC1 DVB-C MK3", BUDGET_KNC1C_MK3); | ||
1272 | MAKE_BUDGET_INFO(knc1cpmk3, "KNC1 DVB-C Plus MK3", BUDGET_KNC1CP_MK3); | ||
1265 | MAKE_BUDGET_INFO(knc1tp, "KNC1 DVB-T Plus", BUDGET_KNC1TP); | 1273 | MAKE_BUDGET_INFO(knc1tp, "KNC1 DVB-T Plus", BUDGET_KNC1TP); |
1266 | MAKE_BUDGET_INFO(cin1200s, "TerraTec Cinergy 1200 DVB-S", BUDGET_CIN1200S); | 1274 | MAKE_BUDGET_INFO(cin1200s, "TerraTec Cinergy 1200 DVB-S", BUDGET_CIN1200S); |
1267 | MAKE_BUDGET_INFO(cin1200sn, "TerraTec Cinergy 1200 DVB-S", BUDGET_CIN1200S); | 1275 | MAKE_BUDGET_INFO(cin1200sn, "TerraTec Cinergy 1200 DVB-S", BUDGET_CIN1200S); |
1268 | MAKE_BUDGET_INFO(cin1200c, "Terratec Cinergy 1200 DVB-C", BUDGET_CIN1200C); | 1276 | MAKE_BUDGET_INFO(cin1200c, "Terratec Cinergy 1200 DVB-C", BUDGET_CIN1200C); |
1277 | MAKE_BUDGET_INFO(cin1200cmk3, "Terratec Cinergy 1200 DVB-C MK3", BUDGET_CIN1200C_MK3); | ||
1269 | MAKE_BUDGET_INFO(cin1200t, "Terratec Cinergy 1200 DVB-T", BUDGET_CIN1200T); | 1278 | MAKE_BUDGET_INFO(cin1200t, "Terratec Cinergy 1200 DVB-T", BUDGET_CIN1200T); |
1270 | 1279 | ||
1271 | static struct pci_device_id pci_tbl[] = { | 1280 | static struct pci_device_id pci_tbl[] = { |
@@ -1279,13 +1288,17 @@ static struct pci_device_id pci_tbl[] = { | |||
1279 | MAKE_EXTENSION_PCI(satewpls, 0x1894, 0x001e), | 1288 | MAKE_EXTENSION_PCI(satewpls, 0x1894, 0x001e), |
1280 | MAKE_EXTENSION_PCI(satewpls1, 0x1894, 0x001a), | 1289 | MAKE_EXTENSION_PCI(satewpls1, 0x1894, 0x001a), |
1281 | MAKE_EXTENSION_PCI(satewplc, 0x1894, 0x002a), | 1290 | MAKE_EXTENSION_PCI(satewplc, 0x1894, 0x002a), |
1291 | MAKE_EXTENSION_PCI(satewcmk3, 0x1894, 0x002c), | ||
1282 | MAKE_EXTENSION_PCI(knc1c, 0x1894, 0x0020), | 1292 | MAKE_EXTENSION_PCI(knc1c, 0x1894, 0x0020), |
1283 | MAKE_EXTENSION_PCI(knc1cp, 0x1894, 0x0021), | 1293 | MAKE_EXTENSION_PCI(knc1cp, 0x1894, 0x0021), |
1294 | MAKE_EXTENSION_PCI(knc1cmk3, 0x1894, 0x0022), | ||
1295 | MAKE_EXTENSION_PCI(knc1cpmk3, 0x1894, 0x0023), | ||
1284 | MAKE_EXTENSION_PCI(knc1t, 0x1894, 0x0030), | 1296 | MAKE_EXTENSION_PCI(knc1t, 0x1894, 0x0030), |
1285 | MAKE_EXTENSION_PCI(knc1tp, 0x1894, 0x0031), | 1297 | MAKE_EXTENSION_PCI(knc1tp, 0x1894, 0x0031), |
1286 | MAKE_EXTENSION_PCI(cin1200s, 0x153b, 0x1154), | 1298 | MAKE_EXTENSION_PCI(cin1200s, 0x153b, 0x1154), |
1287 | MAKE_EXTENSION_PCI(cin1200sn, 0x153b, 0x1155), | 1299 | MAKE_EXTENSION_PCI(cin1200sn, 0x153b, 0x1155), |
1288 | MAKE_EXTENSION_PCI(cin1200c, 0x153b, 0x1156), | 1300 | MAKE_EXTENSION_PCI(cin1200c, 0x153b, 0x1156), |
1301 | MAKE_EXTENSION_PCI(cin1200cmk3, 0x153b, 0x1176), | ||
1289 | MAKE_EXTENSION_PCI(cin1200t, 0x153b, 0x1157), | 1302 | MAKE_EXTENSION_PCI(cin1200t, 0x153b, 0x1157), |
1290 | { | 1303 | { |
1291 | .vendor = 0, | 1304 | .vendor = 0, |
diff --git a/drivers/media/dvb/ttpci/budget-ci.c b/drivers/media/dvb/ttpci/budget-ci.c index 464feaf1a9ad..4ed4599ce816 100644 --- a/drivers/media/dvb/ttpci/budget-ci.c +++ b/drivers/media/dvb/ttpci/budget-ci.c | |||
@@ -73,21 +73,15 @@ | |||
73 | #define SLOTSTATUS_READY 8 | 73 | #define SLOTSTATUS_READY 8 |
74 | #define SLOTSTATUS_OCCUPIED (SLOTSTATUS_PRESENT|SLOTSTATUS_RESET|SLOTSTATUS_READY) | 74 | #define SLOTSTATUS_OCCUPIED (SLOTSTATUS_PRESENT|SLOTSTATUS_RESET|SLOTSTATUS_READY) |
75 | 75 | ||
76 | /* Milliseconds during which key presses are regarded as key repeat and during | 76 | /* |
77 | * which the debounce logic is active | 77 | * Milliseconds during which a key is regarded as pressed. |
78 | * If an identical command arrives within this time, the timer will start over. | ||
78 | */ | 79 | */ |
79 | #define IR_REPEAT_TIMEOUT 350 | 80 | #define IR_KEYPRESS_TIMEOUT 250 |
80 | 81 | ||
81 | /* RC5 device wildcard */ | 82 | /* RC5 device wildcard */ |
82 | #define IR_DEVICE_ANY 255 | 83 | #define IR_DEVICE_ANY 255 |
83 | 84 | ||
84 | /* Some remotes sends multiple sequences per keypress (e.g. Zenith sends two), | ||
85 | * this setting allows the superflous sequences to be ignored | ||
86 | */ | ||
87 | static int debounce = 0; | ||
88 | module_param(debounce, int, 0644); | ||
89 | MODULE_PARM_DESC(debounce, "ignore repeated IR sequences (default: 0 = ignore no sequences)"); | ||
90 | |||
91 | static int rc5_device = -1; | 85 | static int rc5_device = -1; |
92 | module_param(rc5_device, int, 0644); | 86 | module_param(rc5_device, int, 0644); |
93 | MODULE_PARM_DESC(rc5_device, "only IR commands to given RC5 device (device = 0 - 31, any device = 255, default: autodetect)"); | 87 | MODULE_PARM_DESC(rc5_device, "only IR commands to given RC5 device (device = 0 - 31, any device = 255, default: autodetect)"); |
@@ -99,10 +93,14 @@ MODULE_PARM_DESC(ir_debug, "enable debugging information for IR decoding"); | |||
99 | struct budget_ci_ir { | 93 | struct budget_ci_ir { |
100 | struct input_dev *dev; | 94 | struct input_dev *dev; |
101 | struct tasklet_struct msp430_irq_tasklet; | 95 | struct tasklet_struct msp430_irq_tasklet; |
96 | struct timer_list timer_keyup; | ||
102 | char name[72]; /* 40 + 32 for (struct saa7146_dev).name */ | 97 | char name[72]; /* 40 + 32 for (struct saa7146_dev).name */ |
103 | char phys[32]; | 98 | char phys[32]; |
104 | struct ir_input_state state; | 99 | struct ir_input_state state; |
105 | int rc5_device; | 100 | int rc5_device; |
101 | u32 last_raw; | ||
102 | u32 ir_key; | ||
103 | bool have_command; | ||
106 | }; | 104 | }; |
107 | 105 | ||
108 | struct budget_ci { | 106 | struct budget_ci { |
@@ -125,13 +123,8 @@ static void msp430_ir_interrupt(unsigned long data) | |||
125 | { | 123 | { |
126 | struct budget_ci *budget_ci = (struct budget_ci *) data; | 124 | struct budget_ci *budget_ci = (struct budget_ci *) data; |
127 | struct input_dev *dev = budget_ci->ir.dev; | 125 | struct input_dev *dev = budget_ci->ir.dev; |
128 | static int bounces = 0; | ||
129 | int device; | ||
130 | int toggle; | ||
131 | static int prev_toggle = -1; | ||
132 | static u32 ir_key; | ||
133 | static int state = 0; | ||
134 | u32 command = ttpci_budget_debiread(&budget_ci->budget, DEBINOSWAP, DEBIADDR_IR, 2, 1, 0) >> 8; | 126 | u32 command = ttpci_budget_debiread(&budget_ci->budget, DEBINOSWAP, DEBIADDR_IR, 2, 1, 0) >> 8; |
127 | u32 raw; | ||
135 | 128 | ||
136 | /* | 129 | /* |
137 | * The msp430 chip can generate two different bytes, command and device | 130 | * The msp430 chip can generate two different bytes, command and device |
@@ -143,7 +136,7 @@ static void msp430_ir_interrupt(unsigned long data) | |||
143 | * bytes and one or more device bytes. For the repeated bytes, the | 136 | * bytes and one or more device bytes. For the repeated bytes, the |
144 | * highest bit (X) is set. The first command byte is always generated | 137 | * highest bit (X) is set. The first command byte is always generated |
145 | * before the first device byte. Other than that, no specific order | 138 | * before the first device byte. Other than that, no specific order |
146 | * seems to apply. | 139 | * seems to apply. To make life interesting, bytes can also be lost. |
147 | * | 140 | * |
148 | * Only when we have a command and device byte, a keypress is | 141 | * Only when we have a command and device byte, a keypress is |
149 | * generated. | 142 | * generated. |
@@ -152,53 +145,35 @@ static void msp430_ir_interrupt(unsigned long data) | |||
152 | if (ir_debug) | 145 | if (ir_debug) |
153 | printk("budget_ci: received byte 0x%02x\n", command); | 146 | printk("budget_ci: received byte 0x%02x\n", command); |
154 | 147 | ||
155 | /* Is this a repeated byte? */ | 148 | /* Remove repeat bit, we use every command */ |
156 | if (command & 0x80) | 149 | command = command & 0x7f; |
157 | return; | ||
158 | 150 | ||
159 | /* Is this a RC5 command byte? */ | 151 | /* Is this a RC5 command byte? */ |
160 | if (command & 0x40) { | 152 | if (command & 0x40) { |
161 | state = 1; | 153 | budget_ci->ir.have_command = true; |
162 | ir_key = command & 0x3f; | 154 | budget_ci->ir.ir_key = command & 0x3f; |
163 | return; | 155 | return; |
164 | } | 156 | } |
165 | 157 | ||
166 | /* It's a RC5 device byte */ | 158 | /* It's a RC5 device byte */ |
167 | if (!state) | 159 | if (!budget_ci->ir.have_command) |
168 | return; | 160 | return; |
169 | state = 0; | 161 | budget_ci->ir.have_command = false; |
170 | device = command & 0x1f; | ||
171 | toggle = command & 0x20; | ||
172 | 162 | ||
173 | if (budget_ci->ir.rc5_device != IR_DEVICE_ANY && budget_ci->ir.rc5_device != device) | 163 | if (budget_ci->ir.rc5_device != IR_DEVICE_ANY && |
164 | budget_ci->ir.rc5_device != (command & 0x1f)) | ||
174 | return; | 165 | return; |
175 | 166 | ||
176 | /* Ignore repeated key sequences if requested */ | 167 | /* Is this a repeated key sequence? (same device, command, toggle) */ |
177 | if (toggle == prev_toggle && ir_key == dev->repeat_key && | 168 | raw = budget_ci->ir.ir_key | (command << 8); |
178 | bounces > 0 && timer_pending(&dev->timer)) { | 169 | if (budget_ci->ir.last_raw != raw || !timer_pending(&budget_ci->ir.timer_keyup)) { |
179 | if (ir_debug) | ||
180 | printk("budget_ci: debounce logic ignored IR command\n"); | ||
181 | bounces--; | ||
182 | return; | ||
183 | } | ||
184 | prev_toggle = toggle; | ||
185 | |||
186 | /* Are we still waiting for a keyup event? */ | ||
187 | if (del_timer(&dev->timer)) | ||
188 | ir_input_nokey(dev, &budget_ci->ir.state); | ||
189 | |||
190 | /* Generate keypress */ | ||
191 | if (ir_debug) | ||
192 | printk("budget_ci: generating keypress 0x%02x\n", ir_key); | ||
193 | ir_input_keydown(dev, &budget_ci->ir.state, ir_key, (ir_key & (command << 8))); | ||
194 | |||
195 | /* Do we want to delay the keyup event? */ | ||
196 | if (debounce) { | ||
197 | bounces = debounce; | ||
198 | mod_timer(&dev->timer, jiffies + msecs_to_jiffies(IR_REPEAT_TIMEOUT)); | ||
199 | } else { | ||
200 | ir_input_nokey(dev, &budget_ci->ir.state); | 170 | ir_input_nokey(dev, &budget_ci->ir.state); |
171 | ir_input_keydown(dev, &budget_ci->ir.state, | ||
172 | budget_ci->ir.ir_key, raw); | ||
173 | budget_ci->ir.last_raw = raw; | ||
201 | } | 174 | } |
175 | |||
176 | mod_timer(&budget_ci->ir.timer_keyup, jiffies + msecs_to_jiffies(IR_KEYPRESS_TIMEOUT)); | ||
202 | } | 177 | } |
203 | 178 | ||
204 | static int msp430_ir_init(struct budget_ci *budget_ci) | 179 | static int msp430_ir_init(struct budget_ci *budget_ci) |
@@ -271,16 +246,21 @@ static int msp430_ir_init(struct budget_ci *budget_ci) | |||
271 | break; | 246 | break; |
272 | } | 247 | } |
273 | 248 | ||
274 | /* initialise the key-up debounce timeout handler */ | 249 | /* initialise the key-up timeout handler */ |
275 | input_dev->timer.function = msp430_ir_keyup; | 250 | init_timer(&budget_ci->ir.timer_keyup); |
276 | input_dev->timer.data = (unsigned long) &budget_ci->ir; | 251 | budget_ci->ir.timer_keyup.function = msp430_ir_keyup; |
277 | 252 | budget_ci->ir.timer_keyup.data = (unsigned long) &budget_ci->ir; | |
253 | budget_ci->ir.last_raw = 0xffff; /* An impossible value */ | ||
278 | error = input_register_device(input_dev); | 254 | error = input_register_device(input_dev); |
279 | if (error) { | 255 | if (error) { |
280 | printk(KERN_ERR "budget_ci: could not init driver for IR device (code %d)\n", error); | 256 | printk(KERN_ERR "budget_ci: could not init driver for IR device (code %d)\n", error); |
281 | goto out2; | 257 | goto out2; |
282 | } | 258 | } |
283 | 259 | ||
260 | /* note: these must be after input_register_device */ | ||
261 | input_dev->rep[REP_DELAY] = 400; | ||
262 | input_dev->rep[REP_PERIOD] = 250; | ||
263 | |||
284 | tasklet_init(&budget_ci->ir.msp430_irq_tasklet, msp430_ir_interrupt, | 264 | tasklet_init(&budget_ci->ir.msp430_irq_tasklet, msp430_ir_interrupt, |
285 | (unsigned long) budget_ci); | 265 | (unsigned long) budget_ci); |
286 | 266 | ||
@@ -304,10 +284,8 @@ static void msp430_ir_deinit(struct budget_ci *budget_ci) | |||
304 | saa7146_setgpio(saa, 3, SAA7146_GPIO_INPUT); | 284 | saa7146_setgpio(saa, 3, SAA7146_GPIO_INPUT); |
305 | tasklet_kill(&budget_ci->ir.msp430_irq_tasklet); | 285 | tasklet_kill(&budget_ci->ir.msp430_irq_tasklet); |
306 | 286 | ||
307 | if (del_timer(&dev->timer)) { | 287 | del_timer_sync(&dev->timer); |
308 | ir_input_nokey(dev, &budget_ci->ir.state); | 288 | ir_input_nokey(dev, &budget_ci->ir.state); |
309 | input_sync(dev); | ||
310 | } | ||
311 | 289 | ||
312 | input_unregister_device(dev); | 290 | input_unregister_device(dev); |
313 | } | 291 | } |
diff --git a/drivers/media/dvb/ttpci/budget-core.c b/drivers/media/dvb/ttpci/budget-core.c index e15562f81664..6b97dc1e6b65 100644 --- a/drivers/media/dvb/ttpci/budget-core.c +++ b/drivers/media/dvb/ttpci/budget-core.c | |||
@@ -41,11 +41,14 @@ | |||
41 | 41 | ||
42 | #define TS_WIDTH (2 * TS_SIZE) | 42 | #define TS_WIDTH (2 * TS_SIZE) |
43 | #define TS_WIDTH_ACTIVY TS_SIZE | 43 | #define TS_WIDTH_ACTIVY TS_SIZE |
44 | #define TS_WIDTH_DVBC TS_SIZE | ||
44 | #define TS_HEIGHT_MASK 0xf00 | 45 | #define TS_HEIGHT_MASK 0xf00 |
45 | #define TS_HEIGHT_MASK_ACTIVY 0xc00 | 46 | #define TS_HEIGHT_MASK_ACTIVY 0xc00 |
47 | #define TS_HEIGHT_MASK_DVBC 0xe00 | ||
46 | #define TS_MIN_BUFSIZE_K 188 | 48 | #define TS_MIN_BUFSIZE_K 188 |
47 | #define TS_MAX_BUFSIZE_K 1410 | 49 | #define TS_MAX_BUFSIZE_K 1410 |
48 | #define TS_MAX_BUFSIZE_K_ACTIVY 564 | 50 | #define TS_MAX_BUFSIZE_K_ACTIVY 564 |
51 | #define TS_MAX_BUFSIZE_K_DVBC 1316 | ||
49 | #define BUFFER_WARNING_WAIT (30*HZ) | 52 | #define BUFFER_WARNING_WAIT (30*HZ) |
50 | 53 | ||
51 | int budget_debug; | 54 | int budget_debug; |
@@ -106,6 +109,19 @@ static int start_ts_capture(struct budget *budget) | |||
106 | saa7146_write(dev, MC2, (MASK_10 | MASK_26)); | 109 | saa7146_write(dev, MC2, (MASK_10 | MASK_26)); |
107 | saa7146_write(dev, BRS_CTRL, 0x60000000); | 110 | saa7146_write(dev, BRS_CTRL, 0x60000000); |
108 | break; | 111 | break; |
112 | case BUDGET_CIN1200C_MK3: | ||
113 | case BUDGET_KNC1C_MK3: | ||
114 | case BUDGET_KNC1CP_MK3: | ||
115 | if (budget->video_port == BUDGET_VIDEO_PORTA) { | ||
116 | saa7146_write(dev, DD1_INIT, 0x06000200); | ||
117 | saa7146_write(dev, MC2, (MASK_09 | MASK_25 | MASK_10 | MASK_26)); | ||
118 | saa7146_write(dev, BRS_CTRL, 0x00000000); | ||
119 | } else { | ||
120 | saa7146_write(dev, DD1_INIT, 0x00000600); | ||
121 | saa7146_write(dev, MC2, (MASK_09 | MASK_25 | MASK_10 | MASK_26)); | ||
122 | saa7146_write(dev, BRS_CTRL, 0x60000000); | ||
123 | } | ||
124 | break; | ||
109 | default: | 125 | default: |
110 | if (budget->video_port == BUDGET_VIDEO_PORTA) { | 126 | if (budget->video_port == BUDGET_VIDEO_PORTA) { |
111 | saa7146_write(dev, DD1_INIT, 0x06000200); | 127 | saa7146_write(dev, DD1_INIT, 0x06000200); |
@@ -122,7 +138,13 @@ static int start_ts_capture(struct budget *budget) | |||
122 | mdelay(10); | 138 | mdelay(10); |
123 | 139 | ||
124 | saa7146_write(dev, BASE_ODD3, 0); | 140 | saa7146_write(dev, BASE_ODD3, 0); |
125 | saa7146_write(dev, BASE_EVEN3, 0); | 141 | if (budget->buffer_size > budget->buffer_height * budget->buffer_width) { |
142 | // using odd/even buffers | ||
143 | saa7146_write(dev, BASE_EVEN3, budget->buffer_height * budget->buffer_width); | ||
144 | } else { | ||
145 | // using a single buffer | ||
146 | saa7146_write(dev, BASE_EVEN3, 0); | ||
147 | } | ||
126 | saa7146_write(dev, PROT_ADDR3, budget->buffer_size); | 148 | saa7146_write(dev, PROT_ADDR3, budget->buffer_size); |
127 | saa7146_write(dev, BASE_PAGE3, budget->pt.dma | ME1 | 0x90); | 149 | saa7146_write(dev, BASE_PAGE3, budget->pt.dma | ME1 | 0x90); |
128 | 150 | ||
@@ -399,11 +421,25 @@ int ttpci_budget_init(struct budget *budget, struct saa7146_dev *dev, | |||
399 | budget->card = bi; | 421 | budget->card = bi; |
400 | budget->dev = (struct saa7146_dev *) dev; | 422 | budget->dev = (struct saa7146_dev *) dev; |
401 | 423 | ||
402 | if (budget->card->type == BUDGET_FS_ACTIVY) { | 424 | switch(budget->card->type) { |
425 | case BUDGET_FS_ACTIVY: | ||
403 | budget->buffer_width = TS_WIDTH_ACTIVY; | 426 | budget->buffer_width = TS_WIDTH_ACTIVY; |
404 | max_bufsize = TS_MAX_BUFSIZE_K_ACTIVY; | 427 | max_bufsize = TS_MAX_BUFSIZE_K_ACTIVY; |
405 | height_mask = TS_HEIGHT_MASK_ACTIVY; | 428 | height_mask = TS_HEIGHT_MASK_ACTIVY; |
406 | } else { | 429 | break; |
430 | |||
431 | case BUDGET_KNC1C: | ||
432 | case BUDGET_KNC1CP: | ||
433 | case BUDGET_CIN1200C: | ||
434 | case BUDGET_KNC1C_MK3: | ||
435 | case BUDGET_KNC1CP_MK3: | ||
436 | case BUDGET_CIN1200C_MK3: | ||
437 | budget->buffer_width = TS_WIDTH_DVBC; | ||
438 | max_bufsize = TS_MAX_BUFSIZE_K_DVBC; | ||
439 | height_mask = TS_HEIGHT_MASK_DVBC; | ||
440 | break; | ||
441 | |||
442 | default: | ||
407 | budget->buffer_width = TS_WIDTH; | 443 | budget->buffer_width = TS_WIDTH; |
408 | max_bufsize = TS_MAX_BUFSIZE_K; | 444 | max_bufsize = TS_MAX_BUFSIZE_K; |
409 | height_mask = TS_HEIGHT_MASK; | 445 | height_mask = TS_HEIGHT_MASK; |
@@ -415,14 +451,22 @@ int ttpci_budget_init(struct budget *budget, struct saa7146_dev *dev, | |||
415 | dma_buffer_size = max_bufsize; | 451 | dma_buffer_size = max_bufsize; |
416 | 452 | ||
417 | budget->buffer_height = dma_buffer_size * 1024 / budget->buffer_width; | 453 | budget->buffer_height = dma_buffer_size * 1024 / budget->buffer_width; |
418 | budget->buffer_height &= height_mask; | 454 | if (budget->buffer_height > 0xfff) { |
419 | budget->buffer_size = budget->buffer_height * budget->buffer_width; | 455 | budget->buffer_height /= 2; |
456 | budget->buffer_height &= height_mask; | ||
457 | budget->buffer_size = 2 * budget->buffer_height * budget->buffer_width; | ||
458 | } else { | ||
459 | budget->buffer_height &= height_mask; | ||
460 | budget->buffer_size = budget->buffer_height * budget->buffer_width; | ||
461 | } | ||
420 | budget->buffer_warning_threshold = budget->buffer_size * 80/100; | 462 | budget->buffer_warning_threshold = budget->buffer_size * 80/100; |
421 | budget->buffer_warnings = 0; | 463 | budget->buffer_warnings = 0; |
422 | budget->buffer_warning_time = jiffies; | 464 | budget->buffer_warning_time = jiffies; |
423 | 465 | ||
424 | dprintk(2, "%s: width = %d, height = %d\n", | 466 | dprintk(2, "%s: buffer type = %s, width = %d, height = %d\n", |
425 | budget->dev->name, budget->buffer_width, budget->buffer_height); | 467 | budget->dev->name, |
468 | budget->buffer_size > budget->buffer_width * budget->buffer_height ? "odd/even" : "single", | ||
469 | budget->buffer_width, budget->buffer_height); | ||
426 | printk("%s: dma buffer size %u\n", budget->dev->name, budget->buffer_size); | 470 | printk("%s: dma buffer size %u\n", budget->dev->name, budget->buffer_size); |
427 | 471 | ||
428 | if ((ret = dvb_register_adapter(&budget->dvb_adapter, budget->card->name, owner, &budget->dev->pci->dev)) < 0) { | 472 | if ((ret = dvb_register_adapter(&budget->dvb_adapter, budget->card->name, owner, &budget->dev->pci->dev)) < 0) { |
diff --git a/drivers/media/dvb/ttpci/budget.h b/drivers/media/dvb/ttpci/budget.h index e8a5c79178e1..d764ffa728b0 100644 --- a/drivers/media/dvb/ttpci/budget.h +++ b/drivers/media/dvb/ttpci/budget.h | |||
@@ -99,6 +99,9 @@ static struct saa7146_pci_extension_data x_var = { \ | |||
99 | #define BUDGET_KNC1CP 12 | 99 | #define BUDGET_KNC1CP 12 |
100 | #define BUDGET_KNC1TP 13 | 100 | #define BUDGET_KNC1TP 13 |
101 | #define BUDGET_TVSTAR 14 | 101 | #define BUDGET_TVSTAR 14 |
102 | #define BUDGET_CIN1200C_MK3 15 | ||
103 | #define BUDGET_KNC1C_MK3 16 | ||
104 | #define BUDGET_KNC1CP_MK3 17 | ||
102 | 105 | ||
103 | #define BUDGET_VIDEO_PORTA 0 | 106 | #define BUDGET_VIDEO_PORTA 0 |
104 | #define BUDGET_VIDEO_PORTB 1 | 107 | #define BUDGET_VIDEO_PORTB 1 |
diff --git a/drivers/media/dvb/ttusb-budget/Kconfig b/drivers/media/dvb/ttusb-budget/Kconfig index e78ea9227b0e..f546bccdb997 100644 --- a/drivers/media/dvb/ttusb-budget/Kconfig +++ b/drivers/media/dvb/ttusb-budget/Kconfig | |||
@@ -1,7 +1,6 @@ | |||
1 | config DVB_TTUSB_BUDGET | 1 | config DVB_TTUSB_BUDGET |
2 | tristate "Technotrend/Hauppauge Nova-USB devices" | 2 | tristate "Technotrend/Hauppauge Nova-USB devices" |
3 | depends on DVB_CORE && USB && I2C | 3 | depends on DVB_CORE && USB && I2C |
4 | select DVB_PLL | ||
5 | select DVB_CX22700 if !DVB_FE_CUSTOMISE | 4 | select DVB_CX22700 if !DVB_FE_CUSTOMISE |
6 | select DVB_TDA1004X if !DVB_FE_CUSTOMISE | 5 | select DVB_TDA1004X if !DVB_FE_CUSTOMISE |
7 | select DVB_VES1820 if !DVB_FE_CUSTOMISE | 6 | select DVB_VES1820 if !DVB_FE_CUSTOMISE |
diff --git a/drivers/media/radio/radio-aimslab.c b/drivers/media/radio/radio-aimslab.c index b2e88ad28977..5adc27c3ced9 100644 --- a/drivers/media/radio/radio-aimslab.c +++ b/drivers/media/radio/radio-aimslab.c | |||
@@ -231,129 +231,149 @@ static struct v4l2_queryctrl radio_qctrl[] = { | |||
231 | } | 231 | } |
232 | }; | 232 | }; |
233 | 233 | ||
234 | static int rt_do_ioctl(struct inode *inode, struct file *file, | 234 | static int vidioc_querycap(struct file *file, void *priv, |
235 | unsigned int cmd, void *arg) | 235 | struct v4l2_capability *v) |
236 | { | ||
237 | strlcpy(v->driver, "radio-aimslab", sizeof(v->driver)); | ||
238 | strlcpy(v->card, "RadioTrack", sizeof(v->card)); | ||
239 | sprintf(v->bus_info, "ISA"); | ||
240 | v->version = RADIO_VERSION; | ||
241 | v->capabilities = V4L2_CAP_TUNER; | ||
242 | return 0; | ||
243 | } | ||
244 | |||
245 | static int vidioc_g_tuner(struct file *file, void *priv, | ||
246 | struct v4l2_tuner *v) | ||
236 | { | 247 | { |
237 | struct video_device *dev = video_devdata(file); | 248 | struct video_device *dev = video_devdata(file); |
238 | struct rt_device *rt=dev->priv; | 249 | struct rt_device *rt = dev->priv; |
239 | 250 | ||
240 | switch(cmd) | 251 | if (v->index > 0) |
241 | { | 252 | return -EINVAL; |
242 | case VIDIOC_QUERYCAP: | ||
243 | { | ||
244 | struct v4l2_capability *v = arg; | ||
245 | memset(v,0,sizeof(*v)); | ||
246 | strlcpy(v->driver, "radio-aimslab", sizeof (v->driver)); | ||
247 | strlcpy(v->card, "RadioTrack", sizeof (v->card)); | ||
248 | sprintf(v->bus_info,"ISA"); | ||
249 | v->version = RADIO_VERSION; | ||
250 | v->capabilities = V4L2_CAP_TUNER; | ||
251 | 253 | ||
252 | return 0; | 254 | strcpy(v->name, "FM"); |
253 | } | 255 | v->type = V4L2_TUNER_RADIO; |
254 | case VIDIOC_G_TUNER: | 256 | v->rangelow = (87*16000); |
255 | { | 257 | v->rangehigh = (108*16000); |
256 | struct v4l2_tuner *v = arg; | 258 | v->rxsubchans = V4L2_TUNER_SUB_MONO; |
259 | v->capability = V4L2_TUNER_CAP_LOW; | ||
260 | v->audmode = V4L2_TUNER_MODE_MONO; | ||
261 | v->signal = 0xffff*rt_getsigstr(rt); | ||
262 | return 0; | ||
263 | } | ||
264 | |||
265 | static int vidioc_s_tuner(struct file *file, void *priv, | ||
266 | struct v4l2_tuner *v) | ||
267 | { | ||
268 | if (v->index > 0) | ||
269 | return -EINVAL; | ||
270 | return 0; | ||
271 | } | ||
257 | 272 | ||
258 | if (v->index > 0) | 273 | static int vidioc_s_frequency(struct file *file, void *priv, |
259 | return -EINVAL; | 274 | struct v4l2_frequency *f) |
275 | { | ||
276 | struct video_device *dev = video_devdata(file); | ||
277 | struct rt_device *rt = dev->priv; | ||
260 | 278 | ||
261 | memset(v,0,sizeof(*v)); | 279 | rt->curfreq = f->frequency; |
262 | strcpy(v->name, "FM"); | 280 | rt_setfreq(rt, rt->curfreq); |
263 | v->type = V4L2_TUNER_RADIO; | 281 | return 0; |
282 | } | ||
264 | 283 | ||
265 | v->rangelow=(87*16000); | 284 | static int vidioc_g_frequency(struct file *file, void *priv, |
266 | v->rangehigh=(108*16000); | 285 | struct v4l2_frequency *f) |
267 | v->rxsubchans =V4L2_TUNER_SUB_MONO; | 286 | { |
268 | v->capability=V4L2_TUNER_CAP_LOW; | 287 | struct video_device *dev = video_devdata(file); |
269 | v->audmode = V4L2_TUNER_MODE_MONO; | 288 | struct rt_device *rt = dev->priv; |
270 | v->signal=0xFFFF*rt_getsigstr(rt); | ||
271 | 289 | ||
272 | return 0; | 290 | f->type = V4L2_TUNER_RADIO; |
273 | } | 291 | f->frequency = rt->curfreq; |
274 | case VIDIOC_S_TUNER: | 292 | return 0; |
275 | { | 293 | } |
276 | struct v4l2_tuner *v = arg; | ||
277 | 294 | ||
278 | if (v->index > 0) | 295 | static int vidioc_queryctrl(struct file *file, void *priv, |
279 | return -EINVAL; | 296 | struct v4l2_queryctrl *qc) |
297 | { | ||
298 | int i; | ||
280 | 299 | ||
300 | for (i = 0; i < ARRAY_SIZE(radio_qctrl); i++) { | ||
301 | if (qc->id && qc->id == radio_qctrl[i].id) { | ||
302 | memcpy(qc, &(radio_qctrl[i]), | ||
303 | sizeof(*qc)); | ||
281 | return 0; | 304 | return 0; |
282 | } | 305 | } |
283 | case VIDIOC_S_FREQUENCY: | 306 | } |
284 | { | 307 | return -EINVAL; |
285 | struct v4l2_frequency *f = arg; | 308 | } |
286 | 309 | ||
287 | rt->curfreq = f->frequency; | 310 | static int vidioc_g_ctrl(struct file *file, void *priv, |
288 | rt_setfreq(rt, rt->curfreq); | 311 | struct v4l2_control *ctrl) |
289 | return 0; | 312 | { |
290 | } | 313 | struct video_device *dev = video_devdata(file); |
291 | case VIDIOC_G_FREQUENCY: | 314 | struct rt_device *rt = dev->priv; |
292 | { | ||
293 | struct v4l2_frequency *f = arg; | ||
294 | 315 | ||
295 | f->type = V4L2_TUNER_RADIO; | 316 | switch (ctrl->id) { |
296 | f->frequency = rt->curfreq; | 317 | case V4L2_CID_AUDIO_MUTE: |
318 | ctrl->value = rt->muted; | ||
319 | return 0; | ||
320 | case V4L2_CID_AUDIO_VOLUME: | ||
321 | ctrl->value = rt->curvol * 6554; | ||
322 | return 0; | ||
323 | } | ||
324 | return -EINVAL; | ||
325 | } | ||
297 | 326 | ||
298 | return 0; | 327 | static int vidioc_s_ctrl(struct file *file, void *priv, |
299 | } | 328 | struct v4l2_control *ctrl) |
300 | case VIDIOC_QUERYCTRL: | 329 | { |
301 | { | 330 | struct video_device *dev = video_devdata(file); |
302 | struct v4l2_queryctrl *qc = arg; | 331 | struct rt_device *rt = dev->priv; |
303 | int i; | ||
304 | |||
305 | for (i = 0; i < ARRAY_SIZE(radio_qctrl); i++) { | ||
306 | if (qc->id && qc->id == radio_qctrl[i].id) { | ||
307 | memcpy(qc, &(radio_qctrl[i]), | ||
308 | sizeof(*qc)); | ||
309 | return (0); | ||
310 | } | ||
311 | } | ||
312 | return -EINVAL; | ||
313 | } | ||
314 | case VIDIOC_G_CTRL: | ||
315 | { | ||
316 | struct v4l2_control *ctrl= arg; | ||
317 | |||
318 | switch (ctrl->id) { | ||
319 | case V4L2_CID_AUDIO_MUTE: | ||
320 | ctrl->value=rt->muted; | ||
321 | return (0); | ||
322 | case V4L2_CID_AUDIO_VOLUME: | ||
323 | ctrl->value=rt->curvol * 6554; | ||
324 | return (0); | ||
325 | } | ||
326 | return -EINVAL; | ||
327 | } | ||
328 | case VIDIOC_S_CTRL: | ||
329 | { | ||
330 | struct v4l2_control *ctrl= arg; | ||
331 | |||
332 | switch (ctrl->id) { | ||
333 | case V4L2_CID_AUDIO_MUTE: | ||
334 | if (ctrl->value) { | ||
335 | rt_mute(rt); | ||
336 | } else { | ||
337 | rt_setvol(rt,rt->curvol); | ||
338 | } | ||
339 | return (0); | ||
340 | case V4L2_CID_AUDIO_VOLUME: | ||
341 | rt_setvol(rt,ctrl->value); | ||
342 | return (0); | ||
343 | } | ||
344 | return -EINVAL; | ||
345 | } | ||
346 | 332 | ||
347 | default: | 333 | switch (ctrl->id) { |
348 | return v4l_compat_translate_ioctl(inode,file,cmd,arg, | 334 | case V4L2_CID_AUDIO_MUTE: |
349 | rt_do_ioctl); | 335 | if (ctrl->value) |
336 | rt_mute(rt); | ||
337 | else | ||
338 | rt_setvol(rt,rt->curvol); | ||
339 | return 0; | ||
340 | case V4L2_CID_AUDIO_VOLUME: | ||
341 | rt_setvol(rt,ctrl->value); | ||
342 | return 0; | ||
350 | } | 343 | } |
344 | return -EINVAL; | ||
345 | } | ||
346 | |||
347 | static int vidioc_g_audio (struct file *file, void *priv, | ||
348 | struct v4l2_audio *a) | ||
349 | { | ||
350 | if (a->index > 1) | ||
351 | return -EINVAL; | ||
352 | |||
353 | strcpy(a->name, "Radio"); | ||
354 | a->capability = V4L2_AUDCAP_STEREO; | ||
355 | return 0; | ||
356 | } | ||
357 | |||
358 | static int vidioc_g_input(struct file *filp, void *priv, unsigned int *i) | ||
359 | { | ||
360 | *i = 0; | ||
361 | return 0; | ||
362 | } | ||
363 | |||
364 | static int vidioc_s_input(struct file *filp, void *priv, unsigned int i) | ||
365 | { | ||
366 | if (i != 0) | ||
367 | return -EINVAL; | ||
368 | return 0; | ||
351 | } | 369 | } |
352 | 370 | ||
353 | static int rt_ioctl(struct inode *inode, struct file *file, | 371 | static int vidioc_s_audio(struct file *file, void *priv, |
354 | unsigned int cmd, unsigned long arg) | 372 | struct v4l2_audio *a) |
355 | { | 373 | { |
356 | return video_usercopy(inode, file, cmd, arg, rt_do_ioctl); | 374 | if (a->index != 0) |
375 | return -EINVAL; | ||
376 | return 0; | ||
357 | } | 377 | } |
358 | 378 | ||
359 | static struct rt_device rtrack_unit; | 379 | static struct rt_device rtrack_unit; |
@@ -362,7 +382,7 @@ static const struct file_operations rtrack_fops = { | |||
362 | .owner = THIS_MODULE, | 382 | .owner = THIS_MODULE, |
363 | .open = video_exclusive_open, | 383 | .open = video_exclusive_open, |
364 | .release = video_exclusive_release, | 384 | .release = video_exclusive_release, |
365 | .ioctl = rt_ioctl, | 385 | .ioctl = video_ioctl2, |
366 | .compat_ioctl = v4l_compat_ioctl32, | 386 | .compat_ioctl = v4l_compat_ioctl32, |
367 | .llseek = no_llseek, | 387 | .llseek = no_llseek, |
368 | }; | 388 | }; |
@@ -374,6 +394,18 @@ static struct video_device rtrack_radio= | |||
374 | .type = VID_TYPE_TUNER, | 394 | .type = VID_TYPE_TUNER, |
375 | .hardware = 0, | 395 | .hardware = 0, |
376 | .fops = &rtrack_fops, | 396 | .fops = &rtrack_fops, |
397 | .vidioc_querycap = vidioc_querycap, | ||
398 | .vidioc_g_tuner = vidioc_g_tuner, | ||
399 | .vidioc_s_tuner = vidioc_s_tuner, | ||
400 | .vidioc_g_audio = vidioc_g_audio, | ||
401 | .vidioc_s_audio = vidioc_s_audio, | ||
402 | .vidioc_g_input = vidioc_g_input, | ||
403 | .vidioc_s_input = vidioc_s_input, | ||
404 | .vidioc_g_frequency = vidioc_g_frequency, | ||
405 | .vidioc_s_frequency = vidioc_s_frequency, | ||
406 | .vidioc_queryctrl = vidioc_queryctrl, | ||
407 | .vidioc_g_ctrl = vidioc_g_ctrl, | ||
408 | .vidioc_s_ctrl = vidioc_s_ctrl, | ||
377 | }; | 409 | }; |
378 | 410 | ||
379 | static int __init rtrack_init(void) | 411 | static int __init rtrack_init(void) |
diff --git a/drivers/media/radio/radio-gemtek-pci.c b/drivers/media/radio/radio-gemtek-pci.c index 74976cba869f..fdf5d6e46eac 100644 --- a/drivers/media/radio/radio-gemtek-pci.c +++ b/drivers/media/radio/radio-gemtek-pci.c | |||
@@ -192,131 +192,158 @@ static inline unsigned int gemtek_pci_getsignal( struct gemtek_pci_card *card ) | |||
192 | return ( inb( card->iobase ) & 0x08 ) ? 0 : 1; | 192 | return ( inb( card->iobase ) & 0x08 ) ? 0 : 1; |
193 | } | 193 | } |
194 | 194 | ||
195 | static int gemtek_pci_do_ioctl(struct inode *inode, struct file *file, | 195 | static int vidioc_querycap(struct file *file, void *priv, |
196 | unsigned int cmd, void *arg) | 196 | struct v4l2_capability *v) |
197 | { | ||
198 | strlcpy(v->driver, "radio-gemtek-pci", sizeof(v->driver)); | ||
199 | strlcpy(v->card, "GemTek PCI Radio", sizeof(v->card)); | ||
200 | sprintf(v->bus_info, "ISA"); | ||
201 | v->version = RADIO_VERSION; | ||
202 | v->capabilities = V4L2_CAP_TUNER; | ||
203 | return 0; | ||
204 | } | ||
205 | |||
206 | static int vidioc_g_tuner(struct file *file, void *priv, | ||
207 | struct v4l2_tuner *v) | ||
197 | { | 208 | { |
198 | struct video_device *dev = video_devdata(file); | 209 | struct video_device *dev = video_devdata(file); |
199 | struct gemtek_pci_card *card = dev->priv; | 210 | struct gemtek_pci_card *card = dev->priv; |
200 | 211 | ||
201 | switch ( cmd ) { | 212 | if (v->index > 0) |
202 | case VIDIOC_QUERYCAP: | 213 | return -EINVAL; |
203 | { | 214 | |
204 | struct v4l2_capability *v = arg; | 215 | strcpy(v->name, "FM"); |
205 | memset(v,0,sizeof(*v)); | 216 | v->type = V4L2_TUNER_RADIO; |
206 | strlcpy(v->driver, "radio-gemtek-pci", sizeof (v->driver)); | 217 | v->rangelow = GEMTEK_PCI_RANGE_LOW; |
207 | strlcpy(v->card, "GemTek PCI Radio", sizeof (v->card)); | 218 | v->rangehigh = GEMTEK_PCI_RANGE_HIGH; |
208 | sprintf(v->bus_info,"ISA"); | 219 | v->rxsubchans = V4L2_TUNER_SUB_MONO; |
209 | v->version = RADIO_VERSION; | 220 | v->capability = V4L2_TUNER_CAP_LOW; |
210 | v->capabilities = V4L2_CAP_TUNER; | 221 | v->audmode = V4L2_TUNER_MODE_MONO; |
211 | 222 | v->signal = 0xffff * gemtek_pci_getsignal(card); | |
212 | return 0; | 223 | return 0; |
213 | } | 224 | } |
214 | case VIDIOC_G_TUNER: | ||
215 | { | ||
216 | struct v4l2_tuner *v = arg; | ||
217 | 225 | ||
218 | if (v->index > 0) | 226 | static int vidioc_s_tuner(struct file *file, void *priv, |
219 | return -EINVAL; | 227 | struct v4l2_tuner *v) |
228 | { | ||
229 | if (v->index > 0) | ||
230 | return -EINVAL; | ||
231 | return 0; | ||
232 | } | ||
220 | 233 | ||
221 | memset(v,0,sizeof(*v)); | 234 | static int vidioc_s_frequency(struct file *file, void *priv, |
222 | strcpy(v->name, "FM"); | 235 | struct v4l2_frequency *f) |
223 | v->type = V4L2_TUNER_RADIO; | 236 | { |
237 | struct video_device *dev = video_devdata(file); | ||
238 | struct gemtek_pci_card *card = dev->priv; | ||
224 | 239 | ||
225 | v->rangelow = GEMTEK_PCI_RANGE_LOW; | 240 | if ( (f->frequency < GEMTEK_PCI_RANGE_LOW) || |
226 | v->rangehigh = GEMTEK_PCI_RANGE_HIGH; | 241 | (f->frequency > GEMTEK_PCI_RANGE_HIGH) ) |
227 | v->rxsubchans =V4L2_TUNER_SUB_MONO; | 242 | return -EINVAL; |
228 | v->capability=V4L2_TUNER_CAP_LOW; | 243 | gemtek_pci_setfrequency(card, f->frequency); |
229 | v->audmode = V4L2_TUNER_MODE_MONO; | 244 | card->current_frequency = f->frequency; |
230 | v->signal=0xFFFF*gemtek_pci_getsignal( card ); | 245 | card->mute = false; |
246 | return 0; | ||
247 | } | ||
231 | 248 | ||
232 | return 0; | 249 | static int vidioc_g_frequency(struct file *file, void *priv, |
233 | } | 250 | struct v4l2_frequency *f) |
234 | case VIDIOC_S_TUNER: | 251 | { |
235 | { | 252 | struct video_device *dev = video_devdata(file); |
236 | struct v4l2_tuner *v = arg; | 253 | struct gemtek_pci_card *card = dev->priv; |
237 | 254 | ||
238 | if (v->index > 0) | 255 | f->type = V4L2_TUNER_RADIO; |
239 | return -EINVAL; | 256 | f->frequency = card->current_frequency; |
257 | return 0; | ||
258 | } | ||
240 | 259 | ||
260 | static int vidioc_queryctrl(struct file *file, void *priv, | ||
261 | struct v4l2_queryctrl *qc) | ||
262 | { | ||
263 | int i; | ||
264 | for (i = 0; i < ARRAY_SIZE(radio_qctrl); i++) { | ||
265 | if (qc->id && qc->id == radio_qctrl[i].id) { | ||
266 | memcpy(qc, &(radio_qctrl[i]), | ||
267 | sizeof(*qc)); | ||
241 | return 0; | 268 | return 0; |
242 | } | 269 | } |
243 | case VIDIOC_S_FREQUENCY: | 270 | } |
244 | { | 271 | return -EINVAL; |
245 | struct v4l2_frequency *f = arg; | 272 | } |
246 | 273 | ||
247 | if ( (f->frequency < GEMTEK_PCI_RANGE_LOW) || | 274 | static int vidioc_g_ctrl(struct file *file, void *priv, |
248 | (f->frequency > GEMTEK_PCI_RANGE_HIGH) ) | 275 | struct v4l2_control *ctrl) |
249 | return -EINVAL; | 276 | { |
277 | struct video_device *dev = video_devdata(file); | ||
278 | struct gemtek_pci_card *card = dev->priv; | ||
250 | 279 | ||
280 | switch (ctrl->id) { | ||
281 | case V4L2_CID_AUDIO_MUTE: | ||
282 | ctrl->value = card->mute; | ||
283 | return 0; | ||
284 | case V4L2_CID_AUDIO_VOLUME: | ||
285 | if (card->mute) | ||
286 | ctrl->value = 0; | ||
287 | else | ||
288 | ctrl->value = 65535; | ||
289 | return 0; | ||
290 | } | ||
291 | return -EINVAL; | ||
292 | } | ||
251 | 293 | ||
252 | gemtek_pci_setfrequency( card, f->frequency ); | 294 | static int vidioc_s_ctrl(struct file *file, void *priv, |
253 | card->current_frequency = f->frequency; | 295 | struct v4l2_control *ctrl) |
254 | card->mute = false; | 296 | { |
255 | return 0; | 297 | struct video_device *dev = video_devdata(file); |
256 | } | 298 | struct gemtek_pci_card *card = dev->priv; |
257 | case VIDIOC_QUERYCTRL: | 299 | |
258 | { | 300 | switch (ctrl->id) { |
259 | struct v4l2_queryctrl *qc = arg; | 301 | case V4L2_CID_AUDIO_MUTE: |
260 | int i; | 302 | if (ctrl->value) |
261 | 303 | gemtek_pci_mute(card); | |
262 | for (i = 0; i < ARRAY_SIZE(radio_qctrl); i++) { | 304 | else |
263 | if (qc->id && qc->id == radio_qctrl[i].id) { | 305 | gemtek_pci_unmute(card); |
264 | memcpy(qc, &(radio_qctrl[i]), | 306 | return 0; |
265 | sizeof(*qc)); | 307 | case V4L2_CID_AUDIO_VOLUME: |
266 | return (0); | 308 | if (ctrl->value) |
267 | } | 309 | gemtek_pci_unmute(card); |
268 | } | 310 | else |
269 | return -EINVAL; | 311 | gemtek_pci_mute(card); |
270 | } | 312 | return 0; |
271 | case VIDIOC_G_CTRL: | ||
272 | { | ||
273 | struct v4l2_control *ctrl= arg; | ||
274 | |||
275 | switch (ctrl->id) { | ||
276 | case V4L2_CID_AUDIO_MUTE: | ||
277 | ctrl->value=card->mute; | ||
278 | return (0); | ||
279 | case V4L2_CID_AUDIO_VOLUME: | ||
280 | if (card->mute) | ||
281 | ctrl->value=0; | ||
282 | else | ||
283 | ctrl->value=65535; | ||
284 | return (0); | ||
285 | } | ||
286 | return -EINVAL; | ||
287 | } | ||
288 | case VIDIOC_S_CTRL: | ||
289 | { | ||
290 | struct v4l2_control *ctrl= arg; | ||
291 | |||
292 | switch (ctrl->id) { | ||
293 | case V4L2_CID_AUDIO_MUTE: | ||
294 | if (ctrl->value) { | ||
295 | gemtek_pci_mute(card); | ||
296 | } else { | ||
297 | gemtek_pci_unmute(card); | ||
298 | } | ||
299 | return (0); | ||
300 | case V4L2_CID_AUDIO_VOLUME: | ||
301 | if (ctrl->value) { | ||
302 | gemtek_pci_unmute(card); | ||
303 | } else { | ||
304 | gemtek_pci_mute(card); | ||
305 | } | ||
306 | return (0); | ||
307 | } | ||
308 | return -EINVAL; | ||
309 | } | ||
310 | default: | ||
311 | return v4l_compat_translate_ioctl(inode,file,cmd,arg, | ||
312 | gemtek_pci_do_ioctl); | ||
313 | } | 313 | } |
314 | return -EINVAL; | ||
314 | } | 315 | } |
315 | 316 | ||
316 | static int gemtek_pci_ioctl(struct inode *inode, struct file *file, | 317 | static int vidioc_g_audio(struct file *file, void *priv, |
317 | unsigned int cmd, unsigned long arg) | 318 | struct v4l2_audio *a) |
318 | { | 319 | { |
319 | return video_usercopy(inode, file, cmd, arg, gemtek_pci_do_ioctl); | 320 | if (a->index > 1) |
321 | return -EINVAL; | ||
322 | |||
323 | strcpy(a->name, "Radio"); | ||
324 | a->capability = V4L2_AUDCAP_STEREO; | ||
325 | return 0; | ||
326 | } | ||
327 | |||
328 | static int vidioc_g_input(struct file *filp, void *priv, unsigned int *i) | ||
329 | { | ||
330 | *i = 0; | ||
331 | return 0; | ||
332 | } | ||
333 | |||
334 | static int vidioc_s_input(struct file *filp, void *priv, unsigned int i) | ||
335 | { | ||
336 | if (i != 0) | ||
337 | return -EINVAL; | ||
338 | return 0; | ||
339 | } | ||
340 | |||
341 | static int vidioc_s_audio(struct file *file, void *priv, | ||
342 | struct v4l2_audio *a) | ||
343 | { | ||
344 | if (a->index != 0) | ||
345 | return -EINVAL; | ||
346 | return 0; | ||
320 | } | 347 | } |
321 | 348 | ||
322 | enum { | 349 | enum { |
@@ -342,7 +369,7 @@ static const struct file_operations gemtek_pci_fops = { | |||
342 | .owner = THIS_MODULE, | 369 | .owner = THIS_MODULE, |
343 | .open = video_exclusive_open, | 370 | .open = video_exclusive_open, |
344 | .release = video_exclusive_release, | 371 | .release = video_exclusive_release, |
345 | .ioctl = gemtek_pci_ioctl, | 372 | .ioctl = video_ioctl2, |
346 | .compat_ioctl = v4l_compat_ioctl32, | 373 | .compat_ioctl = v4l_compat_ioctl32, |
347 | .llseek = no_llseek, | 374 | .llseek = no_llseek, |
348 | }; | 375 | }; |
@@ -353,6 +380,18 @@ static struct video_device vdev_template = { | |||
353 | .type = VID_TYPE_TUNER, | 380 | .type = VID_TYPE_TUNER, |
354 | .hardware = 0, | 381 | .hardware = 0, |
355 | .fops = &gemtek_pci_fops, | 382 | .fops = &gemtek_pci_fops, |
383 | .vidioc_querycap = vidioc_querycap, | ||
384 | .vidioc_g_tuner = vidioc_g_tuner, | ||
385 | .vidioc_s_tuner = vidioc_s_tuner, | ||
386 | .vidioc_g_audio = vidioc_g_audio, | ||
387 | .vidioc_s_audio = vidioc_s_audio, | ||
388 | .vidioc_g_input = vidioc_g_input, | ||
389 | .vidioc_s_input = vidioc_s_input, | ||
390 | .vidioc_g_frequency = vidioc_g_frequency, | ||
391 | .vidioc_s_frequency = vidioc_s_frequency, | ||
392 | .vidioc_queryctrl = vidioc_queryctrl, | ||
393 | .vidioc_g_ctrl = vidioc_g_ctrl, | ||
394 | .vidioc_s_ctrl = vidioc_s_ctrl, | ||
356 | }; | 395 | }; |
357 | 396 | ||
358 | static int __devinit gemtek_pci_probe( struct pci_dev *pci_dev, const struct pci_device_id *pci_id ) | 397 | static int __devinit gemtek_pci_probe( struct pci_dev *pci_dev, const struct pci_device_id *pci_id ) |
diff --git a/drivers/media/radio/radio-gemtek.c b/drivers/media/radio/radio-gemtek.c index 36c4be6622c7..b04b6a7fff7c 100644 --- a/drivers/media/radio/radio-gemtek.c +++ b/drivers/media/radio/radio-gemtek.c | |||
@@ -161,137 +161,157 @@ static int gemtek_getsigstr(struct gemtek_device *dev) | |||
161 | return 1; /* signal present */ | 161 | return 1; /* signal present */ |
162 | } | 162 | } |
163 | 163 | ||
164 | static int gemtek_do_ioctl(struct inode *inode, struct file *file, | 164 | static int vidioc_querycap(struct file *file, void *priv, |
165 | unsigned int cmd, void *arg) | 165 | struct v4l2_capability *v) |
166 | { | ||
167 | strlcpy(v->driver, "radio-gemtek", sizeof(v->driver)); | ||
168 | strlcpy(v->card, "GemTek", sizeof(v->card)); | ||
169 | sprintf(v->bus_info, "ISA"); | ||
170 | v->version = RADIO_VERSION; | ||
171 | v->capabilities = V4L2_CAP_TUNER; | ||
172 | return 0; | ||
173 | } | ||
174 | |||
175 | static int vidioc_g_tuner(struct file *file, void *priv, | ||
176 | struct v4l2_tuner *v) | ||
166 | { | 177 | { |
167 | struct video_device *dev = video_devdata(file); | 178 | struct video_device *dev = video_devdata(file); |
168 | struct gemtek_device *rt=dev->priv; | 179 | struct gemtek_device *rt = dev->priv; |
169 | 180 | ||
170 | switch(cmd) | 181 | if (v->index > 0) |
171 | { | 182 | return -EINVAL; |
172 | case VIDIOC_QUERYCAP: | ||
173 | { | ||
174 | struct v4l2_capability *v = arg; | ||
175 | memset(v,0,sizeof(*v)); | ||
176 | strlcpy(v->driver, "radio-gemtek", sizeof (v->driver)); | ||
177 | strlcpy(v->card, "GemTek", sizeof (v->card)); | ||
178 | sprintf(v->bus_info,"ISA"); | ||
179 | v->version = RADIO_VERSION; | ||
180 | v->capabilities = V4L2_CAP_TUNER; | ||
181 | 183 | ||
182 | return 0; | 184 | strcpy(v->name, "FM"); |
183 | } | 185 | v->type = V4L2_TUNER_RADIO; |
184 | case VIDIOC_G_TUNER: | 186 | v->rangelow = (87*16000); |
185 | { | 187 | v->rangehigh = (108*16000); |
186 | struct v4l2_tuner *v = arg; | 188 | v->rxsubchans = V4L2_TUNER_SUB_MONO; |
189 | v->capability = V4L2_TUNER_CAP_LOW; | ||
190 | v->audmode = V4L2_TUNER_MODE_MONO; | ||
191 | v->signal = 0xffff*gemtek_getsigstr(rt); | ||
192 | return 0; | ||
193 | } | ||
194 | |||
195 | static int vidioc_s_tuner(struct file *file, void *priv, | ||
196 | struct v4l2_tuner *v) | ||
197 | { | ||
198 | if (v->index > 0) | ||
199 | return -EINVAL; | ||
200 | return 0; | ||
201 | } | ||
187 | 202 | ||
188 | if (v->index > 0) | 203 | static int vidioc_s_frequency(struct file *file, void *priv, |
189 | return -EINVAL; | 204 | struct v4l2_frequency *f) |
205 | { | ||
206 | struct video_device *dev = video_devdata(file); | ||
207 | struct gemtek_device *rt = dev->priv; | ||
190 | 208 | ||
191 | memset(v,0,sizeof(*v)); | 209 | rt->curfreq = f->frequency; |
192 | strcpy(v->name, "FM"); | 210 | /* needs to be called twice in order for getsigstr to work */ |
193 | v->type = V4L2_TUNER_RADIO; | 211 | gemtek_setfreq(rt, rt->curfreq); |
212 | gemtek_setfreq(rt, rt->curfreq); | ||
213 | return 0; | ||
214 | } | ||
194 | 215 | ||
195 | v->rangelow=(87*16000); | 216 | static int vidioc_g_frequency(struct file *file, void *priv, |
196 | v->rangehigh=(108*16000); | 217 | struct v4l2_frequency *f) |
197 | v->rxsubchans =V4L2_TUNER_SUB_MONO; | 218 | { |
198 | v->capability=V4L2_TUNER_CAP_LOW; | 219 | struct video_device *dev = video_devdata(file); |
199 | v->audmode = V4L2_TUNER_MODE_MONO; | 220 | struct gemtek_device *rt = dev->priv; |
200 | v->signal=0xFFFF*gemtek_getsigstr(rt); | ||
201 | 221 | ||
202 | return 0; | 222 | f->type = V4L2_TUNER_RADIO; |
203 | } | 223 | f->frequency = rt->curfreq; |
204 | case VIDIOC_S_TUNER: | 224 | return 0; |
205 | { | 225 | } |
206 | struct v4l2_tuner *v = arg; | ||
207 | 226 | ||
208 | if (v->index > 0) | 227 | static int vidioc_queryctrl(struct file *file, void *priv, |
209 | return -EINVAL; | 228 | struct v4l2_queryctrl *qc) |
229 | { | ||
230 | int i; | ||
210 | 231 | ||
232 | for (i = 0; i < ARRAY_SIZE(radio_qctrl); i++) { | ||
233 | if (qc->id && qc->id == radio_qctrl[i].id) { | ||
234 | memcpy(qc, &(radio_qctrl[i]), | ||
235 | sizeof(*qc)); | ||
211 | return 0; | 236 | return 0; |
212 | } | 237 | } |
213 | case VIDIOC_S_FREQUENCY: | 238 | } |
214 | { | 239 | return -EINVAL; |
215 | struct v4l2_frequency *f = arg; | 240 | } |
216 | |||
217 | rt->curfreq = f->frequency; | ||
218 | /* needs to be called twice in order for getsigstr to work */ | ||
219 | gemtek_setfreq(rt, rt->curfreq); | ||
220 | gemtek_setfreq(rt, rt->curfreq); | ||
221 | return 0; | ||
222 | } | ||
223 | case VIDIOC_G_FREQUENCY: | ||
224 | { | ||
225 | struct v4l2_frequency *f = arg; | ||
226 | 241 | ||
227 | f->type = V4L2_TUNER_RADIO; | 242 | static int vidioc_g_ctrl(struct file *file, void *priv, |
228 | f->frequency = rt->curfreq; | 243 | struct v4l2_control *ctrl) |
244 | { | ||
245 | struct video_device *dev = video_devdata(file); | ||
246 | struct gemtek_device *rt = dev->priv; | ||
229 | 247 | ||
230 | return 0; | 248 | switch (ctrl->id) { |
231 | } | 249 | case V4L2_CID_AUDIO_MUTE: |
232 | case VIDIOC_QUERYCTRL: | 250 | ctrl->value = rt->muted; |
233 | { | 251 | return 0; |
234 | struct v4l2_queryctrl *qc = arg; | 252 | case V4L2_CID_AUDIO_VOLUME: |
235 | int i; | 253 | if (rt->muted) |
236 | 254 | ctrl->value = 0; | |
237 | for (i = 0; i < ARRAY_SIZE(radio_qctrl); i++) { | 255 | else |
238 | if (qc->id && qc->id == radio_qctrl[i].id) { | 256 | ctrl->value = 65535; |
239 | memcpy(qc, &(radio_qctrl[i]), | 257 | return 0; |
240 | sizeof(*qc)); | 258 | } |
241 | return (0); | 259 | return -EINVAL; |
242 | } | 260 | } |
243 | } | 261 | |
244 | return -EINVAL; | 262 | static int vidioc_s_ctrl(struct file *file, void *priv, |
245 | } | 263 | struct v4l2_control *ctrl) |
246 | case VIDIOC_G_CTRL: | 264 | { |
247 | { | 265 | struct video_device *dev = video_devdata(file); |
248 | struct v4l2_control *ctrl= arg; | 266 | struct gemtek_device *rt = dev->priv; |
249 | 267 | ||
250 | switch (ctrl->id) { | 268 | switch (ctrl->id) { |
251 | case V4L2_CID_AUDIO_MUTE: | 269 | case V4L2_CID_AUDIO_MUTE: |
252 | ctrl->value=rt->muted; | 270 | if (ctrl->value) |
253 | return (0); | 271 | gemtek_mute(rt); |
254 | case V4L2_CID_AUDIO_VOLUME: | 272 | else |
255 | if (rt->muted) | 273 | gemtek_unmute(rt); |
256 | ctrl->value=0; | 274 | return 0; |
257 | else | 275 | case V4L2_CID_AUDIO_VOLUME: |
258 | ctrl->value=65535; | 276 | if (ctrl->value) |
259 | return (0); | 277 | gemtek_unmute(rt); |
260 | } | 278 | else |
261 | return -EINVAL; | 279 | gemtek_mute(rt); |
262 | } | 280 | return 0; |
263 | case VIDIOC_S_CTRL: | ||
264 | { | ||
265 | struct v4l2_control *ctrl= arg; | ||
266 | |||
267 | switch (ctrl->id) { | ||
268 | case V4L2_CID_AUDIO_MUTE: | ||
269 | if (ctrl->value) { | ||
270 | gemtek_mute(rt); | ||
271 | } else { | ||
272 | gemtek_unmute(rt); | ||
273 | } | ||
274 | return (0); | ||
275 | case V4L2_CID_AUDIO_VOLUME: | ||
276 | if (ctrl->value) { | ||
277 | gemtek_unmute(rt); | ||
278 | } else { | ||
279 | gemtek_mute(rt); | ||
280 | } | ||
281 | return (0); | ||
282 | } | ||
283 | return -EINVAL; | ||
284 | } | ||
285 | default: | ||
286 | return v4l_compat_translate_ioctl(inode,file,cmd,arg, | ||
287 | gemtek_do_ioctl); | ||
288 | } | 281 | } |
282 | return -EINVAL; | ||
289 | } | 283 | } |
290 | 284 | ||
291 | static int gemtek_ioctl(struct inode *inode, struct file *file, | 285 | static int vidioc_g_audio (struct file *file, void *priv, |
292 | unsigned int cmd, unsigned long arg) | 286 | struct v4l2_audio *a) |
293 | { | 287 | { |
294 | return video_usercopy(inode, file, cmd, arg, gemtek_do_ioctl); | 288 | if (a->index > 1) |
289 | return -EINVAL; | ||
290 | |||
291 | strcpy(a->name, "Radio"); | ||
292 | a->capability = V4L2_AUDCAP_STEREO; | ||
293 | return 0; | ||
294 | } | ||
295 | |||
296 | static int vidioc_g_input(struct file *filp, void *priv, unsigned int *i) | ||
297 | { | ||
298 | *i = 0; | ||
299 | return 0; | ||
300 | } | ||
301 | |||
302 | static int vidioc_s_input(struct file *filp, void *priv, unsigned int i) | ||
303 | { | ||
304 | if (i != 0) | ||
305 | return -EINVAL; | ||
306 | return 0; | ||
307 | } | ||
308 | |||
309 | static int vidioc_s_audio(struct file *file, void *priv, | ||
310 | struct v4l2_audio *a) | ||
311 | { | ||
312 | if (a->index != 0) | ||
313 | return -EINVAL; | ||
314 | return 0; | ||
295 | } | 315 | } |
296 | 316 | ||
297 | static struct gemtek_device gemtek_unit; | 317 | static struct gemtek_device gemtek_unit; |
@@ -300,7 +320,7 @@ static const struct file_operations gemtek_fops = { | |||
300 | .owner = THIS_MODULE, | 320 | .owner = THIS_MODULE, |
301 | .open = video_exclusive_open, | 321 | .open = video_exclusive_open, |
302 | .release = video_exclusive_release, | 322 | .release = video_exclusive_release, |
303 | .ioctl = gemtek_ioctl, | 323 | .ioctl = video_ioctl2, |
304 | .compat_ioctl = v4l_compat_ioctl32, | 324 | .compat_ioctl = v4l_compat_ioctl32, |
305 | .llseek = no_llseek, | 325 | .llseek = no_llseek, |
306 | }; | 326 | }; |
@@ -312,6 +332,18 @@ static struct video_device gemtek_radio= | |||
312 | .type = VID_TYPE_TUNER, | 332 | .type = VID_TYPE_TUNER, |
313 | .hardware = 0, | 333 | .hardware = 0, |
314 | .fops = &gemtek_fops, | 334 | .fops = &gemtek_fops, |
335 | .vidioc_querycap = vidioc_querycap, | ||
336 | .vidioc_g_tuner = vidioc_g_tuner, | ||
337 | .vidioc_s_tuner = vidioc_s_tuner, | ||
338 | .vidioc_g_audio = vidioc_g_audio, | ||
339 | .vidioc_s_audio = vidioc_s_audio, | ||
340 | .vidioc_g_input = vidioc_g_input, | ||
341 | .vidioc_s_input = vidioc_s_input, | ||
342 | .vidioc_g_frequency = vidioc_g_frequency, | ||
343 | .vidioc_s_frequency = vidioc_s_frequency, | ||
344 | .vidioc_queryctrl = vidioc_queryctrl, | ||
345 | .vidioc_g_ctrl = vidioc_g_ctrl, | ||
346 | .vidioc_s_ctrl = vidioc_s_ctrl, | ||
315 | }; | 347 | }; |
316 | 348 | ||
317 | static int __init gemtek_init(void) | 349 | static int __init gemtek_init(void) |
diff --git a/drivers/media/radio/radio-maestro.c b/drivers/media/radio/radio-maestro.c index e67b7f258029..11f80cacd6ed 100644 --- a/drivers/media/radio/radio-maestro.c +++ b/drivers/media/radio/radio-maestro.c | |||
@@ -75,8 +75,6 @@ static struct v4l2_queryctrl radio_qctrl[] = { | |||
75 | static int radio_nr = -1; | 75 | static int radio_nr = -1; |
76 | module_param(radio_nr, int, 0); | 76 | module_param(radio_nr, int, 0); |
77 | 77 | ||
78 | static int radio_ioctl(struct inode *inode, struct file *file, | ||
79 | unsigned int cmd, unsigned long arg); | ||
80 | static int maestro_probe(struct pci_dev *pdev, const struct pci_device_id *ent); | 78 | static int maestro_probe(struct pci_dev *pdev, const struct pci_device_id *ent); |
81 | static void maestro_remove(struct pci_dev *pdev); | 79 | static void maestro_remove(struct pci_dev *pdev); |
82 | 80 | ||
@@ -102,18 +100,11 @@ static const struct file_operations maestro_fops = { | |||
102 | .owner = THIS_MODULE, | 100 | .owner = THIS_MODULE, |
103 | .open = video_exclusive_open, | 101 | .open = video_exclusive_open, |
104 | .release = video_exclusive_release, | 102 | .release = video_exclusive_release, |
105 | .ioctl = radio_ioctl, | 103 | .ioctl = video_ioctl2, |
106 | .compat_ioctl = v4l_compat_ioctl32, | 104 | .compat_ioctl = v4l_compat_ioctl32, |
107 | .llseek = no_llseek, | 105 | .llseek = no_llseek, |
108 | }; | 106 | }; |
109 | 107 | ||
110 | static struct video_device maestro_radio = { | ||
111 | .name = "Maestro radio", | ||
112 | .type = VID_TYPE_TUNER, | ||
113 | .hardware = 0, | ||
114 | .fops = &maestro_fops, | ||
115 | }; | ||
116 | |||
117 | struct radio_device { | 108 | struct radio_device { |
118 | u16 io, /* base of Maestro card radio io (GPIO_DATA)*/ | 109 | u16 io, /* base of Maestro card radio io (GPIO_DATA)*/ |
119 | muted, /* VIDEO_AUDIO_MUTE */ | 110 | muted, /* VIDEO_AUDIO_MUTE */ |
@@ -190,142 +181,153 @@ static void radio_bits_set(struct radio_device *dev, u32 data) | |||
190 | msleep(125); | 181 | msleep(125); |
191 | } | 182 | } |
192 | 183 | ||
193 | static inline int radio_function(struct inode *inode, struct file *file, | 184 | static int vidioc_querycap(struct file *file, void *priv, |
194 | unsigned int cmd, void *arg) | 185 | struct v4l2_capability *v) |
186 | { | ||
187 | strlcpy(v->driver, "radio-maestro", sizeof(v->driver)); | ||
188 | strlcpy(v->card, "Maestro Radio", sizeof(v->card)); | ||
189 | sprintf(v->bus_info, "PCI"); | ||
190 | v->version = RADIO_VERSION; | ||
191 | v->capabilities = V4L2_CAP_TUNER; | ||
192 | return 0; | ||
193 | } | ||
194 | |||
195 | static int vidioc_g_tuner(struct file *file, void *priv, | ||
196 | struct v4l2_tuner *v) | ||
195 | { | 197 | { |
196 | struct video_device *dev = video_devdata(file); | 198 | struct video_device *dev = video_devdata(file); |
197 | struct radio_device *card = video_get_drvdata(dev); | 199 | struct radio_device *card = video_get_drvdata(dev); |
198 | 200 | ||
199 | switch (cmd) { | 201 | if (v->index > 0) |
200 | case VIDIOC_QUERYCAP: | 202 | return -EINVAL; |
201 | { | 203 | |
202 | struct v4l2_capability *v = arg; | 204 | (void)radio_bits_get(card); |
203 | memset(v,0,sizeof(*v)); | 205 | |
204 | strlcpy(v->driver, "radio-maestro", sizeof (v->driver)); | 206 | strcpy(v->name, "FM"); |
205 | strlcpy(v->card, "Maestro Radio", sizeof (v->card)); | 207 | v->type = V4L2_TUNER_RADIO; |
206 | sprintf(v->bus_info,"PCI"); | 208 | v->rangelow = FREQ_LO; |
207 | v->version = RADIO_VERSION; | 209 | v->rangehigh = FREQ_HI; |
208 | v->capabilities = V4L2_CAP_TUNER; | 210 | v->rxsubchans = V4L2_TUNER_SUB_MONO|V4L2_TUNER_SUB_STEREO; |
209 | 211 | v->capability = V4L2_TUNER_CAP_LOW; | |
210 | return 0; | 212 | if(card->stereo) |
211 | } | 213 | v->audmode = V4L2_TUNER_MODE_STEREO; |
212 | case VIDIOC_G_TUNER: | 214 | else |
213 | { | 215 | v->audmode = V4L2_TUNER_MODE_MONO; |
214 | struct v4l2_tuner *v = arg; | 216 | v->signal = card->tuned; |
215 | 217 | return 0; | |
216 | if (v->index > 0) | 218 | } |
217 | return -EINVAL; | ||
218 | |||
219 | (void)radio_bits_get(card); | ||
220 | 219 | ||
221 | memset(v,0,sizeof(*v)); | 220 | static int vidioc_s_tuner(struct file *file, void *priv, |
222 | strcpy(v->name, "FM"); | 221 | struct v4l2_tuner *v) |
223 | v->type = V4L2_TUNER_RADIO; | 222 | { |
223 | if (v->index > 0) | ||
224 | return -EINVAL; | ||
225 | return 0; | ||
226 | } | ||
224 | 227 | ||
225 | v->rangelow = FREQ_LO; | 228 | static int vidioc_s_frequency(struct file *file, void *priv, |
226 | v->rangehigh = FREQ_HI; | 229 | struct v4l2_frequency *f) |
227 | v->rxsubchans =V4L2_TUNER_SUB_MONO|V4L2_TUNER_SUB_STEREO; | 230 | { |
228 | v->capability=V4L2_TUNER_CAP_LOW; | 231 | struct video_device *dev = video_devdata(file); |
229 | if(card->stereo) | 232 | struct radio_device *card = video_get_drvdata(dev); |
230 | v->audmode = V4L2_TUNER_MODE_STEREO; | ||
231 | else | ||
232 | v->audmode = V4L2_TUNER_MODE_MONO; | ||
233 | v->signal=card->tuned; | ||
234 | 233 | ||
235 | return 0; | 234 | if (f->frequency < FREQ_LO || f->frequency > FREQ_HI) |
236 | } | 235 | return -EINVAL; |
237 | case VIDIOC_S_TUNER: | 236 | radio_bits_set(card, FREQ2BITS(f->frequency)); |
238 | { | 237 | return 0; |
239 | struct v4l2_tuner *v = arg; | 238 | } |
240 | 239 | ||
241 | if (v->index > 0) | 240 | static int vidioc_g_frequency(struct file *file, void *priv, |
242 | return -EINVAL; | 241 | struct v4l2_frequency *f) |
242 | { | ||
243 | struct video_device *dev = video_devdata(file); | ||
244 | struct radio_device *card = video_get_drvdata(dev); | ||
243 | 245 | ||
244 | return 0; | 246 | f->type = V4L2_TUNER_RADIO; |
245 | } | 247 | f->frequency = BITS2FREQ(radio_bits_get(card)); |
246 | case VIDIOC_S_FREQUENCY: | 248 | return 0; |
247 | { | 249 | } |
248 | struct v4l2_frequency *f = arg; | ||
249 | 250 | ||
250 | if (f->frequency < FREQ_LO || f->frequency > FREQ_HI) | 251 | static int vidioc_queryctrl(struct file *file, void *priv, |
251 | return -EINVAL; | 252 | struct v4l2_queryctrl *qc) |
252 | radio_bits_set(card, FREQ2BITS(f->frequency)); | 253 | { |
254 | int i; | ||
253 | 255 | ||
256 | for (i = 0; i < ARRAY_SIZE(radio_qctrl); i++) { | ||
257 | if (qc->id && qc->id == radio_qctrl[i].id) { | ||
258 | memcpy(qc, &(radio_qctrl[i]), | ||
259 | sizeof(*qc)); | ||
254 | return 0; | 260 | return 0; |
255 | } | 261 | } |
256 | case VIDIOC_G_FREQUENCY: | 262 | } |
257 | { | 263 | return -EINVAL; |
258 | struct v4l2_frequency *f = arg; | 264 | } |
259 | 265 | ||
260 | f->type = V4L2_TUNER_RADIO; | 266 | static int vidioc_g_ctrl(struct file *file, void *priv, |
261 | f->frequency = BITS2FREQ(radio_bits_get(card)); | 267 | struct v4l2_control *ctrl) |
268 | { | ||
269 | struct video_device *dev = video_devdata(file); | ||
270 | struct radio_device *card = video_get_drvdata(dev); | ||
262 | 271 | ||
263 | return 0; | 272 | switch (ctrl->id) { |
264 | } | 273 | case V4L2_CID_AUDIO_MUTE: |
265 | case VIDIOC_QUERYCTRL: | 274 | ctrl->value = card->muted; |
266 | { | 275 | return 0; |
267 | struct v4l2_queryctrl *qc = arg; | ||
268 | int i; | ||
269 | |||
270 | for (i = 0; i < ARRAY_SIZE(radio_qctrl); i++) { | ||
271 | if (qc->id && qc->id == radio_qctrl[i].id) { | ||
272 | memcpy(qc, &(radio_qctrl[i]), | ||
273 | sizeof(*qc)); | ||
274 | return (0); | ||
275 | } | ||
276 | } | ||
277 | return -EINVAL; | ||
278 | } | ||
279 | case VIDIOC_G_CTRL: | ||
280 | { | ||
281 | struct v4l2_control *ctrl= arg; | ||
282 | |||
283 | switch (ctrl->id) { | ||
284 | case V4L2_CID_AUDIO_MUTE: | ||
285 | ctrl->value=card->muted; | ||
286 | return (0); | ||
287 | } | ||
288 | return -EINVAL; | ||
289 | } | ||
290 | case VIDIOC_S_CTRL: | ||
291 | { | ||
292 | struct v4l2_control *ctrl= arg; | ||
293 | |||
294 | switch (ctrl->id) { | ||
295 | case V4L2_CID_AUDIO_MUTE: | ||
296 | { | ||
297 | register u16 io = card->io; | ||
298 | register u16 omask = inw(io + IO_MASK); | ||
299 | outw(~STR_WREN, io + IO_MASK); | ||
300 | outw((card->muted = ctrl->value ) ? | ||
301 | STR_WREN : 0, io); | ||
302 | udelay(4); | ||
303 | outw(omask, io + IO_MASK); | ||
304 | msleep(125); | ||
305 | |||
306 | return (0); | ||
307 | } | ||
308 | } | ||
309 | return -EINVAL; | ||
310 | } | ||
311 | default: | ||
312 | return v4l_compat_translate_ioctl(inode,file,cmd,arg, | ||
313 | radio_function); | ||
314 | } | 276 | } |
277 | return -EINVAL; | ||
315 | } | 278 | } |
316 | 279 | ||
317 | static int radio_ioctl(struct inode *inode, struct file *file, | 280 | static int vidioc_s_ctrl(struct file *file, void *priv, |
318 | unsigned int cmd, unsigned long arg) | 281 | struct v4l2_control *ctrl) |
319 | { | 282 | { |
320 | struct video_device *dev = video_devdata(file); | 283 | struct video_device *dev = video_devdata(file); |
321 | struct radio_device *card = video_get_drvdata(dev); | 284 | struct radio_device *card = video_get_drvdata(dev); |
322 | int ret; | 285 | register u16 io = card->io; |
286 | register u16 omask = inw(io + IO_MASK); | ||
287 | |||
288 | switch (ctrl->id) { | ||
289 | case V4L2_CID_AUDIO_MUTE: | ||
290 | outw(~STR_WREN, io + IO_MASK); | ||
291 | outw((card->muted = ctrl->value ) ? | ||
292 | STR_WREN : 0, io); | ||
293 | udelay(4); | ||
294 | outw(omask, io + IO_MASK); | ||
295 | msleep(125); | ||
296 | return 0; | ||
297 | } | ||
298 | return -EINVAL; | ||
299 | } | ||
323 | 300 | ||
324 | mutex_lock(&card->lock); | 301 | static int vidioc_g_audio(struct file *file, void *priv, |
325 | ret = video_usercopy(inode, file, cmd, arg, radio_function); | 302 | struct v4l2_audio *a) |
326 | mutex_unlock(&card->lock); | 303 | { |
304 | if (a->index > 1) | ||
305 | return -EINVAL; | ||
327 | 306 | ||
328 | return ret; | 307 | strcpy(a->name, "Radio"); |
308 | a->capability = V4L2_AUDCAP_STEREO; | ||
309 | return 0; | ||
310 | } | ||
311 | |||
312 | static int vidioc_g_input(struct file *filp, void *priv, unsigned int *i) | ||
313 | { | ||
314 | *i = 0; | ||
315 | return 0; | ||
316 | } | ||
317 | |||
318 | static int vidioc_s_input(struct file *filp, void *priv, unsigned int i) | ||
319 | { | ||
320 | if (i != 0) | ||
321 | return -EINVAL; | ||
322 | return 0; | ||
323 | } | ||
324 | |||
325 | static int vidioc_s_audio(struct file *file, void *priv, | ||
326 | struct v4l2_audio *a) | ||
327 | { | ||
328 | if (a->index != 0) | ||
329 | return -EINVAL; | ||
330 | return 0; | ||
329 | } | 331 | } |
330 | 332 | ||
331 | static u16 __devinit radio_power_on(struct radio_device *dev) | 333 | static u16 __devinit radio_power_on(struct radio_device *dev) |
@@ -352,6 +354,24 @@ static u16 __devinit radio_power_on(struct radio_device *dev) | |||
352 | return (ofreq == radio_bits_get(dev)); | 354 | return (ofreq == radio_bits_get(dev)); |
353 | } | 355 | } |
354 | 356 | ||
357 | static struct video_device maestro_radio = { | ||
358 | .name = "Maestro radio", | ||
359 | .type = VID_TYPE_TUNER, | ||
360 | .fops = &maestro_fops, | ||
361 | .vidioc_querycap = vidioc_querycap, | ||
362 | .vidioc_g_tuner = vidioc_g_tuner, | ||
363 | .vidioc_s_tuner = vidioc_s_tuner, | ||
364 | .vidioc_g_audio = vidioc_g_audio, | ||
365 | .vidioc_s_audio = vidioc_s_audio, | ||
366 | .vidioc_g_input = vidioc_g_input, | ||
367 | .vidioc_s_input = vidioc_s_input, | ||
368 | .vidioc_g_frequency = vidioc_g_frequency, | ||
369 | .vidioc_s_frequency = vidioc_s_frequency, | ||
370 | .vidioc_queryctrl = vidioc_queryctrl, | ||
371 | .vidioc_g_ctrl = vidioc_g_ctrl, | ||
372 | .vidioc_s_ctrl = vidioc_s_ctrl, | ||
373 | }; | ||
374 | |||
355 | static int __devinit maestro_probe(struct pci_dev *pdev, | 375 | static int __devinit maestro_probe(struct pci_dev *pdev, |
356 | const struct pci_device_id *ent) | 376 | const struct pci_device_id *ent) |
357 | { | 377 | { |
diff --git a/drivers/media/radio/radio-rtrack2.c b/drivers/media/radio/radio-rtrack2.c index f6683872251e..9b493b3298cd 100644 --- a/drivers/media/radio/radio-rtrack2.c +++ b/drivers/media/radio/radio-rtrack2.c | |||
@@ -122,6 +122,26 @@ static int rt_setfreq(struct rt_device *dev, unsigned long freq) | |||
122 | return 0; | 122 | return 0; |
123 | } | 123 | } |
124 | 124 | ||
125 | static int vidioc_querycap(struct file *file, void *priv, | ||
126 | struct v4l2_capability *v) | ||
127 | { | ||
128 | strlcpy(v->driver, "radio-rtrack2", sizeof(v->driver)); | ||
129 | strlcpy(v->card, "RadioTrack II", sizeof(v->card)); | ||
130 | sprintf(v->bus_info, "ISA"); | ||
131 | v->version = RADIO_VERSION; | ||
132 | v->capabilities = V4L2_CAP_TUNER; | ||
133 | return 0; | ||
134 | } | ||
135 | |||
136 | static int vidioc_s_tuner(struct file *file, void *priv, | ||
137 | struct v4l2_tuner *v) | ||
138 | { | ||
139 | if (v->index > 0) | ||
140 | return -EINVAL; | ||
141 | |||
142 | return 0; | ||
143 | } | ||
144 | |||
125 | static int rt_getsigstr(struct rt_device *dev) | 145 | static int rt_getsigstr(struct rt_device *dev) |
126 | { | 146 | { |
127 | if (inb(io) & 2) /* bit set = no signal present */ | 147 | if (inb(io) & 2) /* bit set = no signal present */ |
@@ -129,135 +149,136 @@ static int rt_getsigstr(struct rt_device *dev) | |||
129 | return 1; /* signal present */ | 149 | return 1; /* signal present */ |
130 | } | 150 | } |
131 | 151 | ||
132 | static int rt_do_ioctl(struct inode *inode, struct file *file, | 152 | static int vidioc_g_tuner(struct file *file, void *priv, |
133 | unsigned int cmd, void *arg) | 153 | struct v4l2_tuner *v) |
134 | { | 154 | { |
135 | struct video_device *dev = video_devdata(file); | 155 | struct video_device *dev = video_devdata(file); |
136 | struct rt_device *rt=dev->priv; | 156 | struct rt_device *rt = dev->priv; |
137 | 157 | ||
138 | switch(cmd) | 158 | if (v->index > 0) |
139 | { | 159 | return -EINVAL; |
140 | case VIDIOC_QUERYCAP: | ||
141 | { | ||
142 | struct v4l2_capability *v = arg; | ||
143 | memset(v,0,sizeof(*v)); | ||
144 | strlcpy(v->driver, "radio-rtrack2", sizeof (v->driver)); | ||
145 | strlcpy(v->card, "RadioTrack II", sizeof (v->card)); | ||
146 | sprintf(v->bus_info,"ISA"); | ||
147 | v->version = RADIO_VERSION; | ||
148 | v->capabilities = V4L2_CAP_TUNER; | ||
149 | 160 | ||
150 | return 0; | 161 | strcpy(v->name, "FM"); |
151 | } | 162 | v->type = V4L2_TUNER_RADIO; |
152 | case VIDIOC_G_TUNER: | 163 | v->rangelow = (88*16000); |
153 | { | 164 | v->rangehigh = (108*16000); |
154 | struct v4l2_tuner *v = arg; | 165 | v->rxsubchans = V4L2_TUNER_SUB_MONO; |
166 | v->capability = V4L2_TUNER_CAP_LOW; | ||
167 | v->audmode = V4L2_TUNER_MODE_MONO; | ||
168 | v->signal = 0xFFFF*rt_getsigstr(rt); | ||
169 | return 0; | ||
170 | } | ||
155 | 171 | ||
156 | if (v->index > 0) | 172 | static int vidioc_s_frequency(struct file *file, void *priv, |
157 | return -EINVAL; | 173 | struct v4l2_frequency *f) |
174 | { | ||
175 | struct video_device *dev = video_devdata(file); | ||
176 | struct rt_device *rt = dev->priv; | ||
158 | 177 | ||
159 | memset(v,0,sizeof(*v)); | 178 | rt->curfreq = f->frequency; |
160 | strcpy(v->name, "FM"); | 179 | rt_setfreq(rt, rt->curfreq); |
161 | v->type = V4L2_TUNER_RADIO; | 180 | return 0; |
181 | } | ||
162 | 182 | ||
163 | v->rangelow=(88*16000); | 183 | static int vidioc_g_frequency(struct file *file, void *priv, |
164 | v->rangehigh=(108*16000); | 184 | struct v4l2_frequency *f) |
165 | v->rxsubchans =V4L2_TUNER_SUB_MONO; | 185 | { |
166 | v->capability=V4L2_TUNER_CAP_LOW; | 186 | struct video_device *dev = video_devdata(file); |
167 | v->audmode = V4L2_TUNER_MODE_MONO; | 187 | struct rt_device *rt = dev->priv; |
168 | v->signal=0xFFFF*rt_getsigstr(rt); | ||
169 | 188 | ||
170 | return 0; | 189 | f->type = V4L2_TUNER_RADIO; |
171 | } | 190 | f->frequency = rt->curfreq; |
172 | case VIDIOC_S_TUNER: | 191 | return 0; |
173 | { | 192 | } |
174 | struct v4l2_tuner *v = arg; | ||
175 | 193 | ||
176 | if (v->index > 0) | 194 | static int vidioc_queryctrl(struct file *file, void *priv, |
177 | return -EINVAL; | 195 | struct v4l2_queryctrl *qc) |
196 | { | ||
197 | int i; | ||
178 | 198 | ||
199 | for (i = 0; i < ARRAY_SIZE(radio_qctrl); i++) { | ||
200 | if (qc->id && qc->id == radio_qctrl[i].id) { | ||
201 | memcpy(qc, &(radio_qctrl[i]), | ||
202 | sizeof(*qc)); | ||
179 | return 0; | 203 | return 0; |
180 | } | 204 | } |
181 | case VIDIOC_S_FREQUENCY: | 205 | } |
182 | { | 206 | return -EINVAL; |
183 | struct v4l2_frequency *f = arg; | 207 | } |
184 | 208 | ||
185 | rt->curfreq = f->frequency; | 209 | static int vidioc_g_ctrl(struct file *file, void *priv, |
186 | rt_setfreq(rt, rt->curfreq); | 210 | struct v4l2_control *ctrl) |
187 | return 0; | 211 | { |
188 | } | 212 | struct video_device *dev = video_devdata(file); |
189 | case VIDIOC_G_FREQUENCY: | 213 | struct rt_device *rt = dev->priv; |
190 | { | ||
191 | struct v4l2_frequency *f = arg; | ||
192 | 214 | ||
193 | f->type = V4L2_TUNER_RADIO; | 215 | switch (ctrl->id) { |
194 | f->frequency = rt->curfreq; | 216 | case V4L2_CID_AUDIO_MUTE: |
217 | ctrl->value = rt->muted; | ||
218 | return 0; | ||
219 | case V4L2_CID_AUDIO_VOLUME: | ||
220 | if (rt->muted) | ||
221 | ctrl->value = 0; | ||
222 | else | ||
223 | ctrl->value = 65535; | ||
224 | return 0; | ||
225 | } | ||
226 | return -EINVAL; | ||
227 | } | ||
195 | 228 | ||
196 | return 0; | 229 | static int vidioc_s_ctrl(struct file *file, void *priv, |
197 | } | 230 | struct v4l2_control *ctrl) |
198 | case VIDIOC_QUERYCTRL: | 231 | { |
199 | { | 232 | struct video_device *dev = video_devdata(file); |
200 | struct v4l2_queryctrl *qc = arg; | 233 | struct rt_device *rt = dev->priv; |
201 | int i; | 234 | |
202 | 235 | switch (ctrl->id) { | |
203 | for (i = 0; i < ARRAY_SIZE(radio_qctrl); i++) { | 236 | case V4L2_CID_AUDIO_MUTE: |
204 | if (qc->id && qc->id == radio_qctrl[i].id) { | 237 | if (ctrl->value) |
205 | memcpy(qc, &(radio_qctrl[i]), | 238 | rt_mute(rt); |
206 | sizeof(*qc)); | 239 | else |
207 | return (0); | 240 | rt_unmute(rt); |
208 | } | 241 | return 0; |
209 | } | 242 | case V4L2_CID_AUDIO_VOLUME: |
210 | return -EINVAL; | 243 | if (ctrl->value) |
211 | } | 244 | rt_unmute(rt); |
212 | case VIDIOC_G_CTRL: | 245 | else |
213 | { | 246 | rt_mute(rt); |
214 | struct v4l2_control *ctrl= arg; | 247 | return 0; |
215 | |||
216 | switch (ctrl->id) { | ||
217 | case V4L2_CID_AUDIO_MUTE: | ||
218 | ctrl->value=rt->muted; | ||
219 | return (0); | ||
220 | case V4L2_CID_AUDIO_VOLUME: | ||
221 | if (rt->muted) | ||
222 | ctrl->value=0; | ||
223 | else | ||
224 | ctrl->value=65535; | ||
225 | return (0); | ||
226 | } | ||
227 | return -EINVAL; | ||
228 | } | ||
229 | case VIDIOC_S_CTRL: | ||
230 | { | ||
231 | struct v4l2_control *ctrl= arg; | ||
232 | |||
233 | switch (ctrl->id) { | ||
234 | case V4L2_CID_AUDIO_MUTE: | ||
235 | if (ctrl->value) { | ||
236 | rt_mute(rt); | ||
237 | } else { | ||
238 | rt_unmute(rt); | ||
239 | } | ||
240 | return (0); | ||
241 | case V4L2_CID_AUDIO_VOLUME: | ||
242 | if (ctrl->value) { | ||
243 | rt_unmute(rt); | ||
244 | } else { | ||
245 | rt_mute(rt); | ||
246 | } | ||
247 | return (0); | ||
248 | } | ||
249 | return -EINVAL; | ||
250 | } | ||
251 | default: | ||
252 | return v4l_compat_translate_ioctl(inode,file,cmd,arg, | ||
253 | rt_do_ioctl); | ||
254 | } | 248 | } |
249 | return -EINVAL; | ||
255 | } | 250 | } |
256 | 251 | ||
257 | static int rt_ioctl(struct inode *inode, struct file *file, | 252 | static int vidioc_g_audio(struct file *file, void *priv, |
258 | unsigned int cmd, unsigned long arg) | 253 | struct v4l2_audio *a) |
259 | { | 254 | { |
260 | return video_usercopy(inode, file, cmd, arg, rt_do_ioctl); | 255 | if (a->index > 1) |
256 | return -EINVAL; | ||
257 | |||
258 | strcpy(a->name, "Radio"); | ||
259 | a->capability = V4L2_AUDCAP_STEREO; | ||
260 | return 0; | ||
261 | } | ||
262 | |||
263 | static int vidioc_g_input(struct file *filp, void *priv, unsigned int *i) | ||
264 | { | ||
265 | *i = 0; | ||
266 | return 0; | ||
267 | } | ||
268 | |||
269 | static int vidioc_s_input(struct file *filp, void *priv, unsigned int i) | ||
270 | { | ||
271 | if (i != 0) | ||
272 | return -EINVAL; | ||
273 | return 0; | ||
274 | } | ||
275 | |||
276 | static int vidioc_s_audio(struct file *file, void *priv, | ||
277 | struct v4l2_audio *a) | ||
278 | { | ||
279 | if (a->index != 0) | ||
280 | return -EINVAL; | ||
281 | return 0; | ||
261 | } | 282 | } |
262 | 283 | ||
263 | static struct rt_device rtrack2_unit; | 284 | static struct rt_device rtrack2_unit; |
@@ -266,7 +287,7 @@ static const struct file_operations rtrack2_fops = { | |||
266 | .owner = THIS_MODULE, | 287 | .owner = THIS_MODULE, |
267 | .open = video_exclusive_open, | 288 | .open = video_exclusive_open, |
268 | .release = video_exclusive_release, | 289 | .release = video_exclusive_release, |
269 | .ioctl = rt_ioctl, | 290 | .ioctl = video_ioctl2, |
270 | .compat_ioctl = v4l_compat_ioctl32, | 291 | .compat_ioctl = v4l_compat_ioctl32, |
271 | .llseek = no_llseek, | 292 | .llseek = no_llseek, |
272 | }; | 293 | }; |
@@ -278,6 +299,18 @@ static struct video_device rtrack2_radio= | |||
278 | .type = VID_TYPE_TUNER, | 299 | .type = VID_TYPE_TUNER, |
279 | .hardware = 0, | 300 | .hardware = 0, |
280 | .fops = &rtrack2_fops, | 301 | .fops = &rtrack2_fops, |
302 | .vidioc_querycap = vidioc_querycap, | ||
303 | .vidioc_g_tuner = vidioc_g_tuner, | ||
304 | .vidioc_s_tuner = vidioc_s_tuner, | ||
305 | .vidioc_g_frequency = vidioc_g_frequency, | ||
306 | .vidioc_s_frequency = vidioc_s_frequency, | ||
307 | .vidioc_queryctrl = vidioc_queryctrl, | ||
308 | .vidioc_g_ctrl = vidioc_g_ctrl, | ||
309 | .vidioc_s_ctrl = vidioc_s_ctrl, | ||
310 | .vidioc_g_audio = vidioc_g_audio, | ||
311 | .vidioc_s_audio = vidioc_s_audio, | ||
312 | .vidioc_g_input = vidioc_g_input, | ||
313 | .vidioc_s_input = vidioc_s_input, | ||
281 | }; | 314 | }; |
282 | 315 | ||
283 | static int __init rtrack2_init(void) | 316 | static int __init rtrack2_init(void) |
diff --git a/drivers/media/radio/radio-sf16fmi.c b/drivers/media/radio/radio-sf16fmi.c index f4619e4dda4f..dc33f19c0e2c 100644 --- a/drivers/media/radio/radio-sf16fmi.c +++ b/drivers/media/radio/radio-sf16fmi.c | |||
@@ -130,137 +130,155 @@ static inline int fmi_getsigstr(struct fmi_device *dev) | |||
130 | return (res & 2) ? 0 : 0xFFFF; | 130 | return (res & 2) ? 0 : 0xFFFF; |
131 | } | 131 | } |
132 | 132 | ||
133 | static int fmi_do_ioctl(struct inode *inode, struct file *file, | 133 | static int vidioc_querycap(struct file *file, void *priv, |
134 | unsigned int cmd, void *arg) | 134 | struct v4l2_capability *v) |
135 | { | 135 | { |
136 | strlcpy(v->driver, "radio-sf16fmi", sizeof(v->driver)); | ||
137 | strlcpy(v->card, "SF16-FMx radio", sizeof(v->card)); | ||
138 | sprintf(v->bus_info, "ISA"); | ||
139 | v->version = RADIO_VERSION; | ||
140 | v->capabilities = V4L2_CAP_TUNER; | ||
141 | return 0; | ||
142 | } | ||
143 | |||
144 | static int vidioc_g_tuner(struct file *file, void *priv, | ||
145 | struct v4l2_tuner *v) | ||
146 | { | ||
147 | int mult; | ||
136 | struct video_device *dev = video_devdata(file); | 148 | struct video_device *dev = video_devdata(file); |
137 | struct fmi_device *fmi=dev->priv; | 149 | struct fmi_device *fmi = dev->priv; |
138 | 150 | ||
139 | switch(cmd) | 151 | if (v->index > 0) |
140 | { | 152 | return -EINVAL; |
141 | case VIDIOC_QUERYCAP: | ||
142 | { | ||
143 | struct v4l2_capability *v = arg; | ||
144 | memset(v,0,sizeof(*v)); | ||
145 | strlcpy(v->driver, "radio-sf16fmi", sizeof (v->driver)); | ||
146 | strlcpy(v->card, "SF16-FMx radio", sizeof (v->card)); | ||
147 | sprintf(v->bus_info,"ISA"); | ||
148 | v->version = RADIO_VERSION; | ||
149 | v->capabilities = V4L2_CAP_TUNER; | ||
150 | 153 | ||
151 | return 0; | 154 | strcpy(v->name, "FM"); |
152 | } | 155 | v->type = V4L2_TUNER_RADIO; |
153 | case VIDIOC_G_TUNER: | 156 | mult = (fmi->flags & V4L2_TUNER_CAP_LOW) ? 1 : 1000; |
154 | { | 157 | v->rangelow = RSF16_MINFREQ/mult; |
155 | struct v4l2_tuner *v = arg; | 158 | v->rangehigh = RSF16_MAXFREQ/mult; |
156 | int mult; | 159 | v->rxsubchans = V4L2_TUNER_SUB_MONO | V4L2_TUNER_MODE_STEREO; |
157 | 160 | v->capability = fmi->flags&V4L2_TUNER_CAP_LOW; | |
158 | if (v->index > 0) | 161 | v->audmode = V4L2_TUNER_MODE_STEREO; |
159 | return -EINVAL; | 162 | v->signal = fmi_getsigstr(fmi); |
160 | 163 | return 0; | |
161 | memset(v,0,sizeof(*v)); | 164 | } |
162 | strcpy(v->name, "FM"); | ||
163 | v->type = V4L2_TUNER_RADIO; | ||
164 | |||
165 | mult = (fmi->flags & V4L2_TUNER_CAP_LOW) ? 1 : 1000; | ||
166 | v->rangelow = RSF16_MINFREQ/mult; | ||
167 | v->rangehigh = RSF16_MAXFREQ/mult; | ||
168 | v->rxsubchans =V4L2_TUNER_SUB_MONO | V4L2_TUNER_MODE_STEREO; | ||
169 | v->capability=fmi->flags&V4L2_TUNER_CAP_LOW; | ||
170 | v->audmode = V4L2_TUNER_MODE_STEREO; | ||
171 | v->signal = fmi_getsigstr(fmi); | ||
172 | 165 | ||
173 | return 0; | 166 | static int vidioc_s_tuner(struct file *file, void *priv, |
174 | } | 167 | struct v4l2_tuner *v) |
175 | case VIDIOC_S_TUNER: | 168 | { |
176 | { | 169 | if (v->index > 0) |
177 | struct v4l2_tuner *v = arg; | 170 | return -EINVAL; |
171 | return 0; | ||
172 | } | ||
178 | 173 | ||
179 | if (v->index > 0) | 174 | static int vidioc_s_frequency(struct file *file, void *priv, |
180 | return -EINVAL; | 175 | struct v4l2_frequency *f) |
176 | { | ||
177 | struct video_device *dev = video_devdata(file); | ||
178 | struct fmi_device *fmi = dev->priv; | ||
181 | 179 | ||
182 | return 0; | 180 | if (!(fmi->flags & V4L2_TUNER_CAP_LOW)) |
183 | } | 181 | f->frequency *= 1000; |
184 | case VIDIOC_S_FREQUENCY: | 182 | if (f->frequency < RSF16_MINFREQ || |
185 | { | 183 | f->frequency > RSF16_MAXFREQ ) |
186 | struct v4l2_frequency *f = arg; | 184 | return -EINVAL; |
187 | 185 | /*rounding in steps of 800 to match th freq | |
188 | if (!(fmi->flags & V4L2_TUNER_CAP_LOW)) | 186 | that will be used */ |
189 | f->frequency *= 1000; | 187 | fmi->curfreq = (f->frequency/800)*800; |
190 | if (f->frequency < RSF16_MINFREQ || | 188 | fmi_setfreq(fmi); |
191 | f->frequency > RSF16_MAXFREQ ) | 189 | return 0; |
192 | return -EINVAL; | 190 | } |
193 | /*rounding in steps of 800 to match th freq | ||
194 | that will be used */ | ||
195 | fmi->curfreq = (f->frequency/800)*800; | ||
196 | fmi_setfreq(fmi); | ||
197 | 191 | ||
198 | return 0; | 192 | static int vidioc_g_frequency(struct file *file, void *priv, |
199 | } | 193 | struct v4l2_frequency *f) |
200 | case VIDIOC_G_FREQUENCY: | 194 | { |
201 | { | 195 | struct video_device *dev = video_devdata(file); |
202 | struct v4l2_frequency *f = arg; | 196 | struct fmi_device *fmi = dev->priv; |
203 | 197 | ||
204 | f->type = V4L2_TUNER_RADIO; | 198 | f->type = V4L2_TUNER_RADIO; |
205 | f->frequency = fmi->curfreq; | 199 | f->frequency = fmi->curfreq; |
206 | if (!(fmi->flags & V4L2_TUNER_CAP_LOW)) | 200 | if (!(fmi->flags & V4L2_TUNER_CAP_LOW)) |
207 | f->frequency /= 1000; | 201 | f->frequency /= 1000; |
202 | return 0; | ||
203 | } | ||
204 | |||
205 | static int vidioc_queryctrl(struct file *file, void *priv, | ||
206 | struct v4l2_queryctrl *qc) | ||
207 | { | ||
208 | int i; | ||
208 | 209 | ||
210 | for (i = 0; i < ARRAY_SIZE(radio_qctrl); i++) { | ||
211 | if (qc->id && qc->id == radio_qctrl[i].id) { | ||
212 | memcpy(qc, &(radio_qctrl[i]), | ||
213 | sizeof(*qc)); | ||
209 | return 0; | 214 | return 0; |
210 | } | 215 | } |
211 | case VIDIOC_QUERYCTRL: | ||
212 | { | ||
213 | struct v4l2_queryctrl *qc = arg; | ||
214 | int i; | ||
215 | |||
216 | for (i = 0; i < ARRAY_SIZE(radio_qctrl); i++) { | ||
217 | if (qc->id && qc->id == radio_qctrl[i].id) { | ||
218 | memcpy(qc, &(radio_qctrl[i]), | ||
219 | sizeof(*qc)); | ||
220 | return (0); | ||
221 | } | ||
222 | } | ||
223 | return -EINVAL; | ||
224 | } | ||
225 | case VIDIOC_G_CTRL: | ||
226 | { | ||
227 | struct v4l2_control *ctrl= arg; | ||
228 | |||
229 | switch (ctrl->id) { | ||
230 | case V4L2_CID_AUDIO_MUTE: | ||
231 | ctrl->value=fmi->curvol; | ||
232 | return (0); | ||
233 | } | ||
234 | return -EINVAL; | ||
235 | } | ||
236 | case VIDIOC_S_CTRL: | ||
237 | { | ||
238 | struct v4l2_control *ctrl= arg; | ||
239 | |||
240 | switch (ctrl->id) { | ||
241 | case V4L2_CID_AUDIO_MUTE: | ||
242 | { | ||
243 | if (ctrl->value) | ||
244 | fmi_mute(fmi->port); | ||
245 | else | ||
246 | fmi_unmute(fmi->port); | ||
247 | |||
248 | fmi->curvol=ctrl->value; | ||
249 | return (0); | ||
250 | } | ||
251 | } | ||
252 | return -EINVAL; | ||
253 | } | ||
254 | default: | ||
255 | return v4l_compat_translate_ioctl(inode,file,cmd,arg, | ||
256 | fmi_do_ioctl); | ||
257 | } | 216 | } |
217 | return -EINVAL; | ||
218 | } | ||
219 | |||
220 | static int vidioc_g_ctrl(struct file *file, void *priv, | ||
221 | struct v4l2_control *ctrl) | ||
222 | { | ||
223 | struct video_device *dev = video_devdata(file); | ||
224 | struct fmi_device *fmi = dev->priv; | ||
225 | |||
226 | switch (ctrl->id) { | ||
227 | case V4L2_CID_AUDIO_MUTE: | ||
228 | ctrl->value = fmi->curvol; | ||
229 | return 0; | ||
230 | } | ||
231 | return -EINVAL; | ||
232 | } | ||
233 | |||
234 | static int vidioc_s_ctrl(struct file *file, void *priv, | ||
235 | struct v4l2_control *ctrl) | ||
236 | { | ||
237 | struct video_device *dev = video_devdata(file); | ||
238 | struct fmi_device *fmi = dev->priv; | ||
239 | |||
240 | switch (ctrl->id) { | ||
241 | case V4L2_CID_AUDIO_MUTE: | ||
242 | if (ctrl->value) | ||
243 | fmi_mute(fmi->port); | ||
244 | else | ||
245 | fmi_unmute(fmi->port); | ||
246 | fmi->curvol = ctrl->value; | ||
247 | return 0; | ||
248 | } | ||
249 | return -EINVAL; | ||
258 | } | 250 | } |
259 | 251 | ||
260 | static int fmi_ioctl(struct inode *inode, struct file *file, | 252 | static int vidioc_g_audio(struct file *file, void *priv, |
261 | unsigned int cmd, unsigned long arg) | 253 | struct v4l2_audio *a) |
262 | { | 254 | { |
263 | return video_usercopy(inode, file, cmd, arg, fmi_do_ioctl); | 255 | if (a->index > 1) |
256 | return -EINVAL; | ||
257 | |||
258 | strcpy(a->name, "Radio"); | ||
259 | a->capability = V4L2_AUDCAP_STEREO; | ||
260 | return 0; | ||
261 | } | ||
262 | |||
263 | static int vidioc_g_input(struct file *filp, void *priv, unsigned int *i) | ||
264 | { | ||
265 | *i = 0; | ||
266 | return 0; | ||
267 | } | ||
268 | |||
269 | static int vidioc_s_input(struct file *filp, void *priv, unsigned int i) | ||
270 | { | ||
271 | if (i != 0) | ||
272 | return -EINVAL; | ||
273 | return 0; | ||
274 | } | ||
275 | |||
276 | static int vidioc_s_audio(struct file *file, void *priv, | ||
277 | struct v4l2_audio *a) | ||
278 | { | ||
279 | if (a->index != 0) | ||
280 | return -EINVAL; | ||
281 | return 0; | ||
264 | } | 282 | } |
265 | 283 | ||
266 | static struct fmi_device fmi_unit; | 284 | static struct fmi_device fmi_unit; |
@@ -269,7 +287,7 @@ static const struct file_operations fmi_fops = { | |||
269 | .owner = THIS_MODULE, | 287 | .owner = THIS_MODULE, |
270 | .open = video_exclusive_open, | 288 | .open = video_exclusive_open, |
271 | .release = video_exclusive_release, | 289 | .release = video_exclusive_release, |
272 | .ioctl = fmi_ioctl, | 290 | .ioctl = video_ioctl2, |
273 | .compat_ioctl = v4l_compat_ioctl32, | 291 | .compat_ioctl = v4l_compat_ioctl32, |
274 | .llseek = no_llseek, | 292 | .llseek = no_llseek, |
275 | }; | 293 | }; |
@@ -281,6 +299,18 @@ static struct video_device fmi_radio= | |||
281 | .type = VID_TYPE_TUNER, | 299 | .type = VID_TYPE_TUNER, |
282 | .hardware = 0, | 300 | .hardware = 0, |
283 | .fops = &fmi_fops, | 301 | .fops = &fmi_fops, |
302 | .vidioc_querycap = vidioc_querycap, | ||
303 | .vidioc_g_tuner = vidioc_g_tuner, | ||
304 | .vidioc_s_tuner = vidioc_s_tuner, | ||
305 | .vidioc_g_audio = vidioc_g_audio, | ||
306 | .vidioc_s_audio = vidioc_s_audio, | ||
307 | .vidioc_g_input = vidioc_g_input, | ||
308 | .vidioc_s_input = vidioc_s_input, | ||
309 | .vidioc_g_frequency = vidioc_g_frequency, | ||
310 | .vidioc_s_frequency = vidioc_s_frequency, | ||
311 | .vidioc_queryctrl = vidioc_queryctrl, | ||
312 | .vidioc_g_ctrl = vidioc_g_ctrl, | ||
313 | .vidioc_s_ctrl = vidioc_s_ctrl, | ||
284 | }; | 314 | }; |
285 | 315 | ||
286 | /* ladis: this is my card. does any other types exist? */ | 316 | /* ladis: this is my card. does any other types exist? */ |
diff --git a/drivers/media/radio/radio-sf16fmr2.c b/drivers/media/radio/radio-sf16fmr2.c index b96fafe1f9da..e6c125def5cb 100644 --- a/drivers/media/radio/radio-sf16fmr2.c +++ b/drivers/media/radio/radio-sf16fmr2.c | |||
@@ -226,186 +226,204 @@ static int fmr2_setvolume(struct fmr2_device *dev) | |||
226 | return 0; | 226 | return 0; |
227 | } | 227 | } |
228 | 228 | ||
229 | static int fmr2_do_ioctl(struct inode *inode, struct file *file, | 229 | static int vidioc_querycap(struct file *file, void *priv, |
230 | unsigned int cmd, void *arg) | 230 | struct v4l2_capability *v) |
231 | { | 231 | { |
232 | strlcpy(v->driver, "radio-sf16fmr2", sizeof(v->driver)); | ||
233 | strlcpy(v->card, "SF16-FMR2 radio", sizeof(v->card)); | ||
234 | sprintf(v->bus_info, "ISA"); | ||
235 | v->version = RADIO_VERSION; | ||
236 | v->capabilities = V4L2_CAP_TUNER; | ||
237 | return 0; | ||
238 | } | ||
239 | |||
240 | static int vidioc_g_tuner(struct file *file, void *priv, | ||
241 | struct v4l2_tuner *v) | ||
242 | { | ||
243 | int mult; | ||
232 | struct video_device *dev = video_devdata(file); | 244 | struct video_device *dev = video_devdata(file); |
233 | struct fmr2_device *fmr2 = dev->priv; | 245 | struct fmr2_device *fmr2 = dev->priv; |
234 | debug_print((KERN_DEBUG "freq %ld flags %d vol %d mute %d " | ||
235 | "stereo %d type %d\n", | ||
236 | fmr2->curfreq, fmr2->flags, fmr2->curvol, fmr2->mute, | ||
237 | fmr2->stereo, fmr2->card_type)); | ||
238 | 246 | ||
239 | switch(cmd) | 247 | if (v->index > 0) |
240 | { | 248 | return -EINVAL; |
241 | case VIDIOC_QUERYCAP: | ||
242 | { | ||
243 | struct v4l2_capability *v = arg; | ||
244 | memset(v,0,sizeof(*v)); | ||
245 | strlcpy(v->driver, "radio-sf16fmr2", sizeof (v->driver)); | ||
246 | strlcpy(v->card, "SF16-FMR2 radio", sizeof (v->card)); | ||
247 | sprintf(v->bus_info,"ISA"); | ||
248 | v->version = RADIO_VERSION; | ||
249 | v->capabilities = V4L2_CAP_TUNER; | ||
250 | 249 | ||
251 | return 0; | 250 | strcpy(v->name, "FM"); |
252 | } | 251 | v->type = V4L2_TUNER_RADIO; |
253 | case VIDIOC_G_TUNER: | ||
254 | { | ||
255 | struct v4l2_tuner *v = arg; | ||
256 | int mult; | ||
257 | |||
258 | if (v->index > 0) | ||
259 | return -EINVAL; | ||
260 | |||
261 | memset(v,0,sizeof(*v)); | ||
262 | strcpy(v->name, "FM"); | ||
263 | v->type = V4L2_TUNER_RADIO; | ||
264 | |||
265 | mult = (fmr2->flags & V4L2_TUNER_CAP_LOW) ? 1 : 1000; | ||
266 | v->rangelow = RSF16_MINFREQ/mult; | ||
267 | v->rangehigh = RSF16_MAXFREQ/mult; | ||
268 | v->rxsubchans =V4L2_TUNER_SUB_MONO | V4L2_TUNER_MODE_STEREO; | ||
269 | v->capability=fmr2->flags&V4L2_TUNER_CAP_LOW; | ||
270 | |||
271 | v->audmode = fmr2->stereo ? V4L2_TUNER_MODE_STEREO: | ||
272 | V4L2_TUNER_MODE_MONO; | ||
273 | mutex_lock(&lock); | ||
274 | v->signal = fmr2_getsigstr(fmr2); | ||
275 | mutex_unlock(&lock); | ||
276 | 252 | ||
277 | return 0; | 253 | mult = (fmr2->flags & V4L2_TUNER_CAP_LOW) ? 1 : 1000; |
278 | } | 254 | v->rangelow = RSF16_MINFREQ/mult; |
279 | case VIDIOC_S_TUNER: | 255 | v->rangehigh = RSF16_MAXFREQ/mult; |
280 | { | 256 | v->rxsubchans = V4L2_TUNER_SUB_MONO | V4L2_TUNER_MODE_STEREO; |
281 | struct v4l2_tuner *v = arg; | 257 | v->capability = fmr2->flags&V4L2_TUNER_CAP_LOW; |
258 | v->audmode = fmr2->stereo ? V4L2_TUNER_MODE_STEREO: | ||
259 | V4L2_TUNER_MODE_MONO; | ||
260 | mutex_lock(&lock); | ||
261 | v->signal = fmr2_getsigstr(fmr2); | ||
262 | mutex_unlock(&lock); | ||
263 | return 0; | ||
264 | } | ||
282 | 265 | ||
283 | if (v->index > 0) | 266 | static int vidioc_s_tuner(struct file *file, void *priv, |
284 | return -EINVAL; | 267 | struct v4l2_tuner *v) |
268 | { | ||
269 | if (v->index > 0) | ||
270 | return -EINVAL; | ||
271 | return 0; | ||
272 | } | ||
285 | 273 | ||
286 | return 0; | 274 | static int vidioc_s_frequency(struct file *file, void *priv, |
287 | } | 275 | struct v4l2_frequency *f) |
288 | case VIDIOC_S_FREQUENCY: | 276 | { |
289 | { | 277 | struct video_device *dev = video_devdata(file); |
290 | struct v4l2_frequency *f = arg; | 278 | struct fmr2_device *fmr2 = dev->priv; |
291 | |||
292 | if (!(fmr2->flags & V4L2_TUNER_CAP_LOW)) | ||
293 | f->frequency *= 1000; | ||
294 | if (f->frequency < RSF16_MINFREQ || | ||
295 | f->frequency > RSF16_MAXFREQ ) | ||
296 | return -EINVAL; | ||
297 | /*rounding in steps of 200 to match th freq | ||
298 | that will be used */ | ||
299 | fmr2->curfreq = (f->frequency/200)*200; | ||
300 | |||
301 | /* set card freq (if not muted) */ | ||
302 | if (fmr2->curvol && !fmr2->mute) | ||
303 | { | ||
304 | mutex_lock(&lock); | ||
305 | fmr2_setfreq(fmr2); | ||
306 | mutex_unlock(&lock); | ||
307 | } | ||
308 | 279 | ||
309 | return 0; | 280 | if (!(fmr2->flags & V4L2_TUNER_CAP_LOW)) |
310 | } | 281 | f->frequency *= 1000; |
311 | case VIDIOC_G_FREQUENCY: | 282 | if (f->frequency < RSF16_MINFREQ || |
312 | { | 283 | f->frequency > RSF16_MAXFREQ ) |
313 | struct v4l2_frequency *f = arg; | 284 | return -EINVAL; |
285 | /*rounding in steps of 200 to match th freq | ||
286 | that will be used */ | ||
287 | fmr2->curfreq = (f->frequency/200)*200; | ||
288 | |||
289 | /* set card freq (if not muted) */ | ||
290 | if (fmr2->curvol && !fmr2->mute) { | ||
291 | mutex_lock(&lock); | ||
292 | fmr2_setfreq(fmr2); | ||
293 | mutex_unlock(&lock); | ||
294 | } | ||
295 | return 0; | ||
296 | } | ||
297 | |||
298 | static int vidioc_g_frequency(struct file *file, void *priv, | ||
299 | struct v4l2_frequency *f) | ||
300 | { | ||
301 | struct video_device *dev = video_devdata(file); | ||
302 | struct fmr2_device *fmr2 = dev->priv; | ||
314 | 303 | ||
315 | f->type = V4L2_TUNER_RADIO; | 304 | f->type = V4L2_TUNER_RADIO; |
316 | f->frequency = fmr2->curfreq; | 305 | f->frequency = fmr2->curfreq; |
317 | if (!(fmr2->flags & V4L2_TUNER_CAP_LOW)) | 306 | if (!(fmr2->flags & V4L2_TUNER_CAP_LOW)) |
318 | f->frequency /= 1000; | 307 | f->frequency /= 1000; |
308 | return 0; | ||
309 | } | ||
319 | 310 | ||
311 | static int vidioc_queryctrl(struct file *file, void *priv, | ||
312 | struct v4l2_queryctrl *qc) | ||
313 | { | ||
314 | int i; | ||
315 | struct video_device *dev = video_devdata(file); | ||
316 | struct fmr2_device *fmr2 = dev->priv; | ||
317 | |||
318 | for (i = 0; i < ARRAY_SIZE(radio_qctrl); i++) { | ||
319 | if ((fmr2->card_type != 11) | ||
320 | && V4L2_CID_AUDIO_VOLUME) | ||
321 | radio_qctrl[i].step = 65535; | ||
322 | if (qc->id && qc->id == radio_qctrl[i].id) { | ||
323 | memcpy(qc, &(radio_qctrl[i]), | ||
324 | sizeof(*qc)); | ||
320 | return 0; | 325 | return 0; |
321 | } | 326 | } |
322 | case VIDIOC_QUERYCTRL: | 327 | } |
323 | { | 328 | return -EINVAL; |
324 | struct v4l2_queryctrl *qc = arg; | 329 | } |
325 | int i; | 330 | |
326 | 331 | static int vidioc_g_ctrl(struct file *file, void *priv, | |
327 | for (i = 0; i < ARRAY_SIZE(radio_qctrl); i++) { | 332 | struct v4l2_control *ctrl) |
328 | if ((fmr2->card_type != 11) | 333 | { |
329 | && V4L2_CID_AUDIO_VOLUME) | 334 | struct video_device *dev = video_devdata(file); |
330 | radio_qctrl[i].step=65535; | 335 | struct fmr2_device *fmr2 = dev->priv; |
331 | if (qc->id && qc->id == radio_qctrl[i].id) { | 336 | |
332 | memcpy(qc, &(radio_qctrl[i]), | 337 | switch (ctrl->id) { |
333 | sizeof(*qc)); | 338 | case V4L2_CID_AUDIO_MUTE: |
334 | return (0); | 339 | ctrl->value = fmr2->mute; |
335 | } | 340 | return 0; |
336 | } | 341 | case V4L2_CID_AUDIO_VOLUME: |
337 | return -EINVAL; | 342 | ctrl->value = fmr2->curvol; |
343 | return 0; | ||
344 | } | ||
345 | return -EINVAL; | ||
346 | } | ||
347 | |||
348 | static int vidioc_s_ctrl(struct file *file, void *priv, | ||
349 | struct v4l2_control *ctrl) | ||
350 | { | ||
351 | struct video_device *dev = video_devdata(file); | ||
352 | struct fmr2_device *fmr2 = dev->priv; | ||
353 | |||
354 | switch (ctrl->id) { | ||
355 | case V4L2_CID_AUDIO_MUTE: | ||
356 | fmr2->mute = ctrl->value; | ||
357 | if (fmr2->card_type != 11) { | ||
358 | if (!fmr2->mute) | ||
359 | fmr2->curvol = 65535; | ||
360 | else | ||
361 | fmr2->curvol = 0; | ||
338 | } | 362 | } |
339 | case VIDIOC_G_CTRL: | 363 | break; |
340 | { | 364 | case V4L2_CID_AUDIO_VOLUME: |
341 | struct v4l2_control *ctrl= arg; | 365 | fmr2->curvol = ctrl->value; |
342 | 366 | if (fmr2->card_type != 11) { | |
343 | switch (ctrl->id) { | 367 | if (fmr2->curvol) { |
344 | case V4L2_CID_AUDIO_MUTE: | 368 | fmr2->curvol = 65535; |
345 | ctrl->value=fmr2->mute; | 369 | fmr2->mute = 0; |
346 | return (0); | 370 | } else { |
347 | case V4L2_CID_AUDIO_VOLUME: | 371 | fmr2->curvol = 0; |
348 | ctrl->value=fmr2->curvol; | 372 | fmr2->mute = 1; |
349 | return (0); | ||
350 | } | 373 | } |
351 | return -EINVAL; | ||
352 | } | 374 | } |
353 | case VIDIOC_S_CTRL: | 375 | break; |
354 | { | 376 | default: |
355 | struct v4l2_control *ctrl= arg; | 377 | return -EINVAL; |
356 | 378 | } | |
357 | switch (ctrl->id) { | 379 | |
358 | case V4L2_CID_AUDIO_MUTE: | ||
359 | fmr2->mute=ctrl->value; | ||
360 | if (fmr2->card_type != 11) { | ||
361 | if (!fmr2->mute) { | ||
362 | fmr2->curvol = 65535; | ||
363 | } else { | ||
364 | fmr2->curvol = 0; | ||
365 | } | ||
366 | } | ||
367 | break; | ||
368 | case V4L2_CID_AUDIO_VOLUME: | ||
369 | fmr2->curvol = ctrl->value; | ||
370 | if (fmr2->card_type != 11) { | ||
371 | if (fmr2->curvol) { | ||
372 | fmr2->curvol = 65535; | ||
373 | fmr2->mute = 0; | ||
374 | } else { | ||
375 | fmr2->curvol = 0; | ||
376 | fmr2->mute = 1; | ||
377 | } | ||
378 | } | ||
379 | break; | ||
380 | default: | ||
381 | return -EINVAL; | ||
382 | } | ||
383 | #ifdef DEBUG | 380 | #ifdef DEBUG |
384 | if (fmr2->curvol && !fmr2->mute) | 381 | if (fmr2->curvol && !fmr2->mute) |
385 | printk(KERN_DEBUG "unmute\n"); | 382 | printk(KERN_DEBUG "unmute\n"); |
386 | else | 383 | else |
387 | printk(KERN_DEBUG "mute\n"); | 384 | printk(KERN_DEBUG "mute\n"); |
388 | #endif | 385 | #endif |
389 | mutex_lock(&lock); | ||
390 | if (fmr2->curvol && !fmr2->mute) { | ||
391 | fmr2_setvolume(fmr2); | ||
392 | fmr2_setfreq(fmr2); | ||
393 | } else | ||
394 | fmr2_mute(fmr2->port); | ||
395 | mutex_unlock(&lock); | ||
396 | return (0); | ||
397 | } | ||
398 | default: | ||
399 | return v4l_compat_translate_ioctl(inode,file,cmd,arg, | ||
400 | fmr2_do_ioctl); | ||
401 | 386 | ||
402 | } | 387 | mutex_lock(&lock); |
388 | if (fmr2->curvol && !fmr2->mute) { | ||
389 | fmr2_setvolume(fmr2); | ||
390 | fmr2_setfreq(fmr2); | ||
391 | } else | ||
392 | fmr2_mute(fmr2->port); | ||
393 | mutex_unlock(&lock); | ||
394 | return 0; | ||
403 | } | 395 | } |
404 | 396 | ||
405 | static int fmr2_ioctl(struct inode *inode, struct file *file, | 397 | static int vidioc_g_audio(struct file *file, void *priv, |
406 | unsigned int cmd, unsigned long arg) | 398 | struct v4l2_audio *a) |
407 | { | 399 | { |
408 | return video_usercopy(inode, file, cmd, arg, fmr2_do_ioctl); | 400 | if (a->index > 1) |
401 | return -EINVAL; | ||
402 | |||
403 | strcpy(a->name, "Radio"); | ||
404 | a->capability = V4L2_AUDCAP_STEREO; | ||
405 | return 0; | ||
406 | } | ||
407 | |||
408 | static int vidioc_g_input(struct file *filp, void *priv, unsigned int *i) | ||
409 | { | ||
410 | *i = 0; | ||
411 | return 0; | ||
412 | } | ||
413 | |||
414 | static int vidioc_s_input(struct file *filp, void *priv, unsigned int i) | ||
415 | { | ||
416 | if (i != 0) | ||
417 | return -EINVAL; | ||
418 | return 0; | ||
419 | } | ||
420 | |||
421 | static int vidioc_s_audio(struct file *file, void *priv, | ||
422 | struct v4l2_audio *a) | ||
423 | { | ||
424 | if (a->index != 0) | ||
425 | return -EINVAL; | ||
426 | return 0; | ||
409 | } | 427 | } |
410 | 428 | ||
411 | static struct fmr2_device fmr2_unit; | 429 | static struct fmr2_device fmr2_unit; |
@@ -414,7 +432,7 @@ static const struct file_operations fmr2_fops = { | |||
414 | .owner = THIS_MODULE, | 432 | .owner = THIS_MODULE, |
415 | .open = video_exclusive_open, | 433 | .open = video_exclusive_open, |
416 | .release = video_exclusive_release, | 434 | .release = video_exclusive_release, |
417 | .ioctl = fmr2_ioctl, | 435 | .ioctl = video_ioctl2, |
418 | .compat_ioctl = v4l_compat_ioctl32, | 436 | .compat_ioctl = v4l_compat_ioctl32, |
419 | .llseek = no_llseek, | 437 | .llseek = no_llseek, |
420 | }; | 438 | }; |
@@ -426,6 +444,18 @@ static struct video_device fmr2_radio= | |||
426 | . type = VID_TYPE_TUNER, | 444 | . type = VID_TYPE_TUNER, |
427 | .hardware = 0, | 445 | .hardware = 0, |
428 | .fops = &fmr2_fops, | 446 | .fops = &fmr2_fops, |
447 | .vidioc_querycap = vidioc_querycap, | ||
448 | .vidioc_g_tuner = vidioc_g_tuner, | ||
449 | .vidioc_s_tuner = vidioc_s_tuner, | ||
450 | .vidioc_g_audio = vidioc_g_audio, | ||
451 | .vidioc_s_audio = vidioc_s_audio, | ||
452 | .vidioc_g_input = vidioc_g_input, | ||
453 | .vidioc_s_input = vidioc_s_input, | ||
454 | .vidioc_g_frequency = vidioc_g_frequency, | ||
455 | .vidioc_s_frequency = vidioc_s_frequency, | ||
456 | .vidioc_queryctrl = vidioc_queryctrl, | ||
457 | .vidioc_g_ctrl = vidioc_g_ctrl, | ||
458 | .vidioc_s_ctrl = vidioc_s_ctrl, | ||
429 | }; | 459 | }; |
430 | 460 | ||
431 | static int __init fmr2_init(void) | 461 | static int __init fmr2_init(void) |
diff --git a/drivers/media/radio/radio-terratec.c b/drivers/media/radio/radio-terratec.c index d59a27accb84..e43acfd7e533 100644 --- a/drivers/media/radio/radio-terratec.c +++ b/drivers/media/radio/radio-terratec.c | |||
@@ -205,135 +205,152 @@ static int tt_getsigstr(struct tt_device *dev) /* TODO */ | |||
205 | return 1; /* signal present */ | 205 | return 1; /* signal present */ |
206 | } | 206 | } |
207 | 207 | ||
208 | static int vidioc_querycap(struct file *file, void *priv, | ||
209 | struct v4l2_capability *v) | ||
210 | { | ||
211 | strlcpy(v->driver, "radio-terratec", sizeof(v->driver)); | ||
212 | strlcpy(v->card, "ActiveRadio", sizeof(v->card)); | ||
213 | sprintf(v->bus_info, "ISA"); | ||
214 | v->version = RADIO_VERSION; | ||
215 | v->capabilities = V4L2_CAP_TUNER; | ||
216 | return 0; | ||
217 | } | ||
208 | 218 | ||
209 | /* implement the video4linux api */ | 219 | static int vidioc_g_tuner(struct file *file, void *priv, |
210 | 220 | struct v4l2_tuner *v) | |
211 | static int tt_do_ioctl(struct inode *inode, struct file *file, | ||
212 | unsigned int cmd, void *arg) | ||
213 | { | 221 | { |
214 | struct video_device *dev = video_devdata(file); | 222 | struct video_device *dev = video_devdata(file); |
215 | struct tt_device *tt=dev->priv; | 223 | struct tt_device *tt = dev->priv; |
216 | 224 | ||
217 | switch(cmd) | 225 | if (v->index > 0) |
218 | { | 226 | return -EINVAL; |
219 | case VIDIOC_QUERYCAP: | ||
220 | { | ||
221 | struct v4l2_capability *v = arg; | ||
222 | memset(v,0,sizeof(*v)); | ||
223 | strlcpy(v->driver, "radio-terratec", sizeof (v->driver)); | ||
224 | strlcpy(v->card, "ActiveRadio", sizeof (v->card)); | ||
225 | sprintf(v->bus_info,"ISA"); | ||
226 | v->version = RADIO_VERSION; | ||
227 | v->capabilities = V4L2_CAP_TUNER; | ||
228 | 227 | ||
229 | return 0; | 228 | strcpy(v->name, "FM"); |
230 | } | 229 | v->type = V4L2_TUNER_RADIO; |
231 | case VIDIOC_G_TUNER: | 230 | v->rangelow = (87*16000); |
232 | { | 231 | v->rangehigh = (108*16000); |
233 | struct v4l2_tuner *v = arg; | 232 | v->rxsubchans = V4L2_TUNER_SUB_MONO; |
233 | v->capability = V4L2_TUNER_CAP_LOW; | ||
234 | v->audmode = V4L2_TUNER_MODE_MONO; | ||
235 | v->signal = 0xFFFF*tt_getsigstr(tt); | ||
236 | return 0; | ||
237 | } | ||
234 | 238 | ||
235 | if (v->index > 0) | 239 | static int vidioc_s_tuner(struct file *file, void *priv, |
236 | return -EINVAL; | 240 | struct v4l2_tuner *v) |
241 | { | ||
242 | if (v->index > 0) | ||
243 | return -EINVAL; | ||
244 | return 0; | ||
245 | } | ||
237 | 246 | ||
238 | memset(v,0,sizeof(*v)); | 247 | static int vidioc_s_frequency(struct file *file, void *priv, |
239 | strcpy(v->name, "FM"); | 248 | struct v4l2_frequency *f) |
240 | v->type = V4L2_TUNER_RADIO; | 249 | { |
250 | struct video_device *dev = video_devdata(file); | ||
251 | struct tt_device *tt = dev->priv; | ||
241 | 252 | ||
242 | v->rangelow=(87*16000); | 253 | tt->curfreq = f->frequency; |
243 | v->rangehigh=(108*16000); | 254 | tt_setfreq(tt, tt->curfreq); |
244 | v->rxsubchans =V4L2_TUNER_SUB_MONO; | 255 | return 0; |
245 | v->capability=V4L2_TUNER_CAP_LOW; | 256 | } |
246 | v->audmode = V4L2_TUNER_MODE_MONO; | ||
247 | v->signal=0xFFFF*tt_getsigstr(tt); | ||
248 | 257 | ||
249 | return 0; | 258 | static int vidioc_g_frequency(struct file *file, void *priv, |
250 | } | 259 | struct v4l2_frequency *f) |
251 | case VIDIOC_S_TUNER: | 260 | { |
252 | { | 261 | struct video_device *dev = video_devdata(file); |
253 | struct v4l2_tuner *v = arg; | 262 | struct tt_device *tt = dev->priv; |
254 | 263 | ||
255 | if (v->index > 0) | 264 | f->type = V4L2_TUNER_RADIO; |
256 | return -EINVAL; | 265 | f->frequency = tt->curfreq; |
266 | return 0; | ||
267 | } | ||
257 | 268 | ||
258 | return 0; | 269 | static int vidioc_queryctrl(struct file *file, void *priv, |
259 | } | 270 | struct v4l2_queryctrl *qc) |
260 | case VIDIOC_S_FREQUENCY: | 271 | { |
261 | { | 272 | int i; |
262 | struct v4l2_frequency *f = arg; | ||
263 | 273 | ||
264 | tt->curfreq = f->frequency; | 274 | for (i = 0; i < ARRAY_SIZE(radio_qctrl); i++) { |
265 | tt_setfreq(tt, tt->curfreq); | 275 | if (qc->id && qc->id == radio_qctrl[i].id) { |
276 | memcpy(qc, &(radio_qctrl[i]), | ||
277 | sizeof(*qc)); | ||
266 | return 0; | 278 | return 0; |
267 | } | 279 | } |
268 | case VIDIOC_G_FREQUENCY: | 280 | } |
269 | { | 281 | return -EINVAL; |
270 | struct v4l2_frequency *f = arg; | 282 | } |
271 | 283 | ||
272 | f->type = V4L2_TUNER_RADIO; | 284 | static int vidioc_g_ctrl(struct file *file, void *priv, |
273 | f->frequency = tt->curfreq; | 285 | struct v4l2_control *ctrl) |
286 | { | ||
287 | struct video_device *dev = video_devdata(file); | ||
288 | struct tt_device *tt = dev->priv; | ||
274 | 289 | ||
275 | return 0; | 290 | switch (ctrl->id) { |
276 | } | 291 | case V4L2_CID_AUDIO_MUTE: |
277 | case VIDIOC_QUERYCTRL: | 292 | if (tt->muted) |
278 | { | 293 | ctrl->value = 1; |
279 | struct v4l2_queryctrl *qc = arg; | 294 | else |
280 | int i; | 295 | ctrl->value = 0; |
281 | 296 | return 0; | |
282 | for (i = 0; i < ARRAY_SIZE(radio_qctrl); i++) { | 297 | case V4L2_CID_AUDIO_VOLUME: |
283 | if (qc->id && qc->id == radio_qctrl[i].id) { | 298 | ctrl->value = tt->curvol * 6554; |
284 | memcpy(qc, &(radio_qctrl[i]), | 299 | return 0; |
285 | sizeof(*qc)); | 300 | } |
286 | return (0); | 301 | return -EINVAL; |
287 | } | 302 | } |
288 | } | ||
289 | return -EINVAL; | ||
290 | } | ||
291 | case VIDIOC_G_CTRL: | ||
292 | { | ||
293 | struct v4l2_control *ctrl= arg; | ||
294 | |||
295 | switch (ctrl->id) { | ||
296 | case V4L2_CID_AUDIO_MUTE: | ||
297 | if (tt->muted) | ||
298 | ctrl->value=1; | ||
299 | else | ||
300 | ctrl->value=0; | ||
301 | return (0); | ||
302 | case V4L2_CID_AUDIO_VOLUME: | ||
303 | ctrl->value=tt->curvol * 6554; | ||
304 | return (0); | ||
305 | } | ||
306 | return -EINVAL; | ||
307 | } | ||
308 | case VIDIOC_S_CTRL: | ||
309 | { | ||
310 | struct v4l2_control *ctrl= arg; | ||
311 | |||
312 | switch (ctrl->id) { | ||
313 | case V4L2_CID_AUDIO_MUTE: | ||
314 | if (ctrl->value) { | ||
315 | tt_mute(tt); | ||
316 | } else { | ||
317 | tt_setvol(tt,tt->curvol); | ||
318 | } | ||
319 | return (0); | ||
320 | case V4L2_CID_AUDIO_VOLUME: | ||
321 | tt_setvol(tt,ctrl->value); | ||
322 | return (0); | ||
323 | } | ||
324 | return -EINVAL; | ||
325 | } | ||
326 | 303 | ||
327 | default: | 304 | static int vidioc_s_ctrl(struct file *file, void *priv, |
328 | return v4l_compat_translate_ioctl(inode,file,cmd,arg, | 305 | struct v4l2_control *ctrl) |
329 | tt_do_ioctl); | 306 | { |
307 | struct video_device *dev = video_devdata(file); | ||
308 | struct tt_device *tt = dev->priv; | ||
309 | |||
310 | switch (ctrl->id) { | ||
311 | case V4L2_CID_AUDIO_MUTE: | ||
312 | if (ctrl->value) | ||
313 | tt_mute(tt); | ||
314 | else | ||
315 | tt_setvol(tt,tt->curvol); | ||
316 | return 0; | ||
317 | case V4L2_CID_AUDIO_VOLUME: | ||
318 | tt_setvol(tt,ctrl->value); | ||
319 | return 0; | ||
330 | } | 320 | } |
321 | return -EINVAL; | ||
322 | } | ||
323 | |||
324 | static int vidioc_g_audio(struct file *file, void *priv, | ||
325 | struct v4l2_audio *a) | ||
326 | { | ||
327 | if (a->index > 1) | ||
328 | return -EINVAL; | ||
329 | |||
330 | strcpy(a->name, "Radio"); | ||
331 | a->capability = V4L2_AUDCAP_STEREO; | ||
332 | return 0; | ||
333 | } | ||
334 | |||
335 | static int vidioc_g_input(struct file *filp, void *priv, unsigned int *i) | ||
336 | { | ||
337 | *i = 0; | ||
338 | return 0; | ||
331 | } | 339 | } |
332 | 340 | ||
333 | static int tt_ioctl(struct inode *inode, struct file *file, | 341 | static int vidioc_s_input(struct file *filp, void *priv, unsigned int i) |
334 | unsigned int cmd, unsigned long arg) | ||
335 | { | 342 | { |
336 | return video_usercopy(inode, file, cmd, arg, tt_do_ioctl); | 343 | if (i != 0) |
344 | return -EINVAL; | ||
345 | return 0; | ||
346 | } | ||
347 | |||
348 | static int vidioc_s_audio(struct file *file, void *priv, | ||
349 | struct v4l2_audio *a) | ||
350 | { | ||
351 | if (a->index != 0) | ||
352 | return -EINVAL; | ||
353 | return 0; | ||
337 | } | 354 | } |
338 | 355 | ||
339 | static struct tt_device terratec_unit; | 356 | static struct tt_device terratec_unit; |
@@ -342,7 +359,7 @@ static const struct file_operations terratec_fops = { | |||
342 | .owner = THIS_MODULE, | 359 | .owner = THIS_MODULE, |
343 | .open = video_exclusive_open, | 360 | .open = video_exclusive_open, |
344 | .release = video_exclusive_release, | 361 | .release = video_exclusive_release, |
345 | .ioctl = tt_ioctl, | 362 | .ioctl = video_ioctl2, |
346 | .compat_ioctl = v4l_compat_ioctl32, | 363 | .compat_ioctl = v4l_compat_ioctl32, |
347 | .llseek = no_llseek, | 364 | .llseek = no_llseek, |
348 | }; | 365 | }; |
@@ -354,6 +371,18 @@ static struct video_device terratec_radio= | |||
354 | .type = VID_TYPE_TUNER, | 371 | .type = VID_TYPE_TUNER, |
355 | .hardware = 0, | 372 | .hardware = 0, |
356 | .fops = &terratec_fops, | 373 | .fops = &terratec_fops, |
374 | .vidioc_querycap = vidioc_querycap, | ||
375 | .vidioc_g_tuner = vidioc_g_tuner, | ||
376 | .vidioc_s_tuner = vidioc_s_tuner, | ||
377 | .vidioc_g_frequency = vidioc_g_frequency, | ||
378 | .vidioc_s_frequency = vidioc_s_frequency, | ||
379 | .vidioc_queryctrl = vidioc_queryctrl, | ||
380 | .vidioc_g_ctrl = vidioc_g_ctrl, | ||
381 | .vidioc_s_ctrl = vidioc_s_ctrl, | ||
382 | .vidioc_g_audio = vidioc_g_audio, | ||
383 | .vidioc_s_audio = vidioc_s_audio, | ||
384 | .vidioc_g_input = vidioc_g_input, | ||
385 | .vidioc_s_input = vidioc_s_input, | ||
357 | }; | 386 | }; |
358 | 387 | ||
359 | static int __init terratec_init(void) | 388 | static int __init terratec_init(void) |
diff --git a/drivers/media/radio/radio-trust.c b/drivers/media/radio/radio-trust.c index 6d7f1e7116ea..c27c629d99df 100644 --- a/drivers/media/radio/radio-trust.c +++ b/drivers/media/radio/radio-trust.c | |||
@@ -192,144 +192,154 @@ static void tr_setfreq(unsigned long f) | |||
192 | write_i2c(5, TSA6060T_ADDR, (f << 1) | 1, f >> 7, 0x60 | ((f >> 15) & 1), 0); | 192 | write_i2c(5, TSA6060T_ADDR, (f << 1) | 1, f >> 7, 0x60 | ((f >> 15) & 1), 0); |
193 | } | 193 | } |
194 | 194 | ||
195 | static int tr_do_ioctl(struct inode *inode, struct file *file, | 195 | static int vidioc_querycap(struct file *file, void *priv, |
196 | unsigned int cmd, void *arg) | 196 | struct v4l2_capability *v) |
197 | { | 197 | { |
198 | switch(cmd) | 198 | strlcpy(v->driver, "radio-trust", sizeof(v->driver)); |
199 | { | 199 | strlcpy(v->card, "Trust FM Radio", sizeof(v->card)); |
200 | case VIDIOC_QUERYCAP: | 200 | sprintf(v->bus_info, "ISA"); |
201 | { | 201 | v->version = RADIO_VERSION; |
202 | struct v4l2_capability *v = arg; | 202 | v->capabilities = V4L2_CAP_TUNER; |
203 | memset(v,0,sizeof(*v)); | 203 | return 0; |
204 | strlcpy(v->driver, "radio-trust", sizeof (v->driver)); | 204 | } |
205 | strlcpy(v->card, "Trust FM Radio", sizeof (v->card)); | ||
206 | sprintf(v->bus_info,"ISA"); | ||
207 | v->version = RADIO_VERSION; | ||
208 | v->capabilities = V4L2_CAP_TUNER; | ||
209 | 205 | ||
210 | return 0; | 206 | static int vidioc_g_tuner(struct file *file, void *priv, |
211 | } | 207 | struct v4l2_tuner *v) |
212 | case VIDIOC_G_TUNER: | 208 | { |
213 | { | 209 | if (v->index > 0) |
214 | struct v4l2_tuner *v = arg; | 210 | return -EINVAL; |
215 | |||
216 | if (v->index > 0) | ||
217 | return -EINVAL; | ||
218 | |||
219 | memset(v,0,sizeof(*v)); | ||
220 | strcpy(v->name, "FM"); | ||
221 | v->type = V4L2_TUNER_RADIO; | ||
222 | |||
223 | v->rangelow=(87.5*16000); | ||
224 | v->rangehigh=(108*16000); | ||
225 | v->rxsubchans =V4L2_TUNER_SUB_MONO|V4L2_TUNER_SUB_STEREO; | ||
226 | v->capability=V4L2_TUNER_CAP_LOW; | ||
227 | if(tr_getstereo()) | ||
228 | v->audmode = V4L2_TUNER_MODE_STEREO; | ||
229 | else | ||
230 | v->audmode = V4L2_TUNER_MODE_MONO; | ||
231 | v->signal=tr_getsigstr(); | ||
232 | 211 | ||
233 | return 0; | 212 | strcpy(v->name, "FM"); |
234 | } | 213 | v->type = V4L2_TUNER_RADIO; |
235 | case VIDIOC_S_TUNER: | 214 | v->rangelow = (87.5*16000); |
236 | { | 215 | v->rangehigh = (108*16000); |
237 | struct v4l2_tuner *v = arg; | 216 | v->rxsubchans = V4L2_TUNER_SUB_MONO|V4L2_TUNER_SUB_STEREO; |
217 | v->capability = V4L2_TUNER_CAP_LOW; | ||
218 | if (tr_getstereo()) | ||
219 | v->audmode = V4L2_TUNER_MODE_STEREO; | ||
220 | else | ||
221 | v->audmode = V4L2_TUNER_MODE_MONO; | ||
222 | v->signal = tr_getsigstr(); | ||
223 | return 0; | ||
224 | } | ||
225 | |||
226 | static int vidioc_s_tuner(struct file *file, void *priv, | ||
227 | struct v4l2_tuner *v) | ||
228 | { | ||
229 | if (v->index > 0) | ||
230 | return -EINVAL; | ||
238 | 231 | ||
239 | if (v->index > 0) | 232 | return 0; |
240 | return -EINVAL; | 233 | } |
241 | 234 | ||
242 | return 0; | 235 | static int vidioc_s_frequency(struct file *file, void *priv, |
243 | } | 236 | struct v4l2_frequency *f) |
244 | case VIDIOC_S_FREQUENCY: | 237 | { |
245 | { | 238 | curfreq = f->frequency; |
246 | struct v4l2_frequency *f = arg; | 239 | tr_setfreq(curfreq); |
240 | return 0; | ||
241 | } | ||
247 | 242 | ||
248 | curfreq = f->frequency; | 243 | static int vidioc_g_frequency(struct file *file, void *priv, |
249 | tr_setfreq(curfreq); | 244 | struct v4l2_frequency *f) |
250 | return 0; | 245 | { |
251 | } | 246 | f->type = V4L2_TUNER_RADIO; |
252 | case VIDIOC_G_FREQUENCY: | 247 | f->frequency = curfreq; |
253 | { | 248 | return 0; |
254 | struct v4l2_frequency *f = arg; | 249 | } |
255 | 250 | ||
256 | f->type = V4L2_TUNER_RADIO; | 251 | static int vidioc_queryctrl(struct file *file, void *priv, |
257 | f->frequency = curfreq; | 252 | struct v4l2_queryctrl *qc) |
253 | { | ||
254 | int i; | ||
258 | 255 | ||
256 | for (i = 0; i < ARRAY_SIZE(radio_qctrl); i++) { | ||
257 | if (qc->id && qc->id == radio_qctrl[i].id) { | ||
258 | memcpy(qc, &(radio_qctrl[i]), | ||
259 | sizeof(*qc)); | ||
259 | return 0; | 260 | return 0; |
260 | } | 261 | } |
261 | case VIDIOC_QUERYCTRL: | 262 | } |
262 | { | 263 | return -EINVAL; |
263 | struct v4l2_queryctrl *qc = arg; | 264 | } |
264 | int i; | 265 | |
265 | 266 | static int vidioc_g_ctrl(struct file *file, void *priv, | |
266 | for (i = 0; i < ARRAY_SIZE(radio_qctrl); i++) { | 267 | struct v4l2_control *ctrl) |
267 | if (qc->id && qc->id == radio_qctrl[i].id) { | 268 | { |
268 | memcpy(qc, &(radio_qctrl[i]), | 269 | switch (ctrl->id) { |
269 | sizeof(*qc)); | 270 | case V4L2_CID_AUDIO_MUTE: |
270 | return (0); | 271 | ctrl->value = curmute; |
271 | } | 272 | return 0; |
272 | } | 273 | case V4L2_CID_AUDIO_VOLUME: |
273 | return -EINVAL; | 274 | ctrl->value = curvol * 2048; |
274 | } | 275 | return 0; |
275 | case VIDIOC_G_CTRL: | 276 | case V4L2_CID_AUDIO_BASS: |
276 | { | 277 | ctrl->value = curbass * 4370; |
277 | struct v4l2_control *ctrl= arg; | 278 | return 0; |
278 | 279 | case V4L2_CID_AUDIO_TREBLE: | |
279 | switch (ctrl->id) { | 280 | ctrl->value = curtreble * 4370; |
280 | case V4L2_CID_AUDIO_MUTE: | 281 | return 0; |
281 | ctrl->value=curmute; | 282 | } |
282 | return (0); | 283 | return -EINVAL; |
283 | case V4L2_CID_AUDIO_VOLUME: | 284 | } |
284 | ctrl->value= curvol * 2048; | ||
285 | return (0); | ||
286 | case V4L2_CID_AUDIO_BASS: | ||
287 | ctrl->value= curbass * 4370; | ||
288 | return (0); | ||
289 | case V4L2_CID_AUDIO_TREBLE: | ||
290 | ctrl->value= curtreble * 4370; | ||
291 | return (0); | ||
292 | } | ||
293 | return -EINVAL; | ||
294 | } | ||
295 | case VIDIOC_S_CTRL: | ||
296 | { | ||
297 | struct v4l2_control *ctrl= arg; | ||
298 | |||
299 | switch (ctrl->id) { | ||
300 | case V4L2_CID_AUDIO_MUTE: | ||
301 | tr_setmute(ctrl->value); | ||
302 | return 0; | ||
303 | case V4L2_CID_AUDIO_VOLUME: | ||
304 | tr_setvol(ctrl->value); | ||
305 | return 0; | ||
306 | case V4L2_CID_AUDIO_BASS: | ||
307 | tr_setbass(ctrl->value); | ||
308 | return 0; | ||
309 | case V4L2_CID_AUDIO_TREBLE: | ||
310 | tr_settreble(ctrl->value); | ||
311 | return (0); | ||
312 | } | ||
313 | return -EINVAL; | ||
314 | } | ||
315 | 285 | ||
316 | default: | 286 | static int vidioc_s_ctrl(struct file *file, void *priv, |
317 | return v4l_compat_translate_ioctl(inode,file,cmd,arg, | 287 | struct v4l2_control *ctrl) |
318 | tr_do_ioctl); | 288 | { |
289 | switch (ctrl->id) { | ||
290 | case V4L2_CID_AUDIO_MUTE: | ||
291 | tr_setmute(ctrl->value); | ||
292 | return 0; | ||
293 | case V4L2_CID_AUDIO_VOLUME: | ||
294 | tr_setvol(ctrl->value); | ||
295 | return 0; | ||
296 | case V4L2_CID_AUDIO_BASS: | ||
297 | tr_setbass(ctrl->value); | ||
298 | return 0; | ||
299 | case V4L2_CID_AUDIO_TREBLE: | ||
300 | tr_settreble(ctrl->value); | ||
301 | return 0; | ||
319 | } | 302 | } |
303 | return -EINVAL; | ||
320 | } | 304 | } |
321 | 305 | ||
322 | static int tr_ioctl(struct inode *inode, struct file *file, | 306 | static int vidioc_g_audio(struct file *file, void *priv, |
323 | unsigned int cmd, unsigned long arg) | 307 | struct v4l2_audio *a) |
324 | { | 308 | { |
325 | return video_usercopy(inode, file, cmd, arg, tr_do_ioctl); | 309 | if (a->index > 1) |
310 | return -EINVAL; | ||
311 | |||
312 | strcpy(a->name, "Radio"); | ||
313 | a->capability = V4L2_AUDCAP_STEREO; | ||
314 | return 0; | ||
315 | } | ||
316 | |||
317 | static int vidioc_g_input(struct file *filp, void *priv, unsigned int *i) | ||
318 | { | ||
319 | *i = 0; | ||
320 | return 0; | ||
321 | } | ||
322 | |||
323 | static int vidioc_s_input(struct file *filp, void *priv, unsigned int i) | ||
324 | { | ||
325 | if (i != 0) | ||
326 | return -EINVAL; | ||
327 | return 0; | ||
328 | } | ||
329 | |||
330 | static int vidioc_s_audio(struct file *file, void *priv, | ||
331 | struct v4l2_audio *a) | ||
332 | { | ||
333 | if (a->index != 0) | ||
334 | return -EINVAL; | ||
335 | return 0; | ||
326 | } | 336 | } |
327 | 337 | ||
328 | static const struct file_operations trust_fops = { | 338 | static const struct file_operations trust_fops = { |
329 | .owner = THIS_MODULE, | 339 | .owner = THIS_MODULE, |
330 | .open = video_exclusive_open, | 340 | .open = video_exclusive_open, |
331 | .release = video_exclusive_release, | 341 | .release = video_exclusive_release, |
332 | .ioctl = tr_ioctl, | 342 | .ioctl = video_ioctl2, |
333 | .compat_ioctl = v4l_compat_ioctl32, | 343 | .compat_ioctl = v4l_compat_ioctl32, |
334 | .llseek = no_llseek, | 344 | .llseek = no_llseek, |
335 | }; | 345 | }; |
@@ -341,6 +351,18 @@ static struct video_device trust_radio= | |||
341 | .type = VID_TYPE_TUNER, | 351 | .type = VID_TYPE_TUNER, |
342 | .hardware = 0, | 352 | .hardware = 0, |
343 | .fops = &trust_fops, | 353 | .fops = &trust_fops, |
354 | .vidioc_querycap = vidioc_querycap, | ||
355 | .vidioc_g_tuner = vidioc_g_tuner, | ||
356 | .vidioc_s_tuner = vidioc_s_tuner, | ||
357 | .vidioc_g_frequency = vidioc_g_frequency, | ||
358 | .vidioc_s_frequency = vidioc_s_frequency, | ||
359 | .vidioc_queryctrl = vidioc_queryctrl, | ||
360 | .vidioc_g_ctrl = vidioc_g_ctrl, | ||
361 | .vidioc_s_ctrl = vidioc_s_ctrl, | ||
362 | .vidioc_g_audio = vidioc_g_audio, | ||
363 | .vidioc_s_audio = vidioc_s_audio, | ||
364 | .vidioc_g_input = vidioc_g_input, | ||
365 | .vidioc_s_input = vidioc_s_input, | ||
344 | }; | 366 | }; |
345 | 367 | ||
346 | static int __init trust_init(void) | 368 | static int __init trust_init(void) |
diff --git a/drivers/media/radio/radio-typhoon.c b/drivers/media/radio/radio-typhoon.c index 3031fef178cb..8ff5a23a9f01 100644 --- a/drivers/media/radio/radio-typhoon.c +++ b/drivers/media/radio/radio-typhoon.c | |||
@@ -93,8 +93,6 @@ static int typhoon_setfreq(struct typhoon_device *dev, unsigned long frequency); | |||
93 | static void typhoon_mute(struct typhoon_device *dev); | 93 | static void typhoon_mute(struct typhoon_device *dev); |
94 | static void typhoon_unmute(struct typhoon_device *dev); | 94 | static void typhoon_unmute(struct typhoon_device *dev); |
95 | static int typhoon_setvol(struct typhoon_device *dev, int vol); | 95 | static int typhoon_setvol(struct typhoon_device *dev, int vol); |
96 | static int typhoon_ioctl(struct inode *inode, struct file *file, | ||
97 | unsigned int cmd, unsigned long arg); | ||
98 | #ifdef CONFIG_RADIO_TYPHOON_PROC_FS | 96 | #ifdef CONFIG_RADIO_TYPHOON_PROC_FS |
99 | static int typhoon_get_info(char *buf, char **start, off_t offset, int len); | 97 | static int typhoon_get_info(char *buf, char **start, off_t offset, int len); |
100 | #endif | 98 | #endif |
@@ -186,129 +184,148 @@ static int typhoon_setvol(struct typhoon_device *dev, int vol) | |||
186 | return 0; | 184 | return 0; |
187 | } | 185 | } |
188 | 186 | ||
187 | static int vidioc_querycap(struct file *file, void *priv, | ||
188 | struct v4l2_capability *v) | ||
189 | { | ||
190 | strlcpy(v->driver, "radio-typhoon", sizeof(v->driver)); | ||
191 | strlcpy(v->card, "Typhoon Radio", sizeof(v->card)); | ||
192 | sprintf(v->bus_info, "ISA"); | ||
193 | v->version = RADIO_VERSION; | ||
194 | v->capabilities = V4L2_CAP_TUNER; | ||
195 | return 0; | ||
196 | } | ||
197 | |||
198 | static int vidioc_g_tuner(struct file *file, void *priv, | ||
199 | struct v4l2_tuner *v) | ||
200 | { | ||
201 | if (v->index > 0) | ||
202 | return -EINVAL; | ||
203 | |||
204 | strcpy(v->name, "FM"); | ||
205 | v->type = V4L2_TUNER_RADIO; | ||
206 | v->rangelow = (87.5*16000); | ||
207 | v->rangehigh = (108*16000); | ||
208 | v->rxsubchans = V4L2_TUNER_SUB_MONO; | ||
209 | v->capability = V4L2_TUNER_CAP_LOW; | ||
210 | v->audmode = V4L2_TUNER_MODE_MONO; | ||
211 | v->signal = 0xFFFF; /* We can't get the signal strength */ | ||
212 | return 0; | ||
213 | } | ||
189 | 214 | ||
190 | static int typhoon_do_ioctl(struct inode *inode, struct file *file, | 215 | static int vidioc_s_tuner(struct file *file, void *priv, |
191 | unsigned int cmd, void *arg) | 216 | struct v4l2_tuner *v) |
217 | { | ||
218 | if (v->index > 0) | ||
219 | return -EINVAL; | ||
220 | |||
221 | return 0; | ||
222 | } | ||
223 | |||
224 | static int vidioc_s_frequency(struct file *file, void *priv, | ||
225 | struct v4l2_frequency *f) | ||
192 | { | 226 | { |
193 | struct video_device *dev = video_devdata(file); | 227 | struct video_device *dev = video_devdata(file); |
194 | struct typhoon_device *typhoon = dev->priv; | 228 | struct typhoon_device *typhoon = dev->priv; |
195 | 229 | ||
196 | switch (cmd) { | 230 | typhoon->curfreq = f->frequency; |
197 | case VIDIOC_QUERYCAP: | 231 | typhoon_setfreq(typhoon, typhoon->curfreq); |
198 | { | 232 | return 0; |
199 | struct v4l2_capability *v = arg; | 233 | } |
200 | memset(v,0,sizeof(*v)); | ||
201 | strlcpy(v->driver, "radio-typhoon", sizeof (v->driver)); | ||
202 | strlcpy(v->card, "Typhoon Radio", sizeof (v->card)); | ||
203 | sprintf(v->bus_info,"ISA"); | ||
204 | v->version = RADIO_VERSION; | ||
205 | v->capabilities = V4L2_CAP_TUNER; | ||
206 | 234 | ||
207 | return 0; | 235 | static int vidioc_g_frequency(struct file *file, void *priv, |
208 | } | 236 | struct v4l2_frequency *f) |
209 | case VIDIOC_G_TUNER: | 237 | { |
210 | { | 238 | struct video_device *dev = video_devdata(file); |
211 | struct v4l2_tuner *v = arg; | 239 | struct typhoon_device *typhoon = dev->priv; |
212 | 240 | ||
213 | if (v->index > 0) | 241 | f->type = V4L2_TUNER_RADIO; |
214 | return -EINVAL; | 242 | f->frequency = typhoon->curfreq; |
215 | 243 | ||
216 | memset(v,0,sizeof(*v)); | 244 | return 0; |
217 | strcpy(v->name, "FM"); | 245 | } |
218 | v->type = V4L2_TUNER_RADIO; | ||
219 | 246 | ||
220 | v->rangelow=(87.5*16000); | 247 | static int vidioc_queryctrl(struct file *file, void *priv, |
221 | v->rangehigh=(108*16000); | 248 | struct v4l2_queryctrl *qc) |
222 | v->rxsubchans =V4L2_TUNER_SUB_MONO; | 249 | { |
223 | v->capability=V4L2_TUNER_CAP_LOW; | 250 | int i; |
224 | v->audmode = V4L2_TUNER_MODE_MONO; | ||
225 | v->signal = 0xFFFF; /* We can't get the signal strength */ | ||
226 | 251 | ||
252 | for (i = 0; i < ARRAY_SIZE(radio_qctrl); i++) { | ||
253 | if (qc->id && qc->id == radio_qctrl[i].id) { | ||
254 | memcpy(qc, &(radio_qctrl[i]), | ||
255 | sizeof(*qc)); | ||
227 | return 0; | 256 | return 0; |
228 | } | 257 | } |
229 | case VIDIOC_S_TUNER: | 258 | } |
230 | { | 259 | return -EINVAL; |
231 | struct v4l2_tuner *v = arg; | 260 | } |
232 | 261 | ||
233 | if (v->index > 0) | 262 | static int vidioc_g_ctrl(struct file *file, void *priv, |
234 | return -EINVAL; | 263 | struct v4l2_control *ctrl) |
264 | { | ||
265 | struct video_device *dev = video_devdata(file); | ||
266 | struct typhoon_device *typhoon = dev->priv; | ||
235 | 267 | ||
236 | return 0; | 268 | switch (ctrl->id) { |
237 | } | 269 | case V4L2_CID_AUDIO_MUTE: |
238 | case VIDIOC_S_FREQUENCY: | 270 | ctrl->value = typhoon->muted; |
239 | { | 271 | return 0; |
240 | struct v4l2_frequency *f = arg; | 272 | case V4L2_CID_AUDIO_VOLUME: |
273 | ctrl->value = typhoon->curvol; | ||
274 | return 0; | ||
275 | } | ||
276 | return -EINVAL; | ||
277 | } | ||
241 | 278 | ||
242 | typhoon->curfreq = f->frequency; | 279 | static int vidioc_s_ctrl (struct file *file, void *priv, |
243 | typhoon_setfreq(typhoon, typhoon->curfreq); | 280 | struct v4l2_control *ctrl) |
244 | return 0; | 281 | { |
245 | } | 282 | struct video_device *dev = video_devdata(file); |
246 | case VIDIOC_G_FREQUENCY: | 283 | struct typhoon_device *typhoon = dev->priv; |
247 | { | ||
248 | struct v4l2_frequency *f = arg; | ||
249 | 284 | ||
250 | f->type = V4L2_TUNER_RADIO; | 285 | switch (ctrl->id) { |
251 | f->frequency = typhoon->curfreq; | 286 | case V4L2_CID_AUDIO_MUTE: |
287 | if (ctrl->value) | ||
288 | typhoon_mute(typhoon); | ||
289 | else | ||
290 | typhoon_unmute(typhoon); | ||
291 | return 0; | ||
292 | case V4L2_CID_AUDIO_VOLUME: | ||
293 | typhoon_setvol(typhoon, ctrl->value); | ||
294 | return 0; | ||
295 | } | ||
296 | return -EINVAL; | ||
297 | } | ||
252 | 298 | ||
253 | return 0; | 299 | static int vidioc_g_audio(struct file *file, void *priv, |
254 | } | 300 | struct v4l2_audio *a) |
255 | case VIDIOC_QUERYCTRL: | 301 | { |
256 | { | 302 | if (a->index > 1) |
257 | struct v4l2_queryctrl *qc = arg; | 303 | return -EINVAL; |
258 | int i; | ||
259 | |||
260 | for (i = 0; i < ARRAY_SIZE(radio_qctrl); i++) { | ||
261 | if (qc->id && qc->id == radio_qctrl[i].id) { | ||
262 | memcpy(qc, &(radio_qctrl[i]), | ||
263 | sizeof(*qc)); | ||
264 | return (0); | ||
265 | } | ||
266 | } | ||
267 | return -EINVAL; | ||
268 | } | ||
269 | case VIDIOC_G_CTRL: | ||
270 | { | ||
271 | struct v4l2_control *ctrl= arg; | ||
272 | |||
273 | switch (ctrl->id) { | ||
274 | case V4L2_CID_AUDIO_MUTE: | ||
275 | ctrl->value=typhoon->muted; | ||
276 | return (0); | ||
277 | case V4L2_CID_AUDIO_VOLUME: | ||
278 | ctrl->value=typhoon->curvol; | ||
279 | return (0); | ||
280 | } | ||
281 | return -EINVAL; | ||
282 | } | ||
283 | case VIDIOC_S_CTRL: | ||
284 | { | ||
285 | struct v4l2_control *ctrl= arg; | ||
286 | |||
287 | switch (ctrl->id) { | ||
288 | case V4L2_CID_AUDIO_MUTE: | ||
289 | if (ctrl->value) { | ||
290 | typhoon_mute(typhoon); | ||
291 | } else { | ||
292 | typhoon_unmute(typhoon); | ||
293 | } | ||
294 | return (0); | ||
295 | case V4L2_CID_AUDIO_VOLUME: | ||
296 | typhoon_setvol(typhoon, ctrl->value); | ||
297 | return (0); | ||
298 | } | ||
299 | return -EINVAL; | ||
300 | } | ||
301 | 304 | ||
302 | default: | 305 | strcpy(a->name, "Radio"); |
303 | return v4l_compat_translate_ioctl(inode,file,cmd,arg, | 306 | a->capability = V4L2_AUDCAP_STEREO; |
304 | typhoon_do_ioctl); | 307 | return 0; |
305 | } | 308 | } |
309 | |||
310 | static int vidioc_g_input(struct file *filp, void *priv, unsigned int *i) | ||
311 | { | ||
312 | *i = 0; | ||
313 | return 0; | ||
314 | } | ||
315 | |||
316 | static int vidioc_s_input(struct file *filp, void *priv, unsigned int i) | ||
317 | { | ||
318 | if (i != 0) | ||
319 | return -EINVAL; | ||
320 | return 0; | ||
306 | } | 321 | } |
307 | 322 | ||
308 | static int typhoon_ioctl(struct inode *inode, struct file *file, | 323 | static int vidioc_s_audio(struct file *file, void *priv, |
309 | unsigned int cmd, unsigned long arg) | 324 | struct v4l2_audio *a) |
310 | { | 325 | { |
311 | return video_usercopy(inode, file, cmd, arg, typhoon_do_ioctl); | 326 | if (a->index != 0) |
327 | return -EINVAL; | ||
328 | return 0; | ||
312 | } | 329 | } |
313 | 330 | ||
314 | static struct typhoon_device typhoon_unit = | 331 | static struct typhoon_device typhoon_unit = |
@@ -322,7 +339,7 @@ static const struct file_operations typhoon_fops = { | |||
322 | .owner = THIS_MODULE, | 339 | .owner = THIS_MODULE, |
323 | .open = video_exclusive_open, | 340 | .open = video_exclusive_open, |
324 | .release = video_exclusive_release, | 341 | .release = video_exclusive_release, |
325 | .ioctl = typhoon_ioctl, | 342 | .ioctl = video_ioctl2, |
326 | .compat_ioctl = v4l_compat_ioctl32, | 343 | .compat_ioctl = v4l_compat_ioctl32, |
327 | .llseek = no_llseek, | 344 | .llseek = no_llseek, |
328 | }; | 345 | }; |
@@ -334,6 +351,18 @@ static struct video_device typhoon_radio = | |||
334 | .type = VID_TYPE_TUNER, | 351 | .type = VID_TYPE_TUNER, |
335 | .hardware = 0, | 352 | .hardware = 0, |
336 | .fops = &typhoon_fops, | 353 | .fops = &typhoon_fops, |
354 | .vidioc_querycap = vidioc_querycap, | ||
355 | .vidioc_g_tuner = vidioc_g_tuner, | ||
356 | .vidioc_s_tuner = vidioc_s_tuner, | ||
357 | .vidioc_g_audio = vidioc_g_audio, | ||
358 | .vidioc_s_audio = vidioc_s_audio, | ||
359 | .vidioc_g_input = vidioc_g_input, | ||
360 | .vidioc_s_input = vidioc_s_input, | ||
361 | .vidioc_g_frequency = vidioc_g_frequency, | ||
362 | .vidioc_s_frequency = vidioc_s_frequency, | ||
363 | .vidioc_queryctrl = vidioc_queryctrl, | ||
364 | .vidioc_g_ctrl = vidioc_g_ctrl, | ||
365 | .vidioc_s_ctrl = vidioc_s_ctrl, | ||
337 | }; | 366 | }; |
338 | 367 | ||
339 | #ifdef CONFIG_RADIO_TYPHOON_PROC_FS | 368 | #ifdef CONFIG_RADIO_TYPHOON_PROC_FS |
diff --git a/drivers/media/radio/radio-zoltrix.c b/drivers/media/radio/radio-zoltrix.c index ec08491fb7c5..a4715901512d 100644 --- a/drivers/media/radio/radio-zoltrix.c +++ b/drivers/media/radio/radio-zoltrix.c | |||
@@ -230,121 +230,123 @@ static int zol_is_stereo (struct zol_device *dev) | |||
230 | return 0; | 230 | return 0; |
231 | } | 231 | } |
232 | 232 | ||
233 | static int zol_do_ioctl(struct inode *inode, struct file *file, | 233 | static int vidioc_querycap(struct file *file, void *priv, |
234 | unsigned int cmd, void *arg) | 234 | struct v4l2_capability *v) |
235 | { | ||
236 | strlcpy(v->driver, "radio-zoltrix", sizeof(v->driver)); | ||
237 | strlcpy(v->card, "Zoltrix Radio", sizeof(v->card)); | ||
238 | sprintf(v->bus_info, "ISA"); | ||
239 | v->version = RADIO_VERSION; | ||
240 | v->capabilities = V4L2_CAP_TUNER; | ||
241 | return 0; | ||
242 | } | ||
243 | |||
244 | static int vidioc_g_tuner(struct file *file, void *priv, | ||
245 | struct v4l2_tuner *v) | ||
235 | { | 246 | { |
236 | struct video_device *dev = video_devdata(file); | 247 | struct video_device *dev = video_devdata(file); |
237 | struct zol_device *zol = dev->priv; | 248 | struct zol_device *zol = dev->priv; |
238 | 249 | ||
239 | switch (cmd) { | 250 | if (v->index > 0) |
240 | case VIDIOC_QUERYCAP: | 251 | return -EINVAL; |
241 | { | ||
242 | struct v4l2_capability *v = arg; | ||
243 | memset(v,0,sizeof(*v)); | ||
244 | strlcpy(v->driver, "radio-zoltrix", sizeof (v->driver)); | ||
245 | strlcpy(v->card, "Zoltrix Radio", sizeof (v->card)); | ||
246 | sprintf(v->bus_info,"ISA"); | ||
247 | v->version = RADIO_VERSION; | ||
248 | v->capabilities = V4L2_CAP_TUNER; | ||
249 | 252 | ||
250 | return 0; | 253 | strcpy(v->name, "FM"); |
251 | } | 254 | v->type = V4L2_TUNER_RADIO; |
252 | case VIDIOC_G_TUNER: | 255 | v->rangelow = (88*16000); |
253 | { | 256 | v->rangehigh = (108*16000); |
254 | struct v4l2_tuner *v = arg; | 257 | v->rxsubchans = V4L2_TUNER_SUB_MONO|V4L2_TUNER_SUB_STEREO; |
255 | 258 | v->capability = V4L2_TUNER_CAP_LOW; | |
256 | if (v->index > 0) | 259 | if (zol_is_stereo(zol)) |
257 | return -EINVAL; | 260 | v->audmode = V4L2_TUNER_MODE_STEREO; |
258 | 261 | else | |
259 | memset(v,0,sizeof(*v)); | 262 | v->audmode = V4L2_TUNER_MODE_MONO; |
260 | strcpy(v->name, "FM"); | 263 | v->signal = 0xFFFF*zol_getsigstr(zol); |
261 | v->type = V4L2_TUNER_RADIO; | 264 | return 0; |
262 | 265 | } | |
263 | v->rangelow=(88*16000); | ||
264 | v->rangehigh=(108*16000); | ||
265 | v->rxsubchans =V4L2_TUNER_SUB_MONO|V4L2_TUNER_SUB_STEREO; | ||
266 | v->capability=V4L2_TUNER_CAP_LOW; | ||
267 | if(zol_is_stereo(zol)) | ||
268 | v->audmode = V4L2_TUNER_MODE_STEREO; | ||
269 | else | ||
270 | v->audmode = V4L2_TUNER_MODE_MONO; | ||
271 | v->signal=0xFFFF*zol_getsigstr(zol); | ||
272 | 266 | ||
273 | return 0; | 267 | static int vidioc_s_tuner(struct file *file, void *priv, |
274 | } | 268 | struct v4l2_tuner *v) |
275 | case VIDIOC_S_TUNER: | 269 | { |
276 | { | 270 | if (v->index > 0) |
277 | struct v4l2_tuner *v = arg; | 271 | return -EINVAL; |
272 | return 0; | ||
273 | } | ||
278 | 274 | ||
279 | if (v->index > 0) | 275 | static int vidioc_s_frequency(struct file *file, void *priv, |
280 | return -EINVAL; | 276 | struct v4l2_frequency *f) |
277 | { | ||
278 | struct video_device *dev = video_devdata(file); | ||
279 | struct zol_device *zol = dev->priv; | ||
281 | 280 | ||
282 | return 0; | 281 | zol->curfreq = f->frequency; |
283 | } | 282 | zol_setfreq(zol, zol->curfreq); |
284 | case VIDIOC_S_FREQUENCY: | 283 | return 0; |
285 | { | 284 | } |
286 | struct v4l2_frequency *f = arg; | ||
287 | 285 | ||
288 | zol->curfreq = f->frequency; | 286 | static int vidioc_g_frequency(struct file *file, void *priv, |
289 | zol_setfreq(zol, zol->curfreq); | 287 | struct v4l2_frequency *f) |
290 | return 0; | 288 | { |
291 | } | 289 | struct video_device *dev = video_devdata(file); |
292 | case VIDIOC_G_FREQUENCY: | 290 | struct zol_device *zol = dev->priv; |
293 | { | 291 | |
294 | struct v4l2_frequency *f = arg; | 292 | f->type = V4L2_TUNER_RADIO; |
293 | f->frequency = zol->curfreq; | ||
294 | return 0; | ||
295 | } | ||
295 | 296 | ||
296 | f->type = V4L2_TUNER_RADIO; | 297 | static int vidioc_queryctrl(struct file *file, void *priv, |
297 | f->frequency = zol->curfreq; | 298 | struct v4l2_queryctrl *qc) |
299 | { | ||
300 | int i; | ||
298 | 301 | ||
302 | for (i = 0; i < ARRAY_SIZE(radio_qctrl); i++) { | ||
303 | if (qc->id && qc->id == radio_qctrl[i].id) { | ||
304 | memcpy(qc, &(radio_qctrl[i]), | ||
305 | sizeof(*qc)); | ||
299 | return 0; | 306 | return 0; |
300 | } | 307 | } |
301 | case VIDIOC_QUERYCTRL: | 308 | } |
302 | { | 309 | return -EINVAL; |
303 | struct v4l2_queryctrl *qc = arg; | 310 | } |
304 | int i; | 311 | |
305 | 312 | static int vidioc_g_ctrl(struct file *file, void *priv, | |
306 | for (i = 0; i < ARRAY_SIZE(radio_qctrl); i++) { | 313 | struct v4l2_control *ctrl) |
307 | if (qc->id && qc->id == radio_qctrl[i].id) { | 314 | { |
308 | memcpy(qc, &(radio_qctrl[i]), | 315 | struct video_device *dev = video_devdata(file); |
309 | sizeof(*qc)); | 316 | struct zol_device *zol = dev->priv; |
310 | return (0); | 317 | |
311 | } | 318 | switch (ctrl->id) { |
312 | } | 319 | case V4L2_CID_AUDIO_MUTE: |
313 | return -EINVAL; | 320 | ctrl->value = zol->muted; |
314 | } | 321 | return 0; |
315 | case VIDIOC_G_CTRL: | 322 | case V4L2_CID_AUDIO_VOLUME: |
316 | { | 323 | ctrl->value = zol->curvol * 4096; |
317 | struct v4l2_control *ctrl= arg; | 324 | return 0; |
318 | 325 | } | |
319 | switch (ctrl->id) { | 326 | return -EINVAL; |
320 | case V4L2_CID_AUDIO_MUTE: | 327 | } |
321 | ctrl->value=zol->muted; | 328 | |
322 | return (0); | 329 | static int vidioc_s_ctrl(struct file *file, void *priv, |
323 | case V4L2_CID_AUDIO_VOLUME: | 330 | struct v4l2_control *ctrl) |
324 | ctrl->value=zol->curvol * 4096; | 331 | { |
325 | return (0); | 332 | struct video_device *dev = video_devdata(file); |
326 | } | 333 | struct zol_device *zol = dev->priv; |
327 | return -EINVAL; | 334 | |
335 | switch (ctrl->id) { | ||
336 | case V4L2_CID_AUDIO_MUTE: | ||
337 | if (ctrl->value) | ||
338 | zol_mute(zol); | ||
339 | else { | ||
340 | zol_unmute(zol); | ||
341 | zol_setvol(zol,zol->curvol); | ||
328 | } | 342 | } |
329 | case VIDIOC_S_CTRL: | 343 | return 0; |
330 | { | 344 | case V4L2_CID_AUDIO_VOLUME: |
331 | struct v4l2_control *ctrl= arg; | 345 | zol_setvol(zol,ctrl->value/4096); |
332 | 346 | return 0; | |
333 | switch (ctrl->id) { | 347 | } |
334 | case V4L2_CID_AUDIO_MUTE: | 348 | zol->stereo = 1; |
335 | if (ctrl->value) { | 349 | zol_setfreq(zol, zol->curfreq); |
336 | zol_mute(zol); | ||
337 | } else { | ||
338 | zol_unmute(zol); | ||
339 | zol_setvol(zol,zol->curvol); | ||
340 | } | ||
341 | return (0); | ||
342 | case V4L2_CID_AUDIO_VOLUME: | ||
343 | zol_setvol(zol,ctrl->value/4096); | ||
344 | return (0); | ||
345 | } | ||
346 | zol->stereo = 1; | ||
347 | zol_setfreq(zol, zol->curfreq); | ||
348 | #if 0 | 350 | #if 0 |
349 | /* FIXME: Implement stereo/mono switch on V4L2 */ | 351 | /* FIXME: Implement stereo/mono switch on V4L2 */ |
350 | if (v->mode & VIDEO_SOUND_STEREO) { | 352 | if (v->mode & VIDEO_SOUND_STEREO) { |
@@ -356,19 +358,39 @@ static int zol_do_ioctl(struct inode *inode, struct file *file, | |||
356 | zol_setfreq(zol, zol->curfreq); | 358 | zol_setfreq(zol, zol->curfreq); |
357 | } | 359 | } |
358 | #endif | 360 | #endif |
359 | return -EINVAL; | 361 | return -EINVAL; |
360 | } | 362 | } |
361 | 363 | ||
362 | default: | 364 | static int vidioc_g_audio(struct file *file, void *priv, |
363 | return v4l_compat_translate_ioctl(inode,file,cmd,arg, | 365 | struct v4l2_audio *a) |
364 | zol_do_ioctl); | 366 | { |
365 | } | 367 | if (a->index > 1) |
368 | return -EINVAL; | ||
369 | |||
370 | strcpy(a->name, "Radio"); | ||
371 | a->capability = V4L2_AUDCAP_STEREO; | ||
372 | return 0; | ||
373 | } | ||
374 | |||
375 | static int vidioc_g_input(struct file *filp, void *priv, unsigned int *i) | ||
376 | { | ||
377 | *i = 0; | ||
378 | return 0; | ||
366 | } | 379 | } |
367 | 380 | ||
368 | static int zol_ioctl(struct inode *inode, struct file *file, | 381 | static int vidioc_s_input(struct file *filp, void *priv, unsigned int i) |
369 | unsigned int cmd, unsigned long arg) | ||
370 | { | 382 | { |
371 | return video_usercopy(inode, file, cmd, arg, zol_do_ioctl); | 383 | if (i != 0) |
384 | return -EINVAL; | ||
385 | return 0; | ||
386 | } | ||
387 | |||
388 | static int vidioc_s_audio(struct file *file, void *priv, | ||
389 | struct v4l2_audio *a) | ||
390 | { | ||
391 | if (a->index != 0) | ||
392 | return -EINVAL; | ||
393 | return 0; | ||
372 | } | 394 | } |
373 | 395 | ||
374 | static struct zol_device zoltrix_unit; | 396 | static struct zol_device zoltrix_unit; |
@@ -378,7 +400,7 @@ static const struct file_operations zoltrix_fops = | |||
378 | .owner = THIS_MODULE, | 400 | .owner = THIS_MODULE, |
379 | .open = video_exclusive_open, | 401 | .open = video_exclusive_open, |
380 | .release = video_exclusive_release, | 402 | .release = video_exclusive_release, |
381 | .ioctl = zol_ioctl, | 403 | .ioctl = video_ioctl2, |
382 | .compat_ioctl = v4l_compat_ioctl32, | 404 | .compat_ioctl = v4l_compat_ioctl32, |
383 | .llseek = no_llseek, | 405 | .llseek = no_llseek, |
384 | }; | 406 | }; |
@@ -390,6 +412,18 @@ static struct video_device zoltrix_radio = | |||
390 | .type = VID_TYPE_TUNER, | 412 | .type = VID_TYPE_TUNER, |
391 | .hardware = 0, | 413 | .hardware = 0, |
392 | .fops = &zoltrix_fops, | 414 | .fops = &zoltrix_fops, |
415 | .vidioc_querycap = vidioc_querycap, | ||
416 | .vidioc_g_tuner = vidioc_g_tuner, | ||
417 | .vidioc_s_tuner = vidioc_s_tuner, | ||
418 | .vidioc_g_audio = vidioc_g_audio, | ||
419 | .vidioc_s_audio = vidioc_s_audio, | ||
420 | .vidioc_g_input = vidioc_g_input, | ||
421 | .vidioc_s_input = vidioc_s_input, | ||
422 | .vidioc_g_frequency = vidioc_g_frequency, | ||
423 | .vidioc_s_frequency = vidioc_s_frequency, | ||
424 | .vidioc_queryctrl = vidioc_queryctrl, | ||
425 | .vidioc_g_ctrl = vidioc_g_ctrl, | ||
426 | .vidioc_s_ctrl = vidioc_s_ctrl, | ||
393 | }; | 427 | }; |
394 | 428 | ||
395 | static int __init zoltrix_init(void) | 429 | static int __init zoltrix_init(void) |
diff --git a/drivers/media/video/Kconfig b/drivers/media/video/Kconfig index 7a6105153f23..639e8b6c35b1 100644 --- a/drivers/media/video/Kconfig +++ b/drivers/media/video/Kconfig | |||
@@ -647,6 +647,8 @@ config VIDEO_HEXIUM_GEMINI | |||
647 | 647 | ||
648 | source "drivers/media/video/cx88/Kconfig" | 648 | source "drivers/media/video/cx88/Kconfig" |
649 | 649 | ||
650 | source "drivers/media/video/ivtv/Kconfig" | ||
651 | |||
650 | config VIDEO_M32R_AR | 652 | config VIDEO_M32R_AR |
651 | tristate "AR devices" | 653 | tristate "AR devices" |
652 | depends on M32R && VIDEO_V4L1 | 654 | depends on M32R && VIDEO_V4L1 |
@@ -761,6 +763,18 @@ source "drivers/media/video/zc0301/Kconfig" | |||
761 | 763 | ||
762 | source "drivers/media/video/pwc/Kconfig" | 764 | source "drivers/media/video/pwc/Kconfig" |
763 | 765 | ||
766 | config USB_ZR364XX | ||
767 | tristate "USB ZR364XX Camera support" | ||
768 | depends on USB && VIDEO_V4L2 | ||
769 | ---help--- | ||
770 | Say Y here if you want to connect this type of camera to your | ||
771 | computer's USB port. | ||
772 | See <file:Documentation/video4linux/zr364xx.txt> for more info | ||
773 | and list of supported cameras. | ||
774 | |||
775 | To compile this driver as a module, choose M here: the | ||
776 | module will be called zr364xx. | ||
777 | |||
764 | endmenu # V4L USB devices | 778 | endmenu # V4L USB devices |
765 | 779 | ||
766 | endmenu | 780 | endmenu |
diff --git a/drivers/media/video/Makefile b/drivers/media/video/Makefile index 44ccaed40b49..9c2de501612f 100644 --- a/drivers/media/video/Makefile +++ b/drivers/media/video/Makefile | |||
@@ -61,6 +61,7 @@ obj-$(CONFIG_VIDEO_CPIA_USB) += cpia_usb.o | |||
61 | obj-$(CONFIG_VIDEO_MEYE) += meye.o | 61 | obj-$(CONFIG_VIDEO_MEYE) += meye.o |
62 | obj-$(CONFIG_VIDEO_SAA7134) += ir-kbd-i2c.o saa7134/ | 62 | obj-$(CONFIG_VIDEO_SAA7134) += ir-kbd-i2c.o saa7134/ |
63 | obj-$(CONFIG_VIDEO_CX88) += cx88/ | 63 | obj-$(CONFIG_VIDEO_CX88) += cx88/ |
64 | obj-$(CONFIG_VIDEO_IVTV) += ivtv/ | ||
64 | obj-$(CONFIG_VIDEO_EM28XX) += em28xx/ | 65 | obj-$(CONFIG_VIDEO_EM28XX) += em28xx/ |
65 | obj-$(CONFIG_VIDEO_USBVISION) += usbvision/ | 66 | obj-$(CONFIG_VIDEO_USBVISION) += usbvision/ |
66 | obj-$(CONFIG_VIDEO_TVP5150) += tvp5150.o | 67 | obj-$(CONFIG_VIDEO_TVP5150) += tvp5150.o |
@@ -99,6 +100,7 @@ obj-$(CONFIG_USB_OV511) += ov511.o | |||
99 | obj-$(CONFIG_USB_SE401) += se401.o | 100 | obj-$(CONFIG_USB_SE401) += se401.o |
100 | obj-$(CONFIG_USB_STV680) += stv680.o | 101 | obj-$(CONFIG_USB_STV680) += stv680.o |
101 | obj-$(CONFIG_USB_W9968CF) += w9968cf.o | 102 | obj-$(CONFIG_USB_W9968CF) += w9968cf.o |
103 | obj-$(CONFIG_USB_ZR364XX) += zr364xx.o | ||
102 | 104 | ||
103 | obj-$(CONFIG_USB_SN9C102) += sn9c102/ | 105 | obj-$(CONFIG_USB_SN9C102) += sn9c102/ |
104 | obj-$(CONFIG_USB_ET61X251) += et61x251/ | 106 | obj-$(CONFIG_USB_ET61X251) += et61x251/ |
diff --git a/drivers/media/video/bt8xx/bttv-cards.c b/drivers/media/video/bt8xx/bttv-cards.c index 6addc42df045..6b31e50fb951 100644 --- a/drivers/media/video/bt8xx/bttv-cards.c +++ b/drivers/media/video/bt8xx/bttv-cards.c | |||
@@ -291,6 +291,9 @@ static struct CARD { | |||
291 | 291 | ||
292 | { 0x15409511, BTTV_BOARD_ACORP_Y878F, "Acorp Y878F" }, | 292 | { 0x15409511, BTTV_BOARD_ACORP_Y878F, "Acorp Y878F" }, |
293 | 293 | ||
294 | { 0x53534149, BTTV_BOARD_SSAI_SECURITY, "SSAI Security Video Interface" }, | ||
295 | { 0x5353414a, BTTV_BOARD_SSAI_ULTRASOUND, "SSAI Ultrasound Video Interface" }, | ||
296 | |||
294 | /* likely broken, vendor id doesn't match the other magic views ... | 297 | /* likely broken, vendor id doesn't match the other magic views ... |
295 | * { 0xa0fca04f, BTTV_BOARD_MAGICTVIEW063, "Guillemot Maxi TV Video 3" }, */ | 298 | * { 0xa0fca04f, BTTV_BOARD_MAGICTVIEW063, "Guillemot Maxi TV Video 3" }, */ |
296 | 299 | ||
@@ -2907,6 +2910,28 @@ struct tvcard bttv_tvcards[] = { | |||
2907 | .has_radio = 1, | 2910 | .has_radio = 1, |
2908 | .has_remote = 1, | 2911 | .has_remote = 1, |
2909 | }, | 2912 | }, |
2913 | [BTTV_BOARD_SSAI_SECURITY] = { | ||
2914 | .name = "SSAI Security Video Interface", | ||
2915 | .video_inputs = 4, | ||
2916 | .audio_inputs = 0, | ||
2917 | .tuner = -1, | ||
2918 | .svhs = -1, | ||
2919 | .muxsel = { 0, 1, 2, 3 }, | ||
2920 | .tuner_type = -1, | ||
2921 | .tuner_addr = ADDR_UNSET, | ||
2922 | .radio_addr = ADDR_UNSET, | ||
2923 | }, | ||
2924 | [BTTV_BOARD_SSAI_ULTRASOUND] = { | ||
2925 | .name = "SSAI Ultrasound Video Interface", | ||
2926 | .video_inputs = 2, | ||
2927 | .audio_inputs = 0, | ||
2928 | .tuner = -1, | ||
2929 | .svhs = 1, | ||
2930 | .muxsel = { 2, 0, 1, 3 }, | ||
2931 | .tuner_type = -1, | ||
2932 | .tuner_addr = ADDR_UNSET, | ||
2933 | .radio_addr = ADDR_UNSET, | ||
2934 | }, | ||
2910 | }; | 2935 | }; |
2911 | 2936 | ||
2912 | static const unsigned int bttv_num_tvcards = ARRAY_SIZE(bttv_tvcards); | 2937 | static const unsigned int bttv_num_tvcards = ARRAY_SIZE(bttv_tvcards); |
@@ -2970,20 +2995,20 @@ void __devinit bttv_idcard(struct bttv *btv) | |||
2970 | 2995 | ||
2971 | if (UNSET != audiomux[0]) { | 2996 | if (UNSET != audiomux[0]) { |
2972 | gpiobits = 0; | 2997 | gpiobits = 0; |
2973 | for (i = 0; i < 4; i++) { | 2998 | for (i = 0; i < ARRAY_SIZE(bttv_tvcards->gpiomux); i++) { |
2974 | bttv_tvcards[btv->c.type].gpiomux[i] = audiomux[i]; | 2999 | bttv_tvcards[btv->c.type].gpiomux[i] = audiomux[i]; |
2975 | gpiobits |= audiomux[i]; | 3000 | gpiobits |= audiomux[i]; |
2976 | } | 3001 | } |
2977 | } else { | 3002 | } else { |
2978 | gpiobits = audioall; | 3003 | gpiobits = audioall; |
2979 | for (i = 0; i < 4; i++) { | 3004 | for (i = 0; i < ARRAY_SIZE(bttv_tvcards->gpiomux); i++) { |
2980 | bttv_tvcards[btv->c.type].gpiomux[i] = audioall; | 3005 | bttv_tvcards[btv->c.type].gpiomux[i] = audioall; |
2981 | } | 3006 | } |
2982 | } | 3007 | } |
2983 | bttv_tvcards[btv->c.type].gpiomask = (UNSET != gpiomask) ? gpiomask : gpiobits; | 3008 | bttv_tvcards[btv->c.type].gpiomask = (UNSET != gpiomask) ? gpiomask : gpiobits; |
2984 | printk(KERN_INFO "bttv%d: gpio config override: mask=0x%x, mux=", | 3009 | printk(KERN_INFO "bttv%d: gpio config override: mask=0x%x, mux=", |
2985 | btv->c.nr,bttv_tvcards[btv->c.type].gpiomask); | 3010 | btv->c.nr,bttv_tvcards[btv->c.type].gpiomask); |
2986 | for (i = 0; i < 5; i++) { | 3011 | for (i = 0; i < ARRAY_SIZE(bttv_tvcards->gpiomux); i++) { |
2987 | printk("%s0x%x", i ? "," : "", bttv_tvcards[btv->c.type].gpiomux[i]); | 3012 | printk("%s0x%x", i ? "," : "", bttv_tvcards[btv->c.type].gpiomux[i]); |
2988 | } | 3013 | } |
2989 | printk("\n"); | 3014 | printk("\n"); |
@@ -3638,7 +3663,7 @@ static int __devinit pvr_altera_load(struct bttv *btv, u8 *micro, u32 microlen) | |||
3638 | 3663 | ||
3639 | for (n = 0; n < microlen; n++) { | 3664 | for (n = 0; n < microlen; n++) { |
3640 | bits = micro[n]; | 3665 | bits = micro[n]; |
3641 | for ( i = 0 ; i < 8 ; i++ ) { | 3666 | for (i = 0 ; i < 8 ; i++) { |
3642 | gpio_bits(BTTV_ALT_DCLK,0); | 3667 | gpio_bits(BTTV_ALT_DCLK,0); |
3643 | if (bits & 0x01) | 3668 | if (bits & 0x01) |
3644 | gpio_bits(BTTV_ALT_DATA,BTTV_ALT_DATA); | 3669 | gpio_bits(BTTV_ALT_DATA,BTTV_ALT_DATA); |
@@ -3691,7 +3716,7 @@ static void __devinit osprey_eeprom(struct bttv *btv) | |||
3691 | /* this might be an antique... check for MMAC label in eeprom */ | 3716 | /* this might be an antique... check for MMAC label in eeprom */ |
3692 | if ((ee[0]=='M') && (ee[1]=='M') && (ee[2]=='A') && (ee[3]=='C')) { | 3717 | if ((ee[0]=='M') && (ee[1]=='M') && (ee[2]=='A') && (ee[3]=='C')) { |
3693 | unsigned char checksum = 0; | 3718 | unsigned char checksum = 0; |
3694 | for (i =0; i<21; i++) | 3719 | for (i = 0; i < 21; i++) |
3695 | checksum += ee[i]; | 3720 | checksum += ee[i]; |
3696 | if (checksum != ee[21]) | 3721 | if (checksum != ee[21]) |
3697 | return; | 3722 | return; |
@@ -3703,12 +3728,13 @@ static void __devinit osprey_eeprom(struct bttv *btv) | |||
3703 | unsigned short type; | 3728 | unsigned short type; |
3704 | int offset = 4*16; | 3729 | int offset = 4*16; |
3705 | 3730 | ||
3706 | for(; offset < 8*16; offset += 16) { | 3731 | for (; offset < 8*16; offset += 16) { |
3707 | unsigned short checksum = 0; | 3732 | unsigned short checksum = 0; |
3708 | /* verify the checksum */ | 3733 | /* verify the checksum */ |
3709 | for(i = 0; i<14; i++) checksum += ee[i+offset]; | 3734 | for (i = 0; i < 14; i++) |
3710 | checksum = ~checksum; /* no idea why */ | 3735 | checksum += ee[i+offset]; |
3711 | if ((((checksum>>8)&0x0FF) == ee[offset+14]) && | 3736 | checksum = ~checksum; /* no idea why */ |
3737 | if ((((checksum>>8)&0x0FF) == ee[offset+14]) && | ||
3712 | ((checksum & 0x0FF) == ee[offset+15])) { | 3738 | ((checksum & 0x0FF) == ee[offset+15])) { |
3713 | break; | 3739 | break; |
3714 | } | 3740 | } |
@@ -3721,7 +3747,6 @@ static void __devinit osprey_eeprom(struct bttv *btv) | |||
3721 | type = (ee[offset+4]<<8) | (ee[offset+5]); | 3747 | type = (ee[offset+4]<<8) | (ee[offset+5]); |
3722 | 3748 | ||
3723 | switch(type) { | 3749 | switch(type) { |
3724 | |||
3725 | /* 848 based */ | 3750 | /* 848 based */ |
3726 | case 0x0004: | 3751 | case 0x0004: |
3727 | btv->c.type = BTTV_BOARD_OSPREY1x0_848; | 3752 | btv->c.type = BTTV_BOARD_OSPREY1x0_848; |
@@ -4149,8 +4174,7 @@ static int tea5757_read(struct bttv *btv) | |||
4149 | } | 4174 | } |
4150 | 4175 | ||
4151 | dprintk("bttv%d: tea5757:",btv->c.nr); | 4176 | dprintk("bttv%d: tea5757:",btv->c.nr); |
4152 | for(i = 0; i < 24; i++) | 4177 | for (i = 0; i < 24; i++) { |
4153 | { | ||
4154 | udelay(5); | 4178 | udelay(5); |
4155 | bus_high(btv,btv->mbox_clk); | 4179 | bus_high(btv,btv->mbox_clk); |
4156 | udelay(5); | 4180 | udelay(5); |
@@ -4182,8 +4206,7 @@ static int tea5757_write(struct bttv *btv, int value) | |||
4182 | dprintk("bttv%d: tea5757: write 0x%X\n", btv->c.nr, value); | 4206 | dprintk("bttv%d: tea5757: write 0x%X\n", btv->c.nr, value); |
4183 | bus_low(btv,btv->mbox_clk); | 4207 | bus_low(btv,btv->mbox_clk); |
4184 | bus_high(btv,btv->mbox_we); | 4208 | bus_high(btv,btv->mbox_we); |
4185 | for(i = 0; i < 25; i++) | 4209 | for (i = 0; i < 25; i++) { |
4186 | { | ||
4187 | if (reg & 0x1000000) | 4210 | if (reg & 0x1000000) |
4188 | bus_high(btv,btv->mbox_data); | 4211 | bus_high(btv,btv->mbox_data); |
4189 | else | 4212 | else |
@@ -4755,7 +4778,7 @@ static void kodicom4400r_init(struct bttv *btv) | |||
4755 | gpio_write(1 << 9); /* reset MUX */ | 4778 | gpio_write(1 << 9); /* reset MUX */ |
4756 | gpio_write(0); | 4779 | gpio_write(0); |
4757 | /* Preset camera 0 to the 4 controllers */ | 4780 | /* Preset camera 0 to the 4 controllers */ |
4758 | for (ix=0; ix<4; ix++) { | 4781 | for (ix = 0; ix < 4; ix++) { |
4759 | sw_status[ix] = ix; | 4782 | sw_status[ix] = ix; |
4760 | kodicom4400r_write(btv, ix, ix, 1); | 4783 | kodicom4400r_write(btv, ix, ix, 1); |
4761 | } | 4784 | } |
diff --git a/drivers/media/video/bt8xx/bttv-driver.c b/drivers/media/video/bt8xx/bttv-driver.c index 5720b77ac9a7..1c38723d3169 100644 --- a/drivers/media/video/bt8xx/bttv-driver.c +++ b/drivers/media/video/bt8xx/bttv-driver.c | |||
@@ -164,6 +164,24 @@ static ssize_t show_card(struct class_device *cd, char *buf) | |||
164 | static CLASS_DEVICE_ATTR(card, S_IRUGO, show_card, NULL); | 164 | static CLASS_DEVICE_ATTR(card, S_IRUGO, show_card, NULL); |
165 | 165 | ||
166 | /* ----------------------------------------------------------------------- */ | 166 | /* ----------------------------------------------------------------------- */ |
167 | /* dvb auto-load setup */ | ||
168 | #if defined(CONFIG_MODULES) && defined(MODULE) | ||
169 | static void request_module_async(struct work_struct *work) | ||
170 | { | ||
171 | request_module("dvb-bt8xx"); | ||
172 | } | ||
173 | |||
174 | static void request_modules(struct bttv *dev) | ||
175 | { | ||
176 | INIT_WORK(&dev->request_module_wk, request_module_async); | ||
177 | schedule_work(&dev->request_module_wk); | ||
178 | } | ||
179 | #else | ||
180 | #define request_modules(dev) | ||
181 | #endif /* CONFIG_MODULES */ | ||
182 | |||
183 | |||
184 | /* ----------------------------------------------------------------------- */ | ||
167 | /* static data */ | 185 | /* static data */ |
168 | 186 | ||
169 | /* special timing tables from conexant... */ | 187 | /* special timing tables from conexant... */ |
@@ -4769,9 +4787,11 @@ static int __devinit bttv_probe(struct pci_dev *dev, | |||
4769 | disclaim_video_lines(btv); | 4787 | disclaim_video_lines(btv); |
4770 | } | 4788 | } |
4771 | 4789 | ||
4772 | /* add subdevices */ | 4790 | /* add subdevices and autoload dvb-bt8xx if needed */ |
4773 | if (bttv_tvcards[btv->c.type].has_dvb) | 4791 | if (bttv_tvcards[btv->c.type].has_dvb) { |
4774 | bttv_sub_add_device(&btv->c, "dvb"); | 4792 | bttv_sub_add_device(&btv->c, "dvb"); |
4793 | request_modules(btv); | ||
4794 | } | ||
4775 | 4795 | ||
4776 | bttv_input_init(btv); | 4796 | bttv_input_init(btv); |
4777 | 4797 | ||
diff --git a/drivers/media/video/bt8xx/bttv-gpio.c b/drivers/media/video/bt8xx/bttv-gpio.c index ba081f6f8c82..84154c26f9c5 100644 --- a/drivers/media/video/bt8xx/bttv-gpio.c +++ b/drivers/media/video/bt8xx/bttv-gpio.c | |||
@@ -71,7 +71,6 @@ struct bus_type bttv_sub_bus_type = { | |||
71 | .probe = bttv_sub_probe, | 71 | .probe = bttv_sub_probe, |
72 | .remove = bttv_sub_remove, | 72 | .remove = bttv_sub_remove, |
73 | }; | 73 | }; |
74 | EXPORT_SYMBOL(bttv_sub_bus_type); | ||
75 | 74 | ||
76 | static void release_sub_device(struct device *dev) | 75 | static void release_sub_device(struct device *dev) |
77 | { | 76 | { |
@@ -152,7 +151,6 @@ void bttv_gpio_inout(struct bttv_core *core, u32 mask, u32 outbits) | |||
152 | btwrite(data,BT848_GPIO_OUT_EN); | 151 | btwrite(data,BT848_GPIO_OUT_EN); |
153 | spin_unlock_irqrestore(&btv->gpio_lock,flags); | 152 | spin_unlock_irqrestore(&btv->gpio_lock,flags); |
154 | } | 153 | } |
155 | EXPORT_SYMBOL(bttv_gpio_inout); | ||
156 | 154 | ||
157 | u32 bttv_gpio_read(struct bttv_core *core) | 155 | u32 bttv_gpio_read(struct bttv_core *core) |
158 | { | 156 | { |
@@ -162,7 +160,6 @@ u32 bttv_gpio_read(struct bttv_core *core) | |||
162 | value = btread(BT848_GPIO_DATA); | 160 | value = btread(BT848_GPIO_DATA); |
163 | return value; | 161 | return value; |
164 | } | 162 | } |
165 | EXPORT_SYMBOL(bttv_gpio_read); | ||
166 | 163 | ||
167 | void bttv_gpio_write(struct bttv_core *core, u32 value) | 164 | void bttv_gpio_write(struct bttv_core *core, u32 value) |
168 | { | 165 | { |
@@ -170,7 +167,6 @@ void bttv_gpio_write(struct bttv_core *core, u32 value) | |||
170 | 167 | ||
171 | btwrite(value,BT848_GPIO_DATA); | 168 | btwrite(value,BT848_GPIO_DATA); |
172 | } | 169 | } |
173 | EXPORT_SYMBOL(bttv_gpio_write); | ||
174 | 170 | ||
175 | void bttv_gpio_bits(struct bttv_core *core, u32 mask, u32 bits) | 171 | void bttv_gpio_bits(struct bttv_core *core, u32 mask, u32 bits) |
176 | { | 172 | { |
@@ -185,7 +181,6 @@ void bttv_gpio_bits(struct bttv_core *core, u32 mask, u32 bits) | |||
185 | btwrite(data,BT848_GPIO_DATA); | 181 | btwrite(data,BT848_GPIO_DATA); |
186 | spin_unlock_irqrestore(&btv->gpio_lock,flags); | 182 | spin_unlock_irqrestore(&btv->gpio_lock,flags); |
187 | } | 183 | } |
188 | EXPORT_SYMBOL(bttv_gpio_bits); | ||
189 | 184 | ||
190 | /* | 185 | /* |
191 | * Local variables: | 186 | * Local variables: |
diff --git a/drivers/media/video/bt8xx/bttv-i2c.c b/drivers/media/video/bt8xx/bttv-i2c.c index 62b873076e09..0dfa49b66418 100644 --- a/drivers/media/video/bt8xx/bttv-i2c.c +++ b/drivers/media/video/bt8xx/bttv-i2c.c | |||
@@ -412,7 +412,7 @@ static void do_i2c_scan(char *name, struct i2c_client *c) | |||
412 | unsigned char buf; | 412 | unsigned char buf; |
413 | int i,rc; | 413 | int i,rc; |
414 | 414 | ||
415 | for (i = 0; i < 128; i++) { | 415 | for (i = 0; i < ARRAY_SIZE(i2c_devs); i++) { |
416 | c->addr = i; | 416 | c->addr = i; |
417 | rc = i2c_master_recv(c,&buf,0); | 417 | rc = i2c_master_recv(c,&buf,0); |
418 | if (rc < 0) | 418 | if (rc < 0) |
diff --git a/drivers/media/video/bt8xx/bttv-if.c b/drivers/media/video/bt8xx/bttv-if.c index 19b564ab0e92..ecf07988cd33 100644 --- a/drivers/media/video/bt8xx/bttv-if.c +++ b/drivers/media/video/bt8xx/bttv-if.c | |||
@@ -33,32 +33,16 @@ | |||
33 | 33 | ||
34 | #include "bttvp.h" | 34 | #include "bttvp.h" |
35 | 35 | ||
36 | EXPORT_SYMBOL(bttv_get_cardinfo); | ||
37 | EXPORT_SYMBOL(bttv_get_pcidev); | 36 | EXPORT_SYMBOL(bttv_get_pcidev); |
38 | EXPORT_SYMBOL(bttv_get_id); | ||
39 | EXPORT_SYMBOL(bttv_gpio_enable); | 37 | EXPORT_SYMBOL(bttv_gpio_enable); |
40 | EXPORT_SYMBOL(bttv_read_gpio); | 38 | EXPORT_SYMBOL(bttv_read_gpio); |
41 | EXPORT_SYMBOL(bttv_write_gpio); | 39 | EXPORT_SYMBOL(bttv_write_gpio); |
42 | EXPORT_SYMBOL(bttv_get_gpio_queue); | ||
43 | EXPORT_SYMBOL(bttv_i2c_call); | ||
44 | 40 | ||
45 | /* ----------------------------------------------------------------------- */ | 41 | /* ----------------------------------------------------------------------- */ |
46 | /* Exported functions - for other modules which want to access the */ | 42 | /* Exported functions - for other modules which want to access the */ |
47 | /* gpio ports (IR for example) */ | 43 | /* gpio ports (IR for example) */ |
48 | /* see bttv.h for comments */ | 44 | /* see bttv.h for comments */ |
49 | 45 | ||
50 | int bttv_get_cardinfo(unsigned int card, int *type, unsigned *cardid) | ||
51 | { | ||
52 | printk("The bttv_* interface is obsolete and will go away,\n" | ||
53 | "please use the new, sysfs based interface instead.\n"); | ||
54 | if (card >= bttv_num) { | ||
55 | return -1; | ||
56 | } | ||
57 | *type = bttvs[card].c.type; | ||
58 | *cardid = bttvs[card].cardid; | ||
59 | return 0; | ||
60 | } | ||
61 | |||
62 | struct pci_dev* bttv_get_pcidev(unsigned int card) | 46 | struct pci_dev* bttv_get_pcidev(unsigned int card) |
63 | { | 47 | { |
64 | if (card >= bttv_num) | 48 | if (card >= bttv_num) |
@@ -66,16 +50,6 @@ struct pci_dev* bttv_get_pcidev(unsigned int card) | |||
66 | return bttvs[card].c.pci; | 50 | return bttvs[card].c.pci; |
67 | } | 51 | } |
68 | 52 | ||
69 | int bttv_get_id(unsigned int card) | ||
70 | { | ||
71 | printk("The bttv_* interface is obsolete and will go away,\n" | ||
72 | "please use the new, sysfs based interface instead.\n"); | ||
73 | if (card >= bttv_num) { | ||
74 | return -1; | ||
75 | } | ||
76 | return bttvs[card].c.type; | ||
77 | } | ||
78 | |||
79 | 53 | ||
80 | int bttv_gpio_enable(unsigned int card, unsigned long mask, unsigned long data) | 54 | int bttv_gpio_enable(unsigned int card, unsigned long mask, unsigned long data) |
81 | { | 55 | { |
@@ -130,28 +104,6 @@ int bttv_write_gpio(unsigned int card, unsigned long mask, unsigned long data) | |||
130 | return 0; | 104 | return 0; |
131 | } | 105 | } |
132 | 106 | ||
133 | wait_queue_head_t* bttv_get_gpio_queue(unsigned int card) | ||
134 | { | ||
135 | struct bttv *btv; | ||
136 | |||
137 | if (card >= bttv_num) { | ||
138 | return NULL; | ||
139 | } | ||
140 | |||
141 | btv = &bttvs[card]; | ||
142 | if (bttvs[card].shutdown) { | ||
143 | return NULL; | ||
144 | } | ||
145 | return &btv->gpioq; | ||
146 | } | ||
147 | |||
148 | void bttv_i2c_call(unsigned int card, unsigned int cmd, void *arg) | ||
149 | { | ||
150 | if (card >= bttv_num) | ||
151 | return; | ||
152 | bttv_call_i2c_clients(&bttvs[card], cmd, arg); | ||
153 | } | ||
154 | |||
155 | /* | 107 | /* |
156 | * Local variables: | 108 | * Local variables: |
157 | * c-basic-offset: 8 | 109 | * c-basic-offset: 8 |
diff --git a/drivers/media/video/bt8xx/bttv.h b/drivers/media/video/bt8xx/bttv.h index 5491acbdaf63..f821ba69db99 100644 --- a/drivers/media/video/bt8xx/bttv.h +++ b/drivers/media/video/bt8xx/bttv.h | |||
@@ -168,6 +168,8 @@ | |||
168 | #define BTTV_BOARD_SABRENT_TVFM 0x8e | 168 | #define BTTV_BOARD_SABRENT_TVFM 0x8e |
169 | #define BTTV_BOARD_HAUPPAUGE_IMPACTVCB 0x8f | 169 | #define BTTV_BOARD_HAUPPAUGE_IMPACTVCB 0x8f |
170 | #define BTTV_BOARD_MACHTV_MAGICTV 0x90 | 170 | #define BTTV_BOARD_MACHTV_MAGICTV 0x90 |
171 | #define BTTV_BOARD_SSAI_SECURITY 0x91 | ||
172 | #define BTTV_BOARD_SSAI_ULTRASOUND 0x92 | ||
171 | 173 | ||
172 | /* more card-specific defines */ | 174 | /* more card-specific defines */ |
173 | #define PT2254_L_CHANNEL 0x10 | 175 | #define PT2254_L_CHANNEL 0x10 |
@@ -260,17 +262,8 @@ extern int bttv_handle_chipset(struct bttv *btv); | |||
260 | /* this obsolete -- please use the sysfs-based | 262 | /* this obsolete -- please use the sysfs-based |
261 | interface below for new code */ | 263 | interface below for new code */ |
262 | 264 | ||
263 | /* returns card type + card ID (for bt878-based ones) | ||
264 | for possible values see lines below beginning with #define BTTV_BOARD_UNKNOWN | ||
265 | returns negative value if error occurred | ||
266 | */ | ||
267 | extern int bttv_get_cardinfo(unsigned int card, int *type, | ||
268 | unsigned int *cardid); | ||
269 | extern struct pci_dev* bttv_get_pcidev(unsigned int card); | 265 | extern struct pci_dev* bttv_get_pcidev(unsigned int card); |
270 | 266 | ||
271 | /* obsolete, use bttv_get_cardinfo instead */ | ||
272 | extern int bttv_get_id(unsigned int card); | ||
273 | |||
274 | /* sets GPOE register (BT848_GPIO_OUT_EN) to new value: | 267 | /* sets GPOE register (BT848_GPIO_OUT_EN) to new value: |
275 | data | (current_GPOE_value & ~mask) | 268 | data | (current_GPOE_value & ~mask) |
276 | returns negative value if error occurred | 269 | returns negative value if error occurred |
@@ -290,20 +283,6 @@ extern int bttv_read_gpio(unsigned int card, unsigned long *data); | |||
290 | extern int bttv_write_gpio(unsigned int card, | 283 | extern int bttv_write_gpio(unsigned int card, |
291 | unsigned long mask, unsigned long data); | 284 | unsigned long mask, unsigned long data); |
292 | 285 | ||
293 | /* returns pointer to task queue which can be used as parameter to | ||
294 | interruptible_sleep_on | ||
295 | in interrupt handler if BT848_INT_GPINT bit is set - this queue is activated | ||
296 | (wake_up_interruptible) and following call to the function bttv_read_gpio | ||
297 | should return new value of GPDATA, | ||
298 | returns NULL value if error occurred or queue is not available | ||
299 | WARNING: because there is no buffer for GPIO data, one MUST | ||
300 | process data ASAP | ||
301 | */ | ||
302 | extern wait_queue_head_t* bttv_get_gpio_queue(unsigned int card); | ||
303 | |||
304 | /* call i2c clients | ||
305 | */ | ||
306 | extern void bttv_i2c_call(unsigned int card, unsigned int cmd, void *arg); | ||
307 | 286 | ||
308 | 287 | ||
309 | 288 | ||
diff --git a/drivers/media/video/bt8xx/bttvp.h b/drivers/media/video/bt8xx/bttvp.h index ad79b8d53430..8f44f02029be 100644 --- a/drivers/media/video/bt8xx/bttvp.h +++ b/drivers/media/video/bt8xx/bttvp.h | |||
@@ -434,6 +434,9 @@ struct bttv { | |||
434 | unsigned int users; | 434 | unsigned int users; |
435 | struct bttv_fh init; | 435 | struct bttv_fh init; |
436 | 436 | ||
437 | /* used to make dvb-bt8xx autoloadable */ | ||
438 | struct work_struct request_module_wk; | ||
439 | |||
437 | /* Default (0) and current (1) video capturing and overlay | 440 | /* Default (0) and current (1) video capturing and overlay |
438 | cropping parameters in bttv_tvnorm.cropcap units. Protected | 441 | cropping parameters in bttv_tvnorm.cropcap units. Protected |
439 | by bttv.lock. */ | 442 | by bttv.lock. */ |
diff --git a/drivers/media/video/cafe_ccic.c b/drivers/media/video/cafe_ccic.c index 710c11a68296..96254dbaf625 100644 --- a/drivers/media/video/cafe_ccic.c +++ b/drivers/media/video/cafe_ccic.c | |||
@@ -4,6 +4,7 @@ | |||
4 | * sensor. | 4 | * sensor. |
5 | * | 5 | * |
6 | * Copyright 2006 One Laptop Per Child Association, Inc. | 6 | * Copyright 2006 One Laptop Per Child Association, Inc. |
7 | * Copyright 2006-7 Jonathan Corbet <corbet@lwn.net> | ||
7 | * | 8 | * |
8 | * Written by Jonathan Corbet, corbet@lwn.net. | 9 | * Written by Jonathan Corbet, corbet@lwn.net. |
9 | * | 10 | * |
@@ -22,6 +23,7 @@ | |||
22 | #include <linux/spinlock.h> | 23 | #include <linux/spinlock.h> |
23 | #include <linux/videodev2.h> | 24 | #include <linux/videodev2.h> |
24 | #include <media/v4l2-common.h> | 25 | #include <media/v4l2-common.h> |
26 | #include <media/v4l2-chip-ident.h> | ||
25 | #include <linux/device.h> | 27 | #include <linux/device.h> |
26 | #include <linux/wait.h> | 28 | #include <linux/wait.h> |
27 | #include <linux/list.h> | 29 | #include <linux/list.h> |
@@ -36,7 +38,7 @@ | |||
36 | 38 | ||
37 | #include "cafe_ccic-regs.h" | 39 | #include "cafe_ccic-regs.h" |
38 | 40 | ||
39 | #define CAFE_VERSION 0x000001 | 41 | #define CAFE_VERSION 0x000002 |
40 | 42 | ||
41 | 43 | ||
42 | /* | 44 | /* |
@@ -164,7 +166,7 @@ struct cafe_camera | |||
164 | struct tasklet_struct s_tasklet; | 166 | struct tasklet_struct s_tasklet; |
165 | 167 | ||
166 | /* Current operating parameters */ | 168 | /* Current operating parameters */ |
167 | enum v4l2_chip_ident sensor_type; /* Currently ov7670 only */ | 169 | u32 sensor_type; /* Currently ov7670 only */ |
168 | struct v4l2_pix_format pix_format; | 170 | struct v4l2_pix_format pix_format; |
169 | 171 | ||
170 | /* Locks */ | 172 | /* Locks */ |
@@ -704,7 +706,13 @@ static void cafe_ctlr_init(struct cafe_camera *cam) | |||
704 | cafe_reg_write(cam, REG_GL_CSR, GCSR_SRS|GCSR_MRS); /* Needed? */ | 706 | cafe_reg_write(cam, REG_GL_CSR, GCSR_SRS|GCSR_MRS); /* Needed? */ |
705 | cafe_reg_write(cam, REG_GL_CSR, GCSR_SRC|GCSR_MRC); | 707 | cafe_reg_write(cam, REG_GL_CSR, GCSR_SRC|GCSR_MRC); |
706 | cafe_reg_write(cam, REG_GL_CSR, GCSR_SRC|GCSR_MRS); | 708 | cafe_reg_write(cam, REG_GL_CSR, GCSR_SRC|GCSR_MRS); |
709 | /* | ||
710 | * Here we must wait a bit for the controller to come around. | ||
711 | */ | ||
712 | spin_unlock_irqrestore(&cam->dev_lock, flags); | ||
707 | mdelay(5); /* FIXME revisit this */ | 713 | mdelay(5); /* FIXME revisit this */ |
714 | spin_lock_irqsave(&cam->dev_lock, flags); | ||
715 | |||
708 | cafe_reg_write(cam, REG_GL_CSR, GCSR_CCIC_EN|GCSR_SRC|GCSR_MRC); | 716 | cafe_reg_write(cam, REG_GL_CSR, GCSR_CCIC_EN|GCSR_SRC|GCSR_MRC); |
709 | cafe_reg_set_bit(cam, REG_GL_IMASK, GIMSK_CCIC_EN); | 717 | cafe_reg_set_bit(cam, REG_GL_IMASK, GIMSK_CCIC_EN); |
710 | /* | 718 | /* |
@@ -772,9 +780,9 @@ static void cafe_ctlr_power_up(struct cafe_camera *cam) | |||
772 | * Control 1 is power down, set to 0 to operate. | 780 | * Control 1 is power down, set to 0 to operate. |
773 | */ | 781 | */ |
774 | cafe_reg_write(cam, REG_GPR, GPR_C1EN|GPR_C0EN); /* pwr up, reset */ | 782 | cafe_reg_write(cam, REG_GPR, GPR_C1EN|GPR_C0EN); /* pwr up, reset */ |
775 | mdelay(1); /* Marvell says 1ms will do it */ | 783 | // mdelay(1); /* Marvell says 1ms will do it */ |
776 | cafe_reg_write(cam, REG_GPR, GPR_C1EN|GPR_C0EN|GPR_C0); | 784 | cafe_reg_write(cam, REG_GPR, GPR_C1EN|GPR_C0EN|GPR_C0); |
777 | mdelay(1); /* Enough? */ | 785 | // mdelay(1); /* Enough? */ |
778 | spin_unlock_irqrestore(&cam->dev_lock, flags); | 786 | spin_unlock_irqrestore(&cam->dev_lock, flags); |
779 | } | 787 | } |
780 | 788 | ||
@@ -818,6 +826,7 @@ static int __cafe_cam_reset(struct cafe_camera *cam) | |||
818 | */ | 826 | */ |
819 | static int cafe_cam_init(struct cafe_camera *cam) | 827 | static int cafe_cam_init(struct cafe_camera *cam) |
820 | { | 828 | { |
829 | struct v4l2_chip_ident chip = { V4L2_CHIP_MATCH_I2C_ADDR, 0, 0, 0 }; | ||
821 | int ret; | 830 | int ret; |
822 | 831 | ||
823 | mutex_lock(&cam->s_mutex); | 832 | mutex_lock(&cam->s_mutex); |
@@ -827,9 +836,11 @@ static int cafe_cam_init(struct cafe_camera *cam) | |||
827 | ret = __cafe_cam_reset(cam); | 836 | ret = __cafe_cam_reset(cam); |
828 | if (ret) | 837 | if (ret) |
829 | goto out; | 838 | goto out; |
830 | ret = __cafe_cam_cmd(cam, VIDIOC_INT_G_CHIP_IDENT, &cam->sensor_type); | 839 | chip.match_chip = cam->sensor->addr; |
840 | ret = __cafe_cam_cmd(cam, VIDIOC_G_CHIP_IDENT, &chip); | ||
831 | if (ret) | 841 | if (ret) |
832 | goto out; | 842 | goto out; |
843 | cam->sensor_type = chip.ident; | ||
833 | // if (cam->sensor->addr != OV7xx0_SID) { | 844 | // if (cam->sensor->addr != OV7xx0_SID) { |
834 | if (cam->sensor_type != V4L2_IDENT_OV7670) { | 845 | if (cam->sensor_type != V4L2_IDENT_OV7670) { |
835 | cam_err(cam, "Unsupported sensor type %d", cam->sensor->addr); | 846 | cam_err(cam, "Unsupported sensor type %d", cam->sensor->addr); |
@@ -1792,18 +1803,19 @@ static void cafe_frame_tasklet(unsigned long data) | |||
1792 | if (list_empty(&cam->sb_avail)) | 1803 | if (list_empty(&cam->sb_avail)) |
1793 | break; /* Leave it valid, hope for better later */ | 1804 | break; /* Leave it valid, hope for better later */ |
1794 | clear_bit(bufno, &cam->flags); | 1805 | clear_bit(bufno, &cam->flags); |
1795 | /* | ||
1796 | * We could perhaps drop the spinlock during this | ||
1797 | * big copy. Something to consider. | ||
1798 | */ | ||
1799 | sbuf = list_entry(cam->sb_avail.next, | 1806 | sbuf = list_entry(cam->sb_avail.next, |
1800 | struct cafe_sio_buffer, list); | 1807 | struct cafe_sio_buffer, list); |
1808 | /* | ||
1809 | * Drop the lock during the big copy. This *should* be safe... | ||
1810 | */ | ||
1811 | spin_unlock_irqrestore(&cam->dev_lock, flags); | ||
1801 | memcpy(sbuf->buffer, cam->dma_bufs[bufno], | 1812 | memcpy(sbuf->buffer, cam->dma_bufs[bufno], |
1802 | cam->pix_format.sizeimage); | 1813 | cam->pix_format.sizeimage); |
1803 | sbuf->v4lbuf.bytesused = cam->pix_format.sizeimage; | 1814 | sbuf->v4lbuf.bytesused = cam->pix_format.sizeimage; |
1804 | sbuf->v4lbuf.sequence = cam->buf_seq[bufno]; | 1815 | sbuf->v4lbuf.sequence = cam->buf_seq[bufno]; |
1805 | sbuf->v4lbuf.flags &= ~V4L2_BUF_FLAG_QUEUED; | 1816 | sbuf->v4lbuf.flags &= ~V4L2_BUF_FLAG_QUEUED; |
1806 | sbuf->v4lbuf.flags |= V4L2_BUF_FLAG_DONE; | 1817 | sbuf->v4lbuf.flags |= V4L2_BUF_FLAG_DONE; |
1818 | spin_lock_irqsave(&cam->dev_lock, flags); | ||
1807 | list_move_tail(&sbuf->list, &cam->sb_full); | 1819 | list_move_tail(&sbuf->list, &cam->sb_full); |
1808 | } | 1820 | } |
1809 | if (! list_empty(&cam->sb_full)) | 1821 | if (! list_empty(&cam->sb_full)) |
@@ -2107,6 +2119,7 @@ static int cafe_pci_probe(struct pci_dev *pdev, | |||
2107 | cam->v4ldev = cafe_v4l_template; | 2119 | cam->v4ldev = cafe_v4l_template; |
2108 | cam->v4ldev.debug = 0; | 2120 | cam->v4ldev.debug = 0; |
2109 | // cam->v4ldev.debug = V4L2_DEBUG_IOCTL_ARG; | 2121 | // cam->v4ldev.debug = V4L2_DEBUG_IOCTL_ARG; |
2122 | cam->v4ldev.dev = &pdev->dev; | ||
2110 | ret = video_register_device(&cam->v4ldev, VFL_TYPE_GRABBER, -1); | 2123 | ret = video_register_device(&cam->v4ldev, VFL_TYPE_GRABBER, -1); |
2111 | if (ret) | 2124 | if (ret) |
2112 | goto out_smbus; | 2125 | goto out_smbus; |
@@ -2176,10 +2189,52 @@ static void cafe_pci_remove(struct pci_dev *pdev) | |||
2176 | } | 2189 | } |
2177 | 2190 | ||
2178 | 2191 | ||
2192 | #ifdef CONFIG_PM | ||
2193 | /* | ||
2194 | * Basic power management. | ||
2195 | */ | ||
2196 | static int cafe_pci_suspend(struct pci_dev *pdev, pm_message_t state) | ||
2197 | { | ||
2198 | struct cafe_camera *cam = cafe_find_by_pdev(pdev); | ||
2199 | int ret; | ||
2200 | |||
2201 | ret = pci_save_state(pdev); | ||
2202 | if (ret) | ||
2203 | return ret; | ||
2204 | cafe_ctlr_stop_dma(cam); | ||
2205 | cafe_ctlr_power_down(cam); | ||
2206 | pci_disable_device(pdev); | ||
2207 | return 0; | ||
2208 | } | ||
2209 | |||
2210 | |||
2211 | static int cafe_pci_resume(struct pci_dev *pdev) | ||
2212 | { | ||
2213 | struct cafe_camera *cam = cafe_find_by_pdev(pdev); | ||
2214 | int ret = 0; | ||
2215 | |||
2216 | ret = pci_restore_state(pdev); | ||
2217 | if (ret) | ||
2218 | return ret; | ||
2219 | ret = pci_enable_device(pdev); | ||
2220 | if (ret) { | ||
2221 | cam_warn(cam, "Unable to re-enable device on resume!\n"); | ||
2222 | return ret; | ||
2223 | } | ||
2224 | cafe_ctlr_init(cam); | ||
2225 | cafe_ctlr_power_up(cam); | ||
2226 | set_bit(CF_CONFIG_NEEDED, &cam->flags); | ||
2227 | if (cam->state == S_SPECREAD) | ||
2228 | cam->state = S_IDLE; /* Don't bother restarting */ | ||
2229 | else if (cam->state == S_SINGLEREAD || cam->state == S_STREAMING) | ||
2230 | ret = cafe_read_setup(cam, cam->state); | ||
2231 | return ret; | ||
2232 | } | ||
2233 | |||
2234 | #endif /* CONFIG_PM */ | ||
2179 | 2235 | ||
2180 | 2236 | ||
2181 | static struct pci_device_id cafe_ids[] = { | 2237 | static struct pci_device_id cafe_ids[] = { |
2182 | { PCI_DEVICE(0x1148, 0x4340) }, /* Temporary ID on devel board */ | ||
2183 | { PCI_DEVICE(0x11ab, 0x4100) }, /* Eventual real ID */ | 2238 | { PCI_DEVICE(0x11ab, 0x4100) }, /* Eventual real ID */ |
2184 | { PCI_DEVICE(0x11ab, 0x4102) }, /* Really eventual real ID */ | 2239 | { PCI_DEVICE(0x11ab, 0x4102) }, /* Really eventual real ID */ |
2185 | { 0, } | 2240 | { 0, } |
@@ -2192,6 +2247,10 @@ static struct pci_driver cafe_pci_driver = { | |||
2192 | .id_table = cafe_ids, | 2247 | .id_table = cafe_ids, |
2193 | .probe = cafe_pci_probe, | 2248 | .probe = cafe_pci_probe, |
2194 | .remove = cafe_pci_remove, | 2249 | .remove = cafe_pci_remove, |
2250 | #ifdef CONFIG_PM | ||
2251 | .suspend = cafe_pci_suspend, | ||
2252 | .resume = cafe_pci_resume, | ||
2253 | #endif | ||
2195 | }; | 2254 | }; |
2196 | 2255 | ||
2197 | 2256 | ||
diff --git a/drivers/media/video/cpia_pp.c b/drivers/media/video/cpia_pp.c index b12cec94f4cc..19711aaf9a3e 100644 --- a/drivers/media/video/cpia_pp.c +++ b/drivers/media/video/cpia_pp.c | |||
@@ -62,7 +62,6 @@ static int cpia_pp_close(void *privdata); | |||
62 | #define PPCPIA_PARPORT_OFF -2 | 62 | #define PPCPIA_PARPORT_OFF -2 |
63 | #define PPCPIA_PARPORT_NONE -1 | 63 | #define PPCPIA_PARPORT_NONE -1 |
64 | 64 | ||
65 | #ifdef MODULE | ||
66 | static int parport_nr[PARPORT_MAX] = {[0 ... PARPORT_MAX - 1] = PPCPIA_PARPORT_UNSPEC}; | 65 | static int parport_nr[PARPORT_MAX] = {[0 ... PARPORT_MAX - 1] = PPCPIA_PARPORT_UNSPEC}; |
67 | static char *parport[PARPORT_MAX] = {NULL,}; | 66 | static char *parport[PARPORT_MAX] = {NULL,}; |
68 | 67 | ||
@@ -72,11 +71,6 @@ MODULE_LICENSE("GPL"); | |||
72 | 71 | ||
73 | module_param_array(parport, charp, NULL, 0); | 72 | module_param_array(parport, charp, NULL, 0); |
74 | MODULE_PARM_DESC(parport, "'auto' or a list of parallel port numbers. Just like lp."); | 73 | MODULE_PARM_DESC(parport, "'auto' or a list of parallel port numbers. Just like lp."); |
75 | #else | ||
76 | static int parport_nr[PARPORT_MAX] __initdata = | ||
77 | {[0 ... PARPORT_MAX - 1] = PPCPIA_PARPORT_UNSPEC}; | ||
78 | static int parport_ptr = 0; | ||
79 | #endif | ||
80 | 74 | ||
81 | struct pp_cam_entry { | 75 | struct pp_cam_entry { |
82 | struct pardevice *pdev; | 76 | struct pardevice *pdev; |
@@ -141,7 +135,6 @@ static void cpia_pp_run_callback(struct work_struct *work) | |||
141 | cam = container_of(work, struct pp_cam_entry, cb_task); | 135 | cam = container_of(work, struct pp_cam_entry, cb_task); |
142 | cb_func = cam->cb_func; | 136 | cb_func = cam->cb_func; |
143 | cb_data = cam->cb_data; | 137 | cb_data = cam->cb_data; |
144 | work_release(work); | ||
145 | 138 | ||
146 | cb_func(cb_data); | 139 | cb_func(cb_data); |
147 | } | 140 | } |
@@ -682,7 +675,7 @@ static int cpia_pp_registerCallback(void *privdata, void (*cb)(void *cbdata), vo | |||
682 | if(cam->port->irq != PARPORT_IRQ_NONE) { | 675 | if(cam->port->irq != PARPORT_IRQ_NONE) { |
683 | cam->cb_func = cb; | 676 | cam->cb_func = cb; |
684 | cam->cb_data = cbdata; | 677 | cam->cb_data = cbdata; |
685 | INIT_WORK_NAR(&cam->cb_task, cpia_pp_run_callback); | 678 | INIT_WORK(&cam->cb_task, cpia_pp_run_callback); |
686 | } else { | 679 | } else { |
687 | retval = -1; | 680 | retval = -1; |
688 | } | 681 | } |
@@ -820,7 +813,7 @@ static struct parport_driver cpia_pp_driver = { | |||
820 | .detach = cpia_pp_detach, | 813 | .detach = cpia_pp_detach, |
821 | }; | 814 | }; |
822 | 815 | ||
823 | static int cpia_pp_init(void) | 816 | static int __init cpia_pp_init(void) |
824 | { | 817 | { |
825 | printk(KERN_INFO "%s v%d.%d.%d\n",ABOUT, | 818 | printk(KERN_INFO "%s v%d.%d.%d\n",ABOUT, |
826 | CPIA_PP_MAJ_VER,CPIA_PP_MIN_VER,CPIA_PP_PATCH_VER); | 819 | CPIA_PP_MAJ_VER,CPIA_PP_MIN_VER,CPIA_PP_PATCH_VER); |
@@ -839,8 +832,7 @@ static int cpia_pp_init(void) | |||
839 | return 0; | 832 | return 0; |
840 | } | 833 | } |
841 | 834 | ||
842 | #ifdef MODULE | 835 | static int __init cpia_init(void) |
843 | int init_module(void) | ||
844 | { | 836 | { |
845 | if (parport[0]) { | 837 | if (parport[0]) { |
846 | /* The user gave some parameters. Let's see what they were. */ | 838 | /* The user gave some parameters. Let's see what they were. */ |
@@ -867,38 +859,11 @@ int init_module(void) | |||
867 | return cpia_pp_init(); | 859 | return cpia_pp_init(); |
868 | } | 860 | } |
869 | 861 | ||
870 | void cleanup_module(void) | 862 | static void __exit cpia_cleanup(void) |
871 | { | 863 | { |
872 | parport_unregister_driver (&cpia_pp_driver); | 864 | parport_unregister_driver(&cpia_pp_driver); |
873 | return; | 865 | return; |
874 | } | 866 | } |
875 | 867 | ||
876 | #else /* !MODULE */ | 868 | module_init(cpia_init); |
877 | 869 | module_exit(cpia_cleanup); | |
878 | static int __init cpia_pp_setup(char *str) | ||
879 | { | ||
880 | int err; | ||
881 | |||
882 | if (!strncmp(str, "parport", 7)) { | ||
883 | int n = simple_strtoul(str + 7, NULL, 10); | ||
884 | if (parport_ptr < PARPORT_MAX) { | ||
885 | parport_nr[parport_ptr++] = n; | ||
886 | } else { | ||
887 | LOG("too many ports, %s ignored.\n", str); | ||
888 | } | ||
889 | } else if (!strcmp(str, "auto")) { | ||
890 | parport_nr[0] = PPCPIA_PARPORT_AUTO; | ||
891 | } else if (!strcmp(str, "none")) { | ||
892 | parport_nr[parport_ptr++] = PPCPIA_PARPORT_NONE; | ||
893 | } | ||
894 | |||
895 | err=cpia_pp_init(); | ||
896 | if (err) | ||
897 | return err; | ||
898 | |||
899 | return 1; | ||
900 | } | ||
901 | |||
902 | __setup("cpia_pp=", cpia_pp_setup); | ||
903 | |||
904 | #endif /* !MODULE */ | ||
diff --git a/drivers/media/video/cs53l32a.c b/drivers/media/video/cs53l32a.c index de87247c74ee..a73e285af730 100644 --- a/drivers/media/video/cs53l32a.c +++ b/drivers/media/video/cs53l32a.c | |||
@@ -28,6 +28,7 @@ | |||
28 | #include <linux/i2c-id.h> | 28 | #include <linux/i2c-id.h> |
29 | #include <linux/videodev.h> | 29 | #include <linux/videodev.h> |
30 | #include <media/v4l2-common.h> | 30 | #include <media/v4l2-common.h> |
31 | #include <media/v4l2-chip-ident.h> | ||
31 | 32 | ||
32 | MODULE_DESCRIPTION("i2c device driver for cs53l32a Audio ADC"); | 33 | MODULE_DESCRIPTION("i2c device driver for cs53l32a Audio ADC"); |
33 | MODULE_AUTHOR("Martin Vaughan"); | 34 | MODULE_AUTHOR("Martin Vaughan"); |
@@ -103,6 +104,9 @@ static int cs53l32a_command(struct i2c_client *client, unsigned int cmd, | |||
103 | cs53l32a_write(client, 0x05, (u8) ctrl->value); | 104 | cs53l32a_write(client, 0x05, (u8) ctrl->value); |
104 | break; | 105 | break; |
105 | 106 | ||
107 | case VIDIOC_G_CHIP_IDENT: | ||
108 | return v4l2_chip_ident_i2c_client(client, arg, V4L2_IDENT_CS53l32A, 0); | ||
109 | |||
106 | case VIDIOC_LOG_STATUS: | 110 | case VIDIOC_LOG_STATUS: |
107 | { | 111 | { |
108 | u8 v = cs53l32a_read(client, 0x01); | 112 | u8 v = cs53l32a_read(client, 0x01); |
diff --git a/drivers/media/video/cx2341x.c b/drivers/media/video/cx2341x.c index d60cd5ecf821..88dbdddeec42 100644 --- a/drivers/media/video/cx2341x.c +++ b/drivers/media/video/cx2341x.c | |||
@@ -51,6 +51,7 @@ const u32 cx2341x_mpeg_ctrls[] = { | |||
51 | V4L2_CID_MPEG_AUDIO_MODE_EXTENSION, | 51 | V4L2_CID_MPEG_AUDIO_MODE_EXTENSION, |
52 | V4L2_CID_MPEG_AUDIO_EMPHASIS, | 52 | V4L2_CID_MPEG_AUDIO_EMPHASIS, |
53 | V4L2_CID_MPEG_AUDIO_CRC, | 53 | V4L2_CID_MPEG_AUDIO_CRC, |
54 | V4L2_CID_MPEG_AUDIO_MUTE, | ||
54 | V4L2_CID_MPEG_VIDEO_ENCODING, | 55 | V4L2_CID_MPEG_VIDEO_ENCODING, |
55 | V4L2_CID_MPEG_VIDEO_ASPECT, | 56 | V4L2_CID_MPEG_VIDEO_ASPECT, |
56 | V4L2_CID_MPEG_VIDEO_B_FRAMES, | 57 | V4L2_CID_MPEG_VIDEO_B_FRAMES, |
@@ -60,6 +61,8 @@ const u32 cx2341x_mpeg_ctrls[] = { | |||
60 | V4L2_CID_MPEG_VIDEO_BITRATE, | 61 | V4L2_CID_MPEG_VIDEO_BITRATE, |
61 | V4L2_CID_MPEG_VIDEO_BITRATE_PEAK, | 62 | V4L2_CID_MPEG_VIDEO_BITRATE_PEAK, |
62 | V4L2_CID_MPEG_VIDEO_TEMPORAL_DECIMATION, | 63 | V4L2_CID_MPEG_VIDEO_TEMPORAL_DECIMATION, |
64 | V4L2_CID_MPEG_VIDEO_MUTE, | ||
65 | V4L2_CID_MPEG_VIDEO_MUTE_YUV, | ||
63 | V4L2_CID_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE, | 66 | V4L2_CID_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE, |
64 | V4L2_CID_MPEG_CX2341X_VIDEO_SPATIAL_FILTER, | 67 | V4L2_CID_MPEG_CX2341X_VIDEO_SPATIAL_FILTER, |
65 | V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE, | 68 | V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE, |
@@ -71,6 +74,7 @@ const u32 cx2341x_mpeg_ctrls[] = { | |||
71 | V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_MEDIAN_FILTER_TOP, | 74 | V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_MEDIAN_FILTER_TOP, |
72 | V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_MEDIAN_FILTER_BOTTOM, | 75 | V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_MEDIAN_FILTER_BOTTOM, |
73 | V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_MEDIAN_FILTER_TOP, | 76 | V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_MEDIAN_FILTER_TOP, |
77 | V4L2_CID_MPEG_CX2341X_STREAM_INSERT_NAV_PACKETS, | ||
74 | 0 | 78 | 0 |
75 | }; | 79 | }; |
76 | 80 | ||
@@ -102,6 +106,9 @@ static int cx2341x_get_ctrl(struct cx2341x_mpeg_params *params, | |||
102 | case V4L2_CID_MPEG_AUDIO_CRC: | 106 | case V4L2_CID_MPEG_AUDIO_CRC: |
103 | ctrl->value = params->audio_crc; | 107 | ctrl->value = params->audio_crc; |
104 | break; | 108 | break; |
109 | case V4L2_CID_MPEG_AUDIO_MUTE: | ||
110 | ctrl->value = params->audio_mute; | ||
111 | break; | ||
105 | case V4L2_CID_MPEG_VIDEO_ENCODING: | 112 | case V4L2_CID_MPEG_VIDEO_ENCODING: |
106 | ctrl->value = params->video_encoding; | 113 | ctrl->value = params->video_encoding; |
107 | break; | 114 | break; |
@@ -129,6 +136,12 @@ static int cx2341x_get_ctrl(struct cx2341x_mpeg_params *params, | |||
129 | case V4L2_CID_MPEG_VIDEO_TEMPORAL_DECIMATION: | 136 | case V4L2_CID_MPEG_VIDEO_TEMPORAL_DECIMATION: |
130 | ctrl->value = params->video_temporal_decimation; | 137 | ctrl->value = params->video_temporal_decimation; |
131 | break; | 138 | break; |
139 | case V4L2_CID_MPEG_VIDEO_MUTE: | ||
140 | ctrl->value = params->video_mute; | ||
141 | break; | ||
142 | case V4L2_CID_MPEG_VIDEO_MUTE_YUV: | ||
143 | ctrl->value = params->video_mute_yuv; | ||
144 | break; | ||
132 | case V4L2_CID_MPEG_STREAM_TYPE: | 145 | case V4L2_CID_MPEG_STREAM_TYPE: |
133 | ctrl->value = params->stream_type; | 146 | ctrl->value = params->stream_type; |
134 | break; | 147 | break; |
@@ -168,6 +181,9 @@ static int cx2341x_get_ctrl(struct cx2341x_mpeg_params *params, | |||
168 | case V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_MEDIAN_FILTER_BOTTOM: | 181 | case V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_MEDIAN_FILTER_BOTTOM: |
169 | ctrl->value = params->video_chroma_median_filter_bottom; | 182 | ctrl->value = params->video_chroma_median_filter_bottom; |
170 | break; | 183 | break; |
184 | case V4L2_CID_MPEG_CX2341X_STREAM_INSERT_NAV_PACKETS: | ||
185 | ctrl->value = params->stream_insert_nav_packets; | ||
186 | break; | ||
171 | default: | 187 | default: |
172 | return -EINVAL; | 188 | return -EINVAL; |
173 | } | 189 | } |
@@ -201,6 +217,9 @@ static int cx2341x_set_ctrl(struct cx2341x_mpeg_params *params, | |||
201 | case V4L2_CID_MPEG_AUDIO_CRC: | 217 | case V4L2_CID_MPEG_AUDIO_CRC: |
202 | params->audio_crc = ctrl->value; | 218 | params->audio_crc = ctrl->value; |
203 | break; | 219 | break; |
220 | case V4L2_CID_MPEG_AUDIO_MUTE: | ||
221 | params->audio_mute = ctrl->value; | ||
222 | break; | ||
204 | case V4L2_CID_MPEG_VIDEO_ASPECT: | 223 | case V4L2_CID_MPEG_VIDEO_ASPECT: |
205 | params->video_aspect = ctrl->value; | 224 | params->video_aspect = ctrl->value; |
206 | break; | 225 | break; |
@@ -243,6 +262,12 @@ static int cx2341x_set_ctrl(struct cx2341x_mpeg_params *params, | |||
243 | case V4L2_CID_MPEG_VIDEO_TEMPORAL_DECIMATION: | 262 | case V4L2_CID_MPEG_VIDEO_TEMPORAL_DECIMATION: |
244 | params->video_temporal_decimation = ctrl->value; | 263 | params->video_temporal_decimation = ctrl->value; |
245 | break; | 264 | break; |
265 | case V4L2_CID_MPEG_VIDEO_MUTE: | ||
266 | params->video_mute = (ctrl->value != 0); | ||
267 | break; | ||
268 | case V4L2_CID_MPEG_VIDEO_MUTE_YUV: | ||
269 | params->video_mute_yuv = ctrl->value; | ||
270 | break; | ||
246 | case V4L2_CID_MPEG_STREAM_TYPE: | 271 | case V4L2_CID_MPEG_STREAM_TYPE: |
247 | params->stream_type = ctrl->value; | 272 | params->stream_type = ctrl->value; |
248 | params->video_encoding = | 273 | params->video_encoding = |
@@ -290,6 +315,9 @@ static int cx2341x_set_ctrl(struct cx2341x_mpeg_params *params, | |||
290 | case V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_MEDIAN_FILTER_BOTTOM: | 315 | case V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_MEDIAN_FILTER_BOTTOM: |
291 | params->video_chroma_median_filter_bottom = ctrl->value; | 316 | params->video_chroma_median_filter_bottom = ctrl->value; |
292 | break; | 317 | break; |
318 | case V4L2_CID_MPEG_CX2341X_STREAM_INSERT_NAV_PACKETS: | ||
319 | params->stream_insert_nav_packets = ctrl->value; | ||
320 | break; | ||
293 | default: | 321 | default: |
294 | return -EINVAL; | 322 | return -EINVAL; |
295 | } | 323 | } |
@@ -336,6 +364,9 @@ static int cx2341x_ctrl_query_fill(struct v4l2_queryctrl *qctrl, s32 min, s32 ma | |||
336 | case V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_MEDIAN_FILTER_BOTTOM: | 364 | case V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_MEDIAN_FILTER_BOTTOM: |
337 | name = "Median Chroma Filter Minimum"; | 365 | name = "Median Chroma Filter Minimum"; |
338 | break; | 366 | break; |
367 | case V4L2_CID_MPEG_CX2341X_STREAM_INSERT_NAV_PACKETS: | ||
368 | name = "Insert Navigation Packets"; | ||
369 | break; | ||
339 | 370 | ||
340 | default: | 371 | default: |
341 | return v4l2_ctrl_query_fill(qctrl, min, max, step, def); | 372 | return v4l2_ctrl_query_fill(qctrl, min, max, step, def); |
@@ -350,6 +381,12 @@ static int cx2341x_ctrl_query_fill(struct v4l2_queryctrl *qctrl, s32 min, s32 ma | |||
350 | min = 0; | 381 | min = 0; |
351 | step = 1; | 382 | step = 1; |
352 | break; | 383 | break; |
384 | case V4L2_CID_MPEG_CX2341X_STREAM_INSERT_NAV_PACKETS: | ||
385 | qctrl->type = V4L2_CTRL_TYPE_BOOLEAN; | ||
386 | min = 0; | ||
387 | max = 1; | ||
388 | step = 1; | ||
389 | break; | ||
353 | default: | 390 | default: |
354 | qctrl->type = V4L2_CTRL_TYPE_INTEGER; | 391 | qctrl->type = V4L2_CTRL_TYPE_INTEGER; |
355 | break; | 392 | break; |
@@ -505,6 +542,9 @@ int cx2341x_ctrl_query(struct cx2341x_mpeg_params *params, struct v4l2_queryctrl | |||
505 | qctrl->flags |= V4L2_CTRL_FLAG_INACTIVE; | 542 | qctrl->flags |= V4L2_CTRL_FLAG_INACTIVE; |
506 | return 0; | 543 | return 0; |
507 | 544 | ||
545 | case V4L2_CID_MPEG_CX2341X_STREAM_INSERT_NAV_PACKETS: | ||
546 | return cx2341x_ctrl_query_fill(qctrl, 0, 1, 1, 0); | ||
547 | |||
508 | default: | 548 | default: |
509 | return v4l2_ctrl_query_fill_std(qctrl); | 549 | return v4l2_ctrl_query_fill_std(qctrl); |
510 | 550 | ||
@@ -656,6 +696,7 @@ void cx2341x_fill_defaults(struct cx2341x_mpeg_params *p) | |||
656 | /* stream */ | 696 | /* stream */ |
657 | .stream_type = V4L2_MPEG_STREAM_TYPE_MPEG2_PS, | 697 | .stream_type = V4L2_MPEG_STREAM_TYPE_MPEG2_PS, |
658 | .stream_vbi_fmt = V4L2_MPEG_STREAM_VBI_FMT_NONE, | 698 | .stream_vbi_fmt = V4L2_MPEG_STREAM_VBI_FMT_NONE, |
699 | .stream_insert_nav_packets = 0, | ||
659 | 700 | ||
660 | /* audio */ | 701 | /* audio */ |
661 | .audio_sampling_freq = V4L2_MPEG_AUDIO_SAMPLING_FREQ_48000, | 702 | .audio_sampling_freq = V4L2_MPEG_AUDIO_SAMPLING_FREQ_48000, |
@@ -665,6 +706,7 @@ void cx2341x_fill_defaults(struct cx2341x_mpeg_params *p) | |||
665 | .audio_mode_extension = V4L2_MPEG_AUDIO_MODE_EXTENSION_BOUND_4, | 706 | .audio_mode_extension = V4L2_MPEG_AUDIO_MODE_EXTENSION_BOUND_4, |
666 | .audio_emphasis = V4L2_MPEG_AUDIO_EMPHASIS_NONE, | 707 | .audio_emphasis = V4L2_MPEG_AUDIO_EMPHASIS_NONE, |
667 | .audio_crc = V4L2_MPEG_AUDIO_CRC_NONE, | 708 | .audio_crc = V4L2_MPEG_AUDIO_CRC_NONE, |
709 | .audio_mute = 0, | ||
668 | 710 | ||
669 | /* video */ | 711 | /* video */ |
670 | .video_encoding = V4L2_MPEG_VIDEO_ENCODING_MPEG_2, | 712 | .video_encoding = V4L2_MPEG_VIDEO_ENCODING_MPEG_2, |
@@ -676,6 +718,8 @@ void cx2341x_fill_defaults(struct cx2341x_mpeg_params *p) | |||
676 | .video_bitrate = 6000000, | 718 | .video_bitrate = 6000000, |
677 | .video_bitrate_peak = 8000000, | 719 | .video_bitrate_peak = 8000000, |
678 | .video_temporal_decimation = 0, | 720 | .video_temporal_decimation = 0, |
721 | .video_mute = 0, | ||
722 | .video_mute_yuv = 0x008080, /* YCbCr value for black */ | ||
679 | 723 | ||
680 | /* encoding filters */ | 724 | /* encoding filters */ |
681 | .video_spatial_filter_mode = V4L2_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE_MANUAL, | 725 | .video_spatial_filter_mode = V4L2_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE_MANUAL, |
@@ -779,6 +823,10 @@ int cx2341x_update(void *priv, cx2341x_mbox_func func, | |||
779 | err = cx2341x_api(priv, func, CX2341X_ENC_SET_AUDIO_PROPERTIES, 1, new->audio_properties); | 823 | err = cx2341x_api(priv, func, CX2341X_ENC_SET_AUDIO_PROPERTIES, 1, new->audio_properties); |
780 | if (err) return err; | 824 | if (err) return err; |
781 | } | 825 | } |
826 | if (old == NULL || old->audio_mute != new->audio_mute) { | ||
827 | err = cx2341x_api(priv, func, CX2341X_ENC_MUTE_AUDIO, 1, new->audio_mute); | ||
828 | if (err) return err; | ||
829 | } | ||
782 | if (old == NULL || old->video_bitrate_mode != new->video_bitrate_mode || | 830 | if (old == NULL || old->video_bitrate_mode != new->video_bitrate_mode || |
783 | old->video_bitrate != new->video_bitrate || | 831 | old->video_bitrate != new->video_bitrate || |
784 | old->video_bitrate_peak != new->video_bitrate_peak) { | 832 | old->video_bitrate_peak != new->video_bitrate_peak) { |
@@ -826,6 +874,15 @@ int cx2341x_update(void *priv, cx2341x_mbox_func func, | |||
826 | new->video_temporal_decimation); | 874 | new->video_temporal_decimation); |
827 | if (err) return err; | 875 | if (err) return err; |
828 | } | 876 | } |
877 | if (old == NULL || old->video_mute != new->video_mute || | ||
878 | (new->video_mute && old->video_mute_yuv != new->video_mute_yuv)) { | ||
879 | err = cx2341x_api(priv, func, CX2341X_ENC_MUTE_VIDEO, 1, new->video_mute | (new->video_mute_yuv << 8)); | ||
880 | if (err) return err; | ||
881 | } | ||
882 | if (old == NULL || old->stream_insert_nav_packets != new->stream_insert_nav_packets) { | ||
883 | err = cx2341x_api(priv, func, CX2341X_ENC_MISC, 2, 7, new->stream_insert_nav_packets); | ||
884 | if (err) return err; | ||
885 | } | ||
829 | return 0; | 886 | return 0; |
830 | } | 887 | } |
831 | 888 | ||
@@ -854,18 +911,22 @@ void cx2341x_log_status(struct cx2341x_mpeg_params *p, const char *prefix) | |||
854 | int temporal = p->video_temporal_filter; | 911 | int temporal = p->video_temporal_filter; |
855 | 912 | ||
856 | /* Stream */ | 913 | /* Stream */ |
857 | printk(KERN_INFO "%s: Stream: %s\n", | 914 | printk(KERN_INFO "%s: Stream: %s", |
858 | prefix, | 915 | prefix, |
859 | cx2341x_menu_item(p, V4L2_CID_MPEG_STREAM_TYPE)); | 916 | cx2341x_menu_item(p, V4L2_CID_MPEG_STREAM_TYPE)); |
917 | if (p->stream_insert_nav_packets) | ||
918 | printk(" (with navigation packets)"); | ||
919 | printk("\n"); | ||
860 | printk(KERN_INFO "%s: VBI Format: %s\n", | 920 | printk(KERN_INFO "%s: VBI Format: %s\n", |
861 | prefix, | 921 | prefix, |
862 | cx2341x_menu_item(p, V4L2_CID_MPEG_STREAM_VBI_FMT)); | 922 | cx2341x_menu_item(p, V4L2_CID_MPEG_STREAM_VBI_FMT)); |
863 | 923 | ||
864 | /* Video */ | 924 | /* Video */ |
865 | printk(KERN_INFO "%s: Video: %dx%d, %d fps\n", | 925 | printk(KERN_INFO "%s: Video: %dx%d, %d fps%s\n", |
866 | prefix, | 926 | prefix, |
867 | p->width / (is_mpeg1 ? 2 : 1), p->height / (is_mpeg1 ? 2 : 1), | 927 | p->width / (is_mpeg1 ? 2 : 1), p->height / (is_mpeg1 ? 2 : 1), |
868 | p->is_50hz ? 25 : 30); | 928 | p->is_50hz ? 25 : 30, |
929 | (p->video_mute) ? " (muted)" : ""); | ||
869 | printk(KERN_INFO "%s: Video: %s, %s, %s, %d", | 930 | printk(KERN_INFO "%s: Video: %s, %s, %s, %d", |
870 | prefix, | 931 | prefix, |
871 | cx2341x_menu_item(p, V4L2_CID_MPEG_VIDEO_ENCODING), | 932 | cx2341x_menu_item(p, V4L2_CID_MPEG_VIDEO_ENCODING), |
@@ -886,12 +947,13 @@ void cx2341x_log_status(struct cx2341x_mpeg_params *p, const char *prefix) | |||
886 | } | 947 | } |
887 | 948 | ||
888 | /* Audio */ | 949 | /* Audio */ |
889 | printk(KERN_INFO "%s: Audio: %s, %s, %s, %s", | 950 | printk(KERN_INFO "%s: Audio: %s, %s, %s, %s%s", |
890 | prefix, | 951 | prefix, |
891 | cx2341x_menu_item(p, V4L2_CID_MPEG_AUDIO_SAMPLING_FREQ), | 952 | cx2341x_menu_item(p, V4L2_CID_MPEG_AUDIO_SAMPLING_FREQ), |
892 | cx2341x_menu_item(p, V4L2_CID_MPEG_AUDIO_ENCODING), | 953 | cx2341x_menu_item(p, V4L2_CID_MPEG_AUDIO_ENCODING), |
893 | cx2341x_menu_item(p, V4L2_CID_MPEG_AUDIO_L2_BITRATE), | 954 | cx2341x_menu_item(p, V4L2_CID_MPEG_AUDIO_L2_BITRATE), |
894 | cx2341x_menu_item(p, V4L2_CID_MPEG_AUDIO_MODE)); | 955 | cx2341x_menu_item(p, V4L2_CID_MPEG_AUDIO_MODE), |
956 | p->audio_mute ? " (muted)" : ""); | ||
895 | if (p->audio_mode == V4L2_MPEG_AUDIO_MODE_JOINT_STEREO) { | 957 | if (p->audio_mode == V4L2_MPEG_AUDIO_MODE_JOINT_STEREO) { |
896 | printk(", %s", | 958 | printk(", %s", |
897 | cx2341x_menu_item(p, V4L2_CID_MPEG_AUDIO_MODE_EXTENSION)); | 959 | cx2341x_menu_item(p, V4L2_CID_MPEG_AUDIO_MODE_EXTENSION)); |
diff --git a/drivers/media/video/cx25840/cx25840-core.c b/drivers/media/video/cx25840/cx25840-core.c index 774d2536555b..1757a588970f 100644 --- a/drivers/media/video/cx25840/cx25840-core.c +++ b/drivers/media/video/cx25840/cx25840-core.c | |||
@@ -35,6 +35,7 @@ | |||
35 | #include <linux/videodev2.h> | 35 | #include <linux/videodev2.h> |
36 | #include <linux/i2c.h> | 36 | #include <linux/i2c.h> |
37 | #include <media/v4l2-common.h> | 37 | #include <media/v4l2-common.h> |
38 | #include <media/v4l2-chip-ident.h> | ||
38 | #include <media/cx25840.h> | 39 | #include <media/cx25840.h> |
39 | 40 | ||
40 | #include "cx25840-core.h" | 41 | #include "cx25840-core.h" |
@@ -827,9 +828,8 @@ static int cx25840_command(struct i2c_client *client, unsigned int cmd, | |||
827 | cx25840_initialize(client, 0); | 828 | cx25840_initialize(client, 0); |
828 | break; | 829 | break; |
829 | 830 | ||
830 | case VIDIOC_INT_G_CHIP_IDENT: | 831 | case VIDIOC_G_CHIP_IDENT: |
831 | *(enum v4l2_chip_ident *)arg = state->id; | 832 | return v4l2_chip_ident_i2c_client(client, arg, state->id, state->rev); |
832 | break; | ||
833 | 833 | ||
834 | default: | 834 | default: |
835 | return -EINVAL; | 835 | return -EINVAL; |
@@ -847,7 +847,7 @@ static int cx25840_detect_client(struct i2c_adapter *adapter, int address, | |||
847 | { | 847 | { |
848 | struct i2c_client *client; | 848 | struct i2c_client *client; |
849 | struct cx25840_state *state; | 849 | struct cx25840_state *state; |
850 | enum v4l2_chip_ident id; | 850 | u32 id; |
851 | u16 device_id; | 851 | u16 device_id; |
852 | 852 | ||
853 | /* Check if the adapter supports the needed features | 853 | /* Check if the adapter supports the needed features |
@@ -902,6 +902,7 @@ static int cx25840_detect_client(struct i2c_adapter *adapter, int address, | |||
902 | state->audmode = V4L2_TUNER_MODE_LANG1; | 902 | state->audmode = V4L2_TUNER_MODE_LANG1; |
903 | state->vbi_line_offset = 8; | 903 | state->vbi_line_offset = 8; |
904 | state->id = id; | 904 | state->id = id; |
905 | state->rev = device_id; | ||
905 | 906 | ||
906 | i2c_attach_client(client); | 907 | i2c_attach_client(client); |
907 | 908 | ||
diff --git a/drivers/media/video/cx25840/cx25840-core.h b/drivers/media/video/cx25840/cx25840-core.h index 28049064dd7d..f4b56d2fd6b6 100644 --- a/drivers/media/video/cx25840/cx25840-core.h +++ b/drivers/media/video/cx25840/cx25840-core.h | |||
@@ -43,7 +43,8 @@ struct cx25840_state { | |||
43 | u32 audclk_freq; | 43 | u32 audclk_freq; |
44 | int audmode; | 44 | int audmode; |
45 | int vbi_line_offset; | 45 | int vbi_line_offset; |
46 | enum v4l2_chip_ident id; | 46 | u32 id; |
47 | u32 rev; | ||
47 | int is_cx25836; | 48 | int is_cx25836; |
48 | }; | 49 | }; |
49 | 50 | ||
diff --git a/drivers/media/video/cx25840/cx25840-firmware.c b/drivers/media/video/cx25840/cx25840-firmware.c index 0e86b9d033ac..e852024a5ea3 100644 --- a/drivers/media/video/cx25840/cx25840-firmware.c +++ b/drivers/media/video/cx25840/cx25840-firmware.c | |||
@@ -17,7 +17,6 @@ | |||
17 | 17 | ||
18 | #include <linux/module.h> | 18 | #include <linux/module.h> |
19 | #include <linux/i2c.h> | 19 | #include <linux/i2c.h> |
20 | #include <linux/i2c-algo-bit.h> | ||
21 | #include <linux/firmware.h> | 20 | #include <linux/firmware.h> |
22 | #include <media/v4l2-common.h> | 21 | #include <media/v4l2-common.h> |
23 | #include <media/cx25840.h> | 22 | #include <media/cx25840.h> |
diff --git a/drivers/media/video/cx88/Kconfig b/drivers/media/video/cx88/Kconfig index b2a66ba625f9..0f9d96963618 100644 --- a/drivers/media/video/cx88/Kconfig +++ b/drivers/media/video/cx88/Kconfig | |||
@@ -53,7 +53,6 @@ config VIDEO_CX88_DVB | |||
53 | select DVB_OR51132 if !DVB_FE_CUSTOMISE | 53 | select DVB_OR51132 if !DVB_FE_CUSTOMISE |
54 | select DVB_CX22702 if !DVB_FE_CUSTOMISE | 54 | select DVB_CX22702 if !DVB_FE_CUSTOMISE |
55 | select DVB_LGDT330X if !DVB_FE_CUSTOMISE | 55 | select DVB_LGDT330X if !DVB_FE_CUSTOMISE |
56 | select DVB_TUNER_LGH06XF if !DVB_FE_CUSTOMISE | ||
57 | select DVB_NXT200X if !DVB_FE_CUSTOMISE | 56 | select DVB_NXT200X if !DVB_FE_CUSTOMISE |
58 | select DVB_CX24123 if !DVB_FE_CUSTOMISE | 57 | select DVB_CX24123 if !DVB_FE_CUSTOMISE |
59 | select DVB_ISL6421 if !DVB_FE_CUSTOMISE | 58 | select DVB_ISL6421 if !DVB_FE_CUSTOMISE |
diff --git a/drivers/media/video/cx88/cx88-alsa.c b/drivers/media/video/cx88/cx88-alsa.c index e4355fdc3b6d..3956c257556c 100644 --- a/drivers/media/video/cx88/cx88-alsa.c +++ b/drivers/media/video/cx88/cx88-alsa.c | |||
@@ -232,7 +232,8 @@ static void cx8801_aud_irq(snd_cx88_card_t *chip) | |||
232 | cx_write(MO_AUD_INTSTAT, status); | 232 | cx_write(MO_AUD_INTSTAT, status); |
233 | if (debug > 1 || (status & mask & ~0xff)) | 233 | if (debug > 1 || (status & mask & ~0xff)) |
234 | cx88_print_irqbits(core->name, "irq aud", | 234 | cx88_print_irqbits(core->name, "irq aud", |
235 | cx88_aud_irqs, status, mask); | 235 | cx88_aud_irqs, ARRAY_SIZE(cx88_aud_irqs), |
236 | status, mask); | ||
236 | /* risc op code error */ | 237 | /* risc op code error */ |
237 | if (status & (1 << 16)) { | 238 | if (status & (1 << 16)) { |
238 | printk(KERN_WARNING "%s/0: audio risc op code error\n",core->name); | 239 | printk(KERN_WARNING "%s/0: audio risc op code error\n",core->name); |
@@ -413,11 +414,9 @@ static int snd_cx88_hw_params(struct snd_pcm_substream * substream, | |||
413 | 414 | ||
414 | dprintk(1,"Setting buffer\n"); | 415 | dprintk(1,"Setting buffer\n"); |
415 | 416 | ||
416 | buf = kmalloc(sizeof(*buf),GFP_KERNEL); | 417 | buf = kzalloc(sizeof(*buf),GFP_KERNEL); |
417 | if (NULL == buf) | 418 | if (NULL == buf) |
418 | return -ENOMEM; | 419 | return -ENOMEM; |
419 | memset(buf,0,sizeof(*buf)); | ||
420 | |||
421 | 420 | ||
422 | buf->vb.memory = V4L2_MEMORY_MMAP; | 421 | buf->vb.memory = V4L2_MEMORY_MMAP; |
423 | buf->vb.width = chip->period_size; | 422 | buf->vb.width = chip->period_size; |
@@ -682,7 +681,7 @@ static int __devinit snd_cx88_create(struct snd_card *card, | |||
682 | return err; | 681 | return err; |
683 | } | 682 | } |
684 | 683 | ||
685 | if (!pci_dma_supported(pci,0xffffffff)) { | 684 | if (!pci_dma_supported(pci,DMA_32BIT_MASK)) { |
686 | dprintk(0, "%s/1: Oops: no 32bit PCI DMA ???\n",core->name); | 685 | dprintk(0, "%s/1: Oops: no 32bit PCI DMA ???\n",core->name); |
687 | err = -EIO; | 686 | err = -EIO; |
688 | cx88_core_put(core,pci); | 687 | cx88_core_put(core,pci); |
diff --git a/drivers/media/video/cx88/cx88-cards.c b/drivers/media/video/cx88/cx88-cards.c index 65e9d8096b74..e61102dc8ad7 100644 --- a/drivers/media/video/cx88/cx88-cards.c +++ b/drivers/media/video/cx88/cx88-cards.c | |||
@@ -885,6 +885,12 @@ struct cx88_board cx88_boards[] = { | |||
885 | .input = {{ | 885 | .input = {{ |
886 | .type = CX88_VMUX_DVB, | 886 | .type = CX88_VMUX_DVB, |
887 | .vmux = 0, | 887 | .vmux = 0, |
888 | },{ | ||
889 | .type = CX88_VMUX_COMPOSITE1, | ||
890 | .vmux = 1, | ||
891 | },{ | ||
892 | .type = CX88_VMUX_SVIDEO, | ||
893 | .vmux = 2, | ||
888 | }}, | 894 | }}, |
889 | .mpeg = CX88_MPEG_DVB, | 895 | .mpeg = CX88_MPEG_DVB, |
890 | }, | 896 | }, |
@@ -1537,10 +1543,10 @@ struct cx88_subid cx88_subids[] = { | |||
1537 | },{ | 1543 | },{ |
1538 | .subvendor = 0x17de, | 1544 | .subvendor = 0x17de, |
1539 | .subdevice = 0x0840, | 1545 | .subdevice = 0x0840, |
1540 | .card = CX88_BOARD_KWORLD_HARDWARE_MPEG_TV_XPERT, | 1546 | .card = CX88_BOARD_KWORLD_HARDWARE_MPEG_TV_XPERT, |
1541 | },{ | 1547 | },{ |
1542 | .subvendor = 0x1421, | 1548 | .subvendor = 0x1421, |
1543 | .subdevice = 0x0305, | 1549 | .subdevice = 0x0305, |
1544 | .card = CX88_BOARD_KWORLD_HARDWARE_MPEG_TV_XPERT, | 1550 | .card = CX88_BOARD_KWORLD_HARDWARE_MPEG_TV_XPERT, |
1545 | },{ | 1551 | },{ |
1546 | .subvendor = 0x18ac, | 1552 | .subvendor = 0x18ac, |
@@ -1631,6 +1637,10 @@ struct cx88_subid cx88_subids[] = { | |||
1631 | .subvendor = 0x0070, | 1637 | .subvendor = 0x0070, |
1632 | .subdevice = 0x1402, | 1638 | .subdevice = 0x1402, |
1633 | .card = CX88_BOARD_HAUPPAUGE_HVR3000, | 1639 | .card = CX88_BOARD_HAUPPAUGE_HVR3000, |
1640 | },{ | ||
1641 | .subvendor = 0x1421, | ||
1642 | .subdevice = 0x0341, /* ADS Tech InstantTV DVB-S */ | ||
1643 | .card = CX88_BOARD_KWORLD_DVBS_100, | ||
1634 | }, | 1644 | }, |
1635 | }; | 1645 | }; |
1636 | const unsigned int cx88_idcount = ARRAY_SIZE(cx88_subids); | 1646 | const unsigned int cx88_idcount = ARRAY_SIZE(cx88_subids); |
@@ -1786,7 +1796,7 @@ static void dvico_fusionhdtv_hybrid_init(struct cx88_core *core) | |||
1786 | { 0x03, 0x0C }, | 1796 | { 0x03, 0x0C }, |
1787 | }; | 1797 | }; |
1788 | 1798 | ||
1789 | for (i = 0; i < 13; i++) { | 1799 | for (i = 0; i < ARRAY_SIZE(init_bufs); i++) { |
1790 | msg.buf = init_bufs[i]; | 1800 | msg.buf = init_bufs[i]; |
1791 | msg.len = (i != 12 ? 5 : 2); | 1801 | msg.len = (i != 12 ? 5 : 2); |
1792 | err = i2c_transfer(&core->i2c_adap, &msg, 1); | 1802 | err = i2c_transfer(&core->i2c_adap, &msg, 1); |
@@ -1913,12 +1923,21 @@ void cx88_card_setup(struct cx88_core *core) | |||
1913 | if (0 == core->i2c_rc) { | 1923 | if (0 == core->i2c_rc) { |
1914 | /* enable tuner */ | 1924 | /* enable tuner */ |
1915 | int i; | 1925 | int i; |
1916 | static const u8 buffer [] = { 0x10,0x12,0x13,0x04,0x16,0x00,0x14,0x04,0x017,0x00 }; | 1926 | static const u8 buffer [][2] = { |
1927 | {0x10,0x12}, | ||
1928 | {0x13,0x04}, | ||
1929 | {0x16,0x00}, | ||
1930 | {0x14,0x04}, | ||
1931 | {0x17,0x00} | ||
1932 | }; | ||
1917 | core->i2c_client.addr = 0x0a; | 1933 | core->i2c_client.addr = 0x0a; |
1918 | 1934 | ||
1919 | for (i = 0; i < 5; i++) | 1935 | for (i = 0; i < ARRAY_SIZE(buffer); i++) |
1920 | if (2 != i2c_master_send(&core->i2c_client,&buffer[i*2],2)) | 1936 | if (2 != i2c_master_send(&core->i2c_client, |
1921 | printk(KERN_WARNING "%s: Unable to enable tuner(%i).\n", | 1937 | buffer[i],2)) |
1938 | printk(KERN_WARNING | ||
1939 | "%s: Unable to enable " | ||
1940 | "tuner(%i).\n", | ||
1922 | core->name, i); | 1941 | core->name, i); |
1923 | } | 1942 | } |
1924 | break; | 1943 | break; |
diff --git a/drivers/media/video/cx88/cx88-core.c b/drivers/media/video/cx88/cx88-core.c index d86813be56de..f31ec96924b9 100644 --- a/drivers/media/video/cx88/cx88-core.c +++ b/drivers/media/video/cx88/cx88-core.c | |||
@@ -489,12 +489,12 @@ static char *cx88_pci_irqs[32] = { | |||
489 | }; | 489 | }; |
490 | 490 | ||
491 | void cx88_print_irqbits(char *name, char *tag, char **strings, | 491 | void cx88_print_irqbits(char *name, char *tag, char **strings, |
492 | u32 bits, u32 mask) | 492 | int len, u32 bits, u32 mask) |
493 | { | 493 | { |
494 | unsigned int i; | 494 | unsigned int i; |
495 | 495 | ||
496 | printk(KERN_DEBUG "%s: %s [0x%x]", name, tag, bits); | 496 | printk(KERN_DEBUG "%s: %s [0x%x]", name, tag, bits); |
497 | for (i = 0; i < 32; i++) { | 497 | for (i = 0; i < len; i++) { |
498 | if (!(bits & (1 << i))) | 498 | if (!(bits & (1 << i))) |
499 | continue; | 499 | continue; |
500 | if (strings[i]) | 500 | if (strings[i]) |
@@ -520,8 +520,8 @@ int cx88_core_irq(struct cx88_core *core, u32 status) | |||
520 | } | 520 | } |
521 | if (!handled) | 521 | if (!handled) |
522 | cx88_print_irqbits(core->name, "irq pci", | 522 | cx88_print_irqbits(core->name, "irq pci", |
523 | cx88_pci_irqs, status, | 523 | cx88_pci_irqs, ARRAY_SIZE(cx88_pci_irqs), |
524 | core->pci_irqmask); | 524 | status, core->pci_irqmask); |
525 | return handled; | 525 | return handled; |
526 | } | 526 | } |
527 | 527 | ||
diff --git a/drivers/media/video/cx88/cx88-dvb.c b/drivers/media/video/cx88/cx88-dvb.c index 4f5560285770..dbfe4dc9cf8c 100644 --- a/drivers/media/video/cx88/cx88-dvb.c +++ b/drivers/media/video/cx88/cx88-dvb.c | |||
@@ -42,7 +42,6 @@ | |||
42 | #include "cx22702.h" | 42 | #include "cx22702.h" |
43 | #include "or51132.h" | 43 | #include "or51132.h" |
44 | #include "lgdt330x.h" | 44 | #include "lgdt330x.h" |
45 | #include "lgh06xf.h" | ||
46 | #include "nxt200x.h" | 45 | #include "nxt200x.h" |
47 | #include "cx24123.h" | 46 | #include "cx24123.h" |
48 | #include "isl6421.h" | 47 | #include "isl6421.h" |
@@ -476,6 +475,8 @@ static int dvb_register(struct cx8802_dev *dev) | |||
476 | case CX88_BOARD_WINFAST_DTV2000H: | 475 | case CX88_BOARD_WINFAST_DTV2000H: |
477 | case CX88_BOARD_HAUPPAUGE_HVR1100: | 476 | case CX88_BOARD_HAUPPAUGE_HVR1100: |
478 | case CX88_BOARD_HAUPPAUGE_HVR1100LP: | 477 | case CX88_BOARD_HAUPPAUGE_HVR1100LP: |
478 | case CX88_BOARD_HAUPPAUGE_HVR1300: | ||
479 | case CX88_BOARD_HAUPPAUGE_HVR3000: | ||
479 | dev->dvb.frontend = dvb_attach(cx22702_attach, | 480 | dev->dvb.frontend = dvb_attach(cx22702_attach, |
480 | &hauppauge_hvr_config, | 481 | &hauppauge_hvr_config, |
481 | &dev->core->i2c_adap); | 482 | &dev->core->i2c_adap); |
@@ -631,8 +632,9 @@ static int dvb_register(struct cx8802_dev *dev) | |||
631 | &fusionhdtv_5_gold, | 632 | &fusionhdtv_5_gold, |
632 | &dev->core->i2c_adap); | 633 | &dev->core->i2c_adap); |
633 | if (dev->dvb.frontend != NULL) { | 634 | if (dev->dvb.frontend != NULL) { |
634 | dvb_attach(lgh06xf_attach, dev->dvb.frontend, | 635 | dvb_attach(dvb_pll_attach, dev->dvb.frontend, 0x61, |
635 | &dev->core->i2c_adap); | 636 | &dev->core->i2c_adap, |
637 | &dvb_pll_lg_tdvs_h06xf); | ||
636 | } | 638 | } |
637 | } | 639 | } |
638 | break; | 640 | break; |
@@ -650,8 +652,9 @@ static int dvb_register(struct cx8802_dev *dev) | |||
650 | &pchdtv_hd5500, | 652 | &pchdtv_hd5500, |
651 | &dev->core->i2c_adap); | 653 | &dev->core->i2c_adap); |
652 | if (dev->dvb.frontend != NULL) { | 654 | if (dev->dvb.frontend != NULL) { |
653 | dvb_attach(lgh06xf_attach, dev->dvb.frontend, | 655 | dvb_attach(dvb_pll_attach, dev->dvb.frontend, 0x61, |
654 | &dev->core->i2c_adap); | 656 | &dev->core->i2c_adap, |
657 | &dvb_pll_lg_tdvs_h06xf); | ||
655 | } | 658 | } |
656 | } | 659 | } |
657 | break; | 660 | break; |
@@ -692,24 +695,6 @@ static int dvb_register(struct cx8802_dev *dev) | |||
692 | dev->dvb.frontend->ops.set_voltage = geniatech_dvbs_set_voltage; | 695 | dev->dvb.frontend->ops.set_voltage = geniatech_dvbs_set_voltage; |
693 | } | 696 | } |
694 | break; | 697 | break; |
695 | case CX88_BOARD_HAUPPAUGE_HVR1300: | ||
696 | dev->dvb.frontend = dvb_attach(cx22702_attach, | ||
697 | &hauppauge_hvr_config, | ||
698 | &dev->core->i2c_adap); | ||
699 | if (dev->dvb.frontend != NULL) { | ||
700 | dvb_attach(dvb_pll_attach, dev->dvb.frontend, 0x61, | ||
701 | &dev->core->i2c_adap, &dvb_pll_fmd1216me); | ||
702 | } | ||
703 | break; | ||
704 | case CX88_BOARD_HAUPPAUGE_HVR3000: | ||
705 | dev->dvb.frontend = dvb_attach(cx22702_attach, | ||
706 | &hauppauge_hvr_config, | ||
707 | &dev->core->i2c_adap); | ||
708 | if (dev->dvb.frontend != NULL) { | ||
709 | dvb_attach(dvb_pll_attach, dev->dvb.frontend, 0x61, | ||
710 | &dev->core->i2c_adap, &dvb_pll_fmd1216me); | ||
711 | } | ||
712 | break; | ||
713 | default: | 698 | default: |
714 | printk("%s: The frontend of your DVB/ATSC card isn't supported yet\n", | 699 | printk("%s: The frontend of your DVB/ATSC card isn't supported yet\n", |
715 | dev->core->name); | 700 | dev->core->name); |
diff --git a/drivers/media/video/cx88/cx88-i2c.c b/drivers/media/video/cx88/cx88-i2c.c index 9830d5c43921..7919a1f9da06 100644 --- a/drivers/media/video/cx88/cx88-i2c.c +++ b/drivers/media/video/cx88/cx88-i2c.c | |||
@@ -1,3 +1,4 @@ | |||
1 | |||
1 | /* | 2 | /* |
2 | 3 | ||
3 | cx88-i2c.c -- all the i2c code is here | 4 | cx88-i2c.c -- all the i2c code is here |
@@ -195,7 +196,7 @@ static void do_i2c_scan(char *name, struct i2c_client *c) | |||
195 | unsigned char buf; | 196 | unsigned char buf; |
196 | int i,rc; | 197 | int i,rc; |
197 | 198 | ||
198 | for (i = 0; i < 128; i++) { | 199 | for (i = 0; i < ARRAY_SIZE(i2c_devs); i++) { |
199 | c->addr = i; | 200 | c->addr = i; |
200 | rc = i2c_master_recv(c,&buf,0); | 201 | rc = i2c_master_recv(c,&buf,0); |
201 | if (rc < 0) | 202 | if (rc < 0) |
diff --git a/drivers/media/video/cx88/cx88-mpeg.c b/drivers/media/video/cx88/cx88-mpeg.c index 1fe1a833c7c7..b2eb32e01aee 100644 --- a/drivers/media/video/cx88/cx88-mpeg.c +++ b/drivers/media/video/cx88/cx88-mpeg.c | |||
@@ -49,6 +49,27 @@ MODULE_PARM_DESC(debug,"enable debug messages [mpeg]"); | |||
49 | #define mpeg_dbg(level,fmt, arg...) if (debug >= level) \ | 49 | #define mpeg_dbg(level,fmt, arg...) if (debug >= level) \ |
50 | printk(KERN_DEBUG "%s/2-mpeg: " fmt, core->name, ## arg) | 50 | printk(KERN_DEBUG "%s/2-mpeg: " fmt, core->name, ## arg) |
51 | 51 | ||
52 | #if defined(CONFIG_MODULES) && defined(MODULE) | ||
53 | static void request_module_async(struct work_struct *work) | ||
54 | { | ||
55 | struct cx8802_dev *dev=container_of(work, struct cx8802_dev, request_module_wk); | ||
56 | |||
57 | if (cx88_boards[dev->core->board].mpeg & CX88_MPEG_DVB) | ||
58 | request_module("cx88-dvb"); | ||
59 | if (cx88_boards[dev->core->board].mpeg & CX88_MPEG_BLACKBIRD) | ||
60 | request_module("cx88-blackbird"); | ||
61 | } | ||
62 | |||
63 | static void request_modules(struct cx8802_dev *dev) | ||
64 | { | ||
65 | INIT_WORK(&dev->request_module_wk, request_module_async); | ||
66 | schedule_work(&dev->request_module_wk); | ||
67 | } | ||
68 | #else | ||
69 | #define request_modules(dev) | ||
70 | #endif /* CONFIG_MODULES */ | ||
71 | |||
72 | |||
52 | static LIST_HEAD(cx8802_devlist); | 73 | static LIST_HEAD(cx8802_devlist); |
53 | /* ------------------------------------------------------------------ */ | 74 | /* ------------------------------------------------------------------ */ |
54 | 75 | ||
@@ -345,7 +366,8 @@ static void cx8802_mpeg_irq(struct cx8802_dev *dev) | |||
345 | 366 | ||
346 | if (debug || (status & mask & ~0xff)) | 367 | if (debug || (status & mask & ~0xff)) |
347 | cx88_print_irqbits(core->name, "irq mpeg ", | 368 | cx88_print_irqbits(core->name, "irq mpeg ", |
348 | cx88_mpeg_irqs, status, mask); | 369 | cx88_mpeg_irqs, ARRAY_SIZE(cx88_mpeg_irqs), |
370 | status, mask); | ||
349 | 371 | ||
350 | /* risc op code error */ | 372 | /* risc op code error */ |
351 | if (status & (1 << 16)) { | 373 | if (status & (1 << 16)) { |
@@ -427,7 +449,7 @@ int cx8802_init_common(struct cx8802_dev *dev) | |||
427 | if (pci_enable_device(dev->pci)) | 449 | if (pci_enable_device(dev->pci)) |
428 | return -EIO; | 450 | return -EIO; |
429 | pci_set_master(dev->pci); | 451 | pci_set_master(dev->pci); |
430 | if (!pci_dma_supported(dev->pci,0xffffffff)) { | 452 | if (!pci_dma_supported(dev->pci,DMA_32BIT_MASK)) { |
431 | printk("%s/2: Oops: no 32bit PCI DMA ???\n",dev->core->name); | 453 | printk("%s/2: Oops: no 32bit PCI DMA ???\n",dev->core->name); |
432 | return -EIO; | 454 | return -EIO; |
433 | } | 455 | } |
@@ -778,6 +800,9 @@ static int __devinit cx8802_probe(struct pci_dev *pci_dev, | |||
778 | 800 | ||
779 | /* Maintain a reference so cx88-video can query the 8802 device. */ | 801 | /* Maintain a reference so cx88-video can query the 8802 device. */ |
780 | core->dvbdev = dev; | 802 | core->dvbdev = dev; |
803 | |||
804 | /* now autoload cx88-dvb or cx88-blackbird */ | ||
805 | request_modules(dev); | ||
781 | return 0; | 806 | return 0; |
782 | 807 | ||
783 | fail_free: | 808 | fail_free: |
diff --git a/drivers/media/video/cx88/cx88-video.c b/drivers/media/video/cx88/cx88-video.c index bdfe2af70124..fbce1d50578b 100644 --- a/drivers/media/video/cx88/cx88-video.c +++ b/drivers/media/video/cx88/cx88-video.c | |||
@@ -1555,7 +1555,8 @@ static void cx8800_vid_irq(struct cx8800_dev *dev) | |||
1555 | cx_write(MO_VID_INTSTAT, status); | 1555 | cx_write(MO_VID_INTSTAT, status); |
1556 | if (irq_debug || (status & mask & ~0xff)) | 1556 | if (irq_debug || (status & mask & ~0xff)) |
1557 | cx88_print_irqbits(core->name, "irq vid", | 1557 | cx88_print_irqbits(core->name, "irq vid", |
1558 | cx88_vid_irqs, status, mask); | 1558 | cx88_vid_irqs, ARRAY_SIZE(cx88_vid_irqs), |
1559 | status, mask); | ||
1559 | 1560 | ||
1560 | /* risc op code error */ | 1561 | /* risc op code error */ |
1561 | if (status & (1 << 16)) { | 1562 | if (status & (1 << 16)) { |
@@ -1778,7 +1779,7 @@ static int __devinit cx8800_initdev(struct pci_dev *pci_dev, | |||
1778 | dev->pci_lat,(unsigned long long)pci_resource_start(pci_dev,0)); | 1779 | dev->pci_lat,(unsigned long long)pci_resource_start(pci_dev,0)); |
1779 | 1780 | ||
1780 | pci_set_master(pci_dev); | 1781 | pci_set_master(pci_dev); |
1781 | if (!pci_dma_supported(pci_dev,0xffffffff)) { | 1782 | if (!pci_dma_supported(pci_dev,DMA_32BIT_MASK)) { |
1782 | printk("%s/0: Oops: no 32bit PCI DMA ???\n",core->name); | 1783 | printk("%s/0: Oops: no 32bit PCI DMA ???\n",core->name); |
1783 | err = -EIO; | 1784 | err = -EIO; |
1784 | goto fail_core; | 1785 | goto fail_core; |
diff --git a/drivers/media/video/cx88/cx88.h b/drivers/media/video/cx88/cx88.h index a4f7befda5b0..738d4f20c580 100644 --- a/drivers/media/video/cx88/cx88.h +++ b/drivers/media/video/cx88/cx88.h | |||
@@ -481,6 +481,8 @@ struct cx8802_dev { | |||
481 | 481 | ||
482 | /* List of attached drivers */ | 482 | /* List of attached drivers */ |
483 | struct cx8802_driver drvlist; | 483 | struct cx8802_driver drvlist; |
484 | struct work_struct request_module_wk; | ||
485 | |||
484 | }; | 486 | }; |
485 | 487 | ||
486 | /* ----------------------------------------------------------- */ | 488 | /* ----------------------------------------------------------- */ |
@@ -510,7 +512,7 @@ struct cx8802_dev { | |||
510 | /* cx88-core.c */ | 512 | /* cx88-core.c */ |
511 | 513 | ||
512 | extern void cx88_print_irqbits(char *name, char *tag, char **strings, | 514 | extern void cx88_print_irqbits(char *name, char *tag, char **strings, |
513 | u32 bits, u32 mask); | 515 | int len, u32 bits, u32 mask); |
514 | 516 | ||
515 | extern int cx88_core_irq(struct cx88_core *core, u32 status); | 517 | extern int cx88_core_irq(struct cx88_core *core, u32 status); |
516 | extern void cx88_wakeup(struct cx88_core *core, | 518 | extern void cx88_wakeup(struct cx88_core *core, |
diff --git a/drivers/media/video/em28xx/em28xx-i2c.c b/drivers/media/video/em28xx/em28xx-i2c.c index d829d8f8c1f6..563a8319e608 100644 --- a/drivers/media/video/em28xx/em28xx-i2c.c +++ b/drivers/media/video/em28xx/em28xx-i2c.c | |||
@@ -523,7 +523,7 @@ static void do_i2c_scan(char *name, struct i2c_client *c) | |||
523 | unsigned char buf; | 523 | unsigned char buf; |
524 | int i, rc; | 524 | int i, rc; |
525 | 525 | ||
526 | for (i = 0; i < 128; i++) { | 526 | for (i = 0; i < ARRAY_SIZE(i2c_devs); i++) { |
527 | c->addr = i; | 527 | c->addr = i; |
528 | rc = i2c_master_recv(c, &buf, 0); | 528 | rc = i2c_master_recv(c, &buf, 0); |
529 | if (rc < 0) | 529 | if (rc < 0) |
diff --git a/drivers/media/video/ir-kbd-i2c.c b/drivers/media/video/ir-kbd-i2c.c index 210582d420f8..ed92b6f7187a 100644 --- a/drivers/media/video/ir-kbd-i2c.c +++ b/drivers/media/video/ir-kbd-i2c.c | |||
@@ -173,7 +173,7 @@ static int get_key_pinnacle(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw, | |||
173 | return -EIO; | 173 | return -EIO; |
174 | } | 174 | } |
175 | 175 | ||
176 | for (start = 0; start<4; start++) { | 176 | for (start = 0; start < ARRAY_SIZE(b); start++) { |
177 | if (b[start] == marker) { | 177 | if (b[start] == marker) { |
178 | code=b[(start+parity_offset+1)%4]; | 178 | code=b[(start+parity_offset+1)%4]; |
179 | parity=b[(start+parity_offset)%4]; | 179 | parity=b[(start+parity_offset)%4]; |
diff --git a/drivers/media/video/ivtv/Kconfig b/drivers/media/video/ivtv/Kconfig new file mode 100644 index 000000000000..e854f3f1b70f --- /dev/null +++ b/drivers/media/video/ivtv/Kconfig | |||
@@ -0,0 +1,26 @@ | |||
1 | config VIDEO_IVTV | ||
2 | tristate "Conexant cx23416/cx23415 MPEG encoder/decoder support" | ||
3 | depends on VIDEO_V4L1 && VIDEO_V4L2 && USB && I2C && EXPERIMENTAL | ||
4 | select FW_LOADER | ||
5 | select VIDEO_TUNER | ||
6 | select VIDEO_TVEEPROM | ||
7 | select VIDEO_CX2341X | ||
8 | select VIDEO_CX25840 | ||
9 | select VIDEO_MSP3400 | ||
10 | select VIDEO_SAA711X | ||
11 | select VIDEO_SAA7127 | ||
12 | select VIDEO_TVAUDIO | ||
13 | select VIDEO_CS53L32A | ||
14 | select VIDEO_WM8775 | ||
15 | select VIDEO_WM8739 | ||
16 | select VIDEO_UPD64031A | ||
17 | select VIDEO_UPD64083 | ||
18 | ---help--- | ||
19 | This is a video4linux driver for Conexant cx23416 or cx23416 based | ||
20 | PCI personal video recorder devices. | ||
21 | |||
22 | This is used in devices such as the Hauppauge PVR-150/250/350/500 | ||
23 | cards. | ||
24 | |||
25 | To compile this driver as a module, choose M here: the | ||
26 | module will be called ivtv. | ||
diff --git a/drivers/media/video/ivtv/Makefile b/drivers/media/video/ivtv/Makefile new file mode 100644 index 000000000000..7e95148fbf4f --- /dev/null +++ b/drivers/media/video/ivtv/Makefile | |||
@@ -0,0 +1,7 @@ | |||
1 | ivtv-objs := ivtv-audio.o ivtv-cards.o ivtv-controls.o \ | ||
2 | ivtv-driver.o ivtv-fileops.o ivtv-firmware.o \ | ||
3 | ivtv-gpio.o ivtv-i2c.o ivtv-ioctl.o ivtv-irq.o \ | ||
4 | ivtv-mailbox.o ivtv-queue.o ivtv-streams.o ivtv-udma.o \ | ||
5 | ivtv-vbi.o ivtv-video.o ivtv-yuv.o | ||
6 | |||
7 | obj-$(CONFIG_VIDEO_IVTV) += ivtv.o | ||
diff --git a/drivers/media/video/ivtv/ivtv-audio.c b/drivers/media/video/ivtv/ivtv-audio.c new file mode 100644 index 000000000000..d702b8b539a1 --- /dev/null +++ b/drivers/media/video/ivtv/ivtv-audio.c | |||
@@ -0,0 +1,74 @@ | |||
1 | /* | ||
2 | Audio-related ivtv functions. | ||
3 | Copyright (C) 2003-2004 Kevin Thayer <nufan_wfk at yahoo.com> | ||
4 | Copyright (C) 2005-2007 Hans Verkuil <hverkuil@xs4all.nl> | ||
5 | |||
6 | This program is free software; you can redistribute it and/or modify | ||
7 | it under the terms of the GNU General Public License as published by | ||
8 | the Free Software Foundation; either version 2 of the License, or | ||
9 | (at your option) any later version. | ||
10 | |||
11 | This program is distributed in the hope that it will be useful, | ||
12 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
14 | GNU General Public License for more details. | ||
15 | |||
16 | You should have received a copy of the GNU General Public License | ||
17 | along with this program; if not, write to the Free Software | ||
18 | Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
19 | */ | ||
20 | |||
21 | #include "ivtv-driver.h" | ||
22 | #include "ivtv-mailbox.h" | ||
23 | #include "ivtv-i2c.h" | ||
24 | #include "ivtv-gpio.h" | ||
25 | #include "ivtv-cards.h" | ||
26 | #include "ivtv-audio.h" | ||
27 | #include <media/msp3400.h> | ||
28 | #include <linux/videodev.h> | ||
29 | |||
30 | /* Selects the audio input and output according to the current | ||
31 | settings. */ | ||
32 | int ivtv_audio_set_io(struct ivtv *itv) | ||
33 | { | ||
34 | struct v4l2_routing route; | ||
35 | u32 audio_input; | ||
36 | int mux_input; | ||
37 | |||
38 | /* Determine which input to use */ | ||
39 | if (test_bit(IVTV_F_I_RADIO_USER, &itv->i_flags)) { | ||
40 | audio_input = itv->card->radio_input.audio_input; | ||
41 | mux_input = itv->card->radio_input.muxer_input; | ||
42 | } else { | ||
43 | audio_input = itv->card->audio_inputs[itv->audio_input].audio_input; | ||
44 | mux_input = itv->card->audio_inputs[itv->audio_input].muxer_input; | ||
45 | } | ||
46 | |||
47 | /* handle muxer chips */ | ||
48 | route.input = mux_input; | ||
49 | route.output = 0; | ||
50 | ivtv_i2c_hw(itv, itv->card->hw_muxer, VIDIOC_INT_S_AUDIO_ROUTING, &route); | ||
51 | |||
52 | route.input = audio_input; | ||
53 | if (itv->card->hw_audio & IVTV_HW_MSP34XX) { | ||
54 | route.output = MSP_OUTPUT(MSP_SC_IN_DSP_SCART1); | ||
55 | } | ||
56 | return ivtv_i2c_hw(itv, itv->card->hw_audio, VIDIOC_INT_S_AUDIO_ROUTING, &route); | ||
57 | } | ||
58 | |||
59 | void ivtv_audio_set_route(struct ivtv *itv, struct v4l2_routing *route) | ||
60 | { | ||
61 | ivtv_i2c_hw(itv, itv->card->hw_audio, VIDIOC_INT_S_AUDIO_ROUTING, route); | ||
62 | } | ||
63 | |||
64 | void ivtv_audio_set_audio_clock_freq(struct ivtv *itv, u8 freq) | ||
65 | { | ||
66 | static u32 freqs[3] = { 44100, 48000, 32000 }; | ||
67 | |||
68 | /* The audio clock of the digitizer must match the codec sample | ||
69 | rate otherwise you get some very strange effects. */ | ||
70 | if (freq > 2) | ||
71 | return; | ||
72 | ivtv_call_i2c_clients(itv, VIDIOC_INT_AUDIO_CLOCK_FREQ, &freqs[freq]); | ||
73 | } | ||
74 | |||
diff --git a/drivers/media/video/ivtv/ivtv-audio.h b/drivers/media/video/ivtv/ivtv-audio.h new file mode 100644 index 000000000000..9c42846d8124 --- /dev/null +++ b/drivers/media/video/ivtv/ivtv-audio.h | |||
@@ -0,0 +1,23 @@ | |||
1 | /* | ||
2 | Audio-related ivtv functions. | ||
3 | Copyright (C) 2003-2004 Kevin Thayer <nufan_wfk at yahoo.com> | ||
4 | Copyright (C) 2005-2007 Hans Verkuil <hverkuil@xs4all.nl> | ||
5 | |||
6 | This program is free software; you can redistribute it and/or modify | ||
7 | it under the terms of the GNU General Public License as published by | ||
8 | the Free Software Foundation; either version 2 of the License, or | ||
9 | (at your option) any later version. | ||
10 | |||
11 | This program is distributed in the hope that it will be useful, | ||
12 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
14 | GNU General Public License for more details. | ||
15 | |||
16 | You should have received a copy of the GNU General Public License | ||
17 | along with this program; if not, write to the Free Software | ||
18 | Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
19 | */ | ||
20 | |||
21 | int ivtv_audio_set_io(struct ivtv *itv); | ||
22 | void ivtv_audio_set_route(struct ivtv *itv, struct v4l2_routing *route); | ||
23 | void ivtv_audio_set_audio_clock_freq(struct ivtv *itv, u8 freq); | ||
diff --git a/drivers/media/video/ivtv/ivtv-cards.c b/drivers/media/video/ivtv/ivtv-cards.c new file mode 100644 index 000000000000..8eab02083887 --- /dev/null +++ b/drivers/media/video/ivtv/ivtv-cards.c | |||
@@ -0,0 +1,964 @@ | |||
1 | /* | ||
2 | Functions to query card hardware | ||
3 | Copyright (C) 2003-2004 Kevin Thayer <nufan_wfk at yahoo.com> | ||
4 | Copyright (C) 2005-2007 Hans Verkuil <hverkuil@xs4all.nl> | ||
5 | |||
6 | This program is free software; you can redistribute it and/or modify | ||
7 | it under the terms of the GNU General Public License as published by | ||
8 | the Free Software Foundation; either version 2 of the License, or | ||
9 | (at your option) any later version. | ||
10 | |||
11 | This program is distributed in the hope that it will be useful, | ||
12 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
14 | GNU General Public License for more details. | ||
15 | |||
16 | You should have received a copy of the GNU General Public License | ||
17 | along with this program; if not, write to the Free Software | ||
18 | Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
19 | */ | ||
20 | |||
21 | #include "ivtv-driver.h" | ||
22 | #include "ivtv-cards.h" | ||
23 | #include "ivtv-i2c.h" | ||
24 | |||
25 | #include <media/msp3400.h> | ||
26 | #include <media/wm8775.h> | ||
27 | #include <media/cs53l32a.h> | ||
28 | #include <media/cx25840.h> | ||
29 | #include <media/upd64031a.h> | ||
30 | |||
31 | #define MSP_TUNER MSP_INPUT(MSP_IN_SCART1, MSP_IN_TUNER1, \ | ||
32 | MSP_DSP_IN_TUNER, MSP_DSP_IN_TUNER) | ||
33 | #define MSP_SCART1 MSP_INPUT(MSP_IN_SCART1, MSP_IN_TUNER1, \ | ||
34 | MSP_DSP_IN_SCART, MSP_DSP_IN_SCART) | ||
35 | #define MSP_SCART2 MSP_INPUT(MSP_IN_SCART2, MSP_IN_TUNER1, \ | ||
36 | MSP_DSP_IN_SCART, MSP_DSP_IN_SCART) | ||
37 | #define MSP_SCART3 MSP_INPUT(MSP_IN_SCART3, MSP_IN_TUNER1, \ | ||
38 | MSP_DSP_IN_SCART, MSP_DSP_IN_SCART) | ||
39 | #define MSP_MONO MSP_INPUT(MSP_IN_MONO, MSP_IN_TUNER1, \ | ||
40 | MSP_DSP_IN_SCART, MSP_DSP_IN_SCART) | ||
41 | |||
42 | /********************** card configuration *******************************/ | ||
43 | |||
44 | /* Please add new PCI IDs to: http://pci-ids.ucw.cz/iii | ||
45 | This keeps the PCI ID database up to date. Note that the entries | ||
46 | must be added under vendor 0x4444 (Conexant) as subsystem IDs. | ||
47 | New vendor IDs should still be added to the vendor ID list. */ | ||
48 | |||
49 | /* Hauppauge PVR-250 cards */ | ||
50 | |||
51 | /* Note: for Hauppauge cards the tveeprom information is used instead of PCI IDs */ | ||
52 | static const struct ivtv_card ivtv_card_pvr250 = { | ||
53 | .type = IVTV_CARD_PVR_250, | ||
54 | .name = "Hauppauge WinTV PVR-250", | ||
55 | .v4l2_capabilities = IVTV_CAP_ENCODER, | ||
56 | .hw_video = IVTV_HW_SAA7115, | ||
57 | .hw_audio = IVTV_HW_MSP34XX, | ||
58 | .hw_audio_ctrl = IVTV_HW_MSP34XX, | ||
59 | .hw_all = IVTV_HW_MSP34XX | IVTV_HW_SAA7115 | | ||
60 | IVTV_HW_TVEEPROM | IVTV_HW_TUNER, | ||
61 | .video_inputs = { | ||
62 | { IVTV_CARD_INPUT_VID_TUNER, 0, IVTV_SAA71XX_COMPOSITE4 }, | ||
63 | { IVTV_CARD_INPUT_SVIDEO1, 1, IVTV_SAA71XX_SVIDEO0 }, | ||
64 | { IVTV_CARD_INPUT_COMPOSITE1, 1, IVTV_SAA71XX_COMPOSITE0 }, | ||
65 | { IVTV_CARD_INPUT_SVIDEO2, 2, IVTV_SAA71XX_SVIDEO1 }, | ||
66 | { IVTV_CARD_INPUT_COMPOSITE2, 2, IVTV_SAA71XX_COMPOSITE1 }, | ||
67 | { IVTV_CARD_INPUT_COMPOSITE3, 1, IVTV_SAA71XX_COMPOSITE5 }, | ||
68 | }, | ||
69 | .audio_inputs = { | ||
70 | { IVTV_CARD_INPUT_AUD_TUNER, MSP_TUNER }, | ||
71 | { IVTV_CARD_INPUT_LINE_IN1, MSP_SCART1 }, | ||
72 | { IVTV_CARD_INPUT_LINE_IN2, MSP_SCART3 }, | ||
73 | }, | ||
74 | .radio_input = { IVTV_CARD_INPUT_AUD_TUNER, MSP_SCART2 }, | ||
75 | }; | ||
76 | |||
77 | /* ------------------------------------------------------------------------- */ | ||
78 | |||
79 | /* Hauppauge PVR-350 cards */ | ||
80 | |||
81 | /* Outputs for Hauppauge PVR350 cards */ | ||
82 | static struct ivtv_card_output ivtv_pvr350_outputs[] = { | ||
83 | { | ||
84 | .name = "S-Video + Composite", | ||
85 | .video_output = 0, | ||
86 | }, { | ||
87 | .name = "Composite", | ||
88 | .video_output = 1, | ||
89 | }, { | ||
90 | .name = "S-Video", | ||
91 | .video_output = 2, | ||
92 | }, { | ||
93 | .name = "RGB", | ||
94 | .video_output = 3, | ||
95 | }, { | ||
96 | .name = "YUV C", | ||
97 | .video_output = 4, | ||
98 | }, { | ||
99 | .name = "YUV V", | ||
100 | .video_output = 5, | ||
101 | } | ||
102 | }; | ||
103 | |||
104 | static const struct ivtv_card ivtv_card_pvr350 = { | ||
105 | .type = IVTV_CARD_PVR_350, | ||
106 | .name = "Hauppauge WinTV PVR-350", | ||
107 | .v4l2_capabilities = IVTV_CAP_ENCODER | IVTV_CAP_DECODER, | ||
108 | .video_outputs = ivtv_pvr350_outputs, | ||
109 | .nof_outputs = ARRAY_SIZE(ivtv_pvr350_outputs), | ||
110 | .hw_video = IVTV_HW_SAA7115, | ||
111 | .hw_audio = IVTV_HW_MSP34XX, | ||
112 | .hw_audio_ctrl = IVTV_HW_MSP34XX, | ||
113 | .hw_all = IVTV_HW_MSP34XX | IVTV_HW_SAA7115 | | ||
114 | IVTV_HW_SAA7127 | IVTV_HW_TVEEPROM | IVTV_HW_TUNER, | ||
115 | .video_inputs = { | ||
116 | { IVTV_CARD_INPUT_VID_TUNER, 0, IVTV_SAA71XX_COMPOSITE4 }, | ||
117 | { IVTV_CARD_INPUT_SVIDEO1, 1, IVTV_SAA71XX_SVIDEO0 }, | ||
118 | { IVTV_CARD_INPUT_COMPOSITE1, 1, IVTV_SAA71XX_COMPOSITE0 }, | ||
119 | { IVTV_CARD_INPUT_SVIDEO2, 2, IVTV_SAA71XX_SVIDEO1 }, | ||
120 | { IVTV_CARD_INPUT_COMPOSITE2, 2, IVTV_SAA71XX_COMPOSITE1 }, | ||
121 | { IVTV_CARD_INPUT_COMPOSITE3, 1, IVTV_SAA71XX_COMPOSITE5 }, | ||
122 | }, | ||
123 | .audio_inputs = { | ||
124 | { IVTV_CARD_INPUT_AUD_TUNER, MSP_TUNER }, | ||
125 | { IVTV_CARD_INPUT_LINE_IN1, MSP_SCART1 }, | ||
126 | { IVTV_CARD_INPUT_LINE_IN2, MSP_SCART3 }, | ||
127 | }, | ||
128 | .radio_input = { IVTV_CARD_INPUT_AUD_TUNER, MSP_SCART2 }, | ||
129 | }; | ||
130 | |||
131 | /* PVR-350 V1 boards have a different audio tuner input and use a | ||
132 | saa7114 instead of a saa7115. | ||
133 | Note that the info below comes from a pre-production model so it may | ||
134 | not be correct. Especially the audio behaves strangely (mono only it seems) */ | ||
135 | static const struct ivtv_card ivtv_card_pvr350_v1 = { | ||
136 | .type = IVTV_CARD_PVR_350_V1, | ||
137 | .name = "Hauppauge WinTV PVR-350 (V1)", | ||
138 | .v4l2_capabilities = IVTV_CAP_ENCODER | IVTV_CAP_DECODER, | ||
139 | .video_outputs = ivtv_pvr350_outputs, | ||
140 | .nof_outputs = ARRAY_SIZE(ivtv_pvr350_outputs), | ||
141 | .hw_video = IVTV_HW_SAA7114, | ||
142 | .hw_audio = IVTV_HW_MSP34XX, | ||
143 | .hw_audio_ctrl = IVTV_HW_MSP34XX, | ||
144 | .hw_all = IVTV_HW_MSP34XX | IVTV_HW_SAA7114 | | ||
145 | IVTV_HW_SAA7127 | IVTV_HW_TVEEPROM | IVTV_HW_TUNER, | ||
146 | .video_inputs = { | ||
147 | { IVTV_CARD_INPUT_VID_TUNER, 0, IVTV_SAA71XX_COMPOSITE4 }, | ||
148 | { IVTV_CARD_INPUT_SVIDEO1, 1, IVTV_SAA71XX_SVIDEO0 }, | ||
149 | { IVTV_CARD_INPUT_COMPOSITE1, 1, IVTV_SAA71XX_COMPOSITE0 }, | ||
150 | { IVTV_CARD_INPUT_SVIDEO2, 2, IVTV_SAA71XX_SVIDEO1 }, | ||
151 | { IVTV_CARD_INPUT_COMPOSITE2, 2, IVTV_SAA71XX_COMPOSITE1 }, | ||
152 | { IVTV_CARD_INPUT_COMPOSITE3, 1, IVTV_SAA71XX_COMPOSITE5 }, | ||
153 | }, | ||
154 | .audio_inputs = { | ||
155 | { IVTV_CARD_INPUT_AUD_TUNER, MSP_MONO }, | ||
156 | { IVTV_CARD_INPUT_LINE_IN1, MSP_SCART1 }, | ||
157 | { IVTV_CARD_INPUT_LINE_IN2, MSP_SCART3 }, | ||
158 | }, | ||
159 | .radio_input = { IVTV_CARD_INPUT_AUD_TUNER, MSP_SCART2 }, | ||
160 | }; | ||
161 | |||
162 | /* ------------------------------------------------------------------------- */ | ||
163 | |||
164 | /* Hauppauge PVR-150/PVR-500 cards */ | ||
165 | |||
166 | static const struct ivtv_card ivtv_card_pvr150 = { | ||
167 | .type = IVTV_CARD_PVR_150, | ||
168 | .name = "Hauppauge WinTV PVR-150", | ||
169 | .v4l2_capabilities = IVTV_CAP_ENCODER, | ||
170 | .hw_video = IVTV_HW_CX25840, | ||
171 | .hw_audio = IVTV_HW_CX25840, | ||
172 | .hw_audio_ctrl = IVTV_HW_CX25840, | ||
173 | .hw_muxer = IVTV_HW_WM8775, | ||
174 | .hw_all = IVTV_HW_WM8775 | IVTV_HW_CX25840 | | ||
175 | IVTV_HW_TVEEPROM | IVTV_HW_TUNER, | ||
176 | .video_inputs = { | ||
177 | { IVTV_CARD_INPUT_VID_TUNER, 0, CX25840_COMPOSITE7 }, | ||
178 | { IVTV_CARD_INPUT_SVIDEO1, 1, CX25840_SVIDEO1 }, | ||
179 | { IVTV_CARD_INPUT_COMPOSITE1, 1, CX25840_COMPOSITE3 }, | ||
180 | { IVTV_CARD_INPUT_SVIDEO2, 2, CX25840_SVIDEO2 }, | ||
181 | { IVTV_CARD_INPUT_COMPOSITE2, 2, CX25840_COMPOSITE4 }, | ||
182 | }, | ||
183 | .audio_inputs = { | ||
184 | { IVTV_CARD_INPUT_AUD_TUNER, | ||
185 | CX25840_AUDIO8, WM8775_AIN2 }, | ||
186 | { IVTV_CARD_INPUT_LINE_IN1, | ||
187 | CX25840_AUDIO_SERIAL, WM8775_AIN2 }, | ||
188 | { IVTV_CARD_INPUT_LINE_IN2, | ||
189 | CX25840_AUDIO_SERIAL, WM8775_AIN3 }, | ||
190 | }, | ||
191 | .radio_input = { IVTV_CARD_INPUT_AUD_TUNER, | ||
192 | CX25840_AUDIO_SERIAL, WM8775_AIN4 }, | ||
193 | /* apparently needed for the IR blaster */ | ||
194 | .gpio_init = { .direction = 0x1f01, .initial_value = 0x26f3 }, | ||
195 | }; | ||
196 | |||
197 | /* ------------------------------------------------------------------------- */ | ||
198 | |||
199 | /* AVerMedia M179 cards */ | ||
200 | |||
201 | static const struct ivtv_card_pci_info ivtv_pci_m179[] = { | ||
202 | { PCI_DEVICE_ID_IVTV15, IVTV_PCI_ID_AVERMEDIA, 0xa3cf }, | ||
203 | { PCI_DEVICE_ID_IVTV15, IVTV_PCI_ID_AVERMEDIA, 0xa3ce }, | ||
204 | { 0, 0, 0 } | ||
205 | }; | ||
206 | |||
207 | static const struct ivtv_card ivtv_card_m179 = { | ||
208 | .type = IVTV_CARD_M179, | ||
209 | .name = "AVerMedia M179", | ||
210 | .v4l2_capabilities = IVTV_CAP_ENCODER, | ||
211 | .hw_video = IVTV_HW_SAA7114, | ||
212 | .hw_audio = IVTV_HW_GPIO, | ||
213 | .hw_audio_ctrl = IVTV_HW_GPIO, | ||
214 | .hw_all = IVTV_HW_GPIO | IVTV_HW_SAA7114 | IVTV_HW_TUNER, | ||
215 | .video_inputs = { | ||
216 | { IVTV_CARD_INPUT_VID_TUNER, 0, IVTV_SAA71XX_COMPOSITE4 }, | ||
217 | { IVTV_CARD_INPUT_SVIDEO1, 1, IVTV_SAA71XX_SVIDEO0 }, | ||
218 | { IVTV_CARD_INPUT_COMPOSITE1, 1, IVTV_SAA71XX_COMPOSITE3 }, | ||
219 | }, | ||
220 | .audio_inputs = { | ||
221 | { IVTV_CARD_INPUT_AUD_TUNER, IVTV_GPIO_TUNER }, | ||
222 | { IVTV_CARD_INPUT_LINE_IN1, IVTV_GPIO_LINE_IN }, | ||
223 | }, | ||
224 | .gpio_init = { .direction = 0xe380, .initial_value = 0x8290 }, | ||
225 | .gpio_audio_input = { .mask = 0x8040, .tuner = 0x8000, .linein = 0x0000 }, | ||
226 | .gpio_audio_mute = { .mask = 0x2000, .mute = 0x2000 }, | ||
227 | .gpio_audio_mode = { .mask = 0x4300, .mono = 0x4000, .stereo = 0x0200, | ||
228 | .lang1 = 0x0200, .lang2 = 0x0100, .both = 0x0000 }, | ||
229 | .gpio_audio_freq = { .mask = 0x0018, .f32000 = 0x0000, | ||
230 | .f44100 = 0x0008, .f48000 = 0x0010 }, | ||
231 | .gpio_audio_detect = { .mask = 0x4000, .stereo = 0x0000 }, | ||
232 | .tuners = { | ||
233 | /* As far as we know all M179 cards use this tuner */ | ||
234 | { .std = V4L2_STD_ALL, .tuner = TUNER_PHILIPS_NTSC }, | ||
235 | }, | ||
236 | .pci_list = ivtv_pci_m179, | ||
237 | }; | ||
238 | |||
239 | /* ------------------------------------------------------------------------- */ | ||
240 | |||
241 | /* Yuan MPG600/Kuroutoshikou ITVC16-STVLP cards */ | ||
242 | |||
243 | static const struct ivtv_card_pci_info ivtv_pci_mpg600[] = { | ||
244 | { PCI_DEVICE_ID_IVTV16, IVTV_PCI_ID_YUAN1, 0xfff3 }, | ||
245 | { PCI_DEVICE_ID_IVTV16, IVTV_PCI_ID_YUAN1, 0xffff }, | ||
246 | { 0, 0, 0 } | ||
247 | }; | ||
248 | |||
249 | static const struct ivtv_card ivtv_card_mpg600 = { | ||
250 | .type = IVTV_CARD_MPG600, | ||
251 | .name = "Yuan MPG600, Kuroutoshikou ITVC16-STVLP", | ||
252 | .v4l2_capabilities = IVTV_CAP_ENCODER, | ||
253 | .hw_video = IVTV_HW_SAA7115, | ||
254 | .hw_audio = IVTV_HW_GPIO, | ||
255 | .hw_audio_ctrl = IVTV_HW_GPIO, | ||
256 | .hw_all = IVTV_HW_GPIO | IVTV_HW_SAA7115 | IVTV_HW_TUNER, | ||
257 | .video_inputs = { | ||
258 | { IVTV_CARD_INPUT_VID_TUNER, 0, IVTV_SAA71XX_COMPOSITE4 }, | ||
259 | { IVTV_CARD_INPUT_SVIDEO1, 1, IVTV_SAA71XX_SVIDEO0 }, | ||
260 | { IVTV_CARD_INPUT_COMPOSITE1, 1, IVTV_SAA71XX_COMPOSITE3 }, | ||
261 | }, | ||
262 | .audio_inputs = { | ||
263 | { IVTV_CARD_INPUT_AUD_TUNER, IVTV_GPIO_TUNER }, | ||
264 | { IVTV_CARD_INPUT_LINE_IN1, IVTV_GPIO_LINE_IN }, | ||
265 | }, | ||
266 | .gpio_init = { .direction = 0x3080, .initial_value = 0x0004 }, | ||
267 | .gpio_audio_input = { .mask = 0x3000, .tuner = 0x0000, .linein = 0x2000 }, | ||
268 | .gpio_audio_mute = { .mask = 0x0001, .mute = 0x0001 }, | ||
269 | .gpio_audio_mode = { .mask = 0x000e, .mono = 0x0006, .stereo = 0x0004, | ||
270 | .lang1 = 0x0004, .lang2 = 0x0000, .both = 0x0008 }, | ||
271 | .gpio_audio_detect = { .mask = 0x0900, .stereo = 0x0100 }, | ||
272 | .tuners = { | ||
273 | /* The PAL tuner is confirmed */ | ||
274 | { .std = V4L2_STD_625_50, .tuner = TUNER_PHILIPS_FQ1216ME }, | ||
275 | { .std = V4L2_STD_ALL, .tuner = TUNER_PHILIPS_FQ1286 }, | ||
276 | }, | ||
277 | .pci_list = ivtv_pci_mpg600, | ||
278 | }; | ||
279 | |||
280 | /* ------------------------------------------------------------------------- */ | ||
281 | |||
282 | /* Yuan MPG160/Kuroutoshikou ITVC15-STVLP cards */ | ||
283 | |||
284 | static const struct ivtv_card_pci_info ivtv_pci_mpg160[] = { | ||
285 | { PCI_DEVICE_ID_IVTV15, IVTV_PCI_ID_YUAN1, 0 }, | ||
286 | { PCI_DEVICE_ID_IVTV15, IVTV_PCI_ID_IODATA, 0x40a0 }, | ||
287 | { 0, 0, 0 } | ||
288 | }; | ||
289 | |||
290 | static const struct ivtv_card ivtv_card_mpg160 = { | ||
291 | .type = IVTV_CARD_MPG160, | ||
292 | .name = "YUAN MPG160, Kuroutoshikou ITVC15-STVLP, I/O Data GV-M2TV/PCI", | ||
293 | .v4l2_capabilities = IVTV_CAP_ENCODER, | ||
294 | .hw_video = IVTV_HW_SAA7114, | ||
295 | .hw_audio = IVTV_HW_GPIO, | ||
296 | .hw_audio_ctrl = IVTV_HW_GPIO, | ||
297 | .hw_all = IVTV_HW_GPIO | IVTV_HW_SAA7114 | IVTV_HW_TUNER, | ||
298 | .video_inputs = { | ||
299 | { IVTV_CARD_INPUT_VID_TUNER, 0, IVTV_SAA71XX_COMPOSITE4 }, | ||
300 | { IVTV_CARD_INPUT_SVIDEO1, 1, IVTV_SAA71XX_SVIDEO0 }, | ||
301 | { IVTV_CARD_INPUT_COMPOSITE1, 1, IVTV_SAA71XX_COMPOSITE3 }, | ||
302 | }, | ||
303 | .audio_inputs = { | ||
304 | { IVTV_CARD_INPUT_AUD_TUNER, IVTV_GPIO_TUNER }, | ||
305 | { IVTV_CARD_INPUT_LINE_IN1, IVTV_GPIO_LINE_IN }, | ||
306 | }, | ||
307 | .gpio_init = { .direction = 0x7080, .initial_value = 0x400c }, | ||
308 | .gpio_audio_input = { .mask = 0x3000, .tuner = 0x0000, .linein = 0x2000 }, | ||
309 | .gpio_audio_mute = { .mask = 0x0001, .mute = 0x0001 }, | ||
310 | .gpio_audio_mode = { .mask = 0x000e, .mono = 0x0006, .stereo = 0x0004, | ||
311 | .lang1 = 0x0004, .lang2 = 0x0000, .both = 0x0008 }, | ||
312 | .gpio_audio_detect = { .mask = 0x0900, .stereo = 0x0100 }, | ||
313 | .tuners = { | ||
314 | { .std = V4L2_STD_625_50, .tuner = TUNER_PHILIPS_FQ1216ME }, | ||
315 | { .std = V4L2_STD_ALL, .tuner = TUNER_PHILIPS_FQ1286 }, | ||
316 | }, | ||
317 | .pci_list = ivtv_pci_mpg160, | ||
318 | }; | ||
319 | |||
320 | /* ------------------------------------------------------------------------- */ | ||
321 | |||
322 | /* Yuan PG600/Diamond PVR-550 cards */ | ||
323 | |||
324 | static const struct ivtv_card_pci_info ivtv_pci_pg600[] = { | ||
325 | { PCI_DEVICE_ID_IVTV16, IVTV_PCI_ID_DIAMONDMM, 0x0070 }, | ||
326 | { PCI_DEVICE_ID_IVTV16, IVTV_PCI_ID_YUAN3, 0x0600 }, | ||
327 | { 0, 0, 0 } | ||
328 | }; | ||
329 | |||
330 | static const struct ivtv_card ivtv_card_pg600 = { | ||
331 | .type = IVTV_CARD_PG600, | ||
332 | .name = "Yuan PG600, Diamond PVR-550", | ||
333 | .v4l2_capabilities = IVTV_CAP_ENCODER, | ||
334 | .hw_video = IVTV_HW_CX25840, | ||
335 | .hw_audio = IVTV_HW_CX25840, | ||
336 | .hw_audio_ctrl = IVTV_HW_CX25840, | ||
337 | .hw_all = IVTV_HW_CX25840 | IVTV_HW_TUNER, | ||
338 | .video_inputs = { | ||
339 | { IVTV_CARD_INPUT_VID_TUNER, 0, CX25840_COMPOSITE2 }, | ||
340 | { IVTV_CARD_INPUT_SVIDEO1, 1, | ||
341 | CX25840_SVIDEO_LUMA3 | CX25840_SVIDEO_CHROMA4 }, | ||
342 | { IVTV_CARD_INPUT_COMPOSITE1, 1, CX25840_COMPOSITE1 }, | ||
343 | }, | ||
344 | .audio_inputs = { | ||
345 | { IVTV_CARD_INPUT_AUD_TUNER, CX25840_AUDIO5 }, | ||
346 | { IVTV_CARD_INPUT_LINE_IN1, CX25840_AUDIO_SERIAL }, | ||
347 | }, | ||
348 | .tuners = { | ||
349 | { .std = V4L2_STD_625_50, .tuner = TUNER_PHILIPS_FQ1216ME }, | ||
350 | { .std = V4L2_STD_ALL, .tuner = TUNER_PHILIPS_FQ1286 }, | ||
351 | }, | ||
352 | .pci_list = ivtv_pci_pg600, | ||
353 | }; | ||
354 | |||
355 | /* ------------------------------------------------------------------------- */ | ||
356 | |||
357 | /* Adaptec VideOh! AVC-2410 card */ | ||
358 | |||
359 | static const struct ivtv_card_pci_info ivtv_pci_avc2410[] = { | ||
360 | { PCI_DEVICE_ID_IVTV16, IVTV_PCI_ID_ADAPTEC, 0x0093 }, | ||
361 | { 0, 0, 0 } | ||
362 | }; | ||
363 | |||
364 | static const struct ivtv_card ivtv_card_avc2410 = { | ||
365 | .type = IVTV_CARD_AVC2410, | ||
366 | .name = "Adaptec VideOh! AVC-2410", | ||
367 | .v4l2_capabilities = IVTV_CAP_ENCODER, | ||
368 | .hw_video = IVTV_HW_SAA7115, | ||
369 | .hw_audio = IVTV_HW_MSP34XX, | ||
370 | .hw_audio_ctrl = IVTV_HW_MSP34XX, | ||
371 | .hw_muxer = IVTV_HW_CS53L32A, | ||
372 | .hw_all = IVTV_HW_MSP34XX | IVTV_HW_CS53L32A | | ||
373 | IVTV_HW_SAA7115 | IVTV_HW_TUNER, | ||
374 | .video_inputs = { | ||
375 | { IVTV_CARD_INPUT_VID_TUNER, 0, IVTV_SAA71XX_COMPOSITE4 }, | ||
376 | { IVTV_CARD_INPUT_SVIDEO1, 1, IVTV_SAA71XX_SVIDEO0 }, | ||
377 | { IVTV_CARD_INPUT_COMPOSITE1, 1, IVTV_SAA71XX_COMPOSITE3 }, | ||
378 | }, | ||
379 | .audio_inputs = { | ||
380 | { IVTV_CARD_INPUT_AUD_TUNER, | ||
381 | MSP_TUNER, CS53L32A_IN0 }, | ||
382 | { IVTV_CARD_INPUT_LINE_IN1, | ||
383 | MSP_SCART1, CS53L32A_IN2 }, | ||
384 | }, | ||
385 | /* This card has no eeprom and in fact the Windows driver relies | ||
386 | on the country/region setting of the user to decide which tuner | ||
387 | is available. */ | ||
388 | .tuners = { | ||
389 | /* This tuner has been verified for the AVC2410 */ | ||
390 | { .std = V4L2_STD_625_50, .tuner = TUNER_PHILIPS_FM1216ME_MK3 }, | ||
391 | /* This is a good guess, but I'm not totally sure this is | ||
392 | the correct tuner for NTSC. */ | ||
393 | { .std = V4L2_STD_ALL, .tuner = TUNER_PHILIPS_FM1236_MK3 }, | ||
394 | }, | ||
395 | .pci_list = ivtv_pci_avc2410, | ||
396 | }; | ||
397 | |||
398 | /* ------------------------------------------------------------------------- */ | ||
399 | |||
400 | /* Adaptec VideOh! AVC-2010 card */ | ||
401 | |||
402 | static const struct ivtv_card_pci_info ivtv_pci_avc2010[] = { | ||
403 | { PCI_DEVICE_ID_IVTV16, IVTV_PCI_ID_ADAPTEC, 0x0092 }, | ||
404 | { 0, 0, 0 } | ||
405 | }; | ||
406 | |||
407 | static const struct ivtv_card ivtv_card_avc2010 = { | ||
408 | .type = IVTV_CARD_AVC2010, | ||
409 | .name = "Adaptec VideOh! AVC-2010", | ||
410 | .v4l2_capabilities = IVTV_CAP_ENCODER, | ||
411 | .hw_video = IVTV_HW_SAA7115, | ||
412 | .hw_audio = IVTV_HW_CS53L32A, | ||
413 | .hw_audio_ctrl = IVTV_HW_CS53L32A, | ||
414 | .hw_all = IVTV_HW_CS53L32A | IVTV_HW_SAA7115, | ||
415 | .video_inputs = { | ||
416 | { IVTV_CARD_INPUT_SVIDEO1, 0, IVTV_SAA71XX_SVIDEO0 }, | ||
417 | { IVTV_CARD_INPUT_COMPOSITE1, 0, IVTV_SAA71XX_COMPOSITE3 }, | ||
418 | }, | ||
419 | .audio_inputs = { | ||
420 | { IVTV_CARD_INPUT_LINE_IN1, CS53L32A_IN2 }, | ||
421 | }, | ||
422 | /* Does not have a tuner */ | ||
423 | .pci_list = ivtv_pci_avc2010, | ||
424 | }; | ||
425 | |||
426 | /* ------------------------------------------------------------------------- */ | ||
427 | |||
428 | /* Nagase Transgear 5000TV card */ | ||
429 | |||
430 | static const struct ivtv_card_pci_info ivtv_pci_tg5000tv[] = { | ||
431 | { PCI_DEVICE_ID_IVTV16, IVTV_PCI_ID_AVERMEDIA, 0xbfff }, | ||
432 | { 0, 0, 0 } | ||
433 | }; | ||
434 | |||
435 | static const struct ivtv_card ivtv_card_tg5000tv = { | ||
436 | .type = IVTV_CARD_TG5000TV, | ||
437 | .name = "Nagase Transgear 5000TV", | ||
438 | .v4l2_capabilities = IVTV_CAP_ENCODER, | ||
439 | .hw_video = IVTV_HW_SAA7114 | IVTV_HW_UPD64031A | IVTV_HW_UPD6408X | | ||
440 | IVTV_HW_GPIO, | ||
441 | .hw_audio = IVTV_HW_GPIO, | ||
442 | .hw_audio_ctrl = IVTV_HW_GPIO, | ||
443 | .hw_all = IVTV_HW_GPIO | IVTV_HW_SAA7114 | IVTV_HW_TUNER | | ||
444 | IVTV_HW_UPD64031A | IVTV_HW_UPD6408X, | ||
445 | .video_inputs = { | ||
446 | { IVTV_CARD_INPUT_VID_TUNER, 0, IVTV_SAA71XX_SVIDEO0 }, | ||
447 | { IVTV_CARD_INPUT_SVIDEO1, 1, IVTV_SAA71XX_SVIDEO2 }, | ||
448 | { IVTV_CARD_INPUT_COMPOSITE1, 1, IVTV_SAA71XX_SVIDEO2 }, | ||
449 | }, | ||
450 | .audio_inputs = { | ||
451 | { IVTV_CARD_INPUT_AUD_TUNER, IVTV_GPIO_TUNER }, | ||
452 | { IVTV_CARD_INPUT_LINE_IN1, IVTV_GPIO_LINE_IN }, | ||
453 | }, | ||
454 | .gr_config = UPD64031A_VERTICAL_EXTERNAL, | ||
455 | .gpio_init = { .direction = 0xe080, .initial_value = 0x8000 }, | ||
456 | .gpio_audio_input = { .mask = 0x8080, .tuner = 0x8000, .linein = 0x0080 }, | ||
457 | .gpio_audio_mute = { .mask = 0x6000, .mute = 0x6000 }, | ||
458 | .gpio_audio_mode = { .mask = 0x4300, .mono = 0x4000, .stereo = 0x0200, | ||
459 | .lang1 = 0x0300, .lang2 = 0x0000, .both = 0x0200 }, | ||
460 | .gpio_video_input = { .mask = 0x0030, .tuner = 0x0000, | ||
461 | .composite = 0x0010, .svideo = 0x0020 }, | ||
462 | .tuners = { | ||
463 | { .std = V4L2_STD_525_60, .tuner = TUNER_PHILIPS_FQ1286 }, | ||
464 | }, | ||
465 | .pci_list = ivtv_pci_tg5000tv, | ||
466 | }; | ||
467 | |||
468 | /* ------------------------------------------------------------------------- */ | ||
469 | |||
470 | /* AOpen VA2000MAX-SNT6 card */ | ||
471 | |||
472 | static const struct ivtv_card_pci_info ivtv_pci_va2000[] = { | ||
473 | { PCI_DEVICE_ID_IVTV16, 0, 0xff5f }, | ||
474 | { 0, 0, 0 } | ||
475 | }; | ||
476 | |||
477 | static const struct ivtv_card ivtv_card_va2000 = { | ||
478 | .type = IVTV_CARD_VA2000MAX_SNT6, | ||
479 | .name = "AOpen VA2000MAX-SNT6", | ||
480 | .v4l2_capabilities = IVTV_CAP_ENCODER, | ||
481 | .hw_video = IVTV_HW_SAA7115 | IVTV_HW_UPD6408X, | ||
482 | .hw_audio = IVTV_HW_MSP34XX, | ||
483 | .hw_audio_ctrl = IVTV_HW_MSP34XX, | ||
484 | .hw_all = IVTV_HW_MSP34XX | IVTV_HW_SAA7115 | | ||
485 | IVTV_HW_UPD6408X | IVTV_HW_TUNER, | ||
486 | .video_inputs = { | ||
487 | { IVTV_CARD_INPUT_VID_TUNER, 0, IVTV_SAA71XX_SVIDEO0 }, | ||
488 | }, | ||
489 | .audio_inputs = { | ||
490 | { IVTV_CARD_INPUT_AUD_TUNER, MSP_TUNER }, | ||
491 | }, | ||
492 | .tuners = { | ||
493 | { .std = V4L2_STD_525_60, .tuner = TUNER_PHILIPS_FQ1286 }, | ||
494 | }, | ||
495 | .pci_list = ivtv_pci_va2000, | ||
496 | }; | ||
497 | |||
498 | /* ------------------------------------------------------------------------- */ | ||
499 | |||
500 | /* Yuan MPG600GR/Kuroutoshikou CX23416GYC-STVLP cards */ | ||
501 | |||
502 | static const struct ivtv_card_pci_info ivtv_pci_cx23416gyc[] = { | ||
503 | { PCI_DEVICE_ID_IVTV16, IVTV_PCI_ID_YUAN1, 0x0600 }, | ||
504 | { PCI_DEVICE_ID_IVTV16, IVTV_PCI_ID_YUAN4, 0x0600 }, | ||
505 | { PCI_DEVICE_ID_IVTV16, IVTV_PCI_ID_MELCO, 0x0523 }, | ||
506 | { 0, 0, 0 } | ||
507 | }; | ||
508 | |||
509 | static const struct ivtv_card ivtv_card_cx23416gyc = { | ||
510 | .type = IVTV_CARD_CX23416GYC, | ||
511 | .name = "Yuan MPG600GR, Kuroutoshikou CX23416GYC-STVLP", | ||
512 | .v4l2_capabilities = IVTV_CAP_ENCODER, | ||
513 | .hw_video = IVTV_HW_SAA717X | IVTV_HW_GPIO | | ||
514 | IVTV_HW_UPD64031A | IVTV_HW_UPD6408X, | ||
515 | .hw_audio = IVTV_HW_SAA717X, | ||
516 | .hw_audio_ctrl = IVTV_HW_SAA717X, | ||
517 | .hw_all = IVTV_HW_GPIO | IVTV_HW_SAA717X | IVTV_HW_TUNER | | ||
518 | IVTV_HW_UPD64031A | IVTV_HW_UPD6408X, | ||
519 | .video_inputs = { | ||
520 | { IVTV_CARD_INPUT_VID_TUNER, 0, IVTV_SAA71XX_SVIDEO3 | | ||
521 | IVTV_SAA717X_TUNER_FLAG }, | ||
522 | { IVTV_CARD_INPUT_SVIDEO1, 1, IVTV_SAA71XX_SVIDEO0 }, | ||
523 | { IVTV_CARD_INPUT_COMPOSITE1, 1, IVTV_SAA71XX_SVIDEO3 }, | ||
524 | }, | ||
525 | .audio_inputs = { | ||
526 | { IVTV_CARD_INPUT_AUD_TUNER, IVTV_SAA717X_IN2 }, | ||
527 | { IVTV_CARD_INPUT_LINE_IN1, IVTV_SAA717X_IN0 }, | ||
528 | }, | ||
529 | .gr_config = UPD64031A_VERTICAL_EXTERNAL, | ||
530 | .gpio_init = { .direction = 0xf880, .initial_value = 0x8800 }, | ||
531 | .gpio_video_input = { .mask = 0x0020, .tuner = 0x0000, | ||
532 | .composite = 0x0020, .svideo = 0x0020 }, | ||
533 | .gpio_audio_freq = { .mask = 0xc000, .f32000 = 0x0000, | ||
534 | .f44100 = 0x4000, .f48000 = 0x8000 }, | ||
535 | .tuners = { | ||
536 | { .std = V4L2_STD_625_50, .tuner = TUNER_PHILIPS_FM1216ME_MK3 }, | ||
537 | { .std = V4L2_STD_ALL, .tuner = TUNER_PHILIPS_FM1236_MK3 }, | ||
538 | }, | ||
539 | .pci_list = ivtv_pci_cx23416gyc, | ||
540 | }; | ||
541 | |||
542 | static const struct ivtv_card ivtv_card_cx23416gyc_nogr = { | ||
543 | .type = IVTV_CARD_CX23416GYC_NOGR, | ||
544 | .name = "Yuan MPG600GR, Kuroutoshikou CX23416GYC-STVLP (no GR)", | ||
545 | .v4l2_capabilities = IVTV_CAP_ENCODER, | ||
546 | .hw_video = IVTV_HW_SAA717X | IVTV_HW_GPIO | IVTV_HW_UPD6408X, | ||
547 | .hw_audio = IVTV_HW_SAA717X, | ||
548 | .hw_audio_ctrl = IVTV_HW_SAA717X, | ||
549 | .hw_all = IVTV_HW_GPIO | IVTV_HW_SAA717X | IVTV_HW_TUNER | | ||
550 | IVTV_HW_UPD6408X, | ||
551 | .video_inputs = { | ||
552 | { IVTV_CARD_INPUT_VID_TUNER, 0, IVTV_SAA71XX_COMPOSITE4 | | ||
553 | IVTV_SAA717X_TUNER_FLAG }, | ||
554 | { IVTV_CARD_INPUT_SVIDEO1, 1, IVTV_SAA71XX_SVIDEO0 }, | ||
555 | { IVTV_CARD_INPUT_COMPOSITE1, 1, IVTV_SAA71XX_COMPOSITE0 }, | ||
556 | }, | ||
557 | .audio_inputs = { | ||
558 | { IVTV_CARD_INPUT_AUD_TUNER, IVTV_SAA717X_IN2 }, | ||
559 | { IVTV_CARD_INPUT_LINE_IN1, IVTV_SAA717X_IN0 }, | ||
560 | }, | ||
561 | .gpio_init = { .direction = 0xf880, .initial_value = 0x8800 }, | ||
562 | .gpio_video_input = { .mask = 0x0020, .tuner = 0x0000, | ||
563 | .composite = 0x0020, .svideo = 0x0020 }, | ||
564 | .gpio_audio_freq = { .mask = 0xc000, .f32000 = 0x0000, | ||
565 | .f44100 = 0x4000, .f48000 = 0x8000 }, | ||
566 | .tuners = { | ||
567 | { .std = V4L2_STD_625_50, .tuner = TUNER_PHILIPS_FM1216ME_MK3 }, | ||
568 | { .std = V4L2_STD_ALL, .tuner = TUNER_PHILIPS_FM1236_MK3 }, | ||
569 | }, | ||
570 | }; | ||
571 | |||
572 | static const struct ivtv_card ivtv_card_cx23416gyc_nogrycs = { | ||
573 | .type = IVTV_CARD_CX23416GYC_NOGRYCS, | ||
574 | .name = "Yuan MPG600GR, Kuroutoshikou CX23416GYC-STVLP (no GR/YCS)", | ||
575 | .v4l2_capabilities = IVTV_CAP_ENCODER, | ||
576 | .hw_video = IVTV_HW_SAA717X | IVTV_HW_GPIO, | ||
577 | .hw_audio = IVTV_HW_SAA717X, | ||
578 | .hw_audio_ctrl = IVTV_HW_SAA717X, | ||
579 | .hw_all = IVTV_HW_GPIO | IVTV_HW_SAA717X | IVTV_HW_TUNER, | ||
580 | .video_inputs = { | ||
581 | { IVTV_CARD_INPUT_VID_TUNER, 0, IVTV_SAA71XX_COMPOSITE4 | | ||
582 | IVTV_SAA717X_TUNER_FLAG }, | ||
583 | { IVTV_CARD_INPUT_SVIDEO1, 1, IVTV_SAA71XX_SVIDEO0 }, | ||
584 | { IVTV_CARD_INPUT_COMPOSITE1, 1, IVTV_SAA71XX_COMPOSITE0 }, | ||
585 | }, | ||
586 | .audio_inputs = { | ||
587 | { IVTV_CARD_INPUT_AUD_TUNER, IVTV_SAA717X_IN2 }, | ||
588 | { IVTV_CARD_INPUT_LINE_IN1, IVTV_SAA717X_IN0 }, | ||
589 | }, | ||
590 | .gpio_init = { .direction = 0xf880, .initial_value = 0x8800 }, | ||
591 | .gpio_video_input = { .mask = 0x0020, .tuner = 0x0000, | ||
592 | .composite = 0x0020, .svideo = 0x0020 }, | ||
593 | .gpio_audio_freq = { .mask = 0xc000, .f32000 = 0x0000, | ||
594 | .f44100 = 0x4000, .f48000 = 0x8000 }, | ||
595 | .tuners = { | ||
596 | { .std = V4L2_STD_625_50, .tuner = TUNER_PHILIPS_FM1216ME_MK3 }, | ||
597 | { .std = V4L2_STD_ALL, .tuner = TUNER_PHILIPS_FM1236_MK3 }, | ||
598 | }, | ||
599 | }; | ||
600 | |||
601 | /* ------------------------------------------------------------------------- */ | ||
602 | |||
603 | /* I/O Data GV-MVP/RX & GV-MVP/RX2W (dual tuner) cards */ | ||
604 | |||
605 | static const struct ivtv_card_pci_info ivtv_pci_gv_mvprx[] = { | ||
606 | { PCI_DEVICE_ID_IVTV16, IVTV_PCI_ID_IODATA, 0xd01e }, | ||
607 | { PCI_DEVICE_ID_IVTV16, IVTV_PCI_ID_IODATA, 0xd038 }, /* 2W unit #1 */ | ||
608 | { PCI_DEVICE_ID_IVTV16, IVTV_PCI_ID_IODATA, 0xd039 }, /* 2W unit #2 */ | ||
609 | { 0, 0, 0 } | ||
610 | }; | ||
611 | |||
612 | static const struct ivtv_card ivtv_card_gv_mvprx = { | ||
613 | .type = IVTV_CARD_GV_MVPRX, | ||
614 | .name = "I/O Data GV-MVP/RX, GV-MVP/RX2W (dual tuner)", | ||
615 | .v4l2_capabilities = IVTV_CAP_ENCODER, | ||
616 | .hw_video = IVTV_HW_SAA7115 | IVTV_HW_UPD64031A | IVTV_HW_UPD6408X, | ||
617 | .hw_audio = IVTV_HW_GPIO, | ||
618 | .hw_audio_ctrl = IVTV_HW_WM8739, | ||
619 | .hw_all = IVTV_HW_GPIO | IVTV_HW_SAA7115 | IVTV_HW_TVAUDIO | | ||
620 | IVTV_HW_TUNER | IVTV_HW_WM8739 | | ||
621 | IVTV_HW_UPD64031A | IVTV_HW_UPD6408X, | ||
622 | .video_inputs = { | ||
623 | { IVTV_CARD_INPUT_VID_TUNER, 0, IVTV_SAA71XX_SVIDEO0 }, | ||
624 | { IVTV_CARD_INPUT_SVIDEO1, 1, IVTV_SAA71XX_SVIDEO1 }, | ||
625 | { IVTV_CARD_INPUT_COMPOSITE1, 1, IVTV_SAA71XX_SVIDEO2 }, | ||
626 | }, | ||
627 | .audio_inputs = { | ||
628 | { IVTV_CARD_INPUT_AUD_TUNER, IVTV_GPIO_TUNER }, | ||
629 | { IVTV_CARD_INPUT_LINE_IN1, IVTV_GPIO_LINE_IN }, | ||
630 | }, | ||
631 | .gpio_init = { .direction = 0xc301, .initial_value = 0x0200 }, | ||
632 | .gpio_audio_input = { .mask = 0xffff, .tuner = 0x0200, .linein = 0x0300 }, | ||
633 | .tuners = { | ||
634 | /* This card has the Panasonic VP27 tuner */ | ||
635 | { .std = V4L2_STD_525_60, .tuner = TUNER_PANASONIC_VP27 }, | ||
636 | }, | ||
637 | .pci_list = ivtv_pci_gv_mvprx, | ||
638 | }; | ||
639 | |||
640 | /* ------------------------------------------------------------------------- */ | ||
641 | |||
642 | /* I/O Data GV-MVP/RX2E card */ | ||
643 | |||
644 | static const struct ivtv_card_pci_info ivtv_pci_gv_mvprx2e[] = { | ||
645 | { PCI_DEVICE_ID_IVTV16, IVTV_PCI_ID_IODATA, 0xd025 }, | ||
646 | {0, 0, 0} | ||
647 | }; | ||
648 | |||
649 | static const struct ivtv_card ivtv_card_gv_mvprx2e = { | ||
650 | .type = IVTV_CARD_GV_MVPRX2E, | ||
651 | .name = "I/O Data GV-MVP/RX2E", | ||
652 | .v4l2_capabilities = IVTV_CAP_ENCODER, | ||
653 | .hw_video = IVTV_HW_SAA7115, | ||
654 | .hw_audio = IVTV_HW_GPIO, | ||
655 | .hw_audio_ctrl = IVTV_HW_WM8739, | ||
656 | .hw_all = IVTV_HW_GPIO | IVTV_HW_SAA7115 | IVTV_HW_TUNER | | ||
657 | IVTV_HW_TVAUDIO | IVTV_HW_WM8739, | ||
658 | .video_inputs = { | ||
659 | { IVTV_CARD_INPUT_VID_TUNER, 0, IVTV_SAA71XX_COMPOSITE4 }, | ||
660 | { IVTV_CARD_INPUT_SVIDEO1, 1, IVTV_SAA71XX_SVIDEO0 }, | ||
661 | { IVTV_CARD_INPUT_COMPOSITE1, 1, IVTV_SAA71XX_COMPOSITE3 }, | ||
662 | }, | ||
663 | .audio_inputs = { | ||
664 | { IVTV_CARD_INPUT_AUD_TUNER, IVTV_GPIO_TUNER }, | ||
665 | { IVTV_CARD_INPUT_LINE_IN1, IVTV_GPIO_LINE_IN }, | ||
666 | }, | ||
667 | .gpio_init = { .direction = 0xc301, .initial_value = 0x0200 }, | ||
668 | .gpio_audio_input = { .mask = 0xffff, .tuner = 0x0200, .linein = 0x0300 }, | ||
669 | .tuners = { | ||
670 | /* This card has the Panasonic VP27 tuner */ | ||
671 | { .std = V4L2_STD_525_60, .tuner = TUNER_PANASONIC_VP27 }, | ||
672 | }, | ||
673 | .pci_list = ivtv_pci_gv_mvprx2e, | ||
674 | }; | ||
675 | |||
676 | /* ------------------------------------------------------------------------- */ | ||
677 | |||
678 | /* GotVIEW PCI DVD card */ | ||
679 | |||
680 | static const struct ivtv_card_pci_info ivtv_pci_gotview_pci_dvd[] = { | ||
681 | { PCI_DEVICE_ID_IVTV16, IVTV_PCI_ID_YUAN1, 0x0600 }, | ||
682 | { 0, 0, 0 } | ||
683 | }; | ||
684 | |||
685 | static const struct ivtv_card ivtv_card_gotview_pci_dvd = { | ||
686 | .type = IVTV_CARD_GOTVIEW_PCI_DVD, | ||
687 | .name = "GotView PCI DVD", | ||
688 | .v4l2_capabilities = IVTV_CAP_ENCODER, | ||
689 | .hw_video = IVTV_HW_SAA717X, | ||
690 | .hw_audio = IVTV_HW_SAA717X, | ||
691 | .hw_audio_ctrl = IVTV_HW_SAA717X, | ||
692 | .hw_all = IVTV_HW_SAA717X | IVTV_HW_TUNER, | ||
693 | .video_inputs = { | ||
694 | { IVTV_CARD_INPUT_VID_TUNER, 0, IVTV_SAA71XX_COMPOSITE1 }, /* pin 116 */ | ||
695 | { IVTV_CARD_INPUT_SVIDEO1, 1, IVTV_SAA71XX_SVIDEO0 }, /* pin 114/109 */ | ||
696 | { IVTV_CARD_INPUT_COMPOSITE1, 1, IVTV_SAA71XX_COMPOSITE3 }, /* pin 118 */ | ||
697 | }, | ||
698 | .audio_inputs = { | ||
699 | { IVTV_CARD_INPUT_AUD_TUNER, IVTV_SAA717X_IN0 }, | ||
700 | { IVTV_CARD_INPUT_LINE_IN1, IVTV_SAA717X_IN2 }, | ||
701 | }, | ||
702 | .gpio_init = { .direction = 0xf000, .initial_value = 0xA000 }, | ||
703 | .tuners = { | ||
704 | /* This card has a Philips FQ1216ME MK3 tuner */ | ||
705 | { .std = V4L2_STD_625_50, .tuner = TUNER_PHILIPS_FM1216ME_MK3 }, | ||
706 | }, | ||
707 | .pci_list = ivtv_pci_gotview_pci_dvd, | ||
708 | }; | ||
709 | |||
710 | /* ------------------------------------------------------------------------- */ | ||
711 | |||
712 | /* GotVIEW PCI DVD2 Deluxe card */ | ||
713 | |||
714 | static const struct ivtv_card_pci_info ivtv_pci_gotview_pci_dvd2[] = { | ||
715 | { PCI_DEVICE_ID_IVTV16, IVTV_PCI_ID_GOTVIEW1, 0x0600 }, | ||
716 | { 0, 0, 0 } | ||
717 | }; | ||
718 | |||
719 | static const struct ivtv_card ivtv_card_gotview_pci_dvd2 = { | ||
720 | .type = IVTV_CARD_GOTVIEW_PCI_DVD2, | ||
721 | .name = "GotView PCI DVD2 Deluxe", | ||
722 | .v4l2_capabilities = IVTV_CAP_ENCODER, | ||
723 | .hw_video = IVTV_HW_CX25840, | ||
724 | .hw_audio = IVTV_HW_CX25840, | ||
725 | .hw_audio_ctrl = IVTV_HW_CX25840, | ||
726 | .hw_muxer = IVTV_HW_GPIO, | ||
727 | .hw_all = IVTV_HW_CX25840 | IVTV_HW_TUNER, | ||
728 | .video_inputs = { | ||
729 | { IVTV_CARD_INPUT_VID_TUNER, 0, CX25840_COMPOSITE2 }, | ||
730 | { IVTV_CARD_INPUT_SVIDEO1, 1, | ||
731 | CX25840_SVIDEO_LUMA3 | CX25840_SVIDEO_CHROMA4 }, | ||
732 | { IVTV_CARD_INPUT_COMPOSITE1, 1, CX25840_COMPOSITE1 }, | ||
733 | }, | ||
734 | .audio_inputs = { | ||
735 | { IVTV_CARD_INPUT_AUD_TUNER, CX25840_AUDIO5, 0 }, | ||
736 | { IVTV_CARD_INPUT_LINE_IN1, CX25840_AUDIO_SERIAL, 1 }, | ||
737 | }, | ||
738 | .radio_input = { IVTV_CARD_INPUT_AUD_TUNER, CX25840_AUDIO_SERIAL, 2 }, | ||
739 | .gpio_init = { .direction = 0x0800, .initial_value = 0 }, | ||
740 | .gpio_audio_input = { .mask = 0x0800, .tuner = 0, .linein = 0, .radio = 0x0800 }, | ||
741 | .tuners = { | ||
742 | /* This card has a Philips FQ1216ME MK5 tuner */ | ||
743 | { .std = V4L2_STD_625_50, .tuner = TUNER_PHILIPS_FM1216ME_MK3 }, | ||
744 | }, | ||
745 | .pci_list = ivtv_pci_gotview_pci_dvd2, | ||
746 | }; | ||
747 | |||
748 | /* ------------------------------------------------------------------------- */ | ||
749 | |||
750 | /* Yuan MPC622 miniPCI card */ | ||
751 | |||
752 | static const struct ivtv_card_pci_info ivtv_pci_yuan_mpc622[] = { | ||
753 | { PCI_DEVICE_ID_IVTV16, IVTV_PCI_ID_YUAN2, 0xd998 }, | ||
754 | { 0, 0, 0 } | ||
755 | }; | ||
756 | |||
757 | static const struct ivtv_card ivtv_card_yuan_mpc622 = { | ||
758 | .type = IVTV_CARD_YUAN_MPC622, | ||
759 | .name = "Yuan MPC622", | ||
760 | .v4l2_capabilities = IVTV_CAP_ENCODER, | ||
761 | .hw_video = IVTV_HW_CX25840, | ||
762 | .hw_audio = IVTV_HW_CX25840, | ||
763 | .hw_audio_ctrl = IVTV_HW_CX25840, | ||
764 | .hw_all = IVTV_HW_CX25840 | IVTV_HW_TUNER, | ||
765 | .video_inputs = { | ||
766 | { IVTV_CARD_INPUT_VID_TUNER, 0, CX25840_COMPOSITE2 }, | ||
767 | { IVTV_CARD_INPUT_SVIDEO1, 1, | ||
768 | CX25840_SVIDEO_LUMA3 | CX25840_SVIDEO_CHROMA4 }, | ||
769 | { IVTV_CARD_INPUT_COMPOSITE1, 1, CX25840_COMPOSITE1 }, | ||
770 | }, | ||
771 | .audio_inputs = { | ||
772 | { IVTV_CARD_INPUT_AUD_TUNER, CX25840_AUDIO5 }, | ||
773 | { IVTV_CARD_INPUT_LINE_IN1, CX25840_AUDIO_SERIAL }, | ||
774 | }, | ||
775 | .gpio_init = { .direction = 0x00ff, .initial_value = 0x0002 }, | ||
776 | .tuners = { | ||
777 | /* This card has the TDA8290/TDA8275 tuner chips */ | ||
778 | { .std = V4L2_STD_ALL, .tuner = TUNER_PHILIPS_TDA8290 }, | ||
779 | }, | ||
780 | .pci_list = ivtv_pci_yuan_mpc622, | ||
781 | }; | ||
782 | |||
783 | /* ------------------------------------------------------------------------- */ | ||
784 | |||
785 | /* DIGITAL COWBOY DCT-MTVP1 card */ | ||
786 | |||
787 | static const struct ivtv_card_pci_info ivtv_pci_dctmvtvp1[] = { | ||
788 | { PCI_DEVICE_ID_IVTV16, IVTV_PCI_ID_AVERMEDIA, 0xbfff }, | ||
789 | { 0, 0, 0 } | ||
790 | }; | ||
791 | |||
792 | static const struct ivtv_card ivtv_card_dctmvtvp1 = { | ||
793 | .type = IVTV_CARD_DCTMTVP1, | ||
794 | .name = "Digital Cowboy DCT-MTVP1", | ||
795 | .v4l2_capabilities = IVTV_CAP_ENCODER, | ||
796 | .hw_video = IVTV_HW_SAA7115 | IVTV_HW_UPD64031A | IVTV_HW_UPD6408X | | ||
797 | IVTV_HW_GPIO, | ||
798 | .hw_audio = IVTV_HW_GPIO, | ||
799 | .hw_audio_ctrl = IVTV_HW_GPIO, | ||
800 | .hw_all = IVTV_HW_GPIO | IVTV_HW_SAA7115 | IVTV_HW_TUNER | | ||
801 | IVTV_HW_UPD64031A | IVTV_HW_UPD6408X, | ||
802 | .video_inputs = { | ||
803 | { IVTV_CARD_INPUT_VID_TUNER, 0, IVTV_SAA71XX_SVIDEO0 }, | ||
804 | { IVTV_CARD_INPUT_SVIDEO1, 1, IVTV_SAA71XX_SVIDEO2 }, | ||
805 | { IVTV_CARD_INPUT_COMPOSITE1, 1, IVTV_SAA71XX_SVIDEO2 }, | ||
806 | }, | ||
807 | .audio_inputs = { | ||
808 | { IVTV_CARD_INPUT_AUD_TUNER, IVTV_GPIO_TUNER }, | ||
809 | { IVTV_CARD_INPUT_LINE_IN1, IVTV_GPIO_LINE_IN }, | ||
810 | }, | ||
811 | .gpio_init = { .direction = 0xe080, .initial_value = 0x8000 }, | ||
812 | .gpio_audio_input = { .mask = 0x8080, .tuner = 0x8000, .linein = 0x0080 }, | ||
813 | .gpio_audio_mute = { .mask = 0x6000, .mute = 0x6000 }, | ||
814 | .gpio_audio_mode = { .mask = 0x4300, .mono = 0x4000, .stereo = 0x0200, | ||
815 | .lang1 = 0x0300, .lang2 = 0x0000, .both = 0x0200 }, | ||
816 | .gpio_video_input = { .mask = 0x0030, .tuner = 0x0000, | ||
817 | .composite = 0x0010, .svideo = 0x0020}, | ||
818 | .tuners = { | ||
819 | { .std = V4L2_STD_525_60, .tuner = TUNER_PHILIPS_FQ1286 }, | ||
820 | }, | ||
821 | .pci_list = ivtv_pci_dctmvtvp1, | ||
822 | }; | ||
823 | |||
824 | /* ------------------------------------------------------------------------- */ | ||
825 | |||
826 | #ifdef HAVE_XC3028 | ||
827 | |||
828 | /* Yuan PG600-2/GotView PCI DVD Lite/Club3D ZAP-TV1x01 cards */ | ||
829 | |||
830 | static const struct ivtv_card_pci_info ivtv_pci_pg600v2[] = { | ||
831 | { PCI_DEVICE_ID_IVTV16, IVTV_PCI_ID_YUAN3, 0x0600 }, | ||
832 | { PCI_DEVICE_ID_IVTV16, IVTV_PCI_ID_GOTVIEW2, 0x0600 }, | ||
833 | { 0, 0, 0 } | ||
834 | }; | ||
835 | |||
836 | static const struct ivtv_card ivtv_card_pg600v2 = { | ||
837 | .type = IVTV_CARD_PG600V2, | ||
838 | .name = "Yuan PG600-2, GotView PCI DVD Lite, Club3D ZAP-TV1x01", | ||
839 | .v4l2_capabilities = IVTV_CAP_ENCODER, | ||
840 | .hw_video = IVTV_HW_CX25840, | ||
841 | .hw_audio = IVTV_HW_CX25840, | ||
842 | .hw_audio_ctrl = IVTV_HW_CX25840, | ||
843 | .hw_all = IVTV_HW_CX25840 | IVTV_HW_TUNER, | ||
844 | .video_inputs = { | ||
845 | { IVTV_CARD_INPUT_VID_TUNER, 0, CX25840_COMPOSITE2 }, | ||
846 | { IVTV_CARD_INPUT_SVIDEO1, 1, | ||
847 | CX25840_SVIDEO_LUMA3 | CX25840_SVIDEO_CHROMA4 }, | ||
848 | }, | ||
849 | .audio_inputs = { | ||
850 | { IVTV_CARD_INPUT_AUD_TUNER, CX25840_AUDIO5 }, | ||
851 | { IVTV_CARD_INPUT_LINE_IN1, CX25840_AUDIO_SERIAL }, | ||
852 | }, | ||
853 | .radio_input = { IVTV_CARD_INPUT_AUD_TUNER, CX25840_AUDIO5 }, | ||
854 | .tuners = { | ||
855 | { .std = V4L2_STD_ALL, .tuner = TUNER_XCEIVE_XC3028 }, | ||
856 | }, | ||
857 | .gpio_init = { .direction = 0x1000, .initial_value = 0x1000 }, /* tuner reset */ | ||
858 | .pci_list = ivtv_pci_pg600v2, | ||
859 | }; | ||
860 | #endif | ||
861 | |||
862 | static const struct ivtv_card *ivtv_card_list[] = { | ||
863 | &ivtv_card_pvr250, | ||
864 | &ivtv_card_pvr350, | ||
865 | &ivtv_card_pvr150, | ||
866 | &ivtv_card_m179, | ||
867 | &ivtv_card_mpg600, | ||
868 | &ivtv_card_mpg160, | ||
869 | &ivtv_card_pg600, | ||
870 | &ivtv_card_avc2410, | ||
871 | &ivtv_card_avc2010, | ||
872 | &ivtv_card_tg5000tv, | ||
873 | &ivtv_card_va2000, | ||
874 | &ivtv_card_cx23416gyc, | ||
875 | &ivtv_card_gv_mvprx, | ||
876 | &ivtv_card_gv_mvprx2e, | ||
877 | &ivtv_card_gotview_pci_dvd, | ||
878 | &ivtv_card_gotview_pci_dvd2, | ||
879 | &ivtv_card_yuan_mpc622, | ||
880 | &ivtv_card_dctmvtvp1, | ||
881 | #ifdef HAVE_XC3028 | ||
882 | &ivtv_card_pg600v2, | ||
883 | #endif | ||
884 | |||
885 | /* Variations of standard cards but with the same PCI IDs. | ||
886 | These cards must come last in this list. */ | ||
887 | &ivtv_card_pvr350_v1, | ||
888 | &ivtv_card_cx23416gyc_nogr, | ||
889 | &ivtv_card_cx23416gyc_nogrycs, | ||
890 | }; | ||
891 | |||
892 | const struct ivtv_card *ivtv_get_card(u16 index) | ||
893 | { | ||
894 | if (index >= ARRAY_SIZE(ivtv_card_list)) | ||
895 | return NULL; | ||
896 | return ivtv_card_list[index]; | ||
897 | } | ||
898 | |||
899 | int ivtv_get_input(struct ivtv *itv, u16 index, struct v4l2_input *input) | ||
900 | { | ||
901 | const struct ivtv_card_video_input *card_input = itv->card->video_inputs + index; | ||
902 | static const char * const input_strs[] = { | ||
903 | "Tuner 1", | ||
904 | "S-Video 1", | ||
905 | "S-Video 2", | ||
906 | "Composite 1", | ||
907 | "Composite 2", | ||
908 | "Composite 3" | ||
909 | }; | ||
910 | |||
911 | memset(input, 0, sizeof(*input)); | ||
912 | if (index >= itv->nof_inputs) | ||
913 | return -EINVAL; | ||
914 | input->index = index; | ||
915 | strcpy(input->name, input_strs[card_input->video_type - 1]); | ||
916 | input->type = (card_input->video_type == IVTV_CARD_INPUT_VID_TUNER ? | ||
917 | V4L2_INPUT_TYPE_TUNER : V4L2_INPUT_TYPE_CAMERA); | ||
918 | input->audioset = (1 << itv->nof_audio_inputs) - 1; | ||
919 | input->std = (input->type == V4L2_INPUT_TYPE_TUNER) ? | ||
920 | itv->tuner_std : V4L2_STD_ALL; | ||
921 | return 0; | ||
922 | } | ||
923 | |||
924 | int ivtv_get_output(struct ivtv *itv, u16 index, struct v4l2_output *output) | ||
925 | { | ||
926 | const struct ivtv_card_output *card_output = itv->card->video_outputs + index; | ||
927 | |||
928 | memset(output, 0, sizeof(*output)); | ||
929 | if (index >= itv->card->nof_outputs) | ||
930 | return -EINVAL; | ||
931 | output->index = index; | ||
932 | strcpy(output->name, card_output->name); | ||
933 | output->type = V4L2_OUTPUT_TYPE_ANALOG; | ||
934 | output->audioset = 1; | ||
935 | output->std = V4L2_STD_ALL; | ||
936 | return 0; | ||
937 | } | ||
938 | |||
939 | int ivtv_get_audio_input(struct ivtv *itv, u16 index, struct v4l2_audio *audio) | ||
940 | { | ||
941 | const struct ivtv_card_audio_input *aud_input = itv->card->audio_inputs + index; | ||
942 | static const char * const input_strs[] = { | ||
943 | "Tuner 1", | ||
944 | "Line In 1", | ||
945 | "Line In 2" | ||
946 | }; | ||
947 | |||
948 | memset(audio, 0, sizeof(*audio)); | ||
949 | if (index >= itv->nof_audio_inputs) | ||
950 | return -EINVAL; | ||
951 | strcpy(audio->name, input_strs[aud_input->audio_type - 1]); | ||
952 | audio->index = index; | ||
953 | audio->capability = V4L2_AUDCAP_STEREO; | ||
954 | return 0; | ||
955 | } | ||
956 | |||
957 | int ivtv_get_audio_output(struct ivtv *itv, u16 index, struct v4l2_audioout *aud_output) | ||
958 | { | ||
959 | memset(aud_output, 0, sizeof(*aud_output)); | ||
960 | if (itv->card->video_outputs == NULL || index != 0) | ||
961 | return -EINVAL; | ||
962 | strcpy(aud_output->name, "A/V Audio Out"); | ||
963 | return 0; | ||
964 | } | ||
diff --git a/drivers/media/video/ivtv/ivtv-cards.h b/drivers/media/video/ivtv/ivtv-cards.h new file mode 100644 index 000000000000..15012f88b802 --- /dev/null +++ b/drivers/media/video/ivtv/ivtv-cards.h | |||
@@ -0,0 +1,207 @@ | |||
1 | /* | ||
2 | Functions to query card hardware | ||
3 | Copyright (C) 2003-2004 Kevin Thayer <nufan_wfk at yahoo.com> | ||
4 | Copyright (C) 2005-2007 Hans Verkuil <hverkuil@xs4all.nl> | ||
5 | |||
6 | This program is free software; you can redistribute it and/or modify | ||
7 | it under the terms of the GNU General Public License as published by | ||
8 | the Free Software Foundation; either version 2 of the License, or | ||
9 | (at your option) any later version. | ||
10 | |||
11 | This program is distributed in the hope that it will be useful, | ||
12 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
14 | GNU General Public License for more details. | ||
15 | |||
16 | You should have received a copy of the GNU General Public License | ||
17 | along with this program; if not, write to the Free Software | ||
18 | Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
19 | */ | ||
20 | |||
21 | /* hardware flags */ | ||
22 | #define IVTV_HW_CX25840 (1 << 0) | ||
23 | #define IVTV_HW_SAA7115 (1 << 1) | ||
24 | #define IVTV_HW_SAA7127 (1 << 2) | ||
25 | #define IVTV_HW_MSP34XX (1 << 3) | ||
26 | #define IVTV_HW_TUNER (1 << 4) | ||
27 | #define IVTV_HW_WM8775 (1 << 5) | ||
28 | #define IVTV_HW_CS53L32A (1 << 6) | ||
29 | #define IVTV_HW_TVEEPROM (1 << 7) | ||
30 | #define IVTV_HW_SAA7114 (1 << 8) | ||
31 | #define IVTV_HW_TVAUDIO (1 << 9) | ||
32 | #define IVTV_HW_UPD64031A (1 << 10) | ||
33 | #define IVTV_HW_UPD6408X (1 << 11) | ||
34 | #define IVTV_HW_SAA717X (1 << 12) | ||
35 | #define IVTV_HW_WM8739 (1 << 13) | ||
36 | #define IVTV_HW_GPIO (1 << 14) | ||
37 | |||
38 | #define IVTV_HW_SAA711X (IVTV_HW_SAA7115 | IVTV_HW_SAA7114) | ||
39 | |||
40 | /* video inputs */ | ||
41 | #define IVTV_CARD_INPUT_VID_TUNER 1 | ||
42 | #define IVTV_CARD_INPUT_SVIDEO1 2 | ||
43 | #define IVTV_CARD_INPUT_SVIDEO2 3 | ||
44 | #define IVTV_CARD_INPUT_COMPOSITE1 4 | ||
45 | #define IVTV_CARD_INPUT_COMPOSITE2 5 | ||
46 | #define IVTV_CARD_INPUT_COMPOSITE3 6 | ||
47 | |||
48 | /* audio inputs */ | ||
49 | #define IVTV_CARD_INPUT_AUD_TUNER 1 | ||
50 | #define IVTV_CARD_INPUT_LINE_IN1 2 | ||
51 | #define IVTV_CARD_INPUT_LINE_IN2 3 | ||
52 | |||
53 | #define IVTV_CARD_MAX_VIDEO_INPUTS 6 | ||
54 | #define IVTV_CARD_MAX_AUDIO_INPUTS 3 | ||
55 | #define IVTV_CARD_MAX_TUNERS 2 | ||
56 | |||
57 | /* SAA71XX HW inputs */ | ||
58 | #define IVTV_SAA71XX_COMPOSITE0 0 | ||
59 | #define IVTV_SAA71XX_COMPOSITE1 1 | ||
60 | #define IVTV_SAA71XX_COMPOSITE2 2 | ||
61 | #define IVTV_SAA71XX_COMPOSITE3 3 | ||
62 | #define IVTV_SAA71XX_COMPOSITE4 4 | ||
63 | #define IVTV_SAA71XX_COMPOSITE5 5 | ||
64 | #define IVTV_SAA71XX_SVIDEO0 6 | ||
65 | #define IVTV_SAA71XX_SVIDEO1 7 | ||
66 | #define IVTV_SAA71XX_SVIDEO2 8 | ||
67 | #define IVTV_SAA71XX_SVIDEO3 9 | ||
68 | |||
69 | /* SAA717X needs to mark the tuner input by ORing with this flag */ | ||
70 | #define IVTV_SAA717X_TUNER_FLAG 0x80 | ||
71 | |||
72 | /* Dummy HW input */ | ||
73 | #define IVTV_DUMMY_AUDIO 0 | ||
74 | |||
75 | /* GPIO HW inputs */ | ||
76 | #define IVTV_GPIO_TUNER 0 | ||
77 | #define IVTV_GPIO_LINE_IN 1 | ||
78 | |||
79 | /* SAA717X HW inputs */ | ||
80 | #define IVTV_SAA717X_IN0 0 | ||
81 | #define IVTV_SAA717X_IN1 1 | ||
82 | #define IVTV_SAA717X_IN2 2 | ||
83 | |||
84 | /* V4L2 capability aliases */ | ||
85 | #define IVTV_CAP_ENCODER (V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_TUNER | \ | ||
86 | V4L2_CAP_AUDIO | V4L2_CAP_READWRITE | V4L2_CAP_VBI_CAPTURE | \ | ||
87 | V4L2_CAP_SLICED_VBI_CAPTURE) | ||
88 | #define IVTV_CAP_DECODER (V4L2_CAP_VBI_OUTPUT | V4L2_CAP_VIDEO_OUTPUT | \ | ||
89 | V4L2_CAP_SLICED_VBI_OUTPUT | V4L2_CAP_VIDEO_OUTPUT_OVERLAY | V4L2_CAP_VIDEO_OUTPUT_POS) | ||
90 | |||
91 | struct ivtv_card_video_input { | ||
92 | u8 video_type; /* video input type */ | ||
93 | u8 audio_index; /* index in ivtv_card_audio_input array */ | ||
94 | u16 video_input; /* hardware video input */ | ||
95 | }; | ||
96 | |||
97 | struct ivtv_card_audio_input { | ||
98 | u8 audio_type; /* audio input type */ | ||
99 | u32 audio_input; /* hardware audio input */ | ||
100 | u16 muxer_input; /* hardware muxer input for boards with a | ||
101 | multiplexer chip */ | ||
102 | }; | ||
103 | |||
104 | struct ivtv_card_output { | ||
105 | u8 name[32]; | ||
106 | u16 video_output; /* hardware video output */ | ||
107 | }; | ||
108 | |||
109 | struct ivtv_card_pci_info { | ||
110 | u16 device; | ||
111 | u16 subsystem_vendor; | ||
112 | u16 subsystem_device; | ||
113 | }; | ||
114 | |||
115 | /* GPIO definitions */ | ||
116 | |||
117 | /* The mask is the set of bits used by the operation */ | ||
118 | |||
119 | struct ivtv_gpio_init { /* set initial GPIO DIR and OUT values */ | ||
120 | u16 direction; /* DIR setting. Leave to 0 if no init is needed */ | ||
121 | u16 initial_value; | ||
122 | }; | ||
123 | |||
124 | struct ivtv_gpio_video_input { /* select tuner/line in input */ | ||
125 | u16 mask; /* leave to 0 if not supported */ | ||
126 | u16 tuner; | ||
127 | u16 composite; | ||
128 | u16 svideo; | ||
129 | }; | ||
130 | |||
131 | struct ivtv_gpio_audio_input { /* select tuner/line in input */ | ||
132 | u16 mask; /* leave to 0 if not supported */ | ||
133 | u16 tuner; | ||
134 | u16 linein; | ||
135 | u16 radio; | ||
136 | }; | ||
137 | |||
138 | struct ivtv_gpio_audio_mute { | ||
139 | u16 mask; /* leave to 0 if not supported */ | ||
140 | u16 mute; /* set this value to mute, 0 to unmute */ | ||
141 | }; | ||
142 | |||
143 | struct ivtv_gpio_audio_mode { | ||
144 | u16 mask; /* leave to 0 if not supported */ | ||
145 | u16 mono; /* set audio to mono */ | ||
146 | u16 stereo; /* set audio to stereo */ | ||
147 | u16 lang1; /* set audio to the first language */ | ||
148 | u16 lang2; /* set audio to the second language */ | ||
149 | u16 both; /* both languages are output */ | ||
150 | }; | ||
151 | |||
152 | struct ivtv_gpio_audio_freq { | ||
153 | u16 mask; /* leave to 0 if not supported */ | ||
154 | u16 f32000; | ||
155 | u16 f44100; | ||
156 | u16 f48000; | ||
157 | }; | ||
158 | |||
159 | struct ivtv_gpio_audio_detect { | ||
160 | u16 mask; /* leave to 0 if not supported */ | ||
161 | u16 stereo; /* if the input matches this value then | ||
162 | stereo is detected */ | ||
163 | }; | ||
164 | |||
165 | struct ivtv_card_tuner { | ||
166 | v4l2_std_id std; /* standard for which the tuner is suitable */ | ||
167 | int tuner; /* tuner ID (from tuner.h) */ | ||
168 | }; | ||
169 | |||
170 | /* for card information/parameters */ | ||
171 | struct ivtv_card { | ||
172 | int type; | ||
173 | char *name; | ||
174 | u32 v4l2_capabilities; | ||
175 | u32 hw_video; /* hardware used to process video */ | ||
176 | u32 hw_audio; /* hardware used to process audio */ | ||
177 | u32 hw_audio_ctrl; /* hardware used for the V4L2 controls (only 1 dev allowed) */ | ||
178 | u32 hw_muxer; /* hardware used to multiplex audio input */ | ||
179 | u32 hw_all; /* all hardware used by the board */ | ||
180 | struct ivtv_card_video_input video_inputs[IVTV_CARD_MAX_VIDEO_INPUTS]; | ||
181 | struct ivtv_card_audio_input audio_inputs[IVTV_CARD_MAX_AUDIO_INPUTS]; | ||
182 | struct ivtv_card_audio_input radio_input; | ||
183 | int nof_outputs; | ||
184 | const struct ivtv_card_output *video_outputs; | ||
185 | u8 gr_config; /* config byte for the ghost reduction device */ | ||
186 | |||
187 | /* GPIO card-specific settings */ | ||
188 | struct ivtv_gpio_init gpio_init; | ||
189 | struct ivtv_gpio_video_input gpio_video_input; | ||
190 | struct ivtv_gpio_audio_input gpio_audio_input; | ||
191 | struct ivtv_gpio_audio_mute gpio_audio_mute; | ||
192 | struct ivtv_gpio_audio_mode gpio_audio_mode; | ||
193 | struct ivtv_gpio_audio_freq gpio_audio_freq; | ||
194 | struct ivtv_gpio_audio_detect gpio_audio_detect; | ||
195 | |||
196 | struct ivtv_card_tuner tuners[IVTV_CARD_MAX_TUNERS]; | ||
197 | |||
198 | /* list of device and subsystem vendor/devices that | ||
199 | correspond to this card type. */ | ||
200 | const struct ivtv_card_pci_info *pci_list; | ||
201 | }; | ||
202 | |||
203 | int ivtv_get_input(struct ivtv *itv, u16 index, struct v4l2_input *input); | ||
204 | int ivtv_get_output(struct ivtv *itv, u16 index, struct v4l2_output *output); | ||
205 | int ivtv_get_audio_input(struct ivtv *itv, u16 index, struct v4l2_audio *input); | ||
206 | int ivtv_get_audio_output(struct ivtv *itv, u16 index, struct v4l2_audioout *output); | ||
207 | const struct ivtv_card *ivtv_get_card(u16 index); | ||
diff --git a/drivers/media/video/ivtv/ivtv-controls.c b/drivers/media/video/ivtv/ivtv-controls.c new file mode 100644 index 000000000000..7a876c3e5b19 --- /dev/null +++ b/drivers/media/video/ivtv/ivtv-controls.c | |||
@@ -0,0 +1,303 @@ | |||
1 | /* | ||
2 | ioctl control functions | ||
3 | Copyright (C) 2003-2004 Kevin Thayer <nufan_wfk at yahoo.com> | ||
4 | Copyright (C) 2005-2007 Hans Verkuil <hverkuil@xs4all.nl> | ||
5 | |||
6 | This program is free software; you can redistribute it and/or modify | ||
7 | it under the terms of the GNU General Public License as published by | ||
8 | the Free Software Foundation; either version 2 of the License, or | ||
9 | (at your option) any later version. | ||
10 | |||
11 | This program is distributed in the hope that it will be useful, | ||
12 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
14 | GNU General Public License for more details. | ||
15 | |||
16 | You should have received a copy of the GNU General Public License | ||
17 | along with this program; if not, write to the Free Software | ||
18 | Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
19 | */ | ||
20 | |||
21 | #include "ivtv-driver.h" | ||
22 | #include "ivtv-cards.h" | ||
23 | #include "ivtv-ioctl.h" | ||
24 | #include "ivtv-audio.h" | ||
25 | #include "ivtv-i2c.h" | ||
26 | #include "ivtv-mailbox.h" | ||
27 | #include "ivtv-controls.h" | ||
28 | |||
29 | static const u32 user_ctrls[] = { | ||
30 | V4L2_CID_USER_CLASS, | ||
31 | V4L2_CID_BRIGHTNESS, | ||
32 | V4L2_CID_CONTRAST, | ||
33 | V4L2_CID_SATURATION, | ||
34 | V4L2_CID_HUE, | ||
35 | V4L2_CID_AUDIO_VOLUME, | ||
36 | V4L2_CID_AUDIO_BALANCE, | ||
37 | V4L2_CID_AUDIO_BASS, | ||
38 | V4L2_CID_AUDIO_TREBLE, | ||
39 | V4L2_CID_AUDIO_MUTE, | ||
40 | V4L2_CID_AUDIO_LOUDNESS, | ||
41 | 0 | ||
42 | }; | ||
43 | |||
44 | static const u32 *ctrl_classes[] = { | ||
45 | user_ctrls, | ||
46 | cx2341x_mpeg_ctrls, | ||
47 | NULL | ||
48 | }; | ||
49 | |||
50 | static int ivtv_queryctrl(struct ivtv *itv, struct v4l2_queryctrl *qctrl) | ||
51 | { | ||
52 | const char *name; | ||
53 | |||
54 | IVTV_DEBUG_IOCTL("VIDIOC_QUERYCTRL(%08x)\n", qctrl->id); | ||
55 | |||
56 | qctrl->id = v4l2_ctrl_next(ctrl_classes, qctrl->id); | ||
57 | if (qctrl->id == 0) | ||
58 | return -EINVAL; | ||
59 | |||
60 | switch (qctrl->id) { | ||
61 | /* Standard V4L2 controls */ | ||
62 | case V4L2_CID_BRIGHTNESS: | ||
63 | case V4L2_CID_HUE: | ||
64 | case V4L2_CID_SATURATION: | ||
65 | case V4L2_CID_CONTRAST: | ||
66 | if (itv->video_dec_func(itv, VIDIOC_QUERYCTRL, qctrl)) | ||
67 | qctrl->flags |= V4L2_CTRL_FLAG_DISABLED; | ||
68 | return 0; | ||
69 | |||
70 | case V4L2_CID_AUDIO_VOLUME: | ||
71 | case V4L2_CID_AUDIO_MUTE: | ||
72 | case V4L2_CID_AUDIO_BALANCE: | ||
73 | case V4L2_CID_AUDIO_BASS: | ||
74 | case V4L2_CID_AUDIO_TREBLE: | ||
75 | case V4L2_CID_AUDIO_LOUDNESS: | ||
76 | if (ivtv_i2c_hw(itv, itv->card->hw_audio_ctrl, VIDIOC_QUERYCTRL, qctrl)) | ||
77 | qctrl->flags |= V4L2_CTRL_FLAG_DISABLED; | ||
78 | return 0; | ||
79 | |||
80 | default: | ||
81 | if (cx2341x_ctrl_query(&itv->params, qctrl)) | ||
82 | qctrl->flags |= V4L2_CTRL_FLAG_DISABLED; | ||
83 | return 0; | ||
84 | } | ||
85 | strncpy(qctrl->name, name, sizeof(qctrl->name) - 1); | ||
86 | qctrl->name[sizeof(qctrl->name) - 1] = 0; | ||
87 | return 0; | ||
88 | } | ||
89 | |||
90 | static int ivtv_querymenu(struct ivtv *itv, struct v4l2_querymenu *qmenu) | ||
91 | { | ||
92 | struct v4l2_queryctrl qctrl; | ||
93 | |||
94 | qctrl.id = qmenu->id; | ||
95 | ivtv_queryctrl(itv, &qctrl); | ||
96 | return v4l2_ctrl_query_menu(qmenu, &qctrl, cx2341x_ctrl_get_menu(qmenu->id)); | ||
97 | } | ||
98 | |||
99 | static int ivtv_s_ctrl(struct ivtv *itv, struct v4l2_control *vctrl) | ||
100 | { | ||
101 | s32 v = vctrl->value; | ||
102 | |||
103 | IVTV_DEBUG_IOCTL("VIDIOC_S_CTRL(%08x, %x)\n", vctrl->id, v); | ||
104 | |||
105 | switch (vctrl->id) { | ||
106 | /* Standard V4L2 controls */ | ||
107 | case V4L2_CID_BRIGHTNESS: | ||
108 | case V4L2_CID_HUE: | ||
109 | case V4L2_CID_SATURATION: | ||
110 | case V4L2_CID_CONTRAST: | ||
111 | return itv->video_dec_func(itv, VIDIOC_S_CTRL, vctrl); | ||
112 | |||
113 | case V4L2_CID_AUDIO_VOLUME: | ||
114 | case V4L2_CID_AUDIO_MUTE: | ||
115 | case V4L2_CID_AUDIO_BALANCE: | ||
116 | case V4L2_CID_AUDIO_BASS: | ||
117 | case V4L2_CID_AUDIO_TREBLE: | ||
118 | case V4L2_CID_AUDIO_LOUDNESS: | ||
119 | return ivtv_i2c_hw(itv, itv->card->hw_audio_ctrl, VIDIOC_S_CTRL, vctrl); | ||
120 | |||
121 | default: | ||
122 | IVTV_DEBUG_IOCTL("invalid control %x\n", vctrl->id); | ||
123 | return -EINVAL; | ||
124 | } | ||
125 | return 0; | ||
126 | } | ||
127 | |||
128 | static int ivtv_g_ctrl(struct ivtv *itv, struct v4l2_control *vctrl) | ||
129 | { | ||
130 | IVTV_DEBUG_IOCTL("VIDIOC_G_CTRL(%08x)\n", vctrl->id); | ||
131 | |||
132 | switch (vctrl->id) { | ||
133 | /* Standard V4L2 controls */ | ||
134 | case V4L2_CID_BRIGHTNESS: | ||
135 | case V4L2_CID_HUE: | ||
136 | case V4L2_CID_SATURATION: | ||
137 | case V4L2_CID_CONTRAST: | ||
138 | return itv->video_dec_func(itv, VIDIOC_G_CTRL, vctrl); | ||
139 | |||
140 | case V4L2_CID_AUDIO_VOLUME: | ||
141 | case V4L2_CID_AUDIO_MUTE: | ||
142 | case V4L2_CID_AUDIO_BALANCE: | ||
143 | case V4L2_CID_AUDIO_BASS: | ||
144 | case V4L2_CID_AUDIO_TREBLE: | ||
145 | case V4L2_CID_AUDIO_LOUDNESS: | ||
146 | return ivtv_i2c_hw(itv, itv->card->hw_audio_ctrl, VIDIOC_G_CTRL, vctrl); | ||
147 | default: | ||
148 | IVTV_DEBUG_IOCTL("invalid control %x\n", vctrl->id); | ||
149 | return -EINVAL; | ||
150 | } | ||
151 | return 0; | ||
152 | } | ||
153 | |||
154 | static int ivtv_setup_vbi_fmt(struct ivtv *itv, enum v4l2_mpeg_stream_vbi_fmt fmt) | ||
155 | { | ||
156 | if (!(itv->v4l2_cap & V4L2_CAP_SLICED_VBI_CAPTURE)) | ||
157 | return -EINVAL; | ||
158 | if (atomic_read(&itv->capturing) > 0) | ||
159 | return -EBUSY; | ||
160 | |||
161 | /* First try to allocate sliced VBI buffers if needed. */ | ||
162 | if (fmt && itv->vbi.sliced_mpeg_data[0] == NULL) { | ||
163 | int i; | ||
164 | |||
165 | for (i = 0; i < IVTV_VBI_FRAMES; i++) { | ||
166 | /* Yuck, hardcoded. Needs to be a define */ | ||
167 | itv->vbi.sliced_mpeg_data[i] = kmalloc(2049, GFP_KERNEL); | ||
168 | if (itv->vbi.sliced_mpeg_data[i] == NULL) { | ||
169 | while (--i >= 0) { | ||
170 | kfree(itv->vbi.sliced_mpeg_data[i]); | ||
171 | itv->vbi.sliced_mpeg_data[i] = NULL; | ||
172 | } | ||
173 | return -ENOMEM; | ||
174 | } | ||
175 | } | ||
176 | } | ||
177 | |||
178 | itv->vbi.insert_mpeg = fmt; | ||
179 | |||
180 | if (itv->vbi.insert_mpeg == 0) { | ||
181 | return 0; | ||
182 | } | ||
183 | /* Need sliced data for mpeg insertion */ | ||
184 | if (get_service_set(itv->vbi.sliced_in) == 0) { | ||
185 | if (itv->is_60hz) | ||
186 | itv->vbi.sliced_in->service_set = V4L2_SLICED_CAPTION_525; | ||
187 | else | ||
188 | itv->vbi.sliced_in->service_set = V4L2_SLICED_WSS_625; | ||
189 | expand_service_set(itv->vbi.sliced_in, itv->is_50hz); | ||
190 | } | ||
191 | return 0; | ||
192 | } | ||
193 | |||
194 | int ivtv_control_ioctls(struct ivtv *itv, unsigned int cmd, void *arg) | ||
195 | { | ||
196 | struct v4l2_control ctrl; | ||
197 | |||
198 | switch (cmd) { | ||
199 | case VIDIOC_QUERYMENU: | ||
200 | IVTV_DEBUG_IOCTL("VIDIOC_QUERYMENU\n"); | ||
201 | return ivtv_querymenu(itv, arg); | ||
202 | |||
203 | case VIDIOC_QUERYCTRL: | ||
204 | return ivtv_queryctrl(itv, arg); | ||
205 | |||
206 | case VIDIOC_S_CTRL: | ||
207 | return ivtv_s_ctrl(itv, arg); | ||
208 | |||
209 | case VIDIOC_G_CTRL: | ||
210 | return ivtv_g_ctrl(itv, arg); | ||
211 | |||
212 | case VIDIOC_S_EXT_CTRLS: | ||
213 | { | ||
214 | struct v4l2_ext_controls *c = arg; | ||
215 | |||
216 | if (c->ctrl_class == V4L2_CTRL_CLASS_USER) { | ||
217 | int i; | ||
218 | int err = 0; | ||
219 | |||
220 | for (i = 0; i < c->count; i++) { | ||
221 | ctrl.id = c->controls[i].id; | ||
222 | ctrl.value = c->controls[i].value; | ||
223 | err = ivtv_s_ctrl(itv, &ctrl); | ||
224 | c->controls[i].value = ctrl.value; | ||
225 | if (err) { | ||
226 | c->error_idx = i; | ||
227 | break; | ||
228 | } | ||
229 | } | ||
230 | return err; | ||
231 | } | ||
232 | IVTV_DEBUG_IOCTL("VIDIOC_S_EXT_CTRLS\n"); | ||
233 | if (c->ctrl_class == V4L2_CTRL_CLASS_MPEG) { | ||
234 | struct cx2341x_mpeg_params p = itv->params; | ||
235 | int err = cx2341x_ext_ctrls(&p, arg, cmd); | ||
236 | |||
237 | if (err) | ||
238 | return err; | ||
239 | |||
240 | if (p.video_encoding != itv->params.video_encoding) { | ||
241 | int is_mpeg1 = p.video_encoding == | ||
242 | V4L2_MPEG_VIDEO_ENCODING_MPEG_1; | ||
243 | struct v4l2_format fmt; | ||
244 | |||
245 | /* fix videodecoder resolution */ | ||
246 | fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; | ||
247 | fmt.fmt.pix.width = itv->params.width / (is_mpeg1 ? 2 : 1); | ||
248 | fmt.fmt.pix.height = itv->params.height; | ||
249 | itv->video_dec_func(itv, VIDIOC_S_FMT, &fmt); | ||
250 | } | ||
251 | err = cx2341x_update(itv, ivtv_api_func, &itv->params, &p); | ||
252 | if (!err && itv->params.stream_vbi_fmt != p.stream_vbi_fmt) { | ||
253 | err = ivtv_setup_vbi_fmt(itv, p.stream_vbi_fmt); | ||
254 | } | ||
255 | itv->params = p; | ||
256 | itv->dualwatch_stereo_mode = p.audio_properties & 0x0300; | ||
257 | ivtv_audio_set_audio_clock_freq(itv, p.audio_properties & 0x03); | ||
258 | return err; | ||
259 | } | ||
260 | return -EINVAL; | ||
261 | } | ||
262 | |||
263 | case VIDIOC_G_EXT_CTRLS: | ||
264 | { | ||
265 | struct v4l2_ext_controls *c = arg; | ||
266 | |||
267 | if (c->ctrl_class == V4L2_CTRL_CLASS_USER) { | ||
268 | int i; | ||
269 | int err = 0; | ||
270 | |||
271 | for (i = 0; i < c->count; i++) { | ||
272 | ctrl.id = c->controls[i].id; | ||
273 | ctrl.value = c->controls[i].value; | ||
274 | err = ivtv_g_ctrl(itv, &ctrl); | ||
275 | c->controls[i].value = ctrl.value; | ||
276 | if (err) { | ||
277 | c->error_idx = i; | ||
278 | break; | ||
279 | } | ||
280 | } | ||
281 | return err; | ||
282 | } | ||
283 | IVTV_DEBUG_IOCTL("VIDIOC_G_EXT_CTRLS\n"); | ||
284 | if (c->ctrl_class == V4L2_CTRL_CLASS_MPEG) | ||
285 | return cx2341x_ext_ctrls(&itv->params, arg, cmd); | ||
286 | return -EINVAL; | ||
287 | } | ||
288 | |||
289 | case VIDIOC_TRY_EXT_CTRLS: | ||
290 | { | ||
291 | struct v4l2_ext_controls *c = arg; | ||
292 | |||
293 | IVTV_DEBUG_IOCTL("VIDIOC_TRY_EXT_CTRLS\n"); | ||
294 | if (c->ctrl_class == V4L2_CTRL_CLASS_MPEG) | ||
295 | return cx2341x_ext_ctrls(&itv->params, arg, cmd); | ||
296 | return -EINVAL; | ||
297 | } | ||
298 | |||
299 | default: | ||
300 | return -EINVAL; | ||
301 | } | ||
302 | return 0; | ||
303 | } | ||
diff --git a/drivers/media/video/ivtv/ivtv-controls.h b/drivers/media/video/ivtv/ivtv-controls.h new file mode 100644 index 000000000000..5a11149725ad --- /dev/null +++ b/drivers/media/video/ivtv/ivtv-controls.h | |||
@@ -0,0 +1,21 @@ | |||
1 | /* | ||
2 | ioctl control functions | ||
3 | Copyright (C) 2003-2004 Kevin Thayer <nufan_wfk at yahoo.com> | ||
4 | Copyright (C) 2005-2007 Hans Verkuil <hverkuil@xs4all.nl> | ||
5 | |||
6 | This program is free software; you can redistribute it and/or modify | ||
7 | it under the terms of the GNU General Public License as published by | ||
8 | the Free Software Foundation; either version 2 of the License, or | ||
9 | (at your option) any later version. | ||
10 | |||
11 | This program is distributed in the hope that it will be useful, | ||
12 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
14 | GNU General Public License for more details. | ||
15 | |||
16 | You should have received a copy of the GNU General Public License | ||
17 | along with this program; if not, write to the Free Software | ||
18 | Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
19 | */ | ||
20 | |||
21 | int ivtv_control_ioctls(struct ivtv *itv, unsigned int cmd, void *arg); | ||
diff --git a/drivers/media/video/ivtv/ivtv-driver.c b/drivers/media/video/ivtv/ivtv-driver.c new file mode 100644 index 000000000000..45b9328a538f --- /dev/null +++ b/drivers/media/video/ivtv/ivtv-driver.c | |||
@@ -0,0 +1,1374 @@ | |||
1 | /* | ||
2 | ivtv driver initialization and card probing | ||
3 | Copyright (C) 2003-2004 Kevin Thayer <nufan_wfk at yahoo.com> | ||
4 | Copyright (C) 2004 Chris Kennedy <c@groovy.org> | ||
5 | Copyright (C) 2005-2007 Hans Verkuil <hverkuil@xs4all.nl> | ||
6 | |||
7 | This program is free software; you can redistribute it and/or modify | ||
8 | it under the terms of the GNU General Public License as published by | ||
9 | the Free Software Foundation; either version 2 of the License, or | ||
10 | (at your option) any later version. | ||
11 | |||
12 | This program is distributed in the hope that it will be useful, | ||
13 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
15 | GNU General Public License for more details. | ||
16 | |||
17 | You should have received a copy of the GNU General Public License | ||
18 | along with this program; if not, write to the Free Software | ||
19 | Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
20 | */ | ||
21 | |||
22 | /* Main Driver file for the ivtv project: | ||
23 | * Driver for the Conexant CX23415/CX23416 chip. | ||
24 | * Author: Kevin Thayer (nufan_wfk at yahoo.com) | ||
25 | * License: GPL | ||
26 | * http://www.ivtvdriver.org | ||
27 | * | ||
28 | * ----- | ||
29 | * MPG600/MPG160 support by T.Adachi <tadachi@tadachi-net.com> | ||
30 | * and Takeru KOMORIYA<komoriya@paken.org> | ||
31 | * | ||
32 | * AVerMedia M179 GPIO info by Chris Pinkham <cpinkham@bc2va.org> | ||
33 | * using information provided by Jiun-Kuei Jung @ AVerMedia. | ||
34 | * | ||
35 | * Kurouto Sikou CX23416GYC-STVLP tested by K.Ohta <alpha292@bremen.or.jp> | ||
36 | * using information from T.Adachi,Takeru KOMORIYA and others :-) | ||
37 | * | ||
38 | * Nagase TRANSGEAR 5000TV, Aopen VA2000MAX-STN6 and I/O data GV-MVP/RX | ||
39 | * version by T.Adachi. Special thanks Mr.Suzuki | ||
40 | */ | ||
41 | |||
42 | #include "ivtv-driver.h" | ||
43 | #include "ivtv-version.h" | ||
44 | #include "ivtv-fileops.h" | ||
45 | #include "ivtv-i2c.h" | ||
46 | #include "ivtv-firmware.h" | ||
47 | #include "ivtv-queue.h" | ||
48 | #include "ivtv-udma.h" | ||
49 | #include "ivtv-irq.h" | ||
50 | #include "ivtv-mailbox.h" | ||
51 | #include "ivtv-streams.h" | ||
52 | #include "ivtv-ioctl.h" | ||
53 | #include "ivtv-cards.h" | ||
54 | #include "ivtv-vbi.h" | ||
55 | #include "ivtv-audio.h" | ||
56 | #include "ivtv-gpio.h" | ||
57 | #include "ivtv-yuv.h" | ||
58 | |||
59 | #include <linux/vermagic.h> | ||
60 | #include <media/tveeprom.h> | ||
61 | #include <media/v4l2-chip-ident.h> | ||
62 | |||
63 | /* var to keep track of the number of array elements in use */ | ||
64 | int ivtv_cards_active = 0; | ||
65 | |||
66 | /* If you have already X v4l cards, then set this to X. This way | ||
67 | the device numbers stay matched. Example: you have a WinTV card | ||
68 | without radio and a PVR-350 with. Normally this would give a | ||
69 | video1 device together with a radio0 device for the PVR. By | ||
70 | setting this to 1 you ensure that radio0 is now also radio1. */ | ||
71 | int ivtv_first_minor = 0; | ||
72 | |||
73 | /* Master variable for all ivtv info */ | ||
74 | struct ivtv *ivtv_cards[IVTV_MAX_CARDS]; | ||
75 | |||
76 | /* Protects ivtv_cards_active */ | ||
77 | spinlock_t ivtv_cards_lock = SPIN_LOCK_UNLOCKED; | ||
78 | |||
79 | /* add your revision and whatnot here */ | ||
80 | static struct pci_device_id ivtv_pci_tbl[] __devinitdata = { | ||
81 | {PCI_VENDOR_ID_ICOMP, PCI_DEVICE_ID_IVTV15, | ||
82 | PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, | ||
83 | {PCI_VENDOR_ID_ICOMP, PCI_DEVICE_ID_IVTV16, | ||
84 | PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, | ||
85 | {0,} | ||
86 | }; | ||
87 | |||
88 | MODULE_DEVICE_TABLE(pci,ivtv_pci_tbl); | ||
89 | |||
90 | const u32 yuv_offset[4] = { | ||
91 | IVTV_YUV_BUFFER_OFFSET, | ||
92 | IVTV_YUV_BUFFER_OFFSET_1, | ||
93 | IVTV_YUV_BUFFER_OFFSET_2, | ||
94 | IVTV_YUV_BUFFER_OFFSET_3 | ||
95 | }; | ||
96 | |||
97 | /* Parameter declarations */ | ||
98 | static int cardtype[IVTV_MAX_CARDS]; | ||
99 | static int tuner[IVTV_MAX_CARDS] = { -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }; | ||
100 | static int radio[IVTV_MAX_CARDS] = { -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }; | ||
101 | |||
102 | static int cardtype_c = 1; | ||
103 | static int tuner_c = 1; | ||
104 | static int radio_c = 1; | ||
105 | static char pal[] = "--"; | ||
106 | static char secam[] = "--"; | ||
107 | static char ntsc[] = "-"; | ||
108 | |||
109 | /* Buffers */ | ||
110 | static int enc_mpg_buffers = IVTV_DEFAULT_ENC_MPG_BUFFERS; | ||
111 | static int enc_yuv_buffers = IVTV_DEFAULT_ENC_YUV_BUFFERS; | ||
112 | static int enc_vbi_buffers = IVTV_DEFAULT_ENC_VBI_BUFFERS; | ||
113 | static int enc_pcm_buffers = IVTV_DEFAULT_ENC_PCM_BUFFERS; | ||
114 | static int dec_mpg_buffers = IVTV_DEFAULT_DEC_MPG_BUFFERS; | ||
115 | static int dec_yuv_buffers = IVTV_DEFAULT_DEC_YUV_BUFFERS; | ||
116 | static int dec_vbi_buffers = IVTV_DEFAULT_DEC_VBI_BUFFERS; | ||
117 | |||
118 | static int ivtv_yuv_mode = 0; | ||
119 | static int ivtv_yuv_threshold=-1; | ||
120 | static int ivtv_pci_latency = 1; | ||
121 | |||
122 | int ivtv_debug = 0; | ||
123 | |||
124 | static int newi2c = -1; | ||
125 | |||
126 | module_param_array(tuner, int, &tuner_c, 0644); | ||
127 | module_param_array(radio, bool, &radio_c, 0644); | ||
128 | module_param_array(cardtype, int, &cardtype_c, 0644); | ||
129 | module_param_string(pal, pal, sizeof(pal), 0644); | ||
130 | module_param_string(secam, secam, sizeof(secam), 0644); | ||
131 | module_param_string(ntsc, ntsc, sizeof(ntsc), 0644); | ||
132 | module_param_named(debug,ivtv_debug, int, 0644); | ||
133 | module_param(ivtv_pci_latency, int, 0644); | ||
134 | module_param(ivtv_yuv_mode, int, 0644); | ||
135 | module_param(ivtv_yuv_threshold, int, 0644); | ||
136 | module_param(ivtv_first_minor, int, 0644); | ||
137 | |||
138 | module_param(enc_mpg_buffers, int, 0644); | ||
139 | module_param(enc_yuv_buffers, int, 0644); | ||
140 | module_param(enc_vbi_buffers, int, 0644); | ||
141 | module_param(enc_pcm_buffers, int, 0644); | ||
142 | module_param(dec_mpg_buffers, int, 0644); | ||
143 | module_param(dec_yuv_buffers, int, 0644); | ||
144 | module_param(dec_vbi_buffers, int, 0644); | ||
145 | |||
146 | module_param(newi2c, int, 0644); | ||
147 | |||
148 | MODULE_PARM_DESC(tuner, "Tuner type selection,\n" | ||
149 | "\t\t\tsee tuner.h for values"); | ||
150 | MODULE_PARM_DESC(radio, | ||
151 | "Enable or disable the radio. Use only if autodetection\n" | ||
152 | "\t\t\tfails. 0 = disable, 1 = enable"); | ||
153 | MODULE_PARM_DESC(cardtype, | ||
154 | "Only use this option if your card is not detected properly.\n" | ||
155 | "\t\tSpecify card type:\n" | ||
156 | "\t\t\t 1 = WinTV PVR 250\n" | ||
157 | "\t\t\t 2 = WinTV PVR 350\n" | ||
158 | "\t\t\t 3 = WinTV PVR-150 or PVR-500\n" | ||
159 | "\t\t\t 4 = AVerMedia M179\n" | ||
160 | "\t\t\t 5 = YUAN MPG600/Kuroutoshikou iTVC16-STVLP\n" | ||
161 | "\t\t\t 6 = YUAN MPG160/Kuroutoshikou iTVC15-STVLP\n" | ||
162 | "\t\t\t 7 = YUAN PG600/DIAMONDMM PVR-550 (CX Falcon 2)\n" | ||
163 | "\t\t\t 8 = Adaptec AVC-2410\n" | ||
164 | "\t\t\t 9 = Adaptec AVC-2010\n" | ||
165 | "\t\t\t10 = NAGASE TRANSGEAR 5000TV\n" | ||
166 | "\t\t\t11 = AOpen VA2000MAX-STN6\n" | ||
167 | "\t\t\t12 = YUAN MPG600GR/Kuroutoshikou CX23416GYC-STVLP\n" | ||
168 | "\t\t\t13 = I/O Data GV-MVP/RX\n" | ||
169 | "\t\t\t14 = I/O Data GV-MVP/RX2E\n" | ||
170 | "\t\t\t15 = GOTVIEW PCI DVD\n" | ||
171 | "\t\t\t16 = GOTVIEW PCI DVD2 Deluxe\n" | ||
172 | "\t\t\t17 = Yuan MPC622\n" | ||
173 | "\t\t\t18 = Digital Cowboy DCT-MTVP1\n" | ||
174 | #ifdef HAVE_XC3028 | ||
175 | "\t\t\t19 = Yuan PG600V2/GotView PCI DVD Lite/Club3D ZAP-TV1x01\n" | ||
176 | #endif | ||
177 | "\t\t\t 0 = Autodetect (default)\n" | ||
178 | "\t\t\t-1 = Ignore this card\n\t\t"); | ||
179 | MODULE_PARM_DESC(pal, "Set PAL standard: B, G, H, D, K, I, M, N, Nc, 60"); | ||
180 | MODULE_PARM_DESC(secam, "Set SECAM standard: B, G, H, D, K, L, LC"); | ||
181 | MODULE_PARM_DESC(ntsc, "Set NTSC standard: M, J, K"); | ||
182 | MODULE_PARM_DESC(debug, | ||
183 | "Debug level (bitmask). Default: errors only\n" | ||
184 | "\t\t\t(debug = 511 gives full debugging)"); | ||
185 | MODULE_PARM_DESC(ivtv_pci_latency, | ||
186 | "Change the PCI latency to 64 if lower: 0 = No, 1 = Yes,\n" | ||
187 | "\t\t\tDefault: Yes"); | ||
188 | MODULE_PARM_DESC(ivtv_yuv_mode, | ||
189 | "Specify the yuv playback mode:\n" | ||
190 | "\t\t\t0 = interlaced\n\t\t\t1 = progressive\n\t\t\t2 = auto\n" | ||
191 | "\t\t\tDefault: 0 (interlaced)"); | ||
192 | MODULE_PARM_DESC(ivtv_yuv_threshold, | ||
193 | "If ivtv_yuv_mode is 2 (auto) then playback content as\n\t\tprogressive if src height <= ivtv_yuvthreshold\n" | ||
194 | "\t\t\tDefault: 480");; | ||
195 | MODULE_PARM_DESC(enc_mpg_buffers, | ||
196 | "Encoder MPG Buffers (in MB)\n" | ||
197 | "\t\t\tDefault: " __stringify(IVTV_DEFAULT_ENC_MPG_BUFFERS)); | ||
198 | MODULE_PARM_DESC(enc_yuv_buffers, | ||
199 | "Encoder YUV Buffers (in MB)\n" | ||
200 | "\t\t\tDefault: " __stringify(IVTV_DEFAULT_ENC_YUV_BUFFERS)); | ||
201 | MODULE_PARM_DESC(enc_vbi_buffers, | ||
202 | "Encoder VBI Buffers (in MB)\n" | ||
203 | "\t\t\tDefault: " __stringify(IVTV_DEFAULT_ENC_VBI_BUFFERS)); | ||
204 | MODULE_PARM_DESC(enc_pcm_buffers, | ||
205 | "Encoder PCM buffers (in MB)\n" | ||
206 | "\t\t\tDefault: " __stringify(IVTV_DEFAULT_ENC_PCM_BUFFERS)); | ||
207 | MODULE_PARM_DESC(dec_mpg_buffers, | ||
208 | "Decoder MPG buffers (in MB)\n" | ||
209 | "\t\t\tDefault: " __stringify(IVTV_DEFAULT_DEC_MPG_BUFFERS)); | ||
210 | MODULE_PARM_DESC(dec_yuv_buffers, | ||
211 | "Decoder YUV buffers (in MB)\n" | ||
212 | "\t\t\tDefault: " __stringify(IVTV_DEFAULT_DEC_YUV_BUFFERS)); | ||
213 | MODULE_PARM_DESC(dec_vbi_buffers, | ||
214 | "Decoder VBI buffers (in MB)\n" | ||
215 | "\t\t\tDefault: " __stringify(IVTV_DEFAULT_DEC_VBI_BUFFERS)); | ||
216 | MODULE_PARM_DESC(newi2c, | ||
217 | "Use new I2C implementation\n" | ||
218 | "\t\t\t-1 is autodetect, 0 is off, 1 is on\n" | ||
219 | "\t\t\tDefault is autodetect"); | ||
220 | |||
221 | MODULE_PARM_DESC(ivtv_first_minor, "Set minor assigned to first card"); | ||
222 | |||
223 | MODULE_AUTHOR("Kevin Thayer, Chris Kennedy, Hans Verkuil"); | ||
224 | MODULE_DESCRIPTION("CX23415/CX23416 driver"); | ||
225 | MODULE_SUPPORTED_DEVICE | ||
226 | ("CX23415/CX23416 MPEG2 encoder (WinTV PVR-150/250/350/500,\n" | ||
227 | "\t\t\tYuan MPG series and similar)"); | ||
228 | MODULE_LICENSE("GPL"); | ||
229 | |||
230 | MODULE_VERSION(IVTV_VERSION); | ||
231 | |||
232 | void ivtv_clear_irq_mask(struct ivtv *itv, u32 mask) | ||
233 | { | ||
234 | itv->irqmask &= ~mask; | ||
235 | write_reg_sync(itv->irqmask, IVTV_REG_IRQMASK); | ||
236 | } | ||
237 | |||
238 | void ivtv_set_irq_mask(struct ivtv *itv, u32 mask) | ||
239 | { | ||
240 | itv->irqmask |= mask; | ||
241 | write_reg_sync(itv->irqmask, IVTV_REG_IRQMASK); | ||
242 | } | ||
243 | |||
244 | int ivtv_set_output_mode(struct ivtv *itv, int mode) | ||
245 | { | ||
246 | int old_mode; | ||
247 | |||
248 | spin_lock(&itv->lock); | ||
249 | old_mode = itv->output_mode; | ||
250 | if (old_mode == 0) | ||
251 | itv->output_mode = old_mode = mode; | ||
252 | spin_unlock(&itv->lock); | ||
253 | return old_mode; | ||
254 | } | ||
255 | |||
256 | struct ivtv_stream *ivtv_get_output_stream(struct ivtv *itv) | ||
257 | { | ||
258 | switch (itv->output_mode) { | ||
259 | case OUT_MPG: | ||
260 | return &itv->streams[IVTV_DEC_STREAM_TYPE_MPG]; | ||
261 | case OUT_YUV: | ||
262 | return &itv->streams[IVTV_DEC_STREAM_TYPE_YUV]; | ||
263 | default: | ||
264 | return NULL; | ||
265 | } | ||
266 | } | ||
267 | |||
268 | int ivtv_waitq(wait_queue_head_t *waitq) | ||
269 | { | ||
270 | DEFINE_WAIT(wait); | ||
271 | |||
272 | prepare_to_wait(waitq, &wait, TASK_INTERRUPTIBLE); | ||
273 | schedule(); | ||
274 | finish_wait(waitq, &wait); | ||
275 | return signal_pending(current) ? -EINTR : 0; | ||
276 | } | ||
277 | |||
278 | /* Generic utility functions */ | ||
279 | int ivtv_sleep_timeout(int timeout, int intr) | ||
280 | { | ||
281 | int ret; | ||
282 | |||
283 | do { | ||
284 | set_current_state(intr ? TASK_INTERRUPTIBLE : TASK_UNINTERRUPTIBLE); | ||
285 | timeout = schedule_timeout(timeout); | ||
286 | if (intr && (ret = signal_pending(current))) | ||
287 | return ret; | ||
288 | } while (timeout); | ||
289 | return 0; | ||
290 | } | ||
291 | |||
292 | /* Release ioremapped memory */ | ||
293 | static void ivtv_iounmap(struct ivtv *itv) | ||
294 | { | ||
295 | if (itv == NULL) | ||
296 | return; | ||
297 | |||
298 | /* Release registers memory */ | ||
299 | if (itv->reg_mem != NULL) { | ||
300 | IVTV_DEBUG_INFO("releasing reg_mem\n"); | ||
301 | iounmap(itv->reg_mem); | ||
302 | itv->reg_mem = NULL; | ||
303 | } | ||
304 | /* Release io memory */ | ||
305 | if (itv->has_cx23415 && itv->dec_mem != NULL) { | ||
306 | IVTV_DEBUG_INFO("releasing dec_mem\n"); | ||
307 | iounmap(itv->dec_mem); | ||
308 | } | ||
309 | itv->dec_mem = NULL; | ||
310 | |||
311 | /* Release io memory */ | ||
312 | if (itv->enc_mem != NULL) { | ||
313 | IVTV_DEBUG_INFO("releasing enc_mem\n"); | ||
314 | iounmap(itv->enc_mem); | ||
315 | itv->enc_mem = NULL; | ||
316 | } | ||
317 | } | ||
318 | |||
319 | /* Hauppauge card? get values from tveeprom */ | ||
320 | void ivtv_read_eeprom(struct ivtv *itv, struct tveeprom *tv) | ||
321 | { | ||
322 | u8 eedata[256]; | ||
323 | |||
324 | itv->i2c_client.addr = 0xA0 >> 1; | ||
325 | tveeprom_read(&itv->i2c_client, eedata, sizeof(eedata)); | ||
326 | tveeprom_hauppauge_analog(&itv->i2c_client, tv, eedata); | ||
327 | } | ||
328 | |||
329 | static void ivtv_process_eeprom(struct ivtv *itv) | ||
330 | { | ||
331 | struct tveeprom tv; | ||
332 | int pci_slot = PCI_SLOT(itv->dev->devfn); | ||
333 | |||
334 | ivtv_read_eeprom(itv, &tv); | ||
335 | |||
336 | /* Many thanks to Steven Toth from Hauppauge for providing the | ||
337 | model numbers */ | ||
338 | switch (tv.model) { | ||
339 | /* In a few cases the PCI subsystem IDs do not correctly | ||
340 | identify the card. A better method is to check the | ||
341 | model number from the eeprom instead. */ | ||
342 | case 32000 ... 32999: | ||
343 | case 48000 ... 48099: /* 48??? range are PVR250s with a cx23415 */ | ||
344 | case 48400 ... 48599: | ||
345 | itv->card = ivtv_get_card(IVTV_CARD_PVR_250); | ||
346 | break; | ||
347 | case 48100 ... 48399: | ||
348 | case 48600 ... 48999: | ||
349 | itv->card = ivtv_get_card(IVTV_CARD_PVR_350); | ||
350 | break; | ||
351 | case 23000 ... 23999: /* PVR500 */ | ||
352 | case 25000 ... 25999: /* Low profile PVR150 */ | ||
353 | case 26000 ... 26999: /* Regular PVR150 */ | ||
354 | itv->card = ivtv_get_card(IVTV_CARD_PVR_150); | ||
355 | break; | ||
356 | case 0: | ||
357 | IVTV_ERR("Invalid EEPROM\n"); | ||
358 | return; | ||
359 | default: | ||
360 | IVTV_ERR("Unknown model %d, defaulting to PVR-150\n", tv.model); | ||
361 | itv->card = ivtv_get_card(IVTV_CARD_PVR_150); | ||
362 | break; | ||
363 | } | ||
364 | |||
365 | switch (tv.model) { | ||
366 | /* Old style PVR350 (with an saa7114) uses this input for | ||
367 | the tuner. */ | ||
368 | case 48254: | ||
369 | itv->card = ivtv_get_card(IVTV_CARD_PVR_350_V1); | ||
370 | break; | ||
371 | default: | ||
372 | break; | ||
373 | } | ||
374 | |||
375 | itv->v4l2_cap = itv->card->v4l2_capabilities; | ||
376 | itv->card_name = itv->card->name; | ||
377 | |||
378 | /* If this is a PVR500 then it should be possible to detect whether it is the | ||
379 | first or second unit by looking at the subsystem device ID: is bit 4 is | ||
380 | set, then it is the second unit (according to info from Hauppauge). | ||
381 | |||
382 | However, while this works for most cards, I have seen a few PVR500 cards | ||
383 | where both units have the same subsystem ID. | ||
384 | |||
385 | So instead I look at the reported 'PCI slot' (which is the slot on the PVR500 | ||
386 | PCI bridge) and if it is 8, then it is assumed to be the first unit, otherwise | ||
387 | it is the second unit. It is possible that it is a different slot when ivtv is | ||
388 | used in Xen, in that case I ignore this card here. The worst that can happen | ||
389 | is that the card presents itself with a non-working radio device. | ||
390 | |||
391 | This detection is needed since the eeprom reports incorrectly that a radio is | ||
392 | present on the second unit. */ | ||
393 | if (tv.model / 1000 == 23) { | ||
394 | itv->card_name = "WinTV PVR 500"; | ||
395 | if (pci_slot == 8 || pci_slot == 9) { | ||
396 | int is_first = (pci_slot & 1) == 0; | ||
397 | |||
398 | itv->card_name = is_first ? "WinTV PVR 500 (unit #1)" : | ||
399 | "WinTV PVR 500 (unit #2)"; | ||
400 | if (!is_first) { | ||
401 | IVTV_INFO("Correcting tveeprom data: no radio present on second unit\n"); | ||
402 | tv.has_radio = 0; | ||
403 | } | ||
404 | } | ||
405 | } | ||
406 | IVTV_INFO("Autodetected %s\n", itv->card_name); | ||
407 | |||
408 | switch (tv.tuner_hauppauge_model) { | ||
409 | case 85: | ||
410 | case 99: | ||
411 | case 112: | ||
412 | itv->pvr150_workaround = 1; | ||
413 | break; | ||
414 | default: | ||
415 | break; | ||
416 | } | ||
417 | if (tv.tuner_type == TUNER_ABSENT) | ||
418 | IVTV_ERR("tveeprom cannot autodetect tuner!"); | ||
419 | |||
420 | if (itv->options.tuner == -1) | ||
421 | itv->options.tuner = tv.tuner_type; | ||
422 | if (itv->options.radio == -1) | ||
423 | itv->options.radio = (tv.has_radio != 0); | ||
424 | /* only enable newi2c if an IR blaster is present */ | ||
425 | /* FIXME: for 2.6.20 the test against 2 should be removed */ | ||
426 | if (itv->options.newi2c == -1 && tv.has_ir != -1 && tv.has_ir != 2) { | ||
427 | itv->options.newi2c = (tv.has_ir & 2) ? 1 : 0; | ||
428 | if (itv->options.newi2c) { | ||
429 | IVTV_INFO("reopen i2c bus for IR-blaster support\n"); | ||
430 | exit_ivtv_i2c(itv); | ||
431 | init_ivtv_i2c(itv); | ||
432 | } | ||
433 | } | ||
434 | |||
435 | if (itv->std != 0) | ||
436 | /* user specified tuner standard */ | ||
437 | return; | ||
438 | |||
439 | /* autodetect tuner standard */ | ||
440 | if (tv.tuner_formats & V4L2_STD_PAL) { | ||
441 | IVTV_DEBUG_INFO("PAL tuner detected\n"); | ||
442 | itv->std |= V4L2_STD_PAL_BG | V4L2_STD_PAL_H; | ||
443 | } else if (tv.tuner_formats & V4L2_STD_NTSC) { | ||
444 | IVTV_DEBUG_INFO("NTSC tuner detected\n"); | ||
445 | itv->std |= V4L2_STD_NTSC_M; | ||
446 | } else if (tv.tuner_formats & V4L2_STD_SECAM) { | ||
447 | IVTV_DEBUG_INFO("SECAM tuner detected\n"); | ||
448 | itv->std |= V4L2_STD_SECAM_L; | ||
449 | } else { | ||
450 | IVTV_INFO("No tuner detected, default to NTSC-M\n"); | ||
451 | itv->std |= V4L2_STD_NTSC_M; | ||
452 | } | ||
453 | } | ||
454 | |||
455 | static v4l2_std_id ivtv_parse_std(struct ivtv *itv) | ||
456 | { | ||
457 | switch (pal[0]) { | ||
458 | case '6': | ||
459 | return V4L2_STD_PAL_60; | ||
460 | case 'b': | ||
461 | case 'B': | ||
462 | case 'g': | ||
463 | case 'G': | ||
464 | return V4L2_STD_PAL_BG; | ||
465 | case 'h': | ||
466 | case 'H': | ||
467 | return V4L2_STD_PAL_H; | ||
468 | case 'n': | ||
469 | case 'N': | ||
470 | if (pal[1] == 'c' || pal[1] == 'C') | ||
471 | return V4L2_STD_PAL_Nc; | ||
472 | return V4L2_STD_PAL_N; | ||
473 | case 'i': | ||
474 | case 'I': | ||
475 | return V4L2_STD_PAL_I; | ||
476 | case 'd': | ||
477 | case 'D': | ||
478 | case 'k': | ||
479 | case 'K': | ||
480 | return V4L2_STD_PAL_DK; | ||
481 | case 'M': | ||
482 | case 'm': | ||
483 | return V4L2_STD_PAL_M; | ||
484 | case '-': | ||
485 | break; | ||
486 | default: | ||
487 | IVTV_WARN("pal= argument not recognised\n"); | ||
488 | return 0; | ||
489 | } | ||
490 | |||
491 | switch (secam[0]) { | ||
492 | case 'b': | ||
493 | case 'B': | ||
494 | case 'g': | ||
495 | case 'G': | ||
496 | case 'h': | ||
497 | case 'H': | ||
498 | return V4L2_STD_SECAM_B | V4L2_STD_SECAM_G | V4L2_STD_SECAM_H; | ||
499 | case 'd': | ||
500 | case 'D': | ||
501 | case 'k': | ||
502 | case 'K': | ||
503 | return V4L2_STD_SECAM_DK; | ||
504 | case 'l': | ||
505 | case 'L': | ||
506 | if (secam[1] == 'C' || secam[1] == 'c') | ||
507 | return V4L2_STD_SECAM_LC; | ||
508 | return V4L2_STD_SECAM_L; | ||
509 | case '-': | ||
510 | break; | ||
511 | default: | ||
512 | IVTV_WARN("secam= argument not recognised\n"); | ||
513 | return 0; | ||
514 | } | ||
515 | |||
516 | switch (ntsc[0]) { | ||
517 | case 'm': | ||
518 | case 'M': | ||
519 | return V4L2_STD_NTSC_M; | ||
520 | case 'j': | ||
521 | case 'J': | ||
522 | return V4L2_STD_NTSC_M_JP; | ||
523 | case 'k': | ||
524 | case 'K': | ||
525 | return V4L2_STD_NTSC_M_KR; | ||
526 | case '-': | ||
527 | break; | ||
528 | default: | ||
529 | IVTV_WARN("ntsc= argument not recognised\n"); | ||
530 | return 0; | ||
531 | } | ||
532 | |||
533 | /* no match found */ | ||
534 | return 0; | ||
535 | } | ||
536 | |||
537 | static void ivtv_process_options(struct ivtv *itv) | ||
538 | { | ||
539 | const char *chipname; | ||
540 | int i, j; | ||
541 | |||
542 | itv->options.megabytes[IVTV_ENC_STREAM_TYPE_MPG] = enc_mpg_buffers; | ||
543 | itv->options.megabytes[IVTV_ENC_STREAM_TYPE_YUV] = enc_yuv_buffers; | ||
544 | itv->options.megabytes[IVTV_ENC_STREAM_TYPE_VBI] = enc_vbi_buffers; | ||
545 | itv->options.megabytes[IVTV_ENC_STREAM_TYPE_PCM] = enc_pcm_buffers; | ||
546 | itv->options.megabytes[IVTV_DEC_STREAM_TYPE_MPG] = dec_mpg_buffers; | ||
547 | itv->options.megabytes[IVTV_DEC_STREAM_TYPE_YUV] = dec_yuv_buffers; | ||
548 | itv->options.megabytes[IVTV_DEC_STREAM_TYPE_VBI] = dec_vbi_buffers; | ||
549 | itv->options.cardtype = cardtype[itv->num]; | ||
550 | itv->options.tuner = tuner[itv->num]; | ||
551 | itv->options.radio = radio[itv->num]; | ||
552 | itv->options.newi2c = newi2c; | ||
553 | |||
554 | itv->std = ivtv_parse_std(itv); | ||
555 | itv->has_cx23415 = (itv->dev->device == PCI_DEVICE_ID_IVTV15); | ||
556 | chipname = itv->has_cx23415 ? "cx23415" : "cx23416"; | ||
557 | if (itv->options.cardtype == -1) { | ||
558 | IVTV_INFO("Ignore card (detected %s based chip)\n", chipname); | ||
559 | return; | ||
560 | } | ||
561 | if ((itv->card = ivtv_get_card(itv->options.cardtype - 1))) { | ||
562 | IVTV_INFO("User specified %s card (detected %s based chip)\n", | ||
563 | itv->card->name, chipname); | ||
564 | } else if (itv->options.cardtype != 0) { | ||
565 | IVTV_ERR("Unknown user specified type, trying to autodetect card\n"); | ||
566 | } | ||
567 | if (itv->card == NULL) { | ||
568 | if (itv->dev->subsystem_vendor == IVTV_PCI_ID_HAUPPAUGE || | ||
569 | itv->dev->subsystem_vendor == IVTV_PCI_ID_HAUPPAUGE_ALT1 || | ||
570 | itv->dev->subsystem_vendor == IVTV_PCI_ID_HAUPPAUGE_ALT2) { | ||
571 | itv->card = ivtv_get_card(itv->has_cx23415 ? IVTV_CARD_PVR_350 : IVTV_CARD_PVR_150); | ||
572 | IVTV_INFO("Autodetected Hauppauge card (%s based)\n", | ||
573 | chipname); | ||
574 | } | ||
575 | } | ||
576 | if (itv->card == NULL) { | ||
577 | for (i = 0; (itv->card = ivtv_get_card(i)); i++) { | ||
578 | if (itv->card->pci_list == NULL) | ||
579 | continue; | ||
580 | for (j = 0; itv->card->pci_list[j].device; j++) { | ||
581 | if (itv->dev->device != | ||
582 | itv->card->pci_list[j].device) | ||
583 | continue; | ||
584 | if (itv->dev->subsystem_vendor != | ||
585 | itv->card->pci_list[j].subsystem_vendor) | ||
586 | continue; | ||
587 | if (itv->dev->subsystem_device != | ||
588 | itv->card->pci_list[j].subsystem_device) | ||
589 | continue; | ||
590 | IVTV_INFO("Autodetected %s card (%s based)\n", | ||
591 | itv->card->name, chipname); | ||
592 | goto done; | ||
593 | } | ||
594 | } | ||
595 | } | ||
596 | done: | ||
597 | |||
598 | if (itv->card == NULL) { | ||
599 | itv->card = ivtv_get_card(IVTV_CARD_PVR_150); | ||
600 | IVTV_ERR("Unknown card: vendor/device: %04x/%04x\n", | ||
601 | itv->dev->vendor, itv->dev->device); | ||
602 | IVTV_ERR(" subsystem vendor/device: %04x/%04x\n", | ||
603 | itv->dev->subsystem_vendor, itv->dev->subsystem_device); | ||
604 | IVTV_ERR(" %s based\n", chipname); | ||
605 | IVTV_ERR("Defaulting to %s card\n", itv->card->name); | ||
606 | IVTV_ERR("Please mail the vendor/device and subsystem vendor/device IDs and what kind of\n"); | ||
607 | IVTV_ERR("card you have to the ivtv-devel mailinglist (www.ivtvdriver.org)\n"); | ||
608 | IVTV_ERR("Prefix your subject line with [UNKNOWN CARD].\n"); | ||
609 | } | ||
610 | itv->v4l2_cap = itv->card->v4l2_capabilities; | ||
611 | itv->card_name = itv->card->name; | ||
612 | } | ||
613 | |||
614 | /* Precondition: the ivtv structure has been memset to 0. Only | ||
615 | the dev and num fields have been filled in. | ||
616 | No assumptions on the card type may be made here (see ivtv_init_struct2 | ||
617 | for that). | ||
618 | */ | ||
619 | static int __devinit ivtv_init_struct1(struct ivtv *itv) | ||
620 | { | ||
621 | itv->base_addr = pci_resource_start(itv->dev, 0); | ||
622 | itv->enc_mbox.max_mbox = 2; /* the encoder has 3 mailboxes (0-2) */ | ||
623 | itv->dec_mbox.max_mbox = 1; /* the decoder has 2 mailboxes (0-1) */ | ||
624 | |||
625 | mutex_init(&itv->i2c_bus_lock); | ||
626 | mutex_init(&itv->udma.lock); | ||
627 | |||
628 | spin_lock_init(&itv->lock); | ||
629 | spin_lock_init(&itv->dma_reg_lock); | ||
630 | |||
631 | itv->irq_work_queues = create_workqueue(itv->name); | ||
632 | if (itv->irq_work_queues == NULL) { | ||
633 | IVTV_ERR("Could not create ivtv workqueue\n"); | ||
634 | return -1; | ||
635 | } | ||
636 | |||
637 | INIT_WORK(&itv->irq_work_queue, ivtv_irq_work_handler); | ||
638 | |||
639 | /* start counting open_id at 1 */ | ||
640 | itv->open_id = 1; | ||
641 | |||
642 | /* Initial settings */ | ||
643 | cx2341x_fill_defaults(&itv->params); | ||
644 | itv->params.port = CX2341X_PORT_MEMORY; | ||
645 | itv->params.capabilities = CX2341X_CAP_HAS_SLICED_VBI; | ||
646 | init_waitqueue_head(&itv->cap_w); | ||
647 | init_waitqueue_head(&itv->event_waitq); | ||
648 | init_waitqueue_head(&itv->vsync_waitq); | ||
649 | init_waitqueue_head(&itv->dma_waitq); | ||
650 | init_timer(&itv->dma_timer); | ||
651 | itv->dma_timer.function = ivtv_unfinished_dma; | ||
652 | itv->dma_timer.data = (unsigned long)itv; | ||
653 | |||
654 | itv->cur_dma_stream = -1; | ||
655 | itv->audio_stereo_mode = AUDIO_STEREO; | ||
656 | itv->audio_bilingual_mode = AUDIO_MONO_LEFT; | ||
657 | |||
658 | /* Ctrls */ | ||
659 | itv->speed = 1000; | ||
660 | |||
661 | /* VBI */ | ||
662 | itv->vbi.in.type = V4L2_BUF_TYPE_SLICED_VBI_CAPTURE; | ||
663 | itv->vbi.sliced_in = &itv->vbi.in.fmt.sliced; | ||
664 | |||
665 | /* OSD */ | ||
666 | itv->osd_global_alpha_state = 1; | ||
667 | itv->osd_global_alpha = 255; | ||
668 | |||
669 | /* YUV */ | ||
670 | atomic_set(&itv->yuv_info.next_dma_frame, -1); | ||
671 | itv->yuv_info.lace_mode = ivtv_yuv_mode; | ||
672 | itv->yuv_info.lace_threshold = ivtv_yuv_threshold; | ||
673 | return 0; | ||
674 | } | ||
675 | |||
676 | /* Second initialization part. Here the card type has been | ||
677 | autodetected. */ | ||
678 | static void __devinit ivtv_init_struct2(struct ivtv *itv) | ||
679 | { | ||
680 | int i; | ||
681 | |||
682 | for (i = 0; i < IVTV_CARD_MAX_VIDEO_INPUTS; i++) | ||
683 | if (itv->card->video_inputs[i].video_type == 0) | ||
684 | break; | ||
685 | itv->nof_inputs = i; | ||
686 | for (i = 0; i < IVTV_CARD_MAX_AUDIO_INPUTS; i++) | ||
687 | if (itv->card->audio_inputs[i].audio_type == 0) | ||
688 | break; | ||
689 | itv->nof_audio_inputs = i; | ||
690 | |||
691 | /* 0x00EF = saa7114(239) 0x00F0 = saa7115(240) 0x0106 = micro */ | ||
692 | if (itv->card->hw_all & (IVTV_HW_SAA7115 | IVTV_HW_SAA717X)) | ||
693 | itv->digitizer = 0xF1; | ||
694 | else if (itv->card->hw_all & IVTV_HW_SAA7114) | ||
695 | itv->digitizer = 0xEF; | ||
696 | else /* cx25840 */ | ||
697 | itv->digitizer = 0x140; | ||
698 | |||
699 | if (itv->card->hw_all & IVTV_HW_CX25840) { | ||
700 | itv->vbi.sliced_size = 288; /* multiple of 16, real size = 284 */ | ||
701 | } else { | ||
702 | itv->vbi.sliced_size = 64; /* multiple of 16, real size = 52 */ | ||
703 | } | ||
704 | |||
705 | /* Find tuner input */ | ||
706 | for (i = 0; i < itv->nof_inputs; i++) { | ||
707 | if (itv->card->video_inputs[i].video_type == | ||
708 | IVTV_CARD_INPUT_VID_TUNER) | ||
709 | break; | ||
710 | } | ||
711 | if (i == itv->nof_inputs) | ||
712 | i = 0; | ||
713 | itv->active_input = i; | ||
714 | itv->audio_input = itv->card->video_inputs[i].audio_index; | ||
715 | if (itv->card->hw_all & IVTV_HW_CX25840) | ||
716 | itv->video_dec_func = ivtv_cx25840; | ||
717 | else if (itv->card->hw_all & IVTV_HW_SAA717X) | ||
718 | itv->video_dec_func = ivtv_saa717x; | ||
719 | else | ||
720 | itv->video_dec_func = ivtv_saa7115; | ||
721 | } | ||
722 | |||
723 | static int ivtv_setup_pci(struct ivtv *itv, struct pci_dev *dev, | ||
724 | const struct pci_device_id *pci_id) | ||
725 | { | ||
726 | u16 cmd; | ||
727 | unsigned char pci_latency; | ||
728 | |||
729 | IVTV_DEBUG_INFO("Enabling pci device\n"); | ||
730 | |||
731 | if (pci_enable_device(dev)) { | ||
732 | IVTV_ERR("Can't enable device %d!\n", itv->num); | ||
733 | return -EIO; | ||
734 | } | ||
735 | if (pci_set_dma_mask(dev, 0xffffffff)) { | ||
736 | IVTV_ERR("No suitable DMA available on card %d.\n", itv->num); | ||
737 | return -EIO; | ||
738 | } | ||
739 | if (!request_mem_region(itv->base_addr, IVTV_ENCODER_SIZE, "ivtv encoder")) { | ||
740 | IVTV_ERR("Cannot request encoder memory region on card %d.\n", itv->num); | ||
741 | return -EIO; | ||
742 | } | ||
743 | |||
744 | if (!request_mem_region(itv->base_addr + IVTV_REG_OFFSET, | ||
745 | IVTV_REG_SIZE, "ivtv registers")) { | ||
746 | IVTV_ERR("Cannot request register memory region on card %d.\n", itv->num); | ||
747 | release_mem_region(itv->base_addr, IVTV_ENCODER_SIZE); | ||
748 | return -EIO; | ||
749 | } | ||
750 | |||
751 | if (itv->has_cx23415 && | ||
752 | !request_mem_region(itv->base_addr + IVTV_DECODER_OFFSET, | ||
753 | IVTV_DECODER_SIZE, "ivtv decoder")) { | ||
754 | IVTV_ERR("Cannot request decoder memory region on card %d.\n", itv->num); | ||
755 | release_mem_region(itv->base_addr, IVTV_ENCODER_SIZE); | ||
756 | release_mem_region(itv->base_addr + IVTV_REG_OFFSET, IVTV_REG_SIZE); | ||
757 | return -EIO; | ||
758 | } | ||
759 | |||
760 | /* Check for bus mastering */ | ||
761 | pci_read_config_word(dev, PCI_COMMAND, &cmd); | ||
762 | if (!(cmd & PCI_COMMAND_MASTER)) { | ||
763 | IVTV_DEBUG_INFO("Attempting to enable Bus Mastering\n"); | ||
764 | pci_set_master(dev); | ||
765 | pci_read_config_word(dev, PCI_COMMAND, &cmd); | ||
766 | if (!(cmd & PCI_COMMAND_MASTER)) { | ||
767 | IVTV_ERR("Bus Mastering is not enabled\n"); | ||
768 | return -ENXIO; | ||
769 | } | ||
770 | } | ||
771 | IVTV_DEBUG_INFO("Bus Mastering Enabled.\n"); | ||
772 | |||
773 | pci_read_config_byte(dev, PCI_CLASS_REVISION, &itv->card_rev); | ||
774 | pci_read_config_byte(dev, PCI_LATENCY_TIMER, &pci_latency); | ||
775 | |||
776 | if (pci_latency < 64 && ivtv_pci_latency) { | ||
777 | IVTV_INFO("Unreasonably low latency timer, " | ||
778 | "setting to 64 (was %d)\n", pci_latency); | ||
779 | pci_write_config_byte(dev, PCI_LATENCY_TIMER, 64); | ||
780 | pci_read_config_byte(dev, PCI_LATENCY_TIMER, &pci_latency); | ||
781 | } | ||
782 | /* This config space value relates to DMA latencies. The | ||
783 | default value 0x8080 is too low however and will lead | ||
784 | to DMA errors. 0xffff is the max value which solves | ||
785 | these problems. */ | ||
786 | pci_write_config_dword(dev, 0x40, 0xffff); | ||
787 | |||
788 | IVTV_DEBUG_INFO("%d (rev %d) at %02x:%02x.%x, " | ||
789 | "irq: %d, latency: %d, memory: 0x%lx\n", | ||
790 | itv->dev->device, itv->card_rev, dev->bus->number, | ||
791 | PCI_SLOT(dev->devfn), PCI_FUNC(dev->devfn), | ||
792 | itv->dev->irq, pci_latency, (unsigned long)itv->base_addr); | ||
793 | |||
794 | return 0; | ||
795 | } | ||
796 | |||
797 | static void ivtv_request_module(struct ivtv *itv, const char *name) | ||
798 | { | ||
799 | if (request_module(name) != 0) { | ||
800 | IVTV_ERR("Failed to load module %s\n", name); | ||
801 | } else { | ||
802 | IVTV_DEBUG_INFO("Loaded module %s\n", name); | ||
803 | } | ||
804 | } | ||
805 | |||
806 | static void ivtv_load_and_init_modules(struct ivtv *itv) | ||
807 | { | ||
808 | struct v4l2_control ctrl; | ||
809 | u32 hw = itv->card->hw_all; | ||
810 | int i; | ||
811 | |||
812 | /* load modules */ | ||
813 | #ifndef CONFIG_VIDEO_TUNER | ||
814 | if (hw & IVTV_HW_TUNER) { | ||
815 | ivtv_request_module(itv, "tuner"); | ||
816 | #ifdef HAVE_XC3028 | ||
817 | if (itv->options.tuner == TUNER_XCEIVE_XC3028) | ||
818 | ivtv_request_module(itv, "xc3028-tuner"); | ||
819 | #endif | ||
820 | } | ||
821 | #endif | ||
822 | #ifndef CONFIG_VIDEO_CX25840 | ||
823 | if (hw & IVTV_HW_CX25840) | ||
824 | ivtv_request_module(itv, "cx25840"); | ||
825 | #endif | ||
826 | #ifndef CONFIG_VIDEO_SAA711X | ||
827 | if (hw & IVTV_HW_SAA711X) | ||
828 | ivtv_request_module(itv, "saa7115"); | ||
829 | #endif | ||
830 | #ifndef CONFIG_VIDEO_SAA7127 | ||
831 | if (hw & IVTV_HW_SAA7127) | ||
832 | ivtv_request_module(itv, "saa7127"); | ||
833 | #endif | ||
834 | if (hw & IVTV_HW_SAA717X) | ||
835 | ivtv_request_module(itv, "saa717x"); | ||
836 | #ifndef CONFIG_VIDEO_UPD64031A | ||
837 | if (hw & IVTV_HW_UPD64031A) | ||
838 | ivtv_request_module(itv, "upd64031a"); | ||
839 | #endif | ||
840 | #ifndef CONFIG_VIDEO_UPD64083 | ||
841 | if (hw & IVTV_HW_UPD6408X) | ||
842 | ivtv_request_module(itv, "upd64083"); | ||
843 | #endif | ||
844 | #ifndef CONFIG_VIDEO_MSP3400 | ||
845 | if (hw & IVTV_HW_MSP34XX) | ||
846 | ivtv_request_module(itv, "msp3400"); | ||
847 | #endif | ||
848 | if (hw & IVTV_HW_TVAUDIO) | ||
849 | ivtv_request_module(itv, "tvaudio"); | ||
850 | #ifndef CONFIG_VIDEO_WM8775 | ||
851 | if (hw & IVTV_HW_WM8775) | ||
852 | ivtv_request_module(itv, "wm8775"); | ||
853 | #endif | ||
854 | #ifndef CONFIG_VIDEO_WM8739 | ||
855 | if (hw & IVTV_HW_WM8739) | ||
856 | ivtv_request_module(itv, "wm8739"); | ||
857 | #endif | ||
858 | #ifndef CONFIG_VIDEO_CS53L32A | ||
859 | if (hw & IVTV_HW_CS53L32A) | ||
860 | ivtv_request_module(itv, "cs53l32a"); | ||
861 | #endif | ||
862 | |||
863 | /* check which i2c devices are actually found */ | ||
864 | for (i = 0; i < 32; i++) { | ||
865 | u32 device = 1 << i; | ||
866 | |||
867 | if (!(device & hw)) | ||
868 | continue; | ||
869 | if (device == IVTV_HW_GPIO) { | ||
870 | /* GPIO is always available */ | ||
871 | itv->hw_flags |= IVTV_HW_GPIO; | ||
872 | continue; | ||
873 | } | ||
874 | if (ivtv_i2c_hw_addr(itv, device) > 0) | ||
875 | itv->hw_flags |= device; | ||
876 | } | ||
877 | |||
878 | hw = itv->hw_flags; | ||
879 | |||
880 | if (itv->card->type == IVTV_CARD_CX23416GYC) { | ||
881 | /* Several variations of this card exist, detect which card | ||
882 | type should be used. */ | ||
883 | if ((hw & (IVTV_HW_UPD64031A | IVTV_HW_UPD6408X)) == 0) | ||
884 | itv->card = ivtv_get_card(IVTV_CARD_CX23416GYC_NOGRYCS); | ||
885 | else if ((hw & IVTV_HW_UPD64031A) == 0) | ||
886 | itv->card = ivtv_get_card(IVTV_CARD_CX23416GYC_NOGR); | ||
887 | } | ||
888 | |||
889 | if (hw & IVTV_HW_CX25840) { | ||
890 | /* CX25840_CID_ENABLE_PVR150_WORKAROUND */ | ||
891 | ctrl.id = V4L2_CID_PRIVATE_BASE; | ||
892 | ctrl.value = itv->pvr150_workaround; | ||
893 | itv->video_dec_func(itv, VIDIOC_S_CTRL, &ctrl); | ||
894 | |||
895 | itv->vbi.raw_decoder_line_size = 1444; | ||
896 | itv->vbi.raw_decoder_sav_odd_field = 0x20; | ||
897 | itv->vbi.raw_decoder_sav_even_field = 0x60; | ||
898 | itv->vbi.sliced_decoder_line_size = 272; | ||
899 | itv->vbi.sliced_decoder_sav_odd_field = 0xB0; | ||
900 | itv->vbi.sliced_decoder_sav_even_field = 0xF0; | ||
901 | } | ||
902 | |||
903 | if (hw & IVTV_HW_SAA711X) { | ||
904 | struct v4l2_chip_ident v = { V4L2_CHIP_MATCH_I2C_DRIVER, I2C_DRIVERID_SAA711X }; | ||
905 | |||
906 | /* determine the exact saa711x model */ | ||
907 | itv->hw_flags &= ~IVTV_HW_SAA711X; | ||
908 | |||
909 | ivtv_saa7115(itv, VIDIOC_G_CHIP_IDENT, &v); | ||
910 | if (v.ident == V4L2_IDENT_SAA7114) { | ||
911 | itv->hw_flags |= IVTV_HW_SAA7114; | ||
912 | /* VBI is not yet supported by the saa7114 driver. */ | ||
913 | itv->v4l2_cap &= ~(V4L2_CAP_SLICED_VBI_CAPTURE|V4L2_CAP_VBI_CAPTURE); | ||
914 | } | ||
915 | else { | ||
916 | itv->hw_flags |= IVTV_HW_SAA7115; | ||
917 | } | ||
918 | itv->vbi.raw_decoder_line_size = 1443; | ||
919 | itv->vbi.raw_decoder_sav_odd_field = 0x25; | ||
920 | itv->vbi.raw_decoder_sav_even_field = 0x62; | ||
921 | itv->vbi.sliced_decoder_line_size = 51; | ||
922 | itv->vbi.sliced_decoder_sav_odd_field = 0xAB; | ||
923 | itv->vbi.sliced_decoder_sav_even_field = 0xEC; | ||
924 | } | ||
925 | |||
926 | if (hw & IVTV_HW_SAA717X) { | ||
927 | itv->vbi.raw_decoder_line_size = 1443; | ||
928 | itv->vbi.raw_decoder_sav_odd_field = 0x25; | ||
929 | itv->vbi.raw_decoder_sav_even_field = 0x62; | ||
930 | itv->vbi.sliced_decoder_line_size = 51; | ||
931 | itv->vbi.sliced_decoder_sav_odd_field = 0xAB; | ||
932 | itv->vbi.sliced_decoder_sav_even_field = 0xEC; | ||
933 | } | ||
934 | } | ||
935 | |||
936 | static int __devinit ivtv_probe(struct pci_dev *dev, | ||
937 | const struct pci_device_id *pci_id) | ||
938 | { | ||
939 | int retval = 0; | ||
940 | int video_input; | ||
941 | int yuv_buf_size; | ||
942 | int vbi_buf_size; | ||
943 | int fw_retry_count = 3; | ||
944 | struct ivtv *itv; | ||
945 | struct v4l2_frequency vf; | ||
946 | |||
947 | spin_lock(&ivtv_cards_lock); | ||
948 | |||
949 | /* Make sure we've got a place for this card */ | ||
950 | if (ivtv_cards_active == IVTV_MAX_CARDS) { | ||
951 | printk(KERN_ERR "ivtv: Maximum number of cards detected (%d).\n", | ||
952 | ivtv_cards_active); | ||
953 | spin_unlock(&ivtv_cards_lock); | ||
954 | return -ENOMEM; | ||
955 | } | ||
956 | |||
957 | itv = kzalloc(sizeof(struct ivtv), GFP_ATOMIC); | ||
958 | if (itv == 0) { | ||
959 | spin_unlock(&ivtv_cards_lock); | ||
960 | return -ENOMEM; | ||
961 | } | ||
962 | ivtv_cards[ivtv_cards_active] = itv; | ||
963 | itv->dev = dev; | ||
964 | itv->num = ivtv_cards_active++; | ||
965 | snprintf(itv->name, sizeof(itv->name) - 1, "ivtv%d", itv->num); | ||
966 | if (itv->num) { | ||
967 | printk(KERN_INFO "ivtv: ====================== NEXT CARD ======================\n"); | ||
968 | } | ||
969 | |||
970 | spin_unlock(&ivtv_cards_lock); | ||
971 | |||
972 | ivtv_process_options(itv); | ||
973 | if (itv->options.cardtype == -1) { | ||
974 | retval = -ENODEV; | ||
975 | goto err; | ||
976 | } | ||
977 | if (ivtv_init_struct1(itv)) { | ||
978 | retval = -ENOMEM; | ||
979 | goto err; | ||
980 | } | ||
981 | |||
982 | IVTV_DEBUG_INFO("base addr: 0x%08x\n", itv->base_addr); | ||
983 | |||
984 | /* PCI Device Setup */ | ||
985 | if ((retval = ivtv_setup_pci(itv, dev, pci_id)) != 0) { | ||
986 | if (retval == -EIO) | ||
987 | goto free_workqueue; | ||
988 | else if (retval == -ENXIO) | ||
989 | goto free_mem; | ||
990 | } | ||
991 | /* save itv in the pci struct for later use */ | ||
992 | pci_set_drvdata(dev, itv); | ||
993 | |||
994 | /* map io memory */ | ||
995 | IVTV_DEBUG_INFO("attempting ioremap at 0x%08x len 0x%08x\n", | ||
996 | itv->base_addr + IVTV_ENCODER_OFFSET, IVTV_ENCODER_SIZE); | ||
997 | itv->enc_mem = ioremap_nocache(itv->base_addr + IVTV_ENCODER_OFFSET, | ||
998 | IVTV_ENCODER_SIZE); | ||
999 | if (!itv->enc_mem) { | ||
1000 | IVTV_ERR("ioremap failed, perhaps increasing __VMALLOC_RESERVE in page.h\n"); | ||
1001 | IVTV_ERR("or disabling CONFIG_HIMEM4G into the kernel would help\n"); | ||
1002 | retval = -ENOMEM; | ||
1003 | goto free_mem; | ||
1004 | } | ||
1005 | |||
1006 | if (itv->has_cx23415) { | ||
1007 | IVTV_DEBUG_INFO("attempting ioremap at 0x%08x len 0x%08x\n", | ||
1008 | itv->base_addr + IVTV_DECODER_OFFSET, IVTV_DECODER_SIZE); | ||
1009 | itv->dec_mem = ioremap_nocache(itv->base_addr + IVTV_DECODER_OFFSET, | ||
1010 | IVTV_DECODER_SIZE); | ||
1011 | if (!itv->dec_mem) { | ||
1012 | IVTV_ERR("ioremap failed, perhaps increasing __VMALLOC_RESERVE in page.h\n"); | ||
1013 | IVTV_ERR("or disabling CONFIG_HIMEM4G into the kernel would help\n"); | ||
1014 | retval = -ENOMEM; | ||
1015 | goto free_mem; | ||
1016 | } | ||
1017 | } | ||
1018 | else { | ||
1019 | itv->dec_mem = itv->enc_mem; | ||
1020 | } | ||
1021 | |||
1022 | /* map registers memory */ | ||
1023 | IVTV_DEBUG_INFO("attempting ioremap at 0x%08x len 0x%08x\n", | ||
1024 | itv->base_addr + IVTV_REG_OFFSET, IVTV_REG_SIZE); | ||
1025 | itv->reg_mem = | ||
1026 | ioremap_nocache(itv->base_addr + IVTV_REG_OFFSET, IVTV_REG_SIZE); | ||
1027 | if (!itv->reg_mem) { | ||
1028 | IVTV_ERR("ioremap failed, perhaps increasing __VMALLOC_RESERVE in page.h\n"); | ||
1029 | IVTV_ERR("or disabling CONFIG_HIMEM4G into the kernel would help\n"); | ||
1030 | retval = -ENOMEM; | ||
1031 | goto free_io; | ||
1032 | } | ||
1033 | |||
1034 | while (--fw_retry_count > 0) { | ||
1035 | /* load firmware */ | ||
1036 | if (ivtv_firmware_init(itv) == 0) | ||
1037 | break; | ||
1038 | if (fw_retry_count > 1) | ||
1039 | IVTV_WARN("Retry loading firmware\n"); | ||
1040 | } | ||
1041 | if (fw_retry_count == 0) { | ||
1042 | IVTV_ERR("Error initializing firmware\n"); | ||
1043 | goto free_i2c; | ||
1044 | } | ||
1045 | |||
1046 | /* Try and get firmware versions */ | ||
1047 | IVTV_DEBUG_INFO("Getting firmware version..\n"); | ||
1048 | ivtv_firmware_versions(itv); | ||
1049 | |||
1050 | /* Check yuv output filter table */ | ||
1051 | if (itv->has_cx23415) ivtv_yuv_filter_check(itv); | ||
1052 | |||
1053 | ivtv_gpio_init(itv); | ||
1054 | |||
1055 | /* active i2c */ | ||
1056 | IVTV_DEBUG_INFO("activating i2c...\n"); | ||
1057 | if (init_ivtv_i2c(itv)) { | ||
1058 | IVTV_ERR("Could not initialize i2c\n"); | ||
1059 | goto free_irq; | ||
1060 | } | ||
1061 | |||
1062 | IVTV_DEBUG_INFO("Active card count: %d.\n", ivtv_cards_active); | ||
1063 | |||
1064 | if (itv->card->hw_all & IVTV_HW_TVEEPROM) { | ||
1065 | #ifdef CONFIG_VIDEO_TVEEPROM_MODULE | ||
1066 | ivtv_request_module(itv, "tveeprom"); | ||
1067 | #endif | ||
1068 | /* Based on the model number the cardtype may be changed. | ||
1069 | The PCI IDs are not always reliable. */ | ||
1070 | ivtv_process_eeprom(itv); | ||
1071 | } | ||
1072 | |||
1073 | if (itv->std == 0) { | ||
1074 | itv->std = V4L2_STD_NTSC_M; | ||
1075 | } | ||
1076 | |||
1077 | if (itv->options.tuner == -1) { | ||
1078 | int i; | ||
1079 | |||
1080 | for (i = 0; i < IVTV_CARD_MAX_TUNERS; i++) { | ||
1081 | if ((itv->std & itv->card->tuners[i].std) == 0) | ||
1082 | continue; | ||
1083 | itv->options.tuner = itv->card->tuners[i].tuner; | ||
1084 | break; | ||
1085 | } | ||
1086 | } | ||
1087 | /* if no tuner was found, then pick the first tuner in the card list */ | ||
1088 | if (itv->options.tuner == -1 && itv->card->tuners[0].std) { | ||
1089 | itv->std = itv->card->tuners[0].std; | ||
1090 | itv->options.tuner = itv->card->tuners[0].tuner; | ||
1091 | } | ||
1092 | if (itv->options.radio == -1) | ||
1093 | itv->options.radio = (itv->card->radio_input.audio_type != 0); | ||
1094 | |||
1095 | /* The card is now fully identified, continue with card-specific | ||
1096 | initialization. */ | ||
1097 | ivtv_init_struct2(itv); | ||
1098 | |||
1099 | ivtv_load_and_init_modules(itv); | ||
1100 | |||
1101 | if (itv->std & V4L2_STD_525_60) { | ||
1102 | itv->is_60hz = 1; | ||
1103 | itv->is_out_60hz = 1; | ||
1104 | } else { | ||
1105 | itv->is_50hz = 1; | ||
1106 | itv->is_out_50hz = 1; | ||
1107 | } | ||
1108 | itv->params.video_gop_size = itv->is_60hz ? 15 : 12; | ||
1109 | |||
1110 | itv->stream_buf_size[IVTV_ENC_STREAM_TYPE_MPG] = 0x08000; | ||
1111 | itv->stream_buf_size[IVTV_ENC_STREAM_TYPE_PCM] = 0x01200; | ||
1112 | itv->stream_buf_size[IVTV_DEC_STREAM_TYPE_MPG] = 0x10000; | ||
1113 | |||
1114 | /* 0x15180 == 720 * 480 / 4, 0x19500 == 720 * 576 / 4 */ | ||
1115 | yuv_buf_size = itv->is_60hz ? 0x15180 : 0x19500; | ||
1116 | itv->stream_buf_size[IVTV_DEC_STREAM_TYPE_YUV] = yuv_buf_size / 2; | ||
1117 | itv->stream_buf_size[IVTV_ENC_STREAM_TYPE_YUV] = yuv_buf_size / 8; | ||
1118 | |||
1119 | /* Setup VBI Raw Size. Should be big enough to hold PAL. | ||
1120 | It is possible to switch between PAL and NTSC, so we need to | ||
1121 | take the largest size here. */ | ||
1122 | /* 1456 is multiple of 16, real size = 1444 */ | ||
1123 | itv->vbi.raw_size = 1456; | ||
1124 | /* We use a buffer size of 1/2 of the total size needed for a | ||
1125 | frame. This is actually very useful, since we now receive | ||
1126 | a field at a time and that makes 'compressing' the raw data | ||
1127 | down to size by stripping off the SAV codes a lot easier. | ||
1128 | Note: having two different buffer sizes prevents standard | ||
1129 | switching on the fly. We need to find a better solution... */ | ||
1130 | vbi_buf_size = itv->vbi.raw_size * (itv->is_60hz ? 24 : 36) / 2; | ||
1131 | itv->stream_buf_size[IVTV_ENC_STREAM_TYPE_VBI] = vbi_buf_size; | ||
1132 | itv->stream_buf_size[IVTV_DEC_STREAM_TYPE_VBI] = sizeof(struct v4l2_sliced_vbi_data) * 36; | ||
1133 | |||
1134 | if (itv->options.radio > 0) | ||
1135 | itv->v4l2_cap |= V4L2_CAP_RADIO; | ||
1136 | |||
1137 | if (itv->options.tuner > -1) { | ||
1138 | struct tuner_setup setup; | ||
1139 | |||
1140 | setup.addr = ADDR_UNSET; | ||
1141 | setup.type = itv->options.tuner; | ||
1142 | setup.mode_mask = T_ANALOG_TV; /* matches TV tuners */ | ||
1143 | #ifdef HAVE_XC3028 | ||
1144 | setup.initmode = V4L2_TUNER_ANALOG_TV; | ||
1145 | if (itv->options.tuner == TUNER_XCEIVE_XC3028) { | ||
1146 | setup.gpio_write = ivtv_reset_tuner_gpio; | ||
1147 | setup.gpio_priv = itv; | ||
1148 | } | ||
1149 | #endif | ||
1150 | ivtv_call_i2c_clients(itv, TUNER_SET_TYPE_ADDR, &setup); | ||
1151 | } | ||
1152 | |||
1153 | vf.tuner = 0; | ||
1154 | vf.type = V4L2_TUNER_ANALOG_TV; | ||
1155 | vf.frequency = 6400; /* the tuner 'baseline' frequency */ | ||
1156 | if (itv->std & V4L2_STD_NTSC_M) { | ||
1157 | /* Why on earth? */ | ||
1158 | vf.frequency = 1076; /* ch. 4 67250*16/1000 */ | ||
1159 | } | ||
1160 | |||
1161 | /* The tuner is fixed to the standard. The other inputs (e.g. S-Video) | ||
1162 | are not. */ | ||
1163 | itv->tuner_std = itv->std; | ||
1164 | |||
1165 | video_input = itv->active_input; | ||
1166 | itv->active_input++; /* Force update of input */ | ||
1167 | ivtv_v4l2_ioctls(itv, NULL, VIDIOC_S_INPUT, &video_input); | ||
1168 | |||
1169 | /* Let the VIDIOC_S_STD ioctl do all the work, keeps the code | ||
1170 | in one place. */ | ||
1171 | itv->std++; /* Force full standard initialization */ | ||
1172 | itv->std_out = itv->std; | ||
1173 | ivtv_v4l2_ioctls(itv, NULL, VIDIOC_S_FREQUENCY, &vf); | ||
1174 | |||
1175 | retval = ivtv_streams_setup(itv); | ||
1176 | if (retval) { | ||
1177 | IVTV_ERR("Error %d setting up streams\n", retval); | ||
1178 | goto free_i2c; | ||
1179 | } | ||
1180 | |||
1181 | if (itv->card->v4l2_capabilities & V4L2_CAP_VIDEO_OUTPUT) { | ||
1182 | ivtv_init_mpeg_decoder(itv); | ||
1183 | } | ||
1184 | ivtv_v4l2_ioctls(itv, NULL, VIDIOC_S_STD, &itv->tuner_std); | ||
1185 | |||
1186 | IVTV_DEBUG_IRQ("Masking interrupts\n"); | ||
1187 | /* clear interrupt mask, effectively disabling interrupts */ | ||
1188 | ivtv_set_irq_mask(itv, 0xffffffff); | ||
1189 | |||
1190 | /* Register IRQ */ | ||
1191 | retval = request_irq(itv->dev->irq, ivtv_irq_handler, | ||
1192 | IRQF_SHARED | IRQF_DISABLED, itv->name, (void *)itv); | ||
1193 | if (retval) { | ||
1194 | IVTV_ERR("Failed to register irq %d\n", retval); | ||
1195 | goto free_streams; | ||
1196 | } | ||
1197 | |||
1198 | /* On a cx23416 this seems to be able to enable DMA to the chip? */ | ||
1199 | if (!itv->has_cx23415) | ||
1200 | write_reg_sync(0x03, IVTV_REG_DMACONTROL); | ||
1201 | |||
1202 | /* Default interrupts enabled. For the PVR350 this includes the | ||
1203 | decoder VSYNC interrupt, which is always on. It is not only used | ||
1204 | during decoding but also by the OSD. | ||
1205 | Some old PVR250 cards had a cx23415, so testing for that is too | ||
1206 | general. Instead test if the card has video output capability. */ | ||
1207 | if (itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT) | ||
1208 | ivtv_clear_irq_mask(itv, IVTV_IRQ_MASK_INIT | IVTV_IRQ_DEC_VSYNC); | ||
1209 | else | ||
1210 | ivtv_clear_irq_mask(itv, IVTV_IRQ_MASK_INIT); | ||
1211 | |||
1212 | if (itv->has_cx23415) | ||
1213 | ivtv_set_osd_alpha(itv); | ||
1214 | |||
1215 | IVTV_INFO("Initialized %s, card #%d\n", itv->card_name, itv->num); | ||
1216 | |||
1217 | return 0; | ||
1218 | |||
1219 | free_irq: | ||
1220 | free_irq(itv->dev->irq, (void *)itv); | ||
1221 | free_streams: | ||
1222 | ivtv_streams_cleanup(itv); | ||
1223 | free_i2c: | ||
1224 | exit_ivtv_i2c(itv); | ||
1225 | free_io: | ||
1226 | ivtv_iounmap(itv); | ||
1227 | free_mem: | ||
1228 | release_mem_region(itv->base_addr, IVTV_ENCODER_SIZE); | ||
1229 | release_mem_region(itv->base_addr + IVTV_REG_OFFSET, IVTV_REG_SIZE); | ||
1230 | if (itv->has_cx23415) | ||
1231 | release_mem_region(itv->base_addr + IVTV_DECODER_OFFSET, IVTV_DECODER_SIZE); | ||
1232 | free_workqueue: | ||
1233 | destroy_workqueue(itv->irq_work_queues); | ||
1234 | err: | ||
1235 | if (retval == 0) | ||
1236 | retval = -ENODEV; | ||
1237 | IVTV_ERR("Error %d on initialization\n", retval); | ||
1238 | |||
1239 | kfree(ivtv_cards[ivtv_cards_active]); | ||
1240 | ivtv_cards[ivtv_cards_active] = NULL; | ||
1241 | return retval; | ||
1242 | } | ||
1243 | |||
1244 | static void ivtv_remove(struct pci_dev *pci_dev) | ||
1245 | { | ||
1246 | struct ivtv *itv = pci_get_drvdata(pci_dev); | ||
1247 | |||
1248 | IVTV_DEBUG_INFO("Removing Card #%d.\n", itv->num); | ||
1249 | |||
1250 | /* Stop all captures */ | ||
1251 | IVTV_DEBUG_INFO(" Stopping all streams.\n"); | ||
1252 | if (atomic_read(&itv->capturing) > 0) | ||
1253 | ivtv_stop_all_captures(itv); | ||
1254 | |||
1255 | /* Stop all decoding */ | ||
1256 | IVTV_DEBUG_INFO(" Stopping decoding.\n"); | ||
1257 | if (atomic_read(&itv->decoding) > 0) { | ||
1258 | int type; | ||
1259 | |||
1260 | if (test_bit(IVTV_F_I_DEC_YUV, &itv->i_flags)) | ||
1261 | type = IVTV_DEC_STREAM_TYPE_YUV; | ||
1262 | else | ||
1263 | type = IVTV_DEC_STREAM_TYPE_MPG; | ||
1264 | ivtv_stop_v4l2_decode_stream(&itv->streams[type], | ||
1265 | VIDEO_CMD_STOP_TO_BLACK | VIDEO_CMD_STOP_IMMEDIATELY, 0); | ||
1266 | } | ||
1267 | |||
1268 | /* Interrupts */ | ||
1269 | IVTV_DEBUG_INFO(" Disabling interrupts.\n"); | ||
1270 | ivtv_set_irq_mask(itv, 0xffffffff); | ||
1271 | del_timer_sync(&itv->dma_timer); | ||
1272 | |||
1273 | /* Stop all Work Queues */ | ||
1274 | IVTV_DEBUG_INFO(" Stop Work Queues.\n"); | ||
1275 | flush_workqueue(itv->irq_work_queues); | ||
1276 | destroy_workqueue(itv->irq_work_queues); | ||
1277 | |||
1278 | IVTV_DEBUG_INFO(" Stopping Firmware.\n"); | ||
1279 | ivtv_halt_firmware(itv); | ||
1280 | |||
1281 | IVTV_DEBUG_INFO(" Unregistering v4l devices.\n"); | ||
1282 | ivtv_streams_cleanup(itv); | ||
1283 | IVTV_DEBUG_INFO(" Freeing dma resources.\n"); | ||
1284 | ivtv_udma_free(itv); | ||
1285 | |||
1286 | exit_ivtv_i2c(itv); | ||
1287 | |||
1288 | IVTV_DEBUG_INFO(" Releasing irq.\n"); | ||
1289 | free_irq(itv->dev->irq, (void *)itv); | ||
1290 | |||
1291 | if (itv->dev) { | ||
1292 | ivtv_iounmap(itv); | ||
1293 | } | ||
1294 | |||
1295 | IVTV_DEBUG_INFO(" Releasing mem.\n"); | ||
1296 | release_mem_region(itv->base_addr, IVTV_ENCODER_SIZE); | ||
1297 | release_mem_region(itv->base_addr + IVTV_REG_OFFSET, IVTV_REG_SIZE); | ||
1298 | if (itv->has_cx23415) | ||
1299 | release_mem_region(itv->base_addr + IVTV_DECODER_OFFSET, IVTV_DECODER_SIZE); | ||
1300 | |||
1301 | pci_disable_device(itv->dev); | ||
1302 | |||
1303 | IVTV_INFO("Removed %s, card #%d\n", itv->card_name, itv->num); | ||
1304 | } | ||
1305 | |||
1306 | /* define a pci_driver for card detection */ | ||
1307 | static struct pci_driver ivtv_pci_driver = { | ||
1308 | .name = "ivtv", | ||
1309 | .id_table = ivtv_pci_tbl, | ||
1310 | .probe = ivtv_probe, | ||
1311 | .remove = ivtv_remove, | ||
1312 | }; | ||
1313 | |||
1314 | static int module_start(void) | ||
1315 | { | ||
1316 | printk(KERN_INFO "ivtv: ==================== START INIT IVTV ====================\n"); | ||
1317 | printk(KERN_INFO "ivtv: version %s (" VERMAGIC_STRING ") loading\n", IVTV_VERSION); | ||
1318 | |||
1319 | memset(ivtv_cards, 0, sizeof(ivtv_cards)); | ||
1320 | |||
1321 | /* Validate parameters */ | ||
1322 | if (ivtv_first_minor < 0 || ivtv_first_minor >= IVTV_MAX_CARDS) { | ||
1323 | printk(KERN_ERR "ivtv: ivtv_first_minor must be between 0 and %d. Exiting...\n", | ||
1324 | IVTV_MAX_CARDS - 1); | ||
1325 | return -1; | ||
1326 | } | ||
1327 | |||
1328 | if (ivtv_debug < 0 || ivtv_debug > 511) { | ||
1329 | ivtv_debug = 0; | ||
1330 | printk(KERN_INFO "ivtv: debug value must be >= 0 and <= 511!\n"); | ||
1331 | } | ||
1332 | |||
1333 | if (pci_register_driver(&ivtv_pci_driver)) { | ||
1334 | printk(KERN_ERR "ivtv: Error detecting PCI card\n"); | ||
1335 | return -ENODEV; | ||
1336 | } | ||
1337 | printk(KERN_INFO "ivtv: ==================== END INIT IVTV ====================\n"); | ||
1338 | return 0; | ||
1339 | } | ||
1340 | |||
1341 | static void module_cleanup(void) | ||
1342 | { | ||
1343 | int i, j; | ||
1344 | |||
1345 | pci_unregister_driver(&ivtv_pci_driver); | ||
1346 | |||
1347 | for (i = 0; i < ivtv_cards_active; i++) { | ||
1348 | if (ivtv_cards[i] == NULL) | ||
1349 | continue; | ||
1350 | for (j = 0; j < IVTV_VBI_FRAMES; j++) { | ||
1351 | kfree(ivtv_cards[i]->vbi.sliced_mpeg_data[j]); | ||
1352 | } | ||
1353 | kfree(ivtv_cards[i]); | ||
1354 | } | ||
1355 | } | ||
1356 | |||
1357 | /* Note: These symbols are exported because they are used by the ivtv-fb | ||
1358 | framebuffer module and an infrared module for the IR-blaster. */ | ||
1359 | EXPORT_SYMBOL(ivtv_set_irq_mask); | ||
1360 | EXPORT_SYMBOL(ivtv_cards_active); | ||
1361 | EXPORT_SYMBOL(ivtv_cards); | ||
1362 | EXPORT_SYMBOL(ivtv_api); | ||
1363 | EXPORT_SYMBOL(ivtv_vapi); | ||
1364 | EXPORT_SYMBOL(ivtv_vapi_result); | ||
1365 | EXPORT_SYMBOL(ivtv_clear_irq_mask); | ||
1366 | EXPORT_SYMBOL(ivtv_debug); | ||
1367 | EXPORT_SYMBOL(ivtv_reset_ir_gpio); | ||
1368 | EXPORT_SYMBOL(ivtv_udma_setup); | ||
1369 | EXPORT_SYMBOL(ivtv_udma_unmap); | ||
1370 | EXPORT_SYMBOL(ivtv_udma_alloc); | ||
1371 | EXPORT_SYMBOL(ivtv_udma_prepare); | ||
1372 | |||
1373 | module_init(module_start); | ||
1374 | module_exit(module_cleanup); | ||
diff --git a/drivers/media/video/ivtv/ivtv-driver.h b/drivers/media/video/ivtv/ivtv-driver.h new file mode 100644 index 000000000000..9a412d6c6d06 --- /dev/null +++ b/drivers/media/video/ivtv/ivtv-driver.h | |||
@@ -0,0 +1,868 @@ | |||
1 | /* | ||
2 | ivtv driver internal defines and structures | ||
3 | Copyright (C) 2003-2004 Kevin Thayer <nufan_wfk at yahoo.com> | ||
4 | Copyright (C) 2004 Chris Kennedy <c@groovy.org> | ||
5 | Copyright (C) 2005-2007 Hans Verkuil <hverkuil@xs4all.nl> | ||
6 | |||
7 | This program is free software; you can redistribute it and/or modify | ||
8 | it under the terms of the GNU General Public License as published by | ||
9 | the Free Software Foundation; either version 2 of the License, or | ||
10 | (at your option) any later version. | ||
11 | |||
12 | This program is distributed in the hope that it will be useful, | ||
13 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
15 | GNU General Public License for more details. | ||
16 | |||
17 | You should have received a copy of the GNU General Public License | ||
18 | along with this program; if not, write to the Free Software | ||
19 | Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
20 | */ | ||
21 | |||
22 | #ifndef IVTV_DRIVER_H | ||
23 | #define IVTV_DRIVER_H | ||
24 | |||
25 | /* Internal header for ivtv project: | ||
26 | * Driver for the cx23415/6 chip. | ||
27 | * Author: Kevin Thayer (nufan_wfk at yahoo.com) | ||
28 | * License: GPL | ||
29 | * http://www.ivtvdriver.org | ||
30 | * | ||
31 | * ----- | ||
32 | * MPG600/MPG160 support by T.Adachi <tadachi@tadachi-net.com> | ||
33 | * and Takeru KOMORIYA<komoriya@paken.org> | ||
34 | * | ||
35 | * AVerMedia M179 GPIO info by Chris Pinkham <cpinkham@bc2va.org> | ||
36 | * using information provided by Jiun-Kuei Jung @ AVerMedia. | ||
37 | */ | ||
38 | |||
39 | #include <linux/version.h> | ||
40 | #include <linux/module.h> | ||
41 | #include <linux/moduleparam.h> | ||
42 | #include <linux/init.h> | ||
43 | #include <linux/delay.h> | ||
44 | #include <linux/sched.h> | ||
45 | #include <linux/fs.h> | ||
46 | #include <linux/pci.h> | ||
47 | #include <linux/interrupt.h> | ||
48 | #include <linux/spinlock.h> | ||
49 | #include <linux/i2c.h> | ||
50 | #include <linux/i2c-algo-bit.h> | ||
51 | #include <linux/list.h> | ||
52 | #include <linux/unistd.h> | ||
53 | #include <linux/byteorder/swab.h> | ||
54 | #include <linux/pagemap.h> | ||
55 | #include <linux/workqueue.h> | ||
56 | #include <linux/mutex.h> | ||
57 | #include <asm/uaccess.h> | ||
58 | #include <asm/system.h> | ||
59 | |||
60 | #include <linux/dvb/video.h> | ||
61 | #include <linux/dvb/audio.h> | ||
62 | #include <media/v4l2-common.h> | ||
63 | #include <media/tuner.h> | ||
64 | #include <media/cx2341x.h> | ||
65 | |||
66 | /* #define HAVE_XC3028 1 */ | ||
67 | |||
68 | #include <media/ivtv.h> | ||
69 | |||
70 | #ifdef CONFIG_LIRC_I2C | ||
71 | # error "This driver is not compatible with the LIRC I2C kernel configuration option." | ||
72 | #endif /* CONFIG_LIRC_I2C */ | ||
73 | |||
74 | #ifndef CONFIG_PCI | ||
75 | # error "This driver requires kernel PCI support." | ||
76 | #endif /* CONFIG_PCI */ | ||
77 | |||
78 | #define IVTV_ENCODER_OFFSET 0x00000000 | ||
79 | #define IVTV_ENCODER_SIZE 0x00800000 /* Last half isn't needed 0x01000000 */ | ||
80 | |||
81 | #define IVTV_DECODER_OFFSET 0x01000000 | ||
82 | #define IVTV_DECODER_SIZE 0x00800000 /* Last half isn't needed 0x01000000 */ | ||
83 | |||
84 | #define IVTV_REG_OFFSET 0x02000000 | ||
85 | #define IVTV_REG_SIZE 0x00010000 | ||
86 | |||
87 | /* Buffers on hardware offsets */ | ||
88 | #define IVTV_YUV_BUFFER_OFFSET 0x001a8600 /* First YUV Buffer */ | ||
89 | #define IVTV_YUV_BUFFER_OFFSET_1 0x00240400 /* Second YUV Buffer */ | ||
90 | #define IVTV_YUV_BUFFER_OFFSET_2 0x002d8200 /* Third YUV Buffer */ | ||
91 | #define IVTV_YUV_BUFFER_OFFSET_3 0x00370000 /* Fourth YUV Buffer */ | ||
92 | #define IVTV_YUV_BUFFER_UV_OFFSET 0x65400 /* Offset to UV Buffer */ | ||
93 | |||
94 | /* Offset to filter table in firmware */ | ||
95 | #define IVTV_YUV_HORIZONTAL_FILTER_OFFSET 0x025d8 | ||
96 | #define IVTV_YUV_VERTICAL_FILTER_OFFSET 0x03358 | ||
97 | |||
98 | extern const u32 yuv_offset[4]; | ||
99 | |||
100 | /* Maximum ivtv driver instances. | ||
101 | Based on 6 PVR500s each with two PVR15s... | ||
102 | TODO: make this dynamic. I believe it is only a global in order to support | ||
103 | ivtv-fb. There must be a better way to do that. */ | ||
104 | #define IVTV_MAX_CARDS 12 | ||
105 | |||
106 | /* Supported cards */ | ||
107 | #define IVTV_CARD_PVR_250 0 /* WinTV PVR 250 */ | ||
108 | #define IVTV_CARD_PVR_350 1 /* encoder, decoder, tv-out */ | ||
109 | #define IVTV_CARD_PVR_150 2 /* WinTV PVR 150 and PVR 500 (really just two | ||
110 | PVR150s on one PCI board) */ | ||
111 | #define IVTV_CARD_M179 3 /* AVerMedia M179 (encoder only) */ | ||
112 | #define IVTV_CARD_MPG600 4 /* Kuroutoshikou ITVC16-STVLP/YUAN MPG600, encoder only */ | ||
113 | #define IVTV_CARD_MPG160 5 /* Kuroutoshikou ITVC15-STVLP/YUAN MPG160 | ||
114 | cx23415 based, but does not have tv-out */ | ||
115 | #define IVTV_CARD_PG600 6 /* YUAN PG600/DIAMONDMM PVR-550 based on the CX Falcon 2 */ | ||
116 | #define IVTV_CARD_AVC2410 7 /* Adaptec AVC-2410 */ | ||
117 | #define IVTV_CARD_AVC2010 8 /* Adaptec AVD-2010 (No Tuner) */ | ||
118 | #define IVTV_CARD_TG5000TV 9 /* NAGASE TRANSGEAR 5000TV, encoder only */ | ||
119 | #define IVTV_CARD_VA2000MAX_SNT6 10 /* VA2000MAX-STN6 */ | ||
120 | #define IVTV_CARD_CX23416GYC 11 /* Kuroutoshikou CX23416GYC-STVLP (Yuan MPG600GR OEM) */ | ||
121 | #define IVTV_CARD_GV_MVPRX 12 /* I/O Data GV-MVP/RX, RX2, RX2W */ | ||
122 | #define IVTV_CARD_GV_MVPRX2E 13 /* I/O Data GV-MVP/RX2E */ | ||
123 | #define IVTV_CARD_GOTVIEW_PCI_DVD 14 /* GotView PCI DVD */ | ||
124 | #define IVTV_CARD_GOTVIEW_PCI_DVD2 15 /* GotView PCI DVD2 */ | ||
125 | #define IVTV_CARD_YUAN_MPC622 16 /* Yuan MPC622 miniPCI */ | ||
126 | #define IVTV_CARD_DCTMTVP1 17 /* DIGITAL COWBOY DCT-MTVP1 */ | ||
127 | #ifdef HAVE_XC3028 | ||
128 | #define IVTV_CARD_PG600V2 18 /* Yuan PG600V2/GotView PCI DVD Lite/Club3D ZAP-TV1x01 */ | ||
129 | #define IVTV_CARD_LAST 18 | ||
130 | #else | ||
131 | #define IVTV_CARD_LAST 17 | ||
132 | #endif | ||
133 | |||
134 | /* Variants of existing cards but with the same PCI IDs. The driver | ||
135 | detects these based on other device information. | ||
136 | These cards must always come last. | ||
137 | New cards must be inserted above, and the indices of the cards below | ||
138 | must be adjusted accordingly. */ | ||
139 | |||
140 | /* PVR-350 V1 (uses saa7114) */ | ||
141 | #define IVTV_CARD_PVR_350_V1 (IVTV_CARD_LAST+1) | ||
142 | /* 2 variants of Kuroutoshikou CX23416GYC-STVLP (Yuan MPG600GR OEM) */ | ||
143 | #define IVTV_CARD_CX23416GYC_NOGR (IVTV_CARD_LAST+2) | ||
144 | #define IVTV_CARD_CX23416GYC_NOGRYCS (IVTV_CARD_LAST+3) | ||
145 | |||
146 | #define IVTV_ENC_STREAM_TYPE_MPG 0 | ||
147 | #define IVTV_ENC_STREAM_TYPE_YUV 1 | ||
148 | #define IVTV_ENC_STREAM_TYPE_VBI 2 | ||
149 | #define IVTV_ENC_STREAM_TYPE_PCM 3 | ||
150 | #define IVTV_ENC_STREAM_TYPE_RAD 4 | ||
151 | #define IVTV_DEC_STREAM_TYPE_MPG 5 | ||
152 | #define IVTV_DEC_STREAM_TYPE_VBI 6 | ||
153 | #define IVTV_DEC_STREAM_TYPE_VOUT 7 | ||
154 | #define IVTV_DEC_STREAM_TYPE_YUV 8 | ||
155 | #define IVTV_MAX_STREAMS 9 | ||
156 | |||
157 | #define IVTV_V4L2_DEC_MPG_OFFSET 16 /* offset from 0 to register decoder mpg v4l2 minors on */ | ||
158 | #define IVTV_V4L2_ENC_PCM_OFFSET 24 /* offset from 0 to register pcm v4l2 minors on */ | ||
159 | #define IVTV_V4L2_ENC_YUV_OFFSET 32 /* offset from 0 to register yuv v4l2 minors on */ | ||
160 | #define IVTV_V4L2_DEC_YUV_OFFSET 48 /* offset from 0 to register decoder yuv v4l2 minors on */ | ||
161 | #define IVTV_V4L2_DEC_VBI_OFFSET 8 /* offset from 0 to register decoder vbi input v4l2 minors on */ | ||
162 | #define IVTV_V4L2_DEC_VOUT_OFFSET 16 /* offset from 0 to register vbi output v4l2 minors on */ | ||
163 | |||
164 | #define IVTV_ENC_MEM_START 0x00000000 | ||
165 | #define IVTV_DEC_MEM_START 0x01000000 | ||
166 | |||
167 | /* system vendor and device IDs */ | ||
168 | #define PCI_VENDOR_ID_ICOMP 0x4444 | ||
169 | #define PCI_DEVICE_ID_IVTV15 0x0803 | ||
170 | #define PCI_DEVICE_ID_IVTV16 0x0016 | ||
171 | |||
172 | /* subsystem vendor ID */ | ||
173 | #define IVTV_PCI_ID_HAUPPAUGE 0x0070 | ||
174 | #define IVTV_PCI_ID_HAUPPAUGE_ALT1 0x0270 | ||
175 | #define IVTV_PCI_ID_HAUPPAUGE_ALT2 0x4070 | ||
176 | #define IVTV_PCI_ID_ADAPTEC 0x9005 | ||
177 | #define IVTV_PCI_ID_AVERMEDIA 0x1461 | ||
178 | #define IVTV_PCI_ID_YUAN1 0x12ab | ||
179 | #define IVTV_PCI_ID_YUAN2 0xff01 | ||
180 | #define IVTV_PCI_ID_YUAN3 0xffab | ||
181 | #define IVTV_PCI_ID_YUAN4 0xfbab | ||
182 | #define IVTV_PCI_ID_DIAMONDMM 0xff92 | ||
183 | #define IVTV_PCI_ID_IODATA 0x10fc | ||
184 | #define IVTV_PCI_ID_MELCO 0x1154 | ||
185 | #define IVTV_PCI_ID_GOTVIEW1 0xffac | ||
186 | #define IVTV_PCI_ID_GOTVIEW2 0xffad | ||
187 | |||
188 | /* Decoder Buffer hardware size on Chip */ | ||
189 | #define IVTV_DEC_MAX_BUF 0x00100000 /* max bytes in decoder buffer */ | ||
190 | #define IVTV_DEC_MIN_BUF 0x00010000 /* min bytes in dec buffer */ | ||
191 | |||
192 | /* ======================================================================== */ | ||
193 | /* ========================== START USER SETTABLE DMA VARIABLES =========== */ | ||
194 | /* ======================================================================== */ | ||
195 | |||
196 | #define IVTV_DMA_SG_OSD_ENT (2883584/PAGE_SIZE) /* sg entities */ | ||
197 | |||
198 | /* DMA Buffers, Default size in MB allocated */ | ||
199 | #define IVTV_DEFAULT_ENC_MPG_BUFFERS 4 | ||
200 | #define IVTV_DEFAULT_ENC_YUV_BUFFERS 2 | ||
201 | #define IVTV_DEFAULT_ENC_VBI_BUFFERS 1 | ||
202 | #define IVTV_DEFAULT_ENC_PCM_BUFFERS 1 | ||
203 | #define IVTV_DEFAULT_DEC_MPG_BUFFERS 1 | ||
204 | #define IVTV_DEFAULT_DEC_YUV_BUFFERS 1 | ||
205 | #define IVTV_DEFAULT_DEC_VBI_BUFFERS 1 | ||
206 | |||
207 | /* ======================================================================== */ | ||
208 | /* ========================== END USER SETTABLE DMA VARIABLES ============= */ | ||
209 | /* ======================================================================== */ | ||
210 | |||
211 | /* Decoder Status Register */ | ||
212 | #define IVTV_DMA_ERR_LIST 0x00000010 | ||
213 | #define IVTV_DMA_ERR_WRITE 0x00000008 | ||
214 | #define IVTV_DMA_ERR_READ 0x00000004 | ||
215 | #define IVTV_DMA_SUCCESS_WRITE 0x00000002 | ||
216 | #define IVTV_DMA_SUCCESS_READ 0x00000001 | ||
217 | #define IVTV_DMA_READ_ERR (IVTV_DMA_ERR_LIST | IVTV_DMA_ERR_READ) | ||
218 | #define IVTV_DMA_WRITE_ERR (IVTV_DMA_ERR_LIST | IVTV_DMA_ERR_WRITE) | ||
219 | #define IVTV_DMA_ERR (IVTV_DMA_ERR_LIST | IVTV_DMA_ERR_WRITE | IVTV_DMA_ERR_READ) | ||
220 | |||
221 | /* DMA Registers */ | ||
222 | #define IVTV_REG_DMAXFER (0x0000) | ||
223 | #define IVTV_REG_DMASTATUS (0x0004) | ||
224 | #define IVTV_REG_DECDMAADDR (0x0008) | ||
225 | #define IVTV_REG_ENCDMAADDR (0x000c) | ||
226 | #define IVTV_REG_DMACONTROL (0x0010) | ||
227 | #define IVTV_REG_IRQSTATUS (0x0040) | ||
228 | #define IVTV_REG_IRQMASK (0x0048) | ||
229 | |||
230 | /* Setup Registers */ | ||
231 | #define IVTV_REG_ENC_SDRAM_REFRESH (0x07F8) | ||
232 | #define IVTV_REG_ENC_SDRAM_PRECHARGE (0x07FC) | ||
233 | #define IVTV_REG_DEC_SDRAM_REFRESH (0x08F8) | ||
234 | #define IVTV_REG_DEC_SDRAM_PRECHARGE (0x08FC) | ||
235 | #define IVTV_REG_VDM (0x2800) | ||
236 | #define IVTV_REG_AO (0x2D00) | ||
237 | #define IVTV_REG_BYTEFLUSH (0x2D24) | ||
238 | #define IVTV_REG_SPU (0x9050) | ||
239 | #define IVTV_REG_HW_BLOCKS (0x9054) | ||
240 | #define IVTV_REG_VPU (0x9058) | ||
241 | #define IVTV_REG_APU (0xA064) | ||
242 | |||
243 | #define IVTV_IRQ_ENC_START_CAP (0x1 << 31) | ||
244 | #define IVTV_IRQ_ENC_EOS (0x1 << 30) | ||
245 | #define IVTV_IRQ_ENC_VBI_CAP (0x1 << 29) | ||
246 | #define IVTV_IRQ_ENC_VIM_RST (0x1 << 28) | ||
247 | #define IVTV_IRQ_ENC_DMA_COMPLETE (0x1 << 27) | ||
248 | #define IVTV_IRQ_DEC_AUD_MODE_CHG (0x1 << 24) | ||
249 | #define IVTV_IRQ_DEC_DATA_REQ (0x1 << 22) | ||
250 | #define IVTV_IRQ_DEC_DMA_COMPLETE (0x1 << 20) | ||
251 | #define IVTV_IRQ_DEC_VBI_RE_INSERT (0x1 << 19) | ||
252 | #define IVTV_IRQ_DMA_ERR (0x1 << 18) | ||
253 | #define IVTV_IRQ_DMA_WRITE (0x1 << 17) | ||
254 | #define IVTV_IRQ_DMA_READ (0x1 << 16) | ||
255 | #define IVTV_IRQ_DEC_VSYNC (0x1 << 10) | ||
256 | |||
257 | /* IRQ Masks */ | ||
258 | #define IVTV_IRQ_MASK_INIT (IVTV_IRQ_DMA_ERR|IVTV_IRQ_ENC_DMA_COMPLETE|IVTV_IRQ_DMA_READ) | ||
259 | |||
260 | #define IVTV_IRQ_MASK_CAPTURE (IVTV_IRQ_ENC_START_CAP | IVTV_IRQ_ENC_EOS) | ||
261 | #define IVTV_IRQ_MASK_DECODE (IVTV_IRQ_DEC_DATA_REQ|IVTV_IRQ_DEC_AUD_MODE_CHG) | ||
262 | |||
263 | /* i2c stuff */ | ||
264 | #define I2C_CLIENTS_MAX 16 | ||
265 | |||
266 | /* debugging */ | ||
267 | |||
268 | #define IVTV_DBGFLG_WARN (1 << 0) | ||
269 | #define IVTV_DBGFLG_INFO (1 << 1) | ||
270 | #define IVTV_DBGFLG_API (1 << 2) | ||
271 | #define IVTV_DBGFLG_DMA (1 << 3) | ||
272 | #define IVTV_DBGFLG_IOCTL (1 << 4) | ||
273 | #define IVTV_DBGFLG_I2C (1 << 5) | ||
274 | #define IVTV_DBGFLG_IRQ (1 << 6) | ||
275 | #define IVTV_DBGFLG_DEC (1 << 7) | ||
276 | #define IVTV_DBGFLG_YUV (1 << 8) | ||
277 | |||
278 | /* NOTE: extra space before comma in 'itv->num , ## args' is required for | ||
279 | gcc-2.95, otherwise it won't compile. */ | ||
280 | #define IVTV_DEBUG(x, type, fmt, args...) \ | ||
281 | do { \ | ||
282 | if ((x) & ivtv_debug) \ | ||
283 | printk(KERN_INFO "ivtv%d " type ": " fmt, itv->num , ## args); \ | ||
284 | } while (0) | ||
285 | #define IVTV_DEBUG_WARN(fmt, args...) IVTV_DEBUG(IVTV_DBGFLG_WARN, "warning", fmt , ## args) | ||
286 | #define IVTV_DEBUG_INFO(fmt, args...) IVTV_DEBUG(IVTV_DBGFLG_INFO, "info",fmt , ## args) | ||
287 | #define IVTV_DEBUG_API(fmt, args...) IVTV_DEBUG(IVTV_DBGFLG_API, "api", fmt , ## args) | ||
288 | #define IVTV_DEBUG_DMA(fmt, args...) IVTV_DEBUG(IVTV_DBGFLG_DMA, "dma", fmt , ## args) | ||
289 | #define IVTV_DEBUG_IOCTL(fmt, args...) IVTV_DEBUG(IVTV_DBGFLG_IOCTL, "ioctl", fmt , ## args) | ||
290 | #define IVTV_DEBUG_I2C(fmt, args...) IVTV_DEBUG(IVTV_DBGFLG_I2C, "i2c", fmt , ## args) | ||
291 | #define IVTV_DEBUG_IRQ(fmt, args...) IVTV_DEBUG(IVTV_DBGFLG_IRQ, "irq", fmt , ## args) | ||
292 | #define IVTV_DEBUG_DEC(fmt, args...) IVTV_DEBUG(IVTV_DBGFLG_DEC, "dec", fmt , ## args) | ||
293 | #define IVTV_DEBUG_YUV(fmt, args...) IVTV_DEBUG(IVTV_DBGFLG_YUV, "yuv", fmt , ## args) | ||
294 | |||
295 | #define IVTV_FB_DEBUG(x, type, fmt, args...) \ | ||
296 | do { \ | ||
297 | if ((x) & ivtv_debug) \ | ||
298 | printk(KERN_INFO "ivtv%d-fb " type ": " fmt, itv->num , ## args); \ | ||
299 | } while (0) | ||
300 | #define IVTV_FB_DEBUG_WARN(fmt, args...) IVTV_FB_DEBUG(IVTV_DBGFLG_WARN, "warning", fmt , ## args) | ||
301 | #define IVTV_FB_DEBUG_INFO(fmt, args...) IVTV_FB_DEBUG(IVTV_DBGFLG_INFO, "info", fmt , ## args) | ||
302 | #define IVTV_FB_DEBUG_API(fmt, args...) IVTV_FB_DEBUG(IVTV_DBGFLG_API, "api", fmt , ## args) | ||
303 | #define IVTV_FB_DEBUG_DMA(fmt, args...) IVTV_FB_DEBUG(IVTV_DBGFLG_DMA, "dma", fmt , ## args) | ||
304 | #define IVTV_FB_DEBUG_IOCTL(fmt, args...) IVTV_FB_DEBUG(IVTV_DBGFLG_IOCTL, "ioctl", fmt , ## args) | ||
305 | #define IVTV_FB_DEBUG_I2C(fmt, args...) IVTV_FB_DEBUG(IVTV_DBGFLG_I2C, "i2c", fmt , ## args) | ||
306 | #define IVTV_FB_DEBUG_IRQ(fmt, args...) IVTV_FB_DEBUG(IVTV_DBGFLG_IRQ, "irq", fmt , ## args) | ||
307 | #define IVTV_FB_DEBUG_DEC(fmt, args...) IVTV_FB_DEBUG(IVTV_DBGFLG_DEC, "dec", fmt , ## args) | ||
308 | #define IVTV_FB_DEBUG_YUV(fmt, args...) IVTV_FB_DEBUG(IVTV_DBGFLG_YUV, "yuv", fmt , ## args) | ||
309 | |||
310 | /* Standard kernel messages */ | ||
311 | #define IVTV_ERR(fmt, args...) printk(KERN_ERR "ivtv%d: " fmt, itv->num , ## args) | ||
312 | #define IVTV_WARN(fmt, args...) printk(KERN_WARNING "ivtv%d: " fmt, itv->num , ## args) | ||
313 | #define IVTV_INFO(fmt, args...) printk(KERN_INFO "ivtv%d: " fmt, itv->num , ## args) | ||
314 | #define IVTV_FB_ERR(fmt, args...) printk(KERN_ERR "ivtv%d-fb: " fmt, itv->num , ## args) | ||
315 | #define IVTV_FB_WARN(fmt, args...) printk(KERN_WARNING "ivtv%d-fb: " fmt, itv->num , ## args) | ||
316 | #define IVTV_FB_INFO(fmt, args...) printk(KERN_INFO "ivtv%d-fb: " fmt, itv->num , ## args) | ||
317 | |||
318 | /* Values for IVTV_API_DEC_PLAYBACK_SPEED mpeg_frame_type_mask parameter: */ | ||
319 | #define MPEG_FRAME_TYPE_IFRAME 1 | ||
320 | #define MPEG_FRAME_TYPE_IFRAME_PFRAME 3 | ||
321 | #define MPEG_FRAME_TYPE_ALL 7 | ||
322 | |||
323 | /* output modes (cx23415 only) */ | ||
324 | #define OUT_NONE 0 | ||
325 | #define OUT_MPG 1 | ||
326 | #define OUT_YUV 2 | ||
327 | #define OUT_UDMA_YUV 3 | ||
328 | #define OUT_PASSTHROUGH 4 | ||
329 | |||
330 | #define IVTV_MAX_PGM_INDEX (400) | ||
331 | |||
332 | extern int ivtv_debug; | ||
333 | |||
334 | |||
335 | struct ivtv_options { | ||
336 | int megabytes[IVTV_MAX_STREAMS]; /* Size in megabytes of each stream */ | ||
337 | int cardtype; /* force card type on load */ | ||
338 | int tuner; /* set tuner on load */ | ||
339 | int radio; /* enable/disable radio */ | ||
340 | int newi2c; /* New I2C algorithm */ | ||
341 | }; | ||
342 | |||
343 | #define IVTV_MBOX_DMA_START 6 | ||
344 | #define IVTV_MBOX_DMA_END 8 | ||
345 | #define IVTV_MBOX_DMA 9 | ||
346 | #define IVTV_MBOX_FIELD_DISPLAYED 8 | ||
347 | |||
348 | /* ivtv-specific mailbox template */ | ||
349 | struct ivtv_mailbox { | ||
350 | u32 flags; | ||
351 | u32 cmd; | ||
352 | u32 retval; | ||
353 | u32 timeout; | ||
354 | u32 data[CX2341X_MBOX_MAX_DATA]; | ||
355 | }; | ||
356 | |||
357 | struct ivtv_api_cache { | ||
358 | unsigned long last_jiffies; /* when last command was issued */ | ||
359 | u32 data[CX2341X_MBOX_MAX_DATA]; /* last sent api data */ | ||
360 | }; | ||
361 | |||
362 | struct ivtv_mailbox_data { | ||
363 | volatile struct ivtv_mailbox __iomem *mbox; | ||
364 | /* Bits 0-2 are for the encoder mailboxes, 0-1 are for the decoder mailboxes. | ||
365 | If the bit is set, then the corresponding mailbox is in use by the driver. */ | ||
366 | unsigned long busy; | ||
367 | u8 max_mbox; | ||
368 | }; | ||
369 | |||
370 | /* per-buffer bit flags */ | ||
371 | #define IVTV_F_B_NEED_BUF_SWAP 0 /* this buffer should be byte swapped */ | ||
372 | |||
373 | /* per-stream, s_flags */ | ||
374 | #define IVTV_F_S_DMA_PENDING 0 /* this stream has pending DMA */ | ||
375 | #define IVTV_F_S_DMA_HAS_VBI 1 /* the current DMA request also requests VBI data */ | ||
376 | #define IVTV_F_S_NEEDS_DATA 2 /* this decoding stream needs more data */ | ||
377 | |||
378 | #define IVTV_F_S_CLAIMED 3 /* this stream is claimed */ | ||
379 | #define IVTV_F_S_STREAMING 4 /* the fw is decoding/encoding this stream */ | ||
380 | #define IVTV_F_S_INTERNAL_USE 5 /* this stream is used internally (sliced VBI processing) */ | ||
381 | #define IVTV_F_S_PASSTHROUGH 6 /* this stream is in passthrough mode */ | ||
382 | #define IVTV_F_S_STREAMOFF 7 /* signal end of stream EOS */ | ||
383 | #define IVTV_F_S_APPL_IO 8 /* this stream is used read/written by an application */ | ||
384 | |||
385 | /* per-ivtv, i_flags */ | ||
386 | #define IVTV_F_I_DMA 0 /* DMA in progress */ | ||
387 | #define IVTV_F_I_UDMA 1 /* UDMA in progress */ | ||
388 | #define IVTV_F_I_UDMA_PENDING 2 /* UDMA pending */ | ||
389 | #define IVTV_F_I_SPEED_CHANGE 3 /* A speed change is in progress */ | ||
390 | #define IVTV_F_I_EOS 4 /* End of encoder stream reached */ | ||
391 | #define IVTV_F_I_RADIO_USER 5 /* The radio tuner is selected */ | ||
392 | #define IVTV_F_I_DIG_RST 6 /* Reset digitizer */ | ||
393 | #define IVTV_F_I_DEC_YUV 7 /* YUV instead of MPG is being decoded */ | ||
394 | #define IVTV_F_I_ENC_VBI 8 /* VBI DMA */ | ||
395 | #define IVTV_F_I_UPDATE_CC 9 /* CC should be updated */ | ||
396 | #define IVTV_F_I_UPDATE_WSS 10 /* WSS should be updated */ | ||
397 | #define IVTV_F_I_UPDATE_VPS 11 /* VPS should be updated */ | ||
398 | #define IVTV_F_I_DECODING_YUV 12 /* this stream is YUV frame decoding */ | ||
399 | #define IVTV_F_I_ENC_PAUSED 13 /* the encoder is paused */ | ||
400 | #define IVTV_F_I_VALID_DEC_TIMINGS 14 /* last_dec_timing is valid */ | ||
401 | #define IVTV_F_I_WORK_HANDLER_VBI 15 /* there is work to be done for VBI */ | ||
402 | #define IVTV_F_I_WORK_HANDLER_YUV 16 /* there is work to be done for YUV */ | ||
403 | |||
404 | /* Event notifications */ | ||
405 | #define IVTV_F_I_EV_DEC_STOPPED 28 /* decoder stopped event */ | ||
406 | #define IVTV_F_I_EV_VSYNC 29 /* VSYNC event */ | ||
407 | #define IVTV_F_I_EV_VSYNC_FIELD 30 /* VSYNC event field (0 = first, 1 = second field) */ | ||
408 | #define IVTV_F_I_EV_VSYNC_ENABLED 31 /* VSYNC event enabled */ | ||
409 | |||
410 | /* Scatter-Gather array element, used in DMA transfers */ | ||
411 | struct ivtv_SG_element { | ||
412 | u32 src; | ||
413 | u32 dst; | ||
414 | u32 size; | ||
415 | }; | ||
416 | |||
417 | struct ivtv_user_dma { | ||
418 | struct mutex lock; | ||
419 | int page_count; | ||
420 | struct page *map[IVTV_DMA_SG_OSD_ENT]; | ||
421 | |||
422 | /* Base Dev SG Array for cx23415/6 */ | ||
423 | struct ivtv_SG_element SGarray[IVTV_DMA_SG_OSD_ENT]; | ||
424 | dma_addr_t SG_handle; | ||
425 | int SG_length; | ||
426 | |||
427 | /* SG List of Buffers */ | ||
428 | struct scatterlist SGlist[IVTV_DMA_SG_OSD_ENT]; | ||
429 | }; | ||
430 | |||
431 | struct ivtv_dma_page_info { | ||
432 | unsigned long uaddr; | ||
433 | unsigned long first; | ||
434 | unsigned long last; | ||
435 | unsigned int offset; | ||
436 | unsigned int tail; | ||
437 | int page_count; | ||
438 | }; | ||
439 | |||
440 | struct ivtv_buffer { | ||
441 | struct list_head list; | ||
442 | dma_addr_t dma_handle; | ||
443 | unsigned long b_flags; | ||
444 | char *buf; | ||
445 | |||
446 | u32 bytesused; | ||
447 | u32 readpos; | ||
448 | }; | ||
449 | |||
450 | struct ivtv_queue { | ||
451 | struct list_head list; | ||
452 | u32 buffers; | ||
453 | u32 length; | ||
454 | u32 bytesused; | ||
455 | }; | ||
456 | |||
457 | struct ivtv; /* forward reference */ | ||
458 | |||
459 | struct ivtv_stream { | ||
460 | /* These first four fields are always set, even if the stream | ||
461 | is not actually created. */ | ||
462 | struct video_device *v4l2dev; /* NULL when stream not created */ | ||
463 | struct ivtv *itv; /* for ease of use */ | ||
464 | const char *name; /* name of the stream */ | ||
465 | int type; /* stream type */ | ||
466 | |||
467 | u32 id; | ||
468 | spinlock_t qlock; /* locks access to the queues */ | ||
469 | unsigned long s_flags; /* status flags, see above */ | ||
470 | int dma; /* can be PCI_DMA_TODEVICE, | ||
471 | PCI_DMA_FROMDEVICE or | ||
472 | PCI_DMA_NONE */ | ||
473 | u32 dma_offset; | ||
474 | u32 dma_backup; | ||
475 | u64 dma_pts; | ||
476 | |||
477 | int subtype; | ||
478 | wait_queue_head_t waitq; | ||
479 | u32 dma_last_offset; | ||
480 | |||
481 | /* Buffer Stats */ | ||
482 | u32 buffers; | ||
483 | u32 buf_size; | ||
484 | u32 buffers_stolen; | ||
485 | |||
486 | /* Buffer Queues */ | ||
487 | struct ivtv_queue q_free; /* free buffers */ | ||
488 | struct ivtv_queue q_full; /* full buffers */ | ||
489 | struct ivtv_queue q_io; /* waiting for I/O */ | ||
490 | struct ivtv_queue q_dma; /* waiting for DMA */ | ||
491 | struct ivtv_queue q_predma; /* waiting for DMA */ | ||
492 | |||
493 | /* Base Dev SG Array for cx23415/6 */ | ||
494 | struct ivtv_SG_element *SGarray; | ||
495 | dma_addr_t SG_handle; | ||
496 | int SG_length; | ||
497 | |||
498 | /* SG List of Buffers */ | ||
499 | struct scatterlist *SGlist; | ||
500 | }; | ||
501 | |||
502 | struct ivtv_open_id { | ||
503 | u32 open_id; | ||
504 | int type; | ||
505 | enum v4l2_priority prio; | ||
506 | struct ivtv *itv; | ||
507 | }; | ||
508 | |||
509 | #define IVTV_YUV_UPDATE_HORIZONTAL 0x01 | ||
510 | #define IVTV_YUV_UPDATE_VERTICAL 0x02 | ||
511 | |||
512 | struct yuv_frame_info | ||
513 | { | ||
514 | u32 update; | ||
515 | int src_x; | ||
516 | int src_y; | ||
517 | unsigned int src_w; | ||
518 | unsigned int src_h; | ||
519 | int dst_x; | ||
520 | int dst_y; | ||
521 | unsigned int dst_w; | ||
522 | unsigned int dst_h; | ||
523 | int pan_x; | ||
524 | int pan_y; | ||
525 | u32 vis_w; | ||
526 | u32 vis_h; | ||
527 | u32 interlaced_y; | ||
528 | u32 interlaced_uv; | ||
529 | int tru_x; | ||
530 | u32 tru_w; | ||
531 | u32 tru_h; | ||
532 | u32 offset_y; | ||
533 | }; | ||
534 | |||
535 | #define IVTV_YUV_MODE_INTERLACED 0x00 | ||
536 | #define IVTV_YUV_MODE_PROGRESSIVE 0x01 | ||
537 | #define IVTV_YUV_MODE_AUTO 0x02 | ||
538 | #define IVTV_YUV_MODE_MASK 0x03 | ||
539 | |||
540 | #define IVTV_YUV_SYNC_EVEN 0x00 | ||
541 | #define IVTV_YUV_SYNC_ODD 0x04 | ||
542 | #define IVTV_YUV_SYNC_MASK 0x04 | ||
543 | |||
544 | struct yuv_playback_info | ||
545 | { | ||
546 | u32 reg_2834; | ||
547 | u32 reg_2838; | ||
548 | u32 reg_283c; | ||
549 | u32 reg_2840; | ||
550 | u32 reg_2844; | ||
551 | u32 reg_2848; | ||
552 | u32 reg_2854; | ||
553 | u32 reg_285c; | ||
554 | u32 reg_2864; | ||
555 | |||
556 | u32 reg_2870; | ||
557 | u32 reg_2874; | ||
558 | u32 reg_2890; | ||
559 | u32 reg_2898; | ||
560 | u32 reg_289c; | ||
561 | |||
562 | u32 reg_2918; | ||
563 | u32 reg_291c; | ||
564 | u32 reg_2920; | ||
565 | u32 reg_2924; | ||
566 | u32 reg_2928; | ||
567 | u32 reg_292c; | ||
568 | u32 reg_2930; | ||
569 | |||
570 | u32 reg_2934; | ||
571 | |||
572 | u32 reg_2938; | ||
573 | u32 reg_293c; | ||
574 | u32 reg_2940; | ||
575 | u32 reg_2944; | ||
576 | u32 reg_2948; | ||
577 | u32 reg_294c; | ||
578 | u32 reg_2950; | ||
579 | u32 reg_2954; | ||
580 | u32 reg_2958; | ||
581 | u32 reg_295c; | ||
582 | u32 reg_2960; | ||
583 | u32 reg_2964; | ||
584 | u32 reg_2968; | ||
585 | u32 reg_296c; | ||
586 | |||
587 | u32 reg_2970; | ||
588 | |||
589 | int v_filter_1; | ||
590 | int v_filter_2; | ||
591 | int h_filter; | ||
592 | |||
593 | u32 osd_x_offset; | ||
594 | u32 osd_y_offset; | ||
595 | |||
596 | u32 osd_x_pan; | ||
597 | u32 osd_y_pan; | ||
598 | |||
599 | u32 osd_vis_w; | ||
600 | u32 osd_vis_h; | ||
601 | |||
602 | int decode_height; | ||
603 | |||
604 | int frame_interlaced; | ||
605 | int frame_interlaced_last; | ||
606 | |||
607 | int lace_mode; | ||
608 | int lace_threshold; | ||
609 | int lace_sync_field; | ||
610 | |||
611 | atomic_t next_dma_frame; | ||
612 | atomic_t next_fill_frame; | ||
613 | |||
614 | u32 yuv_forced_update; | ||
615 | int update_frame; | ||
616 | struct yuv_frame_info new_frame_info[4]; | ||
617 | struct yuv_frame_info old_frame_info; | ||
618 | struct yuv_frame_info old_frame_info_args; | ||
619 | |||
620 | void *blanking_ptr; | ||
621 | dma_addr_t blanking_dmaptr; | ||
622 | }; | ||
623 | |||
624 | #define IVTV_VBI_FRAMES 32 | ||
625 | |||
626 | /* VBI data */ | ||
627 | struct vbi_info { | ||
628 | u32 dec_start; | ||
629 | u32 enc_start, enc_size; | ||
630 | int fpi; | ||
631 | u32 frame; | ||
632 | u32 dma_offset; | ||
633 | u8 cc_data_odd[256]; | ||
634 | u8 cc_data_even[256]; | ||
635 | int cc_pos; | ||
636 | u8 cc_no_update; | ||
637 | u8 vps[5]; | ||
638 | u8 vps_found; | ||
639 | int wss; | ||
640 | u8 wss_found; | ||
641 | u8 wss_no_update; | ||
642 | u32 raw_decoder_line_size; | ||
643 | u8 raw_decoder_sav_odd_field; | ||
644 | u8 raw_decoder_sav_even_field; | ||
645 | u32 sliced_decoder_line_size; | ||
646 | u8 sliced_decoder_sav_odd_field; | ||
647 | u8 sliced_decoder_sav_even_field; | ||
648 | struct v4l2_format in; | ||
649 | /* convenience pointer to sliced struct in vbi_in union */ | ||
650 | struct v4l2_sliced_vbi_format *sliced_in; | ||
651 | u32 service_set_in; | ||
652 | u32 service_set_out; | ||
653 | int insert_mpeg; | ||
654 | |||
655 | /* Buffer for the maximum of 2 * 18 * packet_size sliced VBI lines. | ||
656 | One for /dev/vbi0 and one for /dev/vbi8 */ | ||
657 | struct v4l2_sliced_vbi_data sliced_data[36]; | ||
658 | struct v4l2_sliced_vbi_data sliced_dec_data[36]; | ||
659 | |||
660 | /* Buffer for VBI data inserted into MPEG stream. | ||
661 | The first byte is a dummy byte that's never used. | ||
662 | The next 16 bytes contain the MPEG header for the VBI data, | ||
663 | the remainder is the actual VBI data. | ||
664 | The max size accepted by the MPEG VBI reinsertion turns out | ||
665 | to be 1552 bytes, which happens to be 4 + (1 + 42) * (2 * 18) bytes, | ||
666 | where 4 is a four byte header, 42 is the max sliced VBI payload, 1 is | ||
667 | a single line header byte and 2 * 18 is the number of VBI lines per frame. | ||
668 | |||
669 | However, it seems that the data must be 1K aligned, so we have to | ||
670 | pad the data until the 1 or 2 K boundary. | ||
671 | |||
672 | This pointer array will allocate 2049 bytes to store each VBI frame. */ | ||
673 | u8 *sliced_mpeg_data[IVTV_VBI_FRAMES]; | ||
674 | u32 sliced_mpeg_size[IVTV_VBI_FRAMES]; | ||
675 | struct ivtv_buffer sliced_mpeg_buf; | ||
676 | u32 inserted_frame; | ||
677 | |||
678 | u32 start[2], count; | ||
679 | u32 raw_size; | ||
680 | u32 sliced_size; | ||
681 | }; | ||
682 | |||
683 | /* forward declaration of struct defined in ivtv-cards.h */ | ||
684 | struct ivtv_card; | ||
685 | |||
686 | /* Struct to hold info about ivtv cards */ | ||
687 | struct ivtv { | ||
688 | int num; /* board number, -1 during init! */ | ||
689 | char name[8]; /* board name for printk and interrupts (e.g. 'ivtv0') */ | ||
690 | struct pci_dev *dev; /* PCI device */ | ||
691 | const struct ivtv_card *card; /* card information */ | ||
692 | const char *card_name; /* full name of the card */ | ||
693 | u8 has_cx23415; /* 1 if it is a cx23415 based card, 0 for cx23416 */ | ||
694 | u8 is_50hz; | ||
695 | u8 is_60hz; | ||
696 | u8 is_out_50hz; | ||
697 | u8 is_out_60hz; | ||
698 | u8 pvr150_workaround; /* 1 if the cx25840 needs to workaround a PVR150 bug */ | ||
699 | u8 nof_inputs; /* number of video inputs */ | ||
700 | u8 nof_audio_inputs; /* number of audio inputs */ | ||
701 | u32 v4l2_cap; /* V4L2 capabilities of card */ | ||
702 | u32 hw_flags; /* Hardware description of the board */ | ||
703 | |||
704 | /* controlling Video decoder function */ | ||
705 | int (*video_dec_func)(struct ivtv *, unsigned int, void *); | ||
706 | |||
707 | struct ivtv_options options; /* User options */ | ||
708 | int stream_buf_size[IVTV_MAX_STREAMS]; /* Stream buffer size */ | ||
709 | struct ivtv_stream streams[IVTV_MAX_STREAMS]; /* Stream data */ | ||
710 | int speed; | ||
711 | u8 speed_mute_audio; | ||
712 | unsigned long i_flags; /* global ivtv flags */ | ||
713 | atomic_t capturing; /* count number of active capture streams */ | ||
714 | atomic_t decoding; /* count number of active decoding streams */ | ||
715 | u32 irq_rr_idx; /* Round-robin stream index */ | ||
716 | int cur_dma_stream; /* index of stream doing DMA */ | ||
717 | u32 dma_data_req_offset; | ||
718 | u32 dma_data_req_size; | ||
719 | int output_mode; /* NONE, MPG, YUV, UDMA YUV, passthrough */ | ||
720 | spinlock_t lock; /* lock access to this struct */ | ||
721 | int search_pack_header; | ||
722 | |||
723 | spinlock_t dma_reg_lock; /* lock access to DMA engine registers */ | ||
724 | |||
725 | /* User based DMA for OSD */ | ||
726 | struct ivtv_user_dma udma; | ||
727 | |||
728 | int open_id; /* incremented each time an open occurs, used as unique ID. | ||
729 | starts at 1, so 0 can be used as uninitialized value | ||
730 | in the stream->id. */ | ||
731 | |||
732 | u32 base_addr; | ||
733 | u32 irqmask; | ||
734 | |||
735 | struct v4l2_prio_state prio; | ||
736 | struct workqueue_struct *irq_work_queues; | ||
737 | struct work_struct irq_work_queue; | ||
738 | struct timer_list dma_timer; /* Timer used to catch unfinished DMAs */ | ||
739 | |||
740 | struct vbi_info vbi; | ||
741 | |||
742 | struct ivtv_mailbox_data enc_mbox; | ||
743 | struct ivtv_mailbox_data dec_mbox; | ||
744 | struct ivtv_api_cache api_cache[256]; /* Cached API Commands */ | ||
745 | |||
746 | u8 card_rev; | ||
747 | volatile void __iomem *enc_mem, *dec_mem, *reg_mem; | ||
748 | |||
749 | u32 pgm_info_offset; | ||
750 | u32 pgm_info_num; | ||
751 | u32 pgm_info_write_idx; | ||
752 | u32 pgm_info_read_idx; | ||
753 | struct v4l2_enc_idx_entry pgm_info[IVTV_MAX_PGM_INDEX]; | ||
754 | |||
755 | u64 mpg_data_received; | ||
756 | u64 vbi_data_inserted; | ||
757 | |||
758 | wait_queue_head_t cap_w; | ||
759 | /* when the next decoder event arrives this queue is woken up */ | ||
760 | wait_queue_head_t event_waitq; | ||
761 | /* when the next decoder vsync arrives this queue is woken up */ | ||
762 | wait_queue_head_t vsync_waitq; | ||
763 | /* when the current DMA is finished this queue is woken up */ | ||
764 | wait_queue_head_t dma_waitq; | ||
765 | |||
766 | /* OSD support */ | ||
767 | unsigned long osd_video_pbase; | ||
768 | int osd_global_alpha_state; /* 0=off : 1=on */ | ||
769 | int osd_local_alpha_state; /* 0=off : 1=on */ | ||
770 | int osd_color_key_state; /* 0=off : 1=on */ | ||
771 | u8 osd_global_alpha; /* Current global alpha */ | ||
772 | u32 osd_color_key; /* Current color key */ | ||
773 | u32 osd_pixelformat; /* Current pixel format */ | ||
774 | struct v4l2_rect osd_rect; /* Current OSD position and size */ | ||
775 | struct v4l2_rect main_rect; /* Current Main window position and size */ | ||
776 | |||
777 | u32 last_dec_timing[3]; /* Store last retrieved pts/scr/frame values */ | ||
778 | |||
779 | /* i2c */ | ||
780 | struct i2c_adapter i2c_adap; | ||
781 | struct i2c_algo_bit_data i2c_algo; | ||
782 | struct i2c_client i2c_client; | ||
783 | struct mutex i2c_bus_lock; | ||
784 | int i2c_state; | ||
785 | struct i2c_client *i2c_clients[I2C_CLIENTS_MAX]; | ||
786 | |||
787 | /* v4l2 and User settings */ | ||
788 | |||
789 | /* codec settings */ | ||
790 | struct cx2341x_mpeg_params params; | ||
791 | u32 audio_input; | ||
792 | u32 active_input; | ||
793 | u32 active_output; | ||
794 | v4l2_std_id std; | ||
795 | v4l2_std_id std_out; | ||
796 | v4l2_std_id tuner_std; /* The norm of the tuner (fixed) */ | ||
797 | u8 audio_stereo_mode; | ||
798 | u8 audio_bilingual_mode; | ||
799 | |||
800 | /* dualwatch */ | ||
801 | unsigned long dualwatch_jiffies; | ||
802 | u16 dualwatch_stereo_mode; | ||
803 | |||
804 | /* Digitizer type */ | ||
805 | int digitizer; /* 0x00EF = saa7114 0x00FO = saa7115 0x0106 = mic */ | ||
806 | |||
807 | u32 lastVsyncFrame; | ||
808 | |||
809 | struct yuv_playback_info yuv_info; | ||
810 | struct osd_info *osd_info; | ||
811 | }; | ||
812 | |||
813 | /* Globals */ | ||
814 | extern struct ivtv *ivtv_cards[]; | ||
815 | extern int ivtv_cards_active; | ||
816 | extern int ivtv_first_minor; | ||
817 | extern spinlock_t ivtv_cards_lock; | ||
818 | |||
819 | /*==============Prototypes==================*/ | ||
820 | |||
821 | /* Hardware/IRQ */ | ||
822 | void ivtv_set_irq_mask(struct ivtv *itv, u32 mask); | ||
823 | void ivtv_clear_irq_mask(struct ivtv *itv, u32 mask); | ||
824 | |||
825 | /* try to set output mode, return current mode. */ | ||
826 | int ivtv_set_output_mode(struct ivtv *itv, int mode); | ||
827 | |||
828 | /* return current output stream based on current mode */ | ||
829 | struct ivtv_stream *ivtv_get_output_stream(struct ivtv *itv); | ||
830 | |||
831 | /* Return non-zero if a signal is pending */ | ||
832 | int ivtv_sleep_timeout(int timeout, int intr); | ||
833 | |||
834 | /* Wait on queue, returns -EINTR if interrupted */ | ||
835 | int ivtv_waitq(wait_queue_head_t *waitq); | ||
836 | |||
837 | /* Read Hauppauge eeprom */ | ||
838 | struct tveeprom; /* forward reference */ | ||
839 | void ivtv_read_eeprom(struct ivtv *itv, struct tveeprom *tv); | ||
840 | |||
841 | /* This is a PCI post thing, where if the pci register is not read, then | ||
842 | the write doesn't always take effect right away. By reading back the | ||
843 | register any pending PCI writes will be performed (in order), and so | ||
844 | you can be sure that the writes are guaranteed to be done. | ||
845 | |||
846 | Rarely needed, only in some timing sensitive cases. | ||
847 | Apparently if this is not done some motherboards seem | ||
848 | to kill the firmware and get into the broken state until computer is | ||
849 | rebooted. */ | ||
850 | #define write_sync(val, reg) \ | ||
851 | do { writel(val, reg); readl(reg); } while (0) | ||
852 | |||
853 | #define read_reg(reg) readl(itv->reg_mem + (reg)) | ||
854 | #define write_reg(val, reg) writel(val, itv->reg_mem + (reg)) | ||
855 | #define write_reg_sync(val, reg) \ | ||
856 | do { write_reg(val, reg); read_reg(reg); } while (0) | ||
857 | |||
858 | #define read_enc(addr) readl(itv->enc_mem + (u32)(addr)) | ||
859 | #define write_enc(val, addr) writel(val, itv->enc_mem + (u32)(addr)) | ||
860 | #define write_enc_sync(val, addr) \ | ||
861 | do { write_enc(val, addr); read_enc(addr); } while (0) | ||
862 | |||
863 | #define read_dec(addr) readl(itv->dec_mem + (u32)(addr)) | ||
864 | #define write_dec(val, addr) writel(val, itv->dec_mem + (u32)(addr)) | ||
865 | #define write_dec_sync(val, addr) \ | ||
866 | do { write_dec(val, addr); read_dec(addr); } while (0) | ||
867 | |||
868 | #endif /* IVTV_DRIVER_H */ | ||
diff --git a/drivers/media/video/ivtv/ivtv-fileops.c b/drivers/media/video/ivtv/ivtv-fileops.c new file mode 100644 index 000000000000..1637097ddec7 --- /dev/null +++ b/drivers/media/video/ivtv/ivtv-fileops.c | |||
@@ -0,0 +1,921 @@ | |||
1 | /* | ||
2 | file operation functions | ||
3 | Copyright (C) 2003-2004 Kevin Thayer <nufan_wfk at yahoo.com> | ||
4 | Copyright (C) 2004 Chris Kennedy <c@groovy.org> | ||
5 | Copyright (C) 2005-2007 Hans Verkuil <hverkuil@xs4all.nl> | ||
6 | |||
7 | This program is free software; you can redistribute it and/or modify | ||
8 | it under the terms of the GNU General Public License as published by | ||
9 | the Free Software Foundation; either version 2 of the License, or | ||
10 | (at your option) any later version. | ||
11 | |||
12 | This program is distributed in the hope that it will be useful, | ||
13 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
15 | GNU General Public License for more details. | ||
16 | |||
17 | You should have received a copy of the GNU General Public License | ||
18 | along with this program; if not, write to the Free Software | ||
19 | Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
20 | */ | ||
21 | |||
22 | #include "ivtv-driver.h" | ||
23 | #include "ivtv-fileops.h" | ||
24 | #include "ivtv-i2c.h" | ||
25 | #include "ivtv-queue.h" | ||
26 | #include "ivtv-udma.h" | ||
27 | #include "ivtv-irq.h" | ||
28 | #include "ivtv-vbi.h" | ||
29 | #include "ivtv-mailbox.h" | ||
30 | #include "ivtv-audio.h" | ||
31 | #include "ivtv-streams.h" | ||
32 | #include "ivtv-yuv.h" | ||
33 | #include "ivtv-controls.h" | ||
34 | #include "ivtv-ioctl.h" | ||
35 | |||
36 | /* This function tries to claim the stream for a specific file descriptor. | ||
37 | If no one else is using this stream then the stream is claimed and | ||
38 | associated VBI streams are also automatically claimed. | ||
39 | Possible error returns: -EBUSY if someone else has claimed | ||
40 | the stream or 0 on success. */ | ||
41 | int ivtv_claim_stream(struct ivtv_open_id *id, int type) | ||
42 | { | ||
43 | struct ivtv *itv = id->itv; | ||
44 | struct ivtv_stream *s = &itv->streams[type]; | ||
45 | struct ivtv_stream *s_vbi; | ||
46 | int vbi_type; | ||
47 | |||
48 | if (test_and_set_bit(IVTV_F_S_CLAIMED, &s->s_flags)) { | ||
49 | /* someone already claimed this stream */ | ||
50 | if (s->id == id->open_id) { | ||
51 | /* yes, this file descriptor did. So that's OK. */ | ||
52 | return 0; | ||
53 | } | ||
54 | if (s->id == -1 && (type == IVTV_DEC_STREAM_TYPE_VBI || | ||
55 | type == IVTV_ENC_STREAM_TYPE_VBI)) { | ||
56 | /* VBI is handled already internally, now also assign | ||
57 | the file descriptor to this stream for external | ||
58 | reading of the stream. */ | ||
59 | s->id = id->open_id; | ||
60 | IVTV_DEBUG_INFO("Start Read VBI\n"); | ||
61 | return 0; | ||
62 | } | ||
63 | /* someone else is using this stream already */ | ||
64 | IVTV_DEBUG_INFO("Stream %d is busy\n", type); | ||
65 | return -EBUSY; | ||
66 | } | ||
67 | s->id = id->open_id; | ||
68 | if (type == IVTV_DEC_STREAM_TYPE_VBI) { | ||
69 | /* Enable reinsertion interrupt */ | ||
70 | ivtv_clear_irq_mask(itv, IVTV_IRQ_DEC_VBI_RE_INSERT); | ||
71 | } | ||
72 | |||
73 | /* IVTV_DEC_STREAM_TYPE_MPG needs to claim IVTV_DEC_STREAM_TYPE_VBI, | ||
74 | IVTV_ENC_STREAM_TYPE_MPG needs to claim IVTV_ENC_STREAM_TYPE_VBI | ||
75 | (provided VBI insertion is on and sliced VBI is selected), for all | ||
76 | other streams we're done */ | ||
77 | if (type == IVTV_DEC_STREAM_TYPE_MPG) { | ||
78 | vbi_type = IVTV_DEC_STREAM_TYPE_VBI; | ||
79 | } else if (type == IVTV_ENC_STREAM_TYPE_MPG && | ||
80 | itv->vbi.insert_mpeg && itv->vbi.sliced_in->service_set) { | ||
81 | vbi_type = IVTV_ENC_STREAM_TYPE_VBI; | ||
82 | } else { | ||
83 | return 0; | ||
84 | } | ||
85 | s_vbi = &itv->streams[vbi_type]; | ||
86 | |||
87 | if (!test_and_set_bit(IVTV_F_S_CLAIMED, &s_vbi->s_flags)) { | ||
88 | /* Enable reinsertion interrupt */ | ||
89 | if (vbi_type == IVTV_DEC_STREAM_TYPE_VBI) | ||
90 | ivtv_clear_irq_mask(itv, IVTV_IRQ_DEC_VBI_RE_INSERT); | ||
91 | } | ||
92 | /* mark that it is used internally */ | ||
93 | set_bit(IVTV_F_S_INTERNAL_USE, &s_vbi->s_flags); | ||
94 | return 0; | ||
95 | } | ||
96 | |||
97 | /* This function releases a previously claimed stream. It will take into | ||
98 | account associated VBI streams. */ | ||
99 | void ivtv_release_stream(struct ivtv_stream *s) | ||
100 | { | ||
101 | struct ivtv *itv = s->itv; | ||
102 | struct ivtv_stream *s_vbi; | ||
103 | |||
104 | s->id = -1; | ||
105 | if ((s->type == IVTV_DEC_STREAM_TYPE_VBI || s->type == IVTV_ENC_STREAM_TYPE_VBI) && | ||
106 | test_bit(IVTV_F_S_INTERNAL_USE, &s->s_flags)) { | ||
107 | /* this stream is still in use internally */ | ||
108 | return; | ||
109 | } | ||
110 | if (!test_and_clear_bit(IVTV_F_S_CLAIMED, &s->s_flags)) { | ||
111 | IVTV_DEBUG_WARN("Release stream %s not in use!\n", s->name); | ||
112 | return; | ||
113 | } | ||
114 | |||
115 | ivtv_flush_queues(s); | ||
116 | |||
117 | /* disable reinsertion interrupt */ | ||
118 | if (s->type == IVTV_DEC_STREAM_TYPE_VBI) | ||
119 | ivtv_set_irq_mask(itv, IVTV_IRQ_DEC_VBI_RE_INSERT); | ||
120 | |||
121 | /* IVTV_DEC_STREAM_TYPE_MPG needs to release IVTV_DEC_STREAM_TYPE_VBI, | ||
122 | IVTV_ENC_STREAM_TYPE_MPG needs to release IVTV_ENC_STREAM_TYPE_VBI, | ||
123 | for all other streams we're done */ | ||
124 | if (s->type == IVTV_DEC_STREAM_TYPE_MPG) | ||
125 | s_vbi = &itv->streams[IVTV_DEC_STREAM_TYPE_VBI]; | ||
126 | else if (s->type == IVTV_ENC_STREAM_TYPE_MPG) | ||
127 | s_vbi = &itv->streams[IVTV_ENC_STREAM_TYPE_VBI]; | ||
128 | else | ||
129 | return; | ||
130 | |||
131 | /* clear internal use flag */ | ||
132 | if (!test_and_clear_bit(IVTV_F_S_INTERNAL_USE, &s_vbi->s_flags)) { | ||
133 | /* was already cleared */ | ||
134 | return; | ||
135 | } | ||
136 | if (s_vbi->id != -1) { | ||
137 | /* VBI stream still claimed by a file descriptor */ | ||
138 | return; | ||
139 | } | ||
140 | /* disable reinsertion interrupt */ | ||
141 | if (s_vbi->type == IVTV_DEC_STREAM_TYPE_VBI) | ||
142 | ivtv_set_irq_mask(itv, IVTV_IRQ_DEC_VBI_RE_INSERT); | ||
143 | clear_bit(IVTV_F_S_CLAIMED, &s_vbi->s_flags); | ||
144 | ivtv_flush_queues(s_vbi); | ||
145 | } | ||
146 | |||
147 | static void ivtv_dualwatch(struct ivtv *itv) | ||
148 | { | ||
149 | struct v4l2_tuner vt; | ||
150 | u16 new_bitmap; | ||
151 | u16 new_stereo_mode; | ||
152 | const u16 stereo_mask = 0x0300; | ||
153 | const u16 dual = 0x0200; | ||
154 | |||
155 | new_stereo_mode = itv->params.audio_properties & stereo_mask; | ||
156 | memset(&vt, 0, sizeof(vt)); | ||
157 | ivtv_call_i2c_clients(itv, VIDIOC_G_TUNER, &vt); | ||
158 | if (vt.audmode == V4L2_TUNER_MODE_LANG1_LANG2 && (vt.rxsubchans & V4L2_TUNER_SUB_LANG2)) | ||
159 | new_stereo_mode = dual; | ||
160 | |||
161 | if (new_stereo_mode == itv->dualwatch_stereo_mode) | ||
162 | return; | ||
163 | |||
164 | new_bitmap = new_stereo_mode | (itv->params.audio_properties & ~stereo_mask); | ||
165 | |||
166 | IVTV_DEBUG_INFO("dualwatch: change stereo flag from 0x%x to 0x%x. new audio_bitmask=0x%ux\n", | ||
167 | itv->dualwatch_stereo_mode, new_stereo_mode, new_bitmap); | ||
168 | |||
169 | if (ivtv_vapi(itv, CX2341X_ENC_SET_AUDIO_PROPERTIES, 1, new_bitmap) == 0) { | ||
170 | itv->dualwatch_stereo_mode = new_stereo_mode; | ||
171 | return; | ||
172 | } | ||
173 | IVTV_DEBUG_INFO("dualwatch: changing stereo flag failed\n"); | ||
174 | } | ||
175 | |||
176 | static void ivtv_update_pgm_info(struct ivtv *itv) | ||
177 | { | ||
178 | u32 wr_idx = (read_enc(itv->pgm_info_offset) - itv->pgm_info_offset - 4) / 24; | ||
179 | int cnt; | ||
180 | int i = 0; | ||
181 | |||
182 | if (wr_idx >= itv->pgm_info_num) { | ||
183 | IVTV_DEBUG_WARN("Invalid PGM index %d (>= %d)\n", wr_idx, itv->pgm_info_num); | ||
184 | return; | ||
185 | } | ||
186 | cnt = (wr_idx + itv->pgm_info_num - itv->pgm_info_write_idx) % itv->pgm_info_num; | ||
187 | while (i < cnt) { | ||
188 | int idx = (itv->pgm_info_write_idx + i) % itv->pgm_info_num; | ||
189 | struct v4l2_enc_idx_entry *e = itv->pgm_info + idx; | ||
190 | u32 addr = itv->pgm_info_offset + 4 + idx * 24; | ||
191 | const int mapping[] = { V4L2_ENC_IDX_FRAME_P, V4L2_ENC_IDX_FRAME_I, V4L2_ENC_IDX_FRAME_B, 0 }; | ||
192 | |||
193 | e->offset = read_enc(addr + 4) + ((u64)read_enc(addr + 8) << 32); | ||
194 | if (e->offset > itv->mpg_data_received) { | ||
195 | break; | ||
196 | } | ||
197 | e->offset += itv->vbi_data_inserted; | ||
198 | e->length = read_enc(addr); | ||
199 | e->pts = read_enc(addr + 16) + ((u64)(read_enc(addr + 20) & 1) << 32); | ||
200 | e->flags = mapping[read_enc(addr + 12) & 3]; | ||
201 | i++; | ||
202 | } | ||
203 | itv->pgm_info_write_idx = (itv->pgm_info_write_idx + i) % itv->pgm_info_num; | ||
204 | } | ||
205 | |||
206 | static struct ivtv_buffer *ivtv_get_buffer(struct ivtv_stream *s, int non_block, int *err) | ||
207 | { | ||
208 | struct ivtv *itv = s->itv; | ||
209 | struct ivtv_stream *s_vbi = &itv->streams[IVTV_ENC_STREAM_TYPE_VBI]; | ||
210 | struct ivtv_buffer *buf; | ||
211 | DEFINE_WAIT(wait); | ||
212 | |||
213 | *err = 0; | ||
214 | while (1) { | ||
215 | if (s->type == IVTV_ENC_STREAM_TYPE_MPG) { | ||
216 | /* Process pending program info updates and pending VBI data */ | ||
217 | ivtv_update_pgm_info(itv); | ||
218 | |||
219 | if (jiffies - itv->dualwatch_jiffies > HZ) { | ||
220 | itv->dualwatch_jiffies = jiffies; | ||
221 | ivtv_dualwatch(itv); | ||
222 | } | ||
223 | |||
224 | if (test_bit(IVTV_F_S_INTERNAL_USE, &s_vbi->s_flags) && | ||
225 | !test_bit(IVTV_F_S_APPL_IO, &s_vbi->s_flags)) { | ||
226 | while ((buf = ivtv_dequeue(s_vbi, &s_vbi->q_full))) { | ||
227 | /* byteswap and process VBI data */ | ||
228 | ivtv_process_vbi_data(itv, buf, s_vbi->dma_pts, s_vbi->type); | ||
229 | ivtv_enqueue(s_vbi, buf, &s_vbi->q_free); | ||
230 | } | ||
231 | } | ||
232 | buf = &itv->vbi.sliced_mpeg_buf; | ||
233 | if (buf->readpos != buf->bytesused) { | ||
234 | return buf; | ||
235 | } | ||
236 | } | ||
237 | |||
238 | /* do we have leftover data? */ | ||
239 | buf = ivtv_dequeue(s, &s->q_io); | ||
240 | if (buf) | ||
241 | return buf; | ||
242 | |||
243 | /* do we have new data? */ | ||
244 | buf = ivtv_dequeue(s, &s->q_full); | ||
245 | if (buf) { | ||
246 | if (!test_and_clear_bit(IVTV_F_B_NEED_BUF_SWAP, &buf->b_flags)) | ||
247 | return buf; | ||
248 | if (s->type == IVTV_ENC_STREAM_TYPE_MPG) | ||
249 | /* byteswap MPG data */ | ||
250 | ivtv_buf_swap(buf); | ||
251 | else if (s->type != IVTV_DEC_STREAM_TYPE_VBI) { | ||
252 | /* byteswap and process VBI data */ | ||
253 | ivtv_process_vbi_data(itv, buf, s->dma_pts, s->type); | ||
254 | } | ||
255 | return buf; | ||
256 | } | ||
257 | /* return if file was opened with O_NONBLOCK */ | ||
258 | if (non_block) { | ||
259 | *err = -EAGAIN; | ||
260 | return NULL; | ||
261 | } | ||
262 | |||
263 | /* return if end of stream */ | ||
264 | if (s->type != IVTV_DEC_STREAM_TYPE_VBI && !test_bit(IVTV_F_S_STREAMING, &s->s_flags)) { | ||
265 | clear_bit(IVTV_F_S_STREAMOFF, &s->s_flags); | ||
266 | IVTV_DEBUG_INFO("EOS %s\n", s->name); | ||
267 | return NULL; | ||
268 | } | ||
269 | |||
270 | /* wait for more data to arrive */ | ||
271 | prepare_to_wait(&s->waitq, &wait, TASK_INTERRUPTIBLE); | ||
272 | /* New buffers might have become available before we were added to the waitqueue */ | ||
273 | if (!s->q_full.buffers) | ||
274 | schedule(); | ||
275 | finish_wait(&s->waitq, &wait); | ||
276 | if (signal_pending(current)) { | ||
277 | /* return if a signal was received */ | ||
278 | IVTV_DEBUG_INFO("User stopped %s\n", s->name); | ||
279 | *err = -EINTR; | ||
280 | return NULL; | ||
281 | } | ||
282 | } | ||
283 | } | ||
284 | |||
285 | static void ivtv_setup_sliced_vbi_buf(struct ivtv *itv) | ||
286 | { | ||
287 | int idx = itv->vbi.inserted_frame % IVTV_VBI_FRAMES; | ||
288 | |||
289 | itv->vbi.sliced_mpeg_buf.buf = itv->vbi.sliced_mpeg_data[idx]; | ||
290 | itv->vbi.sliced_mpeg_buf.bytesused = itv->vbi.sliced_mpeg_size[idx]; | ||
291 | itv->vbi.sliced_mpeg_buf.readpos = 0; | ||
292 | } | ||
293 | |||
294 | static size_t ivtv_copy_buf_to_user(struct ivtv_stream *s, struct ivtv_buffer *buf, | ||
295 | char __user *ubuf, size_t ucount) | ||
296 | { | ||
297 | struct ivtv *itv = s->itv; | ||
298 | size_t len = buf->bytesused - buf->readpos; | ||
299 | |||
300 | if (len > ucount) len = ucount; | ||
301 | if (itv->vbi.insert_mpeg && s->type == IVTV_ENC_STREAM_TYPE_MPG && | ||
302 | itv->vbi.sliced_in->service_set && buf != &itv->vbi.sliced_mpeg_buf) { | ||
303 | const char *start = buf->buf + buf->readpos; | ||
304 | const char *p = start + 1; | ||
305 | const u8 *q; | ||
306 | u8 ch = itv->search_pack_header ? 0xba : 0xe0; | ||
307 | int stuffing, i; | ||
308 | |||
309 | while (start + len > p && (q = memchr(p, 0, start + len - p))) { | ||
310 | p = q + 1; | ||
311 | if ((char *)q + 15 >= buf->buf + buf->bytesused || | ||
312 | q[1] != 0 || q[2] != 1 || q[3] != ch) { | ||
313 | continue; | ||
314 | } | ||
315 | if (!itv->search_pack_header) { | ||
316 | if ((q[6] & 0xc0) != 0x80) | ||
317 | continue; | ||
318 | if (((q[7] & 0xc0) == 0x80 && (q[9] & 0xf0) == 0x20) || | ||
319 | ((q[7] & 0xc0) == 0xc0 && (q[9] & 0xf0) == 0x30)) { | ||
320 | ch = 0xba; | ||
321 | itv->search_pack_header = 1; | ||
322 | p = q + 9; | ||
323 | } | ||
324 | continue; | ||
325 | } | ||
326 | stuffing = q[13] & 7; | ||
327 | /* all stuffing bytes must be 0xff */ | ||
328 | for (i = 0; i < stuffing; i++) | ||
329 | if (q[14 + i] != 0xff) | ||
330 | break; | ||
331 | if (i == stuffing && (q[4] & 0xc4) == 0x44 && (q[12] & 3) == 3 && | ||
332 | q[14 + stuffing] == 0 && q[15 + stuffing] == 0 && | ||
333 | q[16 + stuffing] == 1) { | ||
334 | itv->search_pack_header = 0; | ||
335 | len = (char *)q - start; | ||
336 | ivtv_setup_sliced_vbi_buf(itv); | ||
337 | break; | ||
338 | } | ||
339 | } | ||
340 | } | ||
341 | if (copy_to_user(ubuf, (u8 *)buf->buf + buf->readpos, len)) { | ||
342 | IVTV_DEBUG_WARN("copy %zd bytes to user failed for %s\n", len, s->name); | ||
343 | return -EFAULT; | ||
344 | } | ||
345 | /*IVTV_INFO("copied %lld %d %d %d %d %d vbi %d\n", itv->mpg_data_received, len, ucount, | ||
346 | buf->readpos, buf->bytesused, buf->bytesused - buf->readpos - len, | ||
347 | buf == &itv->vbi.sliced_mpeg_buf); */ | ||
348 | buf->readpos += len; | ||
349 | if (s->type == IVTV_ENC_STREAM_TYPE_MPG && buf != &itv->vbi.sliced_mpeg_buf) | ||
350 | itv->mpg_data_received += len; | ||
351 | return len; | ||
352 | } | ||
353 | |||
354 | static ssize_t ivtv_read(struct ivtv_stream *s, char __user *ubuf, size_t tot_count, int non_block) | ||
355 | { | ||
356 | struct ivtv *itv = s->itv; | ||
357 | size_t tot_written = 0; | ||
358 | int single_frame = 0; | ||
359 | |||
360 | if (atomic_read(&itv->capturing) == 0 && s->id == -1) { | ||
361 | /* shouldn't happen */ | ||
362 | IVTV_DEBUG_WARN("Stream %s not initialized before read\n", s->name); | ||
363 | return -EIO; | ||
364 | } | ||
365 | |||
366 | /* Each VBI buffer is one frame, the v4l2 API says that for VBI the frames should | ||
367 | arrive one-by-one, so make sure we never output more than one VBI frame at a time */ | ||
368 | if (s->type == IVTV_DEC_STREAM_TYPE_VBI || | ||
369 | (s->type == IVTV_ENC_STREAM_TYPE_VBI && itv->vbi.sliced_in->service_set)) | ||
370 | single_frame = 1; | ||
371 | |||
372 | for (;;) { | ||
373 | struct ivtv_buffer *buf; | ||
374 | int rc; | ||
375 | |||
376 | buf = ivtv_get_buffer(s, non_block, &rc); | ||
377 | if (buf == NULL && rc == -EAGAIN && tot_written) | ||
378 | break; | ||
379 | if (buf == NULL) | ||
380 | return rc; | ||
381 | rc = ivtv_copy_buf_to_user(s, buf, ubuf + tot_written, tot_count - tot_written); | ||
382 | if (buf != &itv->vbi.sliced_mpeg_buf) { | ||
383 | ivtv_enqueue(s, buf, (buf->readpos == buf->bytesused) ? &s->q_free : &s->q_io); | ||
384 | } | ||
385 | else if (buf->readpos == buf->bytesused) { | ||
386 | int idx = itv->vbi.inserted_frame % IVTV_VBI_FRAMES; | ||
387 | itv->vbi.sliced_mpeg_size[idx] = 0; | ||
388 | itv->vbi.inserted_frame++; | ||
389 | itv->vbi_data_inserted += buf->bytesused; | ||
390 | } | ||
391 | if (rc < 0) | ||
392 | return rc; | ||
393 | tot_written += rc; | ||
394 | |||
395 | if (tot_written == tot_count || single_frame) | ||
396 | break; | ||
397 | } | ||
398 | return tot_written; | ||
399 | } | ||
400 | |||
401 | static ssize_t ivtv_read_pos(struct ivtv_stream *s, char __user *ubuf, size_t count, | ||
402 | loff_t *pos, int non_block) | ||
403 | { | ||
404 | ssize_t rc = count ? ivtv_read(s, ubuf, count, non_block) : 0; | ||
405 | struct ivtv *itv = s->itv; | ||
406 | |||
407 | IVTV_DEBUG_INFO("read %zd from %s, got %zd\n", count, s->name, rc); | ||
408 | if (rc > 0) | ||
409 | pos += rc; | ||
410 | return rc; | ||
411 | } | ||
412 | |||
413 | int ivtv_start_capture(struct ivtv_open_id *id) | ||
414 | { | ||
415 | struct ivtv *itv = id->itv; | ||
416 | struct ivtv_stream *s = &itv->streams[id->type]; | ||
417 | struct ivtv_stream *s_vbi; | ||
418 | |||
419 | if (s->type == IVTV_ENC_STREAM_TYPE_RAD || | ||
420 | s->type == IVTV_DEC_STREAM_TYPE_MPG || | ||
421 | s->type == IVTV_DEC_STREAM_TYPE_YUV || | ||
422 | s->type == IVTV_DEC_STREAM_TYPE_VOUT) { | ||
423 | /* you cannot read from these stream types. */ | ||
424 | return -EPERM; | ||
425 | } | ||
426 | |||
427 | /* Try to claim this stream. */ | ||
428 | if (ivtv_claim_stream(id, s->type)) | ||
429 | return -EBUSY; | ||
430 | |||
431 | /* This stream does not need to start capturing */ | ||
432 | if (s->type == IVTV_DEC_STREAM_TYPE_VBI) { | ||
433 | set_bit(IVTV_F_S_APPL_IO, &s->s_flags); | ||
434 | return 0; | ||
435 | } | ||
436 | |||
437 | /* If capture is already in progress, then we also have to | ||
438 | do nothing extra. */ | ||
439 | if (test_bit(IVTV_F_S_STREAMOFF, &s->s_flags) || test_and_set_bit(IVTV_F_S_STREAMING, &s->s_flags)) { | ||
440 | set_bit(IVTV_F_S_APPL_IO, &s->s_flags); | ||
441 | return 0; | ||
442 | } | ||
443 | |||
444 | /* Start VBI capture if required */ | ||
445 | s_vbi = &itv->streams[IVTV_ENC_STREAM_TYPE_VBI]; | ||
446 | if (s->type == IVTV_ENC_STREAM_TYPE_MPG && | ||
447 | test_bit(IVTV_F_S_INTERNAL_USE, &s_vbi->s_flags) && | ||
448 | !test_and_set_bit(IVTV_F_S_STREAMING, &s_vbi->s_flags)) { | ||
449 | /* Note: the IVTV_ENC_STREAM_TYPE_VBI is claimed | ||
450 | automatically when the MPG stream is claimed. | ||
451 | We only need to start the VBI capturing. */ | ||
452 | if (ivtv_start_v4l2_encode_stream(s_vbi)) { | ||
453 | IVTV_DEBUG_WARN("VBI capture start failed\n"); | ||
454 | |||
455 | /* Failure, clean up and return an error */ | ||
456 | clear_bit(IVTV_F_S_STREAMING, &s_vbi->s_flags); | ||
457 | clear_bit(IVTV_F_S_STREAMING, &s->s_flags); | ||
458 | /* also releases the associated VBI stream */ | ||
459 | ivtv_release_stream(s); | ||
460 | return -EIO; | ||
461 | } | ||
462 | IVTV_DEBUG_INFO("VBI insertion started\n"); | ||
463 | } | ||
464 | |||
465 | /* Tell the card to start capturing */ | ||
466 | if (!ivtv_start_v4l2_encode_stream(s)) { | ||
467 | /* We're done */ | ||
468 | set_bit(IVTV_F_S_APPL_IO, &s->s_flags); | ||
469 | /* Resume a possibly paused encoder */ | ||
470 | if (test_and_clear_bit(IVTV_F_I_ENC_PAUSED, &itv->i_flags)) | ||
471 | ivtv_vapi(itv, CX2341X_ENC_PAUSE_ENCODER, 1, 1); | ||
472 | return 0; | ||
473 | } | ||
474 | |||
475 | /* failure, clean up */ | ||
476 | IVTV_DEBUG_WARN("Failed to start capturing for stream %s\n", s->name); | ||
477 | |||
478 | /* Note: the IVTV_ENC_STREAM_TYPE_VBI is released | ||
479 | automatically when the MPG stream is released. | ||
480 | We only need to stop the VBI capturing. */ | ||
481 | if (s->type == IVTV_ENC_STREAM_TYPE_MPG && | ||
482 | test_bit(IVTV_F_S_STREAMING, &s_vbi->s_flags)) { | ||
483 | ivtv_stop_v4l2_encode_stream(s_vbi, 0); | ||
484 | clear_bit(IVTV_F_S_STREAMING, &s_vbi->s_flags); | ||
485 | } | ||
486 | clear_bit(IVTV_F_S_STREAMING, &s->s_flags); | ||
487 | ivtv_release_stream(s); | ||
488 | return -EIO; | ||
489 | } | ||
490 | |||
491 | ssize_t ivtv_v4l2_read(struct file * filp, char __user *buf, size_t count, loff_t * pos) | ||
492 | { | ||
493 | struct ivtv_open_id *id = filp->private_data; | ||
494 | struct ivtv *itv = id->itv; | ||
495 | struct ivtv_stream *s = &itv->streams[id->type]; | ||
496 | int rc; | ||
497 | |||
498 | IVTV_DEBUG_IOCTL("read %zd bytes from %s\n", count, s->name); | ||
499 | |||
500 | rc = ivtv_start_capture(id); | ||
501 | if (rc) | ||
502 | return rc; | ||
503 | return ivtv_read_pos(s, buf, count, pos, filp->f_flags & O_NONBLOCK); | ||
504 | } | ||
505 | |||
506 | int ivtv_start_decoding(struct ivtv_open_id *id, int speed) | ||
507 | { | ||
508 | struct ivtv *itv = id->itv; | ||
509 | struct ivtv_stream *s = &itv->streams[id->type]; | ||
510 | |||
511 | if (atomic_read(&itv->decoding) == 0) { | ||
512 | if (ivtv_claim_stream(id, s->type)) { | ||
513 | /* someone else is using this stream already */ | ||
514 | IVTV_DEBUG_WARN("start decode, stream already claimed\n"); | ||
515 | return -EBUSY; | ||
516 | } | ||
517 | ivtv_start_v4l2_decode_stream(s, 0); | ||
518 | } | ||
519 | if (s->type == IVTV_DEC_STREAM_TYPE_MPG) | ||
520 | return ivtv_set_speed(itv, speed); | ||
521 | return 0; | ||
522 | } | ||
523 | |||
524 | ssize_t ivtv_v4l2_write(struct file *filp, const char __user *user_buf, size_t count, loff_t *pos) | ||
525 | { | ||
526 | struct ivtv_open_id *id = filp->private_data; | ||
527 | struct ivtv *itv = id->itv; | ||
528 | struct ivtv_stream *s = &itv->streams[id->type]; | ||
529 | struct ivtv_buffer *buf; | ||
530 | struct ivtv_queue q; | ||
531 | int bytes_written = 0; | ||
532 | int mode; | ||
533 | int rc; | ||
534 | DEFINE_WAIT(wait); | ||
535 | |||
536 | IVTV_DEBUG_IOCTL("write %zd bytes to %s\n", count, s->name); | ||
537 | |||
538 | if (s->type != IVTV_DEC_STREAM_TYPE_MPG && | ||
539 | s->type != IVTV_DEC_STREAM_TYPE_YUV && | ||
540 | s->type != IVTV_DEC_STREAM_TYPE_VOUT) | ||
541 | /* not decoder streams */ | ||
542 | return -EPERM; | ||
543 | |||
544 | /* Try to claim this stream */ | ||
545 | if (ivtv_claim_stream(id, s->type)) | ||
546 | return -EBUSY; | ||
547 | |||
548 | /* This stream does not need to start any decoding */ | ||
549 | if (s->type == IVTV_DEC_STREAM_TYPE_VOUT) { | ||
550 | set_bit(IVTV_F_S_APPL_IO, &s->s_flags); | ||
551 | return ivtv_write_vbi(itv, user_buf, count); | ||
552 | } | ||
553 | |||
554 | mode = s->type == IVTV_DEC_STREAM_TYPE_MPG ? OUT_MPG : OUT_YUV; | ||
555 | |||
556 | if (ivtv_set_output_mode(itv, mode) != mode) { | ||
557 | ivtv_release_stream(s); | ||
558 | return -EBUSY; | ||
559 | } | ||
560 | ivtv_queue_init(&q); | ||
561 | set_bit(IVTV_F_S_APPL_IO, &s->s_flags); | ||
562 | |||
563 | retry: | ||
564 | for (;;) { | ||
565 | /* Gather buffers */ | ||
566 | while (q.length - q.bytesused < count && (buf = ivtv_dequeue(s, &s->q_io))) | ||
567 | ivtv_enqueue(s, buf, &q); | ||
568 | while (q.length - q.bytesused < count && (buf = ivtv_dequeue(s, &s->q_free))) { | ||
569 | ivtv_enqueue(s, buf, &q); | ||
570 | } | ||
571 | if (q.buffers) | ||
572 | break; | ||
573 | if (filp->f_flags & O_NONBLOCK) | ||
574 | return -EAGAIN; | ||
575 | prepare_to_wait(&s->waitq, &wait, TASK_INTERRUPTIBLE); | ||
576 | /* New buffers might have become free before we were added to the waitqueue */ | ||
577 | if (!s->q_free.buffers) | ||
578 | schedule(); | ||
579 | finish_wait(&s->waitq, &wait); | ||
580 | if (signal_pending(current)) { | ||
581 | IVTV_DEBUG_INFO("User stopped %s\n", s->name); | ||
582 | return -EINTR; | ||
583 | } | ||
584 | } | ||
585 | |||
586 | /* copy user data into buffers */ | ||
587 | while ((buf = ivtv_dequeue(s, &q))) { | ||
588 | /* Make sure we really got all the user data */ | ||
589 | rc = ivtv_buf_copy_from_user(s, buf, user_buf, count); | ||
590 | |||
591 | if (rc < 0) { | ||
592 | ivtv_queue_move(s, &q, NULL, &s->q_free, 0); | ||
593 | return rc; | ||
594 | } | ||
595 | user_buf += rc; | ||
596 | count -= rc; | ||
597 | bytes_written += rc; | ||
598 | |||
599 | if (buf->bytesused != s->buf_size) { | ||
600 | /* incomplete, leave in q_io for next time */ | ||
601 | ivtv_enqueue(s, buf, &s->q_io); | ||
602 | break; | ||
603 | } | ||
604 | /* Byteswap MPEG buffer */ | ||
605 | if (s->type == IVTV_DEC_STREAM_TYPE_MPG) | ||
606 | ivtv_buf_swap(buf); | ||
607 | ivtv_enqueue(s, buf, &s->q_full); | ||
608 | } | ||
609 | |||
610 | /* Start decoder (returns 0 if already started) */ | ||
611 | rc = ivtv_start_decoding(id, itv->speed); | ||
612 | if (rc) { | ||
613 | IVTV_DEBUG_WARN("Failed start decode stream %s\n", s->name); | ||
614 | |||
615 | /* failure, clean up */ | ||
616 | clear_bit(IVTV_F_S_STREAMING, &s->s_flags); | ||
617 | clear_bit(IVTV_F_S_APPL_IO, &s->s_flags); | ||
618 | return rc; | ||
619 | } | ||
620 | if (test_bit(IVTV_F_S_NEEDS_DATA, &s->s_flags)) { | ||
621 | if (s->q_full.length >= itv->dma_data_req_size) { | ||
622 | int got_sig; | ||
623 | |||
624 | prepare_to_wait(&itv->dma_waitq, &wait, TASK_INTERRUPTIBLE); | ||
625 | while (!(got_sig = signal_pending(current)) && | ||
626 | test_bit(IVTV_F_S_DMA_PENDING, &s->s_flags)) { | ||
627 | schedule(); | ||
628 | } | ||
629 | finish_wait(&itv->dma_waitq, &wait); | ||
630 | if (got_sig) { | ||
631 | IVTV_DEBUG_INFO("User interrupted %s\n", s->name); | ||
632 | return -EINTR; | ||
633 | } | ||
634 | |||
635 | clear_bit(IVTV_F_S_NEEDS_DATA, &s->s_flags); | ||
636 | ivtv_queue_move(s, &s->q_full, NULL, &s->q_predma, itv->dma_data_req_size); | ||
637 | ivtv_dma_stream_dec_prepare(s, itv->dma_data_req_offset + IVTV_DECODER_OFFSET, 1); | ||
638 | } | ||
639 | } | ||
640 | /* more user data is available, wait until buffers become free | ||
641 | to transfer the rest. */ | ||
642 | if (count && !(filp->f_flags & O_NONBLOCK)) | ||
643 | goto retry; | ||
644 | IVTV_DEBUG_INFO("Wrote %d bytes to %s (%d)\n", bytes_written, s->name, s->q_full.bytesused); | ||
645 | return bytes_written; | ||
646 | } | ||
647 | |||
648 | unsigned int ivtv_v4l2_dec_poll(struct file *filp, poll_table *wait) | ||
649 | { | ||
650 | struct ivtv_open_id *id = filp->private_data; | ||
651 | struct ivtv *itv = id->itv; | ||
652 | struct ivtv_stream *s = &itv->streams[id->type]; | ||
653 | int res = 0; | ||
654 | |||
655 | /* add stream's waitq to the poll list */ | ||
656 | poll_wait(filp, &s->waitq, wait); | ||
657 | |||
658 | set_bit(IVTV_F_I_EV_VSYNC_ENABLED, &itv->i_flags); | ||
659 | if (test_bit(IVTV_F_I_EV_VSYNC, &itv->i_flags) || | ||
660 | test_bit(IVTV_F_I_EV_DEC_STOPPED, &itv->i_flags)) | ||
661 | res = POLLPRI; | ||
662 | |||
663 | /* Allow write if buffers are available for writing */ | ||
664 | if (s->q_free.buffers) | ||
665 | res |= POLLOUT | POLLWRNORM; | ||
666 | return res; | ||
667 | } | ||
668 | |||
669 | unsigned int ivtv_v4l2_enc_poll(struct file *filp, poll_table * wait) | ||
670 | { | ||
671 | struct ivtv_open_id *id = filp->private_data; | ||
672 | struct ivtv *itv = id->itv; | ||
673 | struct ivtv_stream *s = &itv->streams[id->type]; | ||
674 | int eof = test_bit(IVTV_F_S_STREAMOFF, &s->s_flags); | ||
675 | |||
676 | /* Start a capture if there is none */ | ||
677 | if (!eof && !test_bit(IVTV_F_S_STREAMING, &s->s_flags)) { | ||
678 | int rc = ivtv_start_capture(id); | ||
679 | |||
680 | if (rc) { | ||
681 | IVTV_DEBUG_INFO("Could not start capture for %s (%d)\n", | ||
682 | s->name, rc); | ||
683 | return POLLERR; | ||
684 | } | ||
685 | } | ||
686 | |||
687 | /* add stream's waitq to the poll list */ | ||
688 | poll_wait(filp, &s->waitq, wait); | ||
689 | |||
690 | if (eof || s->q_full.length) | ||
691 | return POLLIN | POLLRDNORM; | ||
692 | return 0; | ||
693 | } | ||
694 | |||
695 | void ivtv_stop_capture(struct ivtv_open_id *id, int gop_end) | ||
696 | { | ||
697 | struct ivtv *itv = id->itv; | ||
698 | struct ivtv_stream *s = &itv->streams[id->type]; | ||
699 | |||
700 | IVTV_DEBUG_IOCTL("close() of %s\n", s->name); | ||
701 | |||
702 | /* 'Unclaim' this stream */ | ||
703 | |||
704 | /* Stop capturing */ | ||
705 | if (test_bit(IVTV_F_S_STREAMING, &s->s_flags)) { | ||
706 | struct ivtv_stream *s_vbi = &itv->streams[IVTV_ENC_STREAM_TYPE_VBI]; | ||
707 | |||
708 | IVTV_DEBUG_INFO("close stopping capture\n"); | ||
709 | /* Special case: a running VBI capture for VBI insertion | ||
710 | in the mpeg stream. Need to stop that too. */ | ||
711 | if (id->type == IVTV_ENC_STREAM_TYPE_MPG && | ||
712 | test_bit(IVTV_F_S_STREAMING, &s_vbi->s_flags) && | ||
713 | !test_bit(IVTV_F_S_APPL_IO, &s_vbi->s_flags)) { | ||
714 | IVTV_DEBUG_INFO("close stopping embedded VBI capture\n"); | ||
715 | ivtv_stop_v4l2_encode_stream(s_vbi, 0); | ||
716 | } | ||
717 | if ((id->type == IVTV_DEC_STREAM_TYPE_VBI || | ||
718 | id->type == IVTV_ENC_STREAM_TYPE_VBI) && | ||
719 | test_bit(IVTV_F_S_INTERNAL_USE, &s->s_flags)) { | ||
720 | /* Also used internally, don't stop capturing */ | ||
721 | s->id = -1; | ||
722 | } | ||
723 | else { | ||
724 | ivtv_stop_v4l2_encode_stream(s, gop_end); | ||
725 | } | ||
726 | } | ||
727 | clear_bit(IVTV_F_S_APPL_IO, &s->s_flags); | ||
728 | clear_bit(IVTV_F_S_STREAMOFF, &s->s_flags); | ||
729 | |||
730 | ivtv_release_stream(s); | ||
731 | } | ||
732 | |||
733 | static void ivtv_stop_decoding(struct ivtv_open_id *id, int flags, u64 pts) | ||
734 | { | ||
735 | struct ivtv *itv = id->itv; | ||
736 | struct ivtv_stream *s = &itv->streams[id->type]; | ||
737 | |||
738 | IVTV_DEBUG_IOCTL("close() of %s\n", s->name); | ||
739 | |||
740 | /* Stop decoding */ | ||
741 | if (test_bit(IVTV_F_S_STREAMING, &s->s_flags)) { | ||
742 | IVTV_DEBUG_INFO("close stopping decode\n"); | ||
743 | |||
744 | ivtv_stop_v4l2_decode_stream(s, flags, pts); | ||
745 | } | ||
746 | clear_bit(IVTV_F_S_APPL_IO, &s->s_flags); | ||
747 | clear_bit(IVTV_F_S_STREAMOFF, &s->s_flags); | ||
748 | if (id->type == IVTV_DEC_STREAM_TYPE_YUV && test_bit(IVTV_F_I_DECODING_YUV, &itv->i_flags)) { | ||
749 | /* Restore registers we've changed & clean up any mess we've made */ | ||
750 | ivtv_yuv_close(itv); | ||
751 | } | ||
752 | if (s->type == IVTV_DEC_STREAM_TYPE_YUV && itv->output_mode == OUT_YUV) | ||
753 | itv->output_mode = OUT_NONE; | ||
754 | else if (s->type == IVTV_DEC_STREAM_TYPE_MPG && itv->output_mode == OUT_MPG) | ||
755 | itv->output_mode = OUT_NONE; | ||
756 | |||
757 | itv->speed = 0; | ||
758 | ivtv_release_stream(s); | ||
759 | } | ||
760 | |||
761 | int ivtv_v4l2_close(struct inode *inode, struct file *filp) | ||
762 | { | ||
763 | struct ivtv_open_id *id = filp->private_data; | ||
764 | struct ivtv *itv = id->itv; | ||
765 | struct ivtv_stream *s = &itv->streams[id->type]; | ||
766 | |||
767 | IVTV_DEBUG_IOCTL("close() of %s\n", s->name); | ||
768 | |||
769 | v4l2_prio_close(&itv->prio, &id->prio); | ||
770 | |||
771 | /* Easy case first: this stream was never claimed by us */ | ||
772 | if (s->id != id->open_id) { | ||
773 | kfree(id); | ||
774 | return 0; | ||
775 | } | ||
776 | |||
777 | /* 'Unclaim' this stream */ | ||
778 | |||
779 | /* Stop radio */ | ||
780 | if (id->type == IVTV_ENC_STREAM_TYPE_RAD) { | ||
781 | /* Closing radio device, return to TV mode */ | ||
782 | ivtv_mute(itv); | ||
783 | /* Mark that the radio is no longer in use */ | ||
784 | clear_bit(IVTV_F_I_RADIO_USER, &itv->i_flags); | ||
785 | /* Switch tuner to TV */ | ||
786 | ivtv_call_i2c_clients(itv, VIDIOC_S_STD, &itv->std); | ||
787 | /* Select correct audio input (i.e. TV tuner or Line in) */ | ||
788 | ivtv_audio_set_io(itv); | ||
789 | /* Done! Unmute and continue. */ | ||
790 | ivtv_unmute(itv); | ||
791 | ivtv_release_stream(s); | ||
792 | } else if (s->type >= IVTV_DEC_STREAM_TYPE_MPG) { | ||
793 | ivtv_stop_decoding(id, VIDEO_CMD_STOP_TO_BLACK | VIDEO_CMD_STOP_IMMEDIATELY, 0); | ||
794 | } else { | ||
795 | ivtv_stop_capture(id, 0); | ||
796 | } | ||
797 | kfree(id); | ||
798 | return 0; | ||
799 | } | ||
800 | |||
801 | int ivtv_v4l2_open(struct inode *inode, struct file *filp) | ||
802 | { | ||
803 | int x, y = 0; | ||
804 | struct ivtv_open_id *item; | ||
805 | struct ivtv *itv = NULL; | ||
806 | struct ivtv_stream *s = NULL; | ||
807 | int minor = MINOR(inode->i_rdev); | ||
808 | |||
809 | /* Find which card this open was on */ | ||
810 | spin_lock(&ivtv_cards_lock); | ||
811 | for (x = 0; itv == NULL && x < ivtv_cards_active; x++) { | ||
812 | /* find out which stream this open was on */ | ||
813 | for (y = 0; y < IVTV_MAX_STREAMS; y++) { | ||
814 | s = &ivtv_cards[x]->streams[y]; | ||
815 | if (s->v4l2dev && s->v4l2dev->minor == minor) { | ||
816 | itv = ivtv_cards[x]; | ||
817 | break; | ||
818 | } | ||
819 | } | ||
820 | } | ||
821 | spin_unlock(&ivtv_cards_lock); | ||
822 | |||
823 | if (itv == NULL) { | ||
824 | /* Couldn't find a device registered | ||
825 | on that minor, shouldn't happen! */ | ||
826 | printk(KERN_WARNING "ivtv: no ivtv device found on minor %d\n", minor); | ||
827 | return -ENXIO; | ||
828 | } | ||
829 | |||
830 | if (y == IVTV_DEC_STREAM_TYPE_MPG && | ||
831 | test_bit(IVTV_F_S_CLAIMED, &itv->streams[IVTV_DEC_STREAM_TYPE_YUV].s_flags)) | ||
832 | return -EBUSY; | ||
833 | |||
834 | if (y == IVTV_DEC_STREAM_TYPE_YUV && | ||
835 | test_bit(IVTV_F_S_CLAIMED, &itv->streams[IVTV_DEC_STREAM_TYPE_MPG].s_flags)) | ||
836 | return -EBUSY; | ||
837 | |||
838 | if (y == IVTV_DEC_STREAM_TYPE_YUV) { | ||
839 | if (read_reg(0x82c) == 0) { | ||
840 | IVTV_ERR("Tried to open YUV output device but need to send data to mpeg decoder before it can be used\n"); | ||
841 | /* return -ENODEV; */ | ||
842 | } | ||
843 | ivtv_udma_alloc(itv); | ||
844 | } | ||
845 | |||
846 | /* Allocate memory */ | ||
847 | item = kmalloc(sizeof(struct ivtv_open_id), GFP_KERNEL); | ||
848 | if (NULL == item) { | ||
849 | IVTV_DEBUG_WARN("nomem on v4l2 open\n"); | ||
850 | return -ENOMEM; | ||
851 | } | ||
852 | item->itv = itv; | ||
853 | item->type = y; | ||
854 | v4l2_prio_open(&itv->prio, &item->prio); | ||
855 | |||
856 | item->open_id = itv->open_id++; | ||
857 | filp->private_data = item; | ||
858 | |||
859 | if (item->type == IVTV_ENC_STREAM_TYPE_RAD) { | ||
860 | /* Try to claim this stream */ | ||
861 | if (ivtv_claim_stream(item, item->type)) { | ||
862 | /* No, it's already in use */ | ||
863 | kfree(item); | ||
864 | return -EBUSY; | ||
865 | } | ||
866 | |||
867 | /* We have the radio */ | ||
868 | ivtv_mute(itv); | ||
869 | /* Switch tuner to radio */ | ||
870 | ivtv_call_i2c_clients(itv, AUDC_SET_RADIO, NULL); | ||
871 | /* Mark that the radio is being used. */ | ||
872 | set_bit(IVTV_F_I_RADIO_USER, &itv->i_flags); | ||
873 | /* Select the correct audio input (i.e. radio tuner) */ | ||
874 | ivtv_audio_set_io(itv); | ||
875 | /* Done! Unmute and continue. */ | ||
876 | ivtv_unmute(itv); | ||
877 | } | ||
878 | |||
879 | /* YUV or MPG Decoding Mode? */ | ||
880 | if (y == IVTV_DEC_STREAM_TYPE_MPG) | ||
881 | clear_bit(IVTV_F_I_DEC_YUV, &itv->i_flags); | ||
882 | else if (y == IVTV_DEC_STREAM_TYPE_YUV) | ||
883 | { | ||
884 | set_bit(IVTV_F_I_DEC_YUV, &itv->i_flags); | ||
885 | } | ||
886 | |||
887 | return 0; | ||
888 | } | ||
889 | |||
890 | void ivtv_mute(struct ivtv *itv) | ||
891 | { | ||
892 | struct v4l2_control ctrl = { V4L2_CID_AUDIO_MUTE, 1 }; | ||
893 | |||
894 | /* Mute sound to avoid pop */ | ||
895 | ivtv_control_ioctls(itv, VIDIOC_S_CTRL, &ctrl); | ||
896 | |||
897 | if (atomic_read(&itv->capturing)) | ||
898 | ivtv_vapi(itv, CX2341X_ENC_MUTE_AUDIO, 1, 1); | ||
899 | |||
900 | IVTV_DEBUG_INFO("Mute\n"); | ||
901 | } | ||
902 | |||
903 | void ivtv_unmute(struct ivtv *itv) | ||
904 | { | ||
905 | struct v4l2_control ctrl = { V4L2_CID_AUDIO_MUTE, 0 }; | ||
906 | |||
907 | /* initialize or refresh input */ | ||
908 | if (atomic_read(&itv->capturing) == 0) | ||
909 | ivtv_vapi(itv, CX2341X_ENC_INITIALIZE_INPUT, 0); | ||
910 | |||
911 | ivtv_sleep_timeout(HZ / 10, 0); | ||
912 | |||
913 | if (atomic_read(&itv->capturing)) { | ||
914 | ivtv_vapi(itv, CX2341X_ENC_MISC, 1, 12); | ||
915 | ivtv_vapi(itv, CX2341X_ENC_MUTE_AUDIO, 1, 0); | ||
916 | } | ||
917 | |||
918 | /* Unmute */ | ||
919 | ivtv_control_ioctls(itv, VIDIOC_S_CTRL, &ctrl); | ||
920 | IVTV_DEBUG_INFO("Unmute\n"); | ||
921 | } | ||
diff --git a/drivers/media/video/ivtv/ivtv-fileops.h b/drivers/media/video/ivtv/ivtv-fileops.h new file mode 100644 index 000000000000..74a1745fabbc --- /dev/null +++ b/drivers/media/video/ivtv/ivtv-fileops.h | |||
@@ -0,0 +1,44 @@ | |||
1 | /* | ||
2 | file operation functions | ||
3 | Copyright (C) 2003-2004 Kevin Thayer <nufan_wfk at yahoo.com> | ||
4 | Copyright (C) 2005-2007 Hans Verkuil <hverkuil@xs4all.nl> | ||
5 | |||
6 | This program is free software; you can redistribute it and/or modify | ||
7 | it under the terms of the GNU General Public License as published by | ||
8 | the Free Software Foundation; either version 2 of the License, or | ||
9 | (at your option) any later version. | ||
10 | |||
11 | This program is distributed in the hope that it will be useful, | ||
12 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
14 | GNU General Public License for more details. | ||
15 | |||
16 | You should have received a copy of the GNU General Public License | ||
17 | along with this program; if not, write to the Free Software | ||
18 | Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
19 | */ | ||
20 | |||
21 | /* Testing/Debugging */ | ||
22 | int ivtv_v4l2_open(struct inode *inode, struct file *filp); | ||
23 | ssize_t ivtv_v4l2_read(struct file *filp, char __user *buf, size_t count, | ||
24 | loff_t * pos); | ||
25 | ssize_t ivtv_v4l2_write(struct file *filp, const char __user *buf, size_t count, | ||
26 | loff_t * pos); | ||
27 | int ivtv_v4l2_close(struct inode *inode, struct file *filp); | ||
28 | unsigned int ivtv_v4l2_enc_poll(struct file *filp, poll_table * wait); | ||
29 | unsigned int ivtv_v4l2_dec_poll(struct file *filp, poll_table * wait); | ||
30 | int ivtv_start_capture(struct ivtv_open_id *id); | ||
31 | void ivtv_stop_capture(struct ivtv_open_id *id, int gop_end); | ||
32 | int ivtv_start_decoding(struct ivtv_open_id *id, int speed); | ||
33 | void ivtv_mute(struct ivtv *itv); | ||
34 | void ivtv_unmute(struct ivtv *itv); | ||
35 | |||
36 | /* Utilities */ | ||
37 | |||
38 | /* Try to claim a stream for the filehandle. Return 0 on success, | ||
39 | -EBUSY if stream already claimed. Once a stream is claimed, it | ||
40 | remains claimed until the associated filehandle is closed. */ | ||
41 | int ivtv_claim_stream(struct ivtv_open_id *id, int type); | ||
42 | |||
43 | /* Release a previously claimed stream. */ | ||
44 | void ivtv_release_stream(struct ivtv_stream *s); | ||
diff --git a/drivers/media/video/ivtv/ivtv-firmware.c b/drivers/media/video/ivtv/ivtv-firmware.c new file mode 100644 index 000000000000..d4c910b782af --- /dev/null +++ b/drivers/media/video/ivtv/ivtv-firmware.c | |||
@@ -0,0 +1,272 @@ | |||
1 | /* | ||
2 | ivtv firmware functions. | ||
3 | Copyright (C) 2003-2004 Kevin Thayer <nufan_wfk at yahoo.com> | ||
4 | Copyright (C) 2004 Chris Kennedy <c@groovy.org> | ||
5 | Copyright (C) 2005-2007 Hans Verkuil <hverkuil@xs4all.nl> | ||
6 | |||
7 | This program is free software; you can redistribute it and/or modify | ||
8 | it under the terms of the GNU General Public License as published by | ||
9 | the Free Software Foundation; either version 2 of the License, or | ||
10 | (at your option) any later version. | ||
11 | |||
12 | This program is distributed in the hope that it will be useful, | ||
13 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
15 | GNU General Public License for more details. | ||
16 | |||
17 | You should have received a copy of the GNU General Public License | ||
18 | along with this program; if not, write to the Free Software | ||
19 | Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
20 | */ | ||
21 | |||
22 | #include "ivtv-driver.h" | ||
23 | #include "ivtv-mailbox.h" | ||
24 | #include "ivtv-firmware.h" | ||
25 | #include <linux/firmware.h> | ||
26 | |||
27 | #define IVTV_MASK_SPU_ENABLE 0xFFFFFFFE | ||
28 | #define IVTV_MASK_VPU_ENABLE15 0xFFFFFFF6 | ||
29 | #define IVTV_MASK_VPU_ENABLE16 0xFFFFFFFB | ||
30 | #define IVTV_CMD_VDM_STOP 0x00000000 | ||
31 | #define IVTV_CMD_AO_STOP 0x00000005 | ||
32 | #define IVTV_CMD_APU_PING 0x00000000 | ||
33 | #define IVTV_CMD_VPU_STOP15 0xFFFFFFFE | ||
34 | #define IVTV_CMD_VPU_STOP16 0xFFFFFFEE | ||
35 | #define IVTV_CMD_HW_BLOCKS_RST 0xFFFFFFFF | ||
36 | #define IVTV_CMD_SPU_STOP 0x00000001 | ||
37 | #define IVTV_CMD_SDRAM_PRECHARGE_INIT 0x0000001A | ||
38 | #define IVTV_CMD_SDRAM_REFRESH_INIT 0x80000640 | ||
39 | #define IVTV_SDRAM_SLEEPTIME (60 * HZ / 100) /* 600 ms */ | ||
40 | |||
41 | #define IVTV_DECODE_INIT_MPEG_FILENAME "v4l-cx2341x-init.mpg" | ||
42 | #define IVTV_DECODE_INIT_MPEG_SIZE (152*1024) | ||
43 | |||
44 | /* Encoder/decoder firmware sizes */ | ||
45 | #define IVTV_FW_ENC_SIZE (376836) | ||
46 | #define IVTV_FW_DEC_SIZE (256*1024) | ||
47 | |||
48 | static int load_fw_direct(const char *fn, volatile u8 __iomem *mem, struct ivtv *itv, long size) | ||
49 | { | ||
50 | const struct firmware *fw = NULL; | ||
51 | int retries = 3; | ||
52 | |||
53 | retry: | ||
54 | if (retries && request_firmware(&fw, fn, &itv->dev->dev) == 0) { | ||
55 | int i; | ||
56 | volatile u32 __iomem *dst = (volatile u32 __iomem *)mem; | ||
57 | const u32 *src = (const u32 *)fw->data; | ||
58 | |||
59 | /* temporarily allow 256 KB encoding firmwares as well for | ||
60 | compatibility with blackbird cards */ | ||
61 | if (fw->size != size && fw->size != 256 * 1024) { | ||
62 | /* Due to race conditions in firmware loading (esp. with udev <0.95) | ||
63 | the wrong file was sometimes loaded. So we check filesizes to | ||
64 | see if at least the right-sized file was loaded. If not, then we | ||
65 | retry. */ | ||
66 | IVTV_INFO("retry: file loaded was not %s (expected size %ld, got %zd)\n", fn, size, fw->size); | ||
67 | release_firmware(fw); | ||
68 | retries--; | ||
69 | goto retry; | ||
70 | } | ||
71 | for (i = 0; i < fw->size; i += 4) { | ||
72 | /* no need for endianness conversion on the ppc */ | ||
73 | __raw_writel(*src, dst); | ||
74 | dst++; | ||
75 | src++; | ||
76 | } | ||
77 | release_firmware(fw); | ||
78 | IVTV_INFO("loaded %s firmware (%zd bytes)\n", fn, fw->size); | ||
79 | return size; | ||
80 | } | ||
81 | IVTV_ERR("unable to open firmware %s (must be %ld bytes)\n", fn, size); | ||
82 | IVTV_ERR("did you put the firmware in the hotplug firmware directory?\n"); | ||
83 | return -ENOMEM; | ||
84 | } | ||
85 | |||
86 | void ivtv_halt_firmware(struct ivtv *itv) | ||
87 | { | ||
88 | IVTV_DEBUG_INFO("Preparing for firmware halt.\n"); | ||
89 | if (itv->has_cx23415 && itv->dec_mbox.mbox) | ||
90 | ivtv_vapi(itv, CX2341X_DEC_HALT_FW, 0); | ||
91 | if (itv->enc_mbox.mbox) | ||
92 | ivtv_vapi(itv, CX2341X_ENC_HALT_FW, 0); | ||
93 | |||
94 | ivtv_sleep_timeout(HZ / 100, 0); | ||
95 | itv->enc_mbox.mbox = itv->dec_mbox.mbox = NULL; | ||
96 | |||
97 | IVTV_DEBUG_INFO("Stopping VDM\n"); | ||
98 | write_reg(IVTV_CMD_VDM_STOP, IVTV_REG_VDM); | ||
99 | |||
100 | IVTV_DEBUG_INFO("Stopping AO\n"); | ||
101 | write_reg(IVTV_CMD_AO_STOP, IVTV_REG_AO); | ||
102 | |||
103 | IVTV_DEBUG_INFO("pinging (?) APU\n"); | ||
104 | write_reg(IVTV_CMD_APU_PING, IVTV_REG_APU); | ||
105 | |||
106 | IVTV_DEBUG_INFO("Stopping VPU\n"); | ||
107 | if (!itv->has_cx23415) | ||
108 | write_reg(IVTV_CMD_VPU_STOP16, IVTV_REG_VPU); | ||
109 | else | ||
110 | write_reg(IVTV_CMD_VPU_STOP15, IVTV_REG_VPU); | ||
111 | |||
112 | IVTV_DEBUG_INFO("Resetting Hw Blocks\n"); | ||
113 | write_reg(IVTV_CMD_HW_BLOCKS_RST, IVTV_REG_HW_BLOCKS); | ||
114 | |||
115 | IVTV_DEBUG_INFO("Stopping SPU\n"); | ||
116 | write_reg(IVTV_CMD_SPU_STOP, IVTV_REG_SPU); | ||
117 | |||
118 | ivtv_sleep_timeout(HZ / 100, 0); | ||
119 | |||
120 | IVTV_DEBUG_INFO("init Encoder SDRAM pre-charge\n"); | ||
121 | write_reg(IVTV_CMD_SDRAM_PRECHARGE_INIT, IVTV_REG_ENC_SDRAM_PRECHARGE); | ||
122 | |||
123 | IVTV_DEBUG_INFO("init Encoder SDRAM refresh to 1us\n"); | ||
124 | write_reg(IVTV_CMD_SDRAM_REFRESH_INIT, IVTV_REG_ENC_SDRAM_REFRESH); | ||
125 | |||
126 | if (itv->has_cx23415) { | ||
127 | IVTV_DEBUG_INFO("init Decoder SDRAM pre-charge\n"); | ||
128 | write_reg(IVTV_CMD_SDRAM_PRECHARGE_INIT, IVTV_REG_DEC_SDRAM_PRECHARGE); | ||
129 | |||
130 | IVTV_DEBUG_INFO("init Decoder SDRAM refresh to 1us\n"); | ||
131 | write_reg(IVTV_CMD_SDRAM_REFRESH_INIT, IVTV_REG_DEC_SDRAM_REFRESH); | ||
132 | } | ||
133 | |||
134 | IVTV_DEBUG_INFO("Sleeping for %dms (600 recommended)\n", | ||
135 | (int)(IVTV_SDRAM_SLEEPTIME * 1000 / HZ)); | ||
136 | ivtv_sleep_timeout(IVTV_SDRAM_SLEEPTIME, 0); | ||
137 | } | ||
138 | |||
139 | void ivtv_firmware_versions(struct ivtv *itv) | ||
140 | { | ||
141 | u32 data[CX2341X_MBOX_MAX_DATA]; | ||
142 | |||
143 | /* Encoder */ | ||
144 | ivtv_vapi_result(itv, data, CX2341X_ENC_GET_VERSION, 0); | ||
145 | IVTV_INFO("Encoder revision: 0x%08x\n", data[0]); | ||
146 | |||
147 | if (data[0] != 0x02060039) | ||
148 | IVTV_WARN("Recommended firmware version is 0x02060039.\n"); | ||
149 | |||
150 | if (itv->has_cx23415) { | ||
151 | /* Decoder */ | ||
152 | ivtv_vapi_result(itv, data, CX2341X_DEC_GET_VERSION, 0); | ||
153 | IVTV_INFO("Decoder revision: 0x%08x\n", data[0]); | ||
154 | } | ||
155 | } | ||
156 | |||
157 | static int ivtv_firmware_copy(struct ivtv *itv) | ||
158 | { | ||
159 | IVTV_DEBUG_INFO("Loading encoder image\n"); | ||
160 | if (load_fw_direct(CX2341X_FIRM_ENC_FILENAME, | ||
161 | itv->enc_mem, itv, IVTV_FW_ENC_SIZE) != IVTV_FW_ENC_SIZE) { | ||
162 | IVTV_DEBUG_WARN("failed loading encoder firmware\n"); | ||
163 | return -3; | ||
164 | } | ||
165 | if (!itv->has_cx23415) | ||
166 | return 0; | ||
167 | |||
168 | IVTV_DEBUG_INFO("Loading decoder image\n"); | ||
169 | if (load_fw_direct(CX2341X_FIRM_DEC_FILENAME, | ||
170 | itv->dec_mem, itv, IVTV_FW_DEC_SIZE) != IVTV_FW_DEC_SIZE) { | ||
171 | IVTV_DEBUG_WARN("failed loading decoder firmware\n"); | ||
172 | return -1; | ||
173 | } | ||
174 | return 0; | ||
175 | } | ||
176 | |||
177 | static volatile struct ivtv_mailbox __iomem *ivtv_search_mailbox(const volatile u8 __iomem *mem, u32 size) | ||
178 | { | ||
179 | int i; | ||
180 | |||
181 | /* mailbox is preceeded by a 16 byte 'magic cookie' starting at a 256-byte | ||
182 | address boundary */ | ||
183 | for (i = 0; i < size; i += 0x100) { | ||
184 | if (readl(mem + i) == 0x12345678 && | ||
185 | readl(mem + i + 4) == 0x34567812 && | ||
186 | readl(mem + i + 8) == 0x56781234 && | ||
187 | readl(mem + i + 12) == 0x78123456) { | ||
188 | return (volatile struct ivtv_mailbox __iomem *)(mem + i + 16); | ||
189 | } | ||
190 | } | ||
191 | return NULL; | ||
192 | } | ||
193 | |||
194 | int ivtv_firmware_init(struct ivtv *itv) | ||
195 | { | ||
196 | int err; | ||
197 | |||
198 | ivtv_halt_firmware(itv); | ||
199 | |||
200 | /* load firmware */ | ||
201 | err = ivtv_firmware_copy(itv); | ||
202 | if (err) { | ||
203 | IVTV_DEBUG_WARN("Error %d loading firmware\n", err); | ||
204 | return err; | ||
205 | } | ||
206 | |||
207 | /* start firmware */ | ||
208 | write_reg(read_reg(IVTV_REG_SPU) & IVTV_MASK_SPU_ENABLE, IVTV_REG_SPU); | ||
209 | ivtv_sleep_timeout(HZ / 10, 0); | ||
210 | if (itv->has_cx23415) | ||
211 | write_reg(read_reg(IVTV_REG_VPU) & IVTV_MASK_VPU_ENABLE15, IVTV_REG_VPU); | ||
212 | else | ||
213 | write_reg(read_reg(IVTV_REG_VPU) & IVTV_MASK_VPU_ENABLE16, IVTV_REG_VPU); | ||
214 | ivtv_sleep_timeout(HZ / 10, 0); | ||
215 | |||
216 | /* find mailboxes and ping firmware */ | ||
217 | itv->enc_mbox.mbox = ivtv_search_mailbox(itv->enc_mem, IVTV_ENCODER_SIZE); | ||
218 | if (itv->enc_mbox.mbox == NULL) | ||
219 | IVTV_ERR("Encoder mailbox not found\n"); | ||
220 | else if (ivtv_vapi(itv, CX2341X_ENC_PING_FW, 0)) { | ||
221 | IVTV_ERR("Encoder firmware dead!\n"); | ||
222 | itv->enc_mbox.mbox = NULL; | ||
223 | } | ||
224 | if (itv->enc_mbox.mbox == NULL) | ||
225 | return -ENODEV; | ||
226 | |||
227 | if (!itv->has_cx23415) | ||
228 | return 0; | ||
229 | |||
230 | itv->dec_mbox.mbox = ivtv_search_mailbox(itv->dec_mem, IVTV_DECODER_SIZE); | ||
231 | if (itv->dec_mbox.mbox == NULL) | ||
232 | IVTV_ERR("Decoder mailbox not found\n"); | ||
233 | else if (itv->has_cx23415 && ivtv_vapi(itv, CX2341X_DEC_PING_FW, 0)) { | ||
234 | IVTV_ERR("Decoder firmware dead!\n"); | ||
235 | itv->dec_mbox.mbox = NULL; | ||
236 | } | ||
237 | return itv->dec_mbox.mbox ? 0 : -ENODEV; | ||
238 | } | ||
239 | |||
240 | void ivtv_init_mpeg_decoder(struct ivtv *itv) | ||
241 | { | ||
242 | u32 data[CX2341X_MBOX_MAX_DATA]; | ||
243 | long readbytes; | ||
244 | volatile u8 __iomem *mem_offset; | ||
245 | |||
246 | data[0] = 0; | ||
247 | data[1] = itv->params.width; /* YUV source width */ | ||
248 | data[2] = itv->params.height; | ||
249 | data[3] = itv->params.audio_properties; /* Audio settings to use, | ||
250 | bitmap. see docs. */ | ||
251 | if (ivtv_api(itv, CX2341X_DEC_SET_DECODER_SOURCE, 4, data)) { | ||
252 | IVTV_ERR("ivtv_init_mpeg_decoder failed to set decoder source\n"); | ||
253 | return; | ||
254 | } | ||
255 | |||
256 | if (ivtv_vapi(itv, CX2341X_DEC_START_PLAYBACK, 2, 0, 1) != 0) { | ||
257 | IVTV_ERR("ivtv_init_mpeg_decoder failed to start playback\n"); | ||
258 | return; | ||
259 | } | ||
260 | ivtv_api_get_data(&itv->dec_mbox, IVTV_MBOX_DMA, data); | ||
261 | mem_offset = itv->dec_mem + data[1]; | ||
262 | |||
263 | if ((readbytes = load_fw_direct(IVTV_DECODE_INIT_MPEG_FILENAME, | ||
264 | mem_offset, itv, IVTV_DECODE_INIT_MPEG_SIZE)) <= 0) { | ||
265 | IVTV_DEBUG_WARN("failed to read mpeg decoder initialisation file %s\n", | ||
266 | IVTV_DECODE_INIT_MPEG_FILENAME); | ||
267 | } else { | ||
268 | ivtv_vapi(itv, CX2341X_DEC_SCHED_DMA_FROM_HOST, 3, 0, readbytes, 0); | ||
269 | ivtv_sleep_timeout(HZ / 10, 0); | ||
270 | } | ||
271 | ivtv_vapi(itv, CX2341X_DEC_STOP_PLAYBACK, 4, 0, 0, 0, 1); | ||
272 | } | ||
diff --git a/drivers/media/video/ivtv/ivtv-firmware.h b/drivers/media/video/ivtv/ivtv-firmware.h new file mode 100644 index 000000000000..8b2ffe658905 --- /dev/null +++ b/drivers/media/video/ivtv/ivtv-firmware.h | |||
@@ -0,0 +1,25 @@ | |||
1 | /* | ||
2 | ivtv firmware functions. | ||
3 | Copyright (C) 2003-2004 Kevin Thayer <nufan_wfk at yahoo.com> | ||
4 | Copyright (C) 2004 Chris Kennedy <c@groovy.org> | ||
5 | Copyright (C) 2005-2007 Hans Verkuil <hverkuil@xs4all.nl> | ||
6 | |||
7 | This program is free software; you can redistribute it and/or modify | ||
8 | it under the terms of the GNU General Public License as published by | ||
9 | the Free Software Foundation; either version 2 of the License, or | ||
10 | (at your option) any later version. | ||
11 | |||
12 | This program is distributed in the hope that it will be useful, | ||
13 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
15 | GNU General Public License for more details. | ||
16 | |||
17 | You should have received a copy of the GNU General Public License | ||
18 | along with this program; if not, write to the Free Software | ||
19 | Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
20 | */ | ||
21 | |||
22 | int ivtv_firmware_init(struct ivtv *itv); | ||
23 | void ivtv_firmware_versions(struct ivtv *itv); | ||
24 | void ivtv_halt_firmware(struct ivtv *itv); | ||
25 | void ivtv_init_mpeg_decoder(struct ivtv *itv); | ||
diff --git a/drivers/media/video/ivtv/ivtv-gpio.c b/drivers/media/video/ivtv/ivtv-gpio.c new file mode 100644 index 000000000000..bc8f8ca2961f --- /dev/null +++ b/drivers/media/video/ivtv/ivtv-gpio.c | |||
@@ -0,0 +1,307 @@ | |||
1 | /* | ||
2 | gpio functions. | ||
3 | Merging GPIO support into driver: | ||
4 | Copyright (C) 2004 Chris Kennedy <c@groovy.org> | ||
5 | Copyright (C) 2005-2007 Hans Verkuil <hverkuil@xs4all.nl> | ||
6 | |||
7 | This program is free software; you can redistribute it and/or modify | ||
8 | it under the terms of the GNU General Public License as published by | ||
9 | the Free Software Foundation; either version 2 of the License, or | ||
10 | (at your option) any later version. | ||
11 | |||
12 | This program is distributed in the hope that it will be useful, | ||
13 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
15 | GNU General Public License for more details. | ||
16 | |||
17 | You should have received a copy of the GNU General Public License | ||
18 | along with this program; if not, write to the Free Software | ||
19 | Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
20 | */ | ||
21 | |||
22 | #include "ivtv-driver.h" | ||
23 | #include "ivtv-cards.h" | ||
24 | #include "ivtv-gpio.h" | ||
25 | #include <media/tuner.h> | ||
26 | |||
27 | /* | ||
28 | * GPIO assignment of Yuan MPG600/MPG160 | ||
29 | * | ||
30 | * bit 15 14 13 12 | 11 10 9 8 | 7 6 5 4 | 3 2 1 0 | ||
31 | * OUTPUT IN1 IN0 AM3 AM2 AM1 AM0 | ||
32 | * INPUT DM1 DM0 | ||
33 | * | ||
34 | * IN* : Input selection | ||
35 | * IN1 IN0 | ||
36 | * 1 1 N/A | ||
37 | * 1 0 Line | ||
38 | * 0 1 N/A | ||
39 | * 0 0 Tuner | ||
40 | * | ||
41 | * AM* : Audio Mode | ||
42 | * AM3 0: Normal 1: Mixed(Sub+Main channel) | ||
43 | * AM2 0: Subchannel 1: Main channel | ||
44 | * AM1 0: Stereo 1: Mono | ||
45 | * AM0 0: Normal 1: Mute | ||
46 | * | ||
47 | * DM* : Detected tuner audio Mode | ||
48 | * DM1 0: Stereo 1: Mono | ||
49 | * DM0 0: Multiplex 1: Normal | ||
50 | * | ||
51 | * GPIO Initial Settings | ||
52 | * MPG600 MPG160 | ||
53 | * DIR 0x3080 0x7080 | ||
54 | * OUTPUT 0x000C 0x400C | ||
55 | * | ||
56 | * Special thanks to Makoto Iguchi <iguchi@tahoo.org> and Mr. Anonymous | ||
57 | * for analyzing GPIO of MPG160. | ||
58 | * | ||
59 | ***************************************************************************** | ||
60 | * | ||
61 | * GPIO assignment of Avermedia M179 (per information direct from AVerMedia) | ||
62 | * | ||
63 | * bit 15 14 13 12 | 11 10 9 8 | 7 6 5 4 | 3 2 1 0 | ||
64 | * OUTPUT IN0 AM0 IN1 AM1 AM2 IN2 BR0 BR1 | ||
65 | * INPUT | ||
66 | * | ||
67 | * IN* : Input selection | ||
68 | * IN0 IN1 IN2 | ||
69 | * * 1 * Mute | ||
70 | * 0 0 0 Line-In | ||
71 | * 1 0 0 TV Tuner Audio | ||
72 | * 0 0 1 FM Audio | ||
73 | * 1 0 1 Mute | ||
74 | * | ||
75 | * AM* : Audio Mode | ||
76 | * AM0 AM1 AM2 | ||
77 | * 0 0 0 TV Tuner Audio: L_OUT=(L+R)/2, R_OUT=SAP | ||
78 | * 0 0 1 TV Tuner Audio: L_OUT=R_OUT=SAP (SAP) | ||
79 | * 0 1 0 TV Tuner Audio: L_OUT=L, R_OUT=R (stereo) | ||
80 | * 0 1 1 TV Tuner Audio: mute | ||
81 | * 1 * * TV Tuner Audio: L_OUT=R_OUT=(L+R)/2 (mono) | ||
82 | * | ||
83 | * BR* : Audio Sample Rate (BR stands for bitrate for some reason) | ||
84 | * BR0 BR1 | ||
85 | * 0 0 32 kHz | ||
86 | * 0 1 44.1 kHz | ||
87 | * 1 0 48 kHz | ||
88 | * | ||
89 | * DM* : Detected tuner audio Mode | ||
90 | * Unknown currently | ||
91 | * | ||
92 | * Special thanks to AVerMedia Technologies, Inc. and Jiun-Kuei Jung at | ||
93 | * AVerMedia for providing the GPIO information used to add support | ||
94 | * for the M179 cards. | ||
95 | */ | ||
96 | |||
97 | /********************* GPIO stuffs *********************/ | ||
98 | |||
99 | /* GPIO registers */ | ||
100 | #define IVTV_REG_GPIO_IN 0x9008 | ||
101 | #define IVTV_REG_GPIO_OUT 0x900c | ||
102 | #define IVTV_REG_GPIO_DIR 0x9020 | ||
103 | |||
104 | void ivtv_reset_ir_gpio(struct ivtv *itv) | ||
105 | { | ||
106 | int curdir, curout; | ||
107 | |||
108 | if (itv->card->type != IVTV_CARD_PVR_150) | ||
109 | return; | ||
110 | IVTV_DEBUG_INFO("Resetting PVR150 IR\n"); | ||
111 | curout = read_reg(IVTV_REG_GPIO_OUT); | ||
112 | curdir = read_reg(IVTV_REG_GPIO_DIR); | ||
113 | curdir |= 0x80; | ||
114 | write_reg(curdir, IVTV_REG_GPIO_DIR); | ||
115 | curout = (curout & ~0xF) | 1; | ||
116 | write_reg(curout, IVTV_REG_GPIO_OUT); | ||
117 | /* We could use something else for smaller time */ | ||
118 | current->state = TASK_INTERRUPTIBLE; | ||
119 | schedule_timeout(1); | ||
120 | curout |= 2; | ||
121 | write_reg(curout, IVTV_REG_GPIO_OUT); | ||
122 | curdir &= ~0x80; | ||
123 | write_reg(curdir, IVTV_REG_GPIO_DIR); | ||
124 | } | ||
125 | |||
126 | #ifdef HAVE_XC3028 | ||
127 | int ivtv_reset_tuner_gpio(enum v4l2_tuner_type mode, void *priv, int ptr) | ||
128 | { | ||
129 | int curdir, curout; | ||
130 | struct ivtv *itv = (struct ivtv *) priv; | ||
131 | |||
132 | if (itv->card->type != IVTV_CARD_PG600V2 || itv->options.tuner != TUNER_XCEIVE_XC3028) | ||
133 | return -EINVAL; | ||
134 | IVTV_INFO("Resetting tuner.\n"); | ||
135 | curout = read_reg(IVTV_REG_GPIO_OUT); | ||
136 | curdir = read_reg(IVTV_REG_GPIO_DIR); | ||
137 | curdir |= (1 << 12); /* GPIO bit 12 */ | ||
138 | |||
139 | curout &= ~(1 << 12); | ||
140 | write_reg(curout, IVTV_REG_GPIO_OUT); | ||
141 | current->state = TASK_INTERRUPTIBLE; | ||
142 | schedule_timeout(1); | ||
143 | |||
144 | curout |= (1 << 12); | ||
145 | write_reg(curout, IVTV_REG_GPIO_OUT); | ||
146 | current->state = TASK_INTERRUPTIBLE; | ||
147 | schedule_timeout(1); | ||
148 | |||
149 | return 0; | ||
150 | } | ||
151 | #endif | ||
152 | |||
153 | void ivtv_gpio_init(struct ivtv *itv) | ||
154 | { | ||
155 | if (itv->card->gpio_init.direction == 0) | ||
156 | return; | ||
157 | |||
158 | IVTV_DEBUG_INFO("GPIO initial dir: %08x out: %08x\n", | ||
159 | read_reg(IVTV_REG_GPIO_DIR), read_reg(IVTV_REG_GPIO_OUT)); | ||
160 | |||
161 | /* init output data then direction */ | ||
162 | write_reg(itv->card->gpio_init.initial_value, IVTV_REG_GPIO_OUT); | ||
163 | write_reg(itv->card->gpio_init.direction, IVTV_REG_GPIO_DIR); | ||
164 | } | ||
165 | |||
166 | static struct v4l2_queryctrl gpio_ctrl_mute = { | ||
167 | .id = V4L2_CID_AUDIO_MUTE, | ||
168 | .type = V4L2_CTRL_TYPE_BOOLEAN, | ||
169 | .name = "Mute", | ||
170 | .minimum = 0, | ||
171 | .maximum = 1, | ||
172 | .step = 1, | ||
173 | .default_value = 1, | ||
174 | .flags = 0, | ||
175 | }; | ||
176 | |||
177 | int ivtv_gpio(struct ivtv *itv, unsigned int command, void *arg) | ||
178 | { | ||
179 | struct v4l2_tuner *tuner = arg; | ||
180 | struct v4l2_control *ctrl = arg; | ||
181 | struct v4l2_routing *route = arg; | ||
182 | u16 mask, data; | ||
183 | |||
184 | switch (command) { | ||
185 | case VIDIOC_INT_AUDIO_CLOCK_FREQ: | ||
186 | mask = itv->card->gpio_audio_freq.mask; | ||
187 | switch (*(u32 *)arg) { | ||
188 | case 32000: | ||
189 | data = itv->card->gpio_audio_freq.f32000; | ||
190 | break; | ||
191 | case 44100: | ||
192 | data = itv->card->gpio_audio_freq.f44100; | ||
193 | break; | ||
194 | case 48000: | ||
195 | default: | ||
196 | data = itv->card->gpio_audio_freq.f48000; | ||
197 | break; | ||
198 | } | ||
199 | break; | ||
200 | |||
201 | case VIDIOC_G_TUNER: | ||
202 | mask = itv->card->gpio_audio_detect.mask; | ||
203 | if (mask == 0 || (read_reg(IVTV_REG_GPIO_IN) & mask)) | ||
204 | tuner->rxsubchans = V4L2_TUNER_MODE_STEREO | | ||
205 | V4L2_TUNER_MODE_LANG1 | V4L2_TUNER_MODE_LANG2; | ||
206 | else | ||
207 | tuner->rxsubchans = V4L2_TUNER_SUB_MONO; | ||
208 | return 0; | ||
209 | |||
210 | case VIDIOC_S_TUNER: | ||
211 | mask = itv->card->gpio_audio_mode.mask; | ||
212 | switch (tuner->audmode) { | ||
213 | case V4L2_TUNER_MODE_LANG1: | ||
214 | data = itv->card->gpio_audio_mode.lang1; | ||
215 | break; | ||
216 | case V4L2_TUNER_MODE_LANG2: | ||
217 | data = itv->card->gpio_audio_mode.lang2; | ||
218 | break; | ||
219 | case V4L2_TUNER_MODE_MONO: | ||
220 | data = itv->card->gpio_audio_mode.mono; | ||
221 | break; | ||
222 | case V4L2_TUNER_MODE_STEREO: | ||
223 | case V4L2_TUNER_MODE_LANG1_LANG2: | ||
224 | default: | ||
225 | data = itv->card->gpio_audio_mode.stereo; | ||
226 | break; | ||
227 | } | ||
228 | break; | ||
229 | |||
230 | case AUDC_SET_RADIO: | ||
231 | mask = itv->card->gpio_audio_input.mask; | ||
232 | data = itv->card->gpio_audio_input.radio; | ||
233 | break; | ||
234 | |||
235 | case VIDIOC_S_STD: | ||
236 | mask = itv->card->gpio_audio_input.mask; | ||
237 | data = itv->card->gpio_audio_input.tuner; | ||
238 | break; | ||
239 | |||
240 | case VIDIOC_INT_S_AUDIO_ROUTING: | ||
241 | if (route->input > 2) | ||
242 | return -EINVAL; | ||
243 | mask = itv->card->gpio_audio_input.mask; | ||
244 | switch (route->input) { | ||
245 | case 0: | ||
246 | data = itv->card->gpio_audio_input.tuner; | ||
247 | break; | ||
248 | case 1: | ||
249 | data = itv->card->gpio_audio_input.linein; | ||
250 | break; | ||
251 | case 2: | ||
252 | default: | ||
253 | data = itv->card->gpio_audio_input.radio; | ||
254 | break; | ||
255 | } | ||
256 | break; | ||
257 | |||
258 | case VIDIOC_G_CTRL: | ||
259 | if (ctrl->id != V4L2_CID_AUDIO_MUTE) | ||
260 | return -EINVAL; | ||
261 | mask = itv->card->gpio_audio_mute.mask; | ||
262 | data = itv->card->gpio_audio_mute.mute; | ||
263 | ctrl->value = (read_reg(IVTV_REG_GPIO_OUT) & mask) == data; | ||
264 | return 0; | ||
265 | |||
266 | case VIDIOC_S_CTRL: | ||
267 | if (ctrl->id != V4L2_CID_AUDIO_MUTE) | ||
268 | return -EINVAL; | ||
269 | mask = itv->card->gpio_audio_mute.mask; | ||
270 | data = ctrl->value ? itv->card->gpio_audio_mute.mute : 0; | ||
271 | break; | ||
272 | |||
273 | case VIDIOC_QUERYCTRL: | ||
274 | { | ||
275 | struct v4l2_queryctrl *qc = arg; | ||
276 | |||
277 | if (qc->id != V4L2_CID_AUDIO_MUTE) | ||
278 | return -EINVAL; | ||
279 | *qc = gpio_ctrl_mute; | ||
280 | return 0; | ||
281 | } | ||
282 | |||
283 | case VIDIOC_LOG_STATUS: | ||
284 | IVTV_INFO("GPIO status: DIR=0x%04x OUT=0x%04x IN=0x%04x\n", | ||
285 | read_reg(IVTV_REG_GPIO_DIR), read_reg(IVTV_REG_GPIO_OUT), | ||
286 | read_reg(IVTV_REG_GPIO_IN)); | ||
287 | return 0; | ||
288 | |||
289 | case VIDIOC_INT_S_VIDEO_ROUTING: | ||
290 | if (route->input > 2) /* 0:Tuner 1:Composite 2:S-Video */ | ||
291 | return -EINVAL; | ||
292 | mask = itv->card->gpio_video_input.mask; | ||
293 | if (route->input == 0) | ||
294 | data = itv->card->gpio_video_input.tuner; | ||
295 | else if (route->input == 1) | ||
296 | data = itv->card->gpio_video_input.composite; | ||
297 | else | ||
298 | data = itv->card->gpio_video_input.svideo; | ||
299 | break; | ||
300 | |||
301 | default: | ||
302 | return -EINVAL; | ||
303 | } | ||
304 | if (mask) | ||
305 | write_reg((read_reg(IVTV_REG_GPIO_OUT) & ~mask) | (data & mask), IVTV_REG_GPIO_OUT); | ||
306 | return 0; | ||
307 | } | ||
diff --git a/drivers/media/video/ivtv/ivtv-gpio.h b/drivers/media/video/ivtv/ivtv-gpio.h new file mode 100644 index 000000000000..c301d2a39346 --- /dev/null +++ b/drivers/media/video/ivtv/ivtv-gpio.h | |||
@@ -0,0 +1,25 @@ | |||
1 | /* | ||
2 | gpio functions. | ||
3 | Copyright (C) 2004 Chris Kennedy <c@groovy.org> | ||
4 | Copyright (C) 2005-2007 Hans Verkuil <hverkuil@xs4all.nl> | ||
5 | |||
6 | This program is free software; you can redistribute it and/or modify | ||
7 | it under the terms of the GNU General Public License as published by | ||
8 | the Free Software Foundation; either version 2 of the License, or | ||
9 | (at your option) any later version. | ||
10 | |||
11 | This program is distributed in the hope that it will be useful, | ||
12 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
14 | GNU General Public License for more details. | ||
15 | |||
16 | You should have received a copy of the GNU General Public License | ||
17 | along with this program; if not, write to the Free Software | ||
18 | Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
19 | */ | ||
20 | |||
21 | /* GPIO stuff */ | ||
22 | void ivtv_gpio_init(struct ivtv *itv); | ||
23 | void ivtv_reset_ir_gpio(struct ivtv *itv); | ||
24 | int ivtv_reset_tuner_gpio(enum v4l2_tuner_type mode, void *priv, int ptr); | ||
25 | int ivtv_gpio(struct ivtv *itv, unsigned int command, void *arg); | ||
diff --git a/drivers/media/video/ivtv/ivtv-i2c.c b/drivers/media/video/ivtv/ivtv-i2c.c new file mode 100644 index 000000000000..50624c6a62a5 --- /dev/null +++ b/drivers/media/video/ivtv/ivtv-i2c.c | |||
@@ -0,0 +1,748 @@ | |||
1 | /* | ||
2 | I2C functions | ||
3 | Copyright (C) 2003-2004 Kevin Thayer <nufan_wfk at yahoo.com> | ||
4 | Copyright (C) 2005-2007 Hans Verkuil <hverkuil@xs4all.nl> | ||
5 | |||
6 | This program is free software; you can redistribute it and/or modify | ||
7 | it under the terms of the GNU General Public License as published by | ||
8 | the Free Software Foundation; either version 2 of the License, or | ||
9 | (at your option) any later version. | ||
10 | |||
11 | This program is distributed in the hope that it will be useful, | ||
12 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
14 | GNU General Public License for more details. | ||
15 | |||
16 | You should have received a copy of the GNU General Public License | ||
17 | along with this program; if not, write to the Free Software | ||
18 | Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
19 | */ | ||
20 | |||
21 | /* | ||
22 | This file includes an i2c implementation that was reverse engineered | ||
23 | from the Hauppauge windows driver. Older ivtv versions used i2c-algo-bit, | ||
24 | which whilst fine under most circumstances, had trouble with the Zilog | ||
25 | CPU on the PVR-150 which handles IR functions (occasional inability to | ||
26 | communicate with the chip until it was reset) and also with the i2c | ||
27 | bus being completely unreachable when multiple PVR cards were present. | ||
28 | |||
29 | The implementation is very similar to i2c-algo-bit, but there are enough | ||
30 | subtle differences that the two are hard to merge. The general strategy | ||
31 | employed by i2c-algo-bit is to use udelay() to implement the timing | ||
32 | when putting out bits on the scl/sda lines. The general strategy taken | ||
33 | here is to poll the lines for state changes (see ivtv_waitscl and | ||
34 | ivtv_waitsda). In addition there are small delays at various locations | ||
35 | which poll the SCL line 5 times (ivtv_scldelay). I would guess that | ||
36 | since this is memory mapped I/O that the length of those delays is tied | ||
37 | to the PCI bus clock. There is some extra code to do with recovery | ||
38 | and retries. Since it is not known what causes the actual i2c problems | ||
39 | in the first place, the only goal if one was to attempt to use | ||
40 | i2c-algo-bit would be to try to make it follow the same code path. | ||
41 | This would be a lot of work, and I'm also not convinced that it would | ||
42 | provide a generic benefit to i2c-algo-bit. Therefore consider this | ||
43 | an engineering solution -- not pretty, but it works. | ||
44 | |||
45 | Some more general comments about what we are doing: | ||
46 | |||
47 | The i2c bus is a 2 wire serial bus, with clock (SCL) and data (SDA) | ||
48 | lines. To communicate on the bus (as a master, we don't act as a slave), | ||
49 | we first initiate a start condition (ivtv_start). We then write the | ||
50 | address of the device that we want to communicate with, along with a flag | ||
51 | that indicates whether this is a read or a write. The slave then issues | ||
52 | an ACK signal (ivtv_ack), which tells us that it is ready for reading / | ||
53 | writing. We then proceed with reading or writing (ivtv_read/ivtv_write), | ||
54 | and finally issue a stop condition (ivtv_stop) to make the bus available | ||
55 | to other masters. | ||
56 | |||
57 | There is an additional form of transaction where a write may be | ||
58 | immediately followed by a read. In this case, there is no intervening | ||
59 | stop condition. (Only the msp3400 chip uses this method of data transfer). | ||
60 | */ | ||
61 | |||
62 | #include "ivtv-driver.h" | ||
63 | #include "ivtv-cards.h" | ||
64 | #include "ivtv-gpio.h" | ||
65 | #include "ivtv-i2c.h" | ||
66 | |||
67 | #include <media/ir-kbd-i2c.h> | ||
68 | |||
69 | /* i2c implementation for cx23415/6 chip, ivtv project. | ||
70 | * Author: Kevin Thayer (nufan_wfk at yahoo.com) | ||
71 | */ | ||
72 | /* i2c stuff */ | ||
73 | #define IVTV_REG_I2C_SETSCL_OFFSET 0x7000 | ||
74 | #define IVTV_REG_I2C_SETSDA_OFFSET 0x7004 | ||
75 | #define IVTV_REG_I2C_GETSCL_OFFSET 0x7008 | ||
76 | #define IVTV_REG_I2C_GETSDA_OFFSET 0x700c | ||
77 | |||
78 | #ifndef I2C_ADAP_CLASS_TV_ANALOG | ||
79 | #define I2C_ADAP_CLASS_TV_ANALOG I2C_CLASS_TV_ANALOG | ||
80 | #endif /* I2C_ADAP_CLASS_TV_ANALOG */ | ||
81 | |||
82 | #define IVTV_CS53L32A_I2C_ADDR 0x11 | ||
83 | #define IVTV_CX25840_I2C_ADDR 0x44 | ||
84 | #define IVTV_SAA7115_I2C_ADDR 0x21 | ||
85 | #define IVTV_SAA7127_I2C_ADDR 0x44 | ||
86 | #define IVTV_SAA717x_I2C_ADDR 0x21 | ||
87 | #define IVTV_MSP3400_I2C_ADDR 0x40 | ||
88 | #define IVTV_HAUPPAUGE_I2C_ADDR 0x50 | ||
89 | #define IVTV_WM8739_I2C_ADDR 0x1a | ||
90 | #define IVTV_WM8775_I2C_ADDR 0x1b | ||
91 | #define IVTV_TEA5767_I2C_ADDR 0x60 | ||
92 | #define IVTV_UPD64031A_I2C_ADDR 0x12 | ||
93 | #define IVTV_UPD64083_I2C_ADDR 0x5c | ||
94 | #define IVTV_TDA985X_I2C_ADDR 0x5b | ||
95 | |||
96 | /* This array should match the IVTV_HW_ defines */ | ||
97 | static const u8 hw_driverids[] = { | ||
98 | I2C_DRIVERID_CX25840, | ||
99 | I2C_DRIVERID_SAA711X, | ||
100 | I2C_DRIVERID_SAA7127, | ||
101 | I2C_DRIVERID_MSP3400, | ||
102 | I2C_DRIVERID_TUNER, | ||
103 | I2C_DRIVERID_WM8775, | ||
104 | I2C_DRIVERID_CS53L32A, | ||
105 | I2C_DRIVERID_TVEEPROM, | ||
106 | I2C_DRIVERID_SAA711X, | ||
107 | I2C_DRIVERID_TVAUDIO, | ||
108 | I2C_DRIVERID_UPD64031A, | ||
109 | I2C_DRIVERID_UPD64083, | ||
110 | I2C_DRIVERID_SAA717X, | ||
111 | I2C_DRIVERID_WM8739, | ||
112 | 0 /* IVTV_HW_GPIO dummy driver ID */ | ||
113 | }; | ||
114 | |||
115 | /* This array should match the IVTV_HW_ defines */ | ||
116 | static const char * const hw_drivernames[] = { | ||
117 | "cx2584x", | ||
118 | "saa7115", | ||
119 | "saa7127", | ||
120 | "msp3400", | ||
121 | "tuner", | ||
122 | "wm8775", | ||
123 | "cs53l32a", | ||
124 | "tveeprom", | ||
125 | "saa7114", | ||
126 | "tvaudio", | ||
127 | "upd64031a", | ||
128 | "upd64083", | ||
129 | "saa717x", | ||
130 | "wm8739", | ||
131 | "gpio", | ||
132 | }; | ||
133 | |||
134 | static int attach_inform(struct i2c_client *client) | ||
135 | { | ||
136 | struct ivtv *itv = (struct ivtv *)i2c_get_adapdata(client->adapter); | ||
137 | int i; | ||
138 | |||
139 | IVTV_DEBUG_I2C("i2c client attach\n"); | ||
140 | for (i = 0; i < I2C_CLIENTS_MAX; i++) { | ||
141 | if (itv->i2c_clients[i] == NULL) { | ||
142 | itv->i2c_clients[i] = client; | ||
143 | break; | ||
144 | } | ||
145 | } | ||
146 | if (i == I2C_CLIENTS_MAX) { | ||
147 | IVTV_ERR("insufficient room for new I2C client!\n"); | ||
148 | } | ||
149 | return 0; | ||
150 | } | ||
151 | |||
152 | static int detach_inform(struct i2c_client *client) | ||
153 | { | ||
154 | int i; | ||
155 | struct ivtv *itv = (struct ivtv *)i2c_get_adapdata(client->adapter); | ||
156 | |||
157 | IVTV_DEBUG_I2C("i2c client detach\n"); | ||
158 | for (i = 0; i < I2C_CLIENTS_MAX; i++) { | ||
159 | if (itv->i2c_clients[i] == client) { | ||
160 | itv->i2c_clients[i] = NULL; | ||
161 | break; | ||
162 | } | ||
163 | } | ||
164 | IVTV_DEBUG_I2C("i2c detach [client=%s,%s]\n", | ||
165 | client->name, (i < I2C_CLIENTS_MAX) ? "ok" : "failed"); | ||
166 | |||
167 | return 0; | ||
168 | } | ||
169 | |||
170 | /* Set the serial clock line to the desired state */ | ||
171 | static void ivtv_setscl(struct ivtv *itv, int state) | ||
172 | { | ||
173 | /* write them out */ | ||
174 | /* write bits are inverted */ | ||
175 | write_reg(~state, IVTV_REG_I2C_SETSCL_OFFSET); | ||
176 | } | ||
177 | |||
178 | /* Set the serial data line to the desired state */ | ||
179 | static void ivtv_setsda(struct ivtv *itv, int state) | ||
180 | { | ||
181 | /* write them out */ | ||
182 | /* write bits are inverted */ | ||
183 | write_reg(~state & 1, IVTV_REG_I2C_SETSDA_OFFSET); | ||
184 | } | ||
185 | |||
186 | /* Read the serial clock line */ | ||
187 | static int ivtv_getscl(struct ivtv *itv) | ||
188 | { | ||
189 | return read_reg(IVTV_REG_I2C_GETSCL_OFFSET) & 1; | ||
190 | } | ||
191 | |||
192 | /* Read the serial data line */ | ||
193 | static int ivtv_getsda(struct ivtv *itv) | ||
194 | { | ||
195 | return read_reg(IVTV_REG_I2C_GETSDA_OFFSET) & 1; | ||
196 | } | ||
197 | |||
198 | /* Implement a short delay by polling the serial clock line */ | ||
199 | static void ivtv_scldelay(struct ivtv *itv) | ||
200 | { | ||
201 | int i; | ||
202 | |||
203 | for (i = 0; i < 5; ++i) | ||
204 | ivtv_getscl(itv); | ||
205 | } | ||
206 | |||
207 | /* Wait for the serial clock line to become set to a specific value */ | ||
208 | static int ivtv_waitscl(struct ivtv *itv, int val) | ||
209 | { | ||
210 | int i; | ||
211 | |||
212 | ivtv_scldelay(itv); | ||
213 | for (i = 0; i < 1000; ++i) { | ||
214 | if (ivtv_getscl(itv) == val) | ||
215 | return 1; | ||
216 | } | ||
217 | return 0; | ||
218 | } | ||
219 | |||
220 | /* Wait for the serial data line to become set to a specific value */ | ||
221 | static int ivtv_waitsda(struct ivtv *itv, int val) | ||
222 | { | ||
223 | int i; | ||
224 | |||
225 | ivtv_scldelay(itv); | ||
226 | for (i = 0; i < 1000; ++i) { | ||
227 | if (ivtv_getsda(itv) == val) | ||
228 | return 1; | ||
229 | } | ||
230 | return 0; | ||
231 | } | ||
232 | |||
233 | /* Wait for the slave to issue an ACK */ | ||
234 | static int ivtv_ack(struct ivtv *itv) | ||
235 | { | ||
236 | int ret = 0; | ||
237 | |||
238 | if (ivtv_getscl(itv) == 1) { | ||
239 | IVTV_DEBUG_I2C("SCL was high starting an ack\n"); | ||
240 | ivtv_setscl(itv, 0); | ||
241 | if (!ivtv_waitscl(itv, 0)) { | ||
242 | IVTV_DEBUG_I2C("Could not set SCL low starting an ack\n"); | ||
243 | return -EREMOTEIO; | ||
244 | } | ||
245 | } | ||
246 | ivtv_setsda(itv, 1); | ||
247 | ivtv_scldelay(itv); | ||
248 | ivtv_setscl(itv, 1); | ||
249 | if (!ivtv_waitsda(itv, 0)) { | ||
250 | IVTV_DEBUG_I2C("Slave did not ack\n"); | ||
251 | ret = -EREMOTEIO; | ||
252 | } | ||
253 | ivtv_setscl(itv, 0); | ||
254 | if (!ivtv_waitscl(itv, 0)) { | ||
255 | IVTV_DEBUG_I2C("Failed to set SCL low after ACK\n"); | ||
256 | ret = -EREMOTEIO; | ||
257 | } | ||
258 | return ret; | ||
259 | } | ||
260 | |||
261 | /* Write a single byte to the i2c bus and wait for the slave to ACK */ | ||
262 | static int ivtv_sendbyte(struct ivtv *itv, unsigned char byte) | ||
263 | { | ||
264 | int i, bit; | ||
265 | |||
266 | IVTV_DEBUG_I2C("write %x\n",byte); | ||
267 | for (i = 0; i < 8; ++i, byte<<=1) { | ||
268 | ivtv_setscl(itv, 0); | ||
269 | if (!ivtv_waitscl(itv, 0)) { | ||
270 | IVTV_DEBUG_I2C("Error setting SCL low\n"); | ||
271 | return -EREMOTEIO; | ||
272 | } | ||
273 | bit = (byte>>7)&1; | ||
274 | ivtv_setsda(itv, bit); | ||
275 | if (!ivtv_waitsda(itv, bit)) { | ||
276 | IVTV_DEBUG_I2C("Error setting SDA\n"); | ||
277 | return -EREMOTEIO; | ||
278 | } | ||
279 | ivtv_setscl(itv, 1); | ||
280 | if (!ivtv_waitscl(itv, 1)) { | ||
281 | IVTV_DEBUG_I2C("Slave not ready for bit\n"); | ||
282 | return -EREMOTEIO; | ||
283 | } | ||
284 | } | ||
285 | ivtv_setscl(itv, 0); | ||
286 | if (!ivtv_waitscl(itv, 0)) { | ||
287 | IVTV_DEBUG_I2C("Error setting SCL low\n"); | ||
288 | return -EREMOTEIO; | ||
289 | } | ||
290 | return ivtv_ack(itv); | ||
291 | } | ||
292 | |||
293 | /* Read a byte from the i2c bus and send a NACK if applicable (i.e. for the | ||
294 | final byte) */ | ||
295 | static int ivtv_readbyte(struct ivtv *itv, unsigned char *byte, int nack) | ||
296 | { | ||
297 | int i; | ||
298 | |||
299 | *byte = 0; | ||
300 | |||
301 | ivtv_setsda(itv, 1); | ||
302 | ivtv_scldelay(itv); | ||
303 | for (i = 0; i < 8; ++i) { | ||
304 | ivtv_setscl(itv, 0); | ||
305 | ivtv_scldelay(itv); | ||
306 | ivtv_setscl(itv, 1); | ||
307 | if (!ivtv_waitscl(itv, 1)) { | ||
308 | IVTV_DEBUG_I2C("Error setting SCL high\n"); | ||
309 | return -EREMOTEIO; | ||
310 | } | ||
311 | *byte = ((*byte)<<1)|ivtv_getsda(itv); | ||
312 | } | ||
313 | ivtv_setscl(itv, 0); | ||
314 | ivtv_scldelay(itv); | ||
315 | ivtv_setsda(itv, nack); | ||
316 | ivtv_scldelay(itv); | ||
317 | ivtv_setscl(itv, 1); | ||
318 | ivtv_scldelay(itv); | ||
319 | ivtv_setscl(itv, 0); | ||
320 | ivtv_scldelay(itv); | ||
321 | IVTV_DEBUG_I2C("read %x\n",*byte); | ||
322 | return 0; | ||
323 | } | ||
324 | |||
325 | /* Issue a start condition on the i2c bus to alert slaves to prepare for | ||
326 | an address write */ | ||
327 | static int ivtv_start(struct ivtv *itv) | ||
328 | { | ||
329 | int sda; | ||
330 | |||
331 | sda = ivtv_getsda(itv); | ||
332 | if (sda != 1) { | ||
333 | IVTV_DEBUG_I2C("SDA was low at start\n"); | ||
334 | ivtv_setsda(itv, 1); | ||
335 | if (!ivtv_waitsda(itv, 1)) { | ||
336 | IVTV_DEBUG_I2C("SDA stuck low\n"); | ||
337 | return -EREMOTEIO; | ||
338 | } | ||
339 | } | ||
340 | if (ivtv_getscl(itv) != 1) { | ||
341 | ivtv_setscl(itv, 1); | ||
342 | if (!ivtv_waitscl(itv, 1)) { | ||
343 | IVTV_DEBUG_I2C("SCL stuck low at start\n"); | ||
344 | return -EREMOTEIO; | ||
345 | } | ||
346 | } | ||
347 | ivtv_setsda(itv, 0); | ||
348 | ivtv_scldelay(itv); | ||
349 | return 0; | ||
350 | } | ||
351 | |||
352 | /* Issue a stop condition on the i2c bus to release it */ | ||
353 | static int ivtv_stop(struct ivtv *itv) | ||
354 | { | ||
355 | int i; | ||
356 | |||
357 | if (ivtv_getscl(itv) != 0) { | ||
358 | IVTV_DEBUG_I2C("SCL not low when stopping\n"); | ||
359 | ivtv_setscl(itv, 0); | ||
360 | if (!ivtv_waitscl(itv, 0)) { | ||
361 | IVTV_DEBUG_I2C("SCL could not be set low\n"); | ||
362 | } | ||
363 | } | ||
364 | ivtv_setsda(itv, 0); | ||
365 | ivtv_scldelay(itv); | ||
366 | ivtv_setscl(itv, 1); | ||
367 | if (!ivtv_waitscl(itv, 1)) { | ||
368 | IVTV_DEBUG_I2C("SCL could not be set high\n"); | ||
369 | return -EREMOTEIO; | ||
370 | } | ||
371 | ivtv_scldelay(itv); | ||
372 | ivtv_setsda(itv, 1); | ||
373 | if (!ivtv_waitsda(itv, 1)) { | ||
374 | IVTV_DEBUG_I2C("resetting I2C\n"); | ||
375 | for (i = 0; i < 16; ++i) { | ||
376 | ivtv_setscl(itv, 0); | ||
377 | ivtv_scldelay(itv); | ||
378 | ivtv_setscl(itv, 1); | ||
379 | ivtv_scldelay(itv); | ||
380 | ivtv_setsda(itv, 1); | ||
381 | } | ||
382 | ivtv_waitsda(itv, 1); | ||
383 | return -EREMOTEIO; | ||
384 | } | ||
385 | return 0; | ||
386 | } | ||
387 | |||
388 | /* Write a message to the given i2c slave. do_stop may be 0 to prevent | ||
389 | issuing the i2c stop condition (when following with a read) */ | ||
390 | static int ivtv_write(struct ivtv *itv, unsigned char addr, unsigned char *data, u32 len, int do_stop) | ||
391 | { | ||
392 | int retry, ret = -EREMOTEIO; | ||
393 | u32 i; | ||
394 | |||
395 | for (retry = 0; ret != 0 && retry < 8; ++retry) { | ||
396 | ret = ivtv_start(itv); | ||
397 | |||
398 | if (ret == 0) { | ||
399 | ret = ivtv_sendbyte(itv, addr<<1); | ||
400 | for (i = 0; ret == 0 && i < len; ++i) | ||
401 | ret = ivtv_sendbyte(itv, data[i]); | ||
402 | } | ||
403 | if (ret != 0 || do_stop) { | ||
404 | ivtv_stop(itv); | ||
405 | } | ||
406 | } | ||
407 | if (ret) | ||
408 | IVTV_DEBUG_I2C("i2c write to %x failed\n", addr); | ||
409 | return ret; | ||
410 | } | ||
411 | |||
412 | /* Read data from the given i2c slave. A stop condition is always issued. */ | ||
413 | static int ivtv_read(struct ivtv *itv, unsigned char addr, unsigned char *data, u32 len) | ||
414 | { | ||
415 | int retry, ret = -EREMOTEIO; | ||
416 | u32 i; | ||
417 | |||
418 | for (retry = 0; ret != 0 && retry < 8; ++retry) { | ||
419 | ret = ivtv_start(itv); | ||
420 | if (ret == 0) | ||
421 | ret = ivtv_sendbyte(itv, (addr << 1) | 1); | ||
422 | for (i = 0; ret == 0 && i < len; ++i) { | ||
423 | ret = ivtv_readbyte(itv, &data[i], i == len - 1); | ||
424 | } | ||
425 | ivtv_stop(itv); | ||
426 | } | ||
427 | if (ret) | ||
428 | IVTV_DEBUG_I2C("i2c read from %x failed\n", addr); | ||
429 | return ret; | ||
430 | } | ||
431 | |||
432 | /* Kernel i2c transfer implementation. Takes a number of messages to be read | ||
433 | or written. If a read follows a write, this will occur without an | ||
434 | intervening stop condition */ | ||
435 | static int ivtv_xfer(struct i2c_adapter *i2c_adap, struct i2c_msg *msgs, int num) | ||
436 | { | ||
437 | struct ivtv *itv = i2c_get_adapdata(i2c_adap); | ||
438 | int retval; | ||
439 | int i; | ||
440 | |||
441 | mutex_lock(&itv->i2c_bus_lock); | ||
442 | for (i = retval = 0; retval == 0 && i < num; i++) { | ||
443 | if (msgs[i].flags & I2C_M_RD) | ||
444 | retval = ivtv_read(itv, msgs[i].addr, msgs[i].buf, msgs[i].len); | ||
445 | else { | ||
446 | /* if followed by a read, don't stop */ | ||
447 | int stop = !(i + 1 < num && msgs[i + 1].flags == I2C_M_RD); | ||
448 | |||
449 | retval = ivtv_write(itv, msgs[i].addr, msgs[i].buf, msgs[i].len, stop); | ||
450 | } | ||
451 | } | ||
452 | mutex_unlock(&itv->i2c_bus_lock); | ||
453 | return retval ? retval : num; | ||
454 | } | ||
455 | |||
456 | /* Kernel i2c capabilities */ | ||
457 | static u32 ivtv_functionality(struct i2c_adapter *adap) | ||
458 | { | ||
459 | return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL; | ||
460 | } | ||
461 | |||
462 | static struct i2c_algorithm ivtv_algo = { | ||
463 | .master_xfer = ivtv_xfer, | ||
464 | .functionality = ivtv_functionality, | ||
465 | }; | ||
466 | |||
467 | /* template for our-bit banger */ | ||
468 | static struct i2c_adapter ivtv_i2c_adap_hw_template = { | ||
469 | .name = "ivtv i2c driver", | ||
470 | .id = I2C_HW_B_CX2341X, | ||
471 | .algo = &ivtv_algo, | ||
472 | .algo_data = NULL, /* filled from template */ | ||
473 | .client_register = attach_inform, | ||
474 | .client_unregister = detach_inform, | ||
475 | .owner = THIS_MODULE, | ||
476 | #ifdef I2C_ADAP_CLASS_TV_ANALOG | ||
477 | .class = I2C_ADAP_CLASS_TV_ANALOG, | ||
478 | #endif | ||
479 | }; | ||
480 | |||
481 | static void ivtv_setscl_old(void *data, int state) | ||
482 | { | ||
483 | struct ivtv *itv = (struct ivtv *)data; | ||
484 | |||
485 | if (state) | ||
486 | itv->i2c_state |= 0x01; | ||
487 | else | ||
488 | itv->i2c_state &= ~0x01; | ||
489 | |||
490 | /* write them out */ | ||
491 | /* write bits are inverted */ | ||
492 | write_reg(~itv->i2c_state, IVTV_REG_I2C_SETSCL_OFFSET); | ||
493 | } | ||
494 | |||
495 | static void ivtv_setsda_old(void *data, int state) | ||
496 | { | ||
497 | struct ivtv *itv = (struct ivtv *)data; | ||
498 | |||
499 | if (state) | ||
500 | itv->i2c_state |= 0x01; | ||
501 | else | ||
502 | itv->i2c_state &= ~0x01; | ||
503 | |||
504 | /* write them out */ | ||
505 | /* write bits are inverted */ | ||
506 | write_reg(~itv->i2c_state, IVTV_REG_I2C_SETSDA_OFFSET); | ||
507 | } | ||
508 | |||
509 | static int ivtv_getscl_old(void *data) | ||
510 | { | ||
511 | struct ivtv *itv = (struct ivtv *)data; | ||
512 | |||
513 | return read_reg(IVTV_REG_I2C_GETSCL_OFFSET) & 1; | ||
514 | } | ||
515 | |||
516 | static int ivtv_getsda_old(void *data) | ||
517 | { | ||
518 | struct ivtv *itv = (struct ivtv *)data; | ||
519 | |||
520 | return read_reg(IVTV_REG_I2C_GETSDA_OFFSET) & 1; | ||
521 | } | ||
522 | |||
523 | /* template for i2c-bit-algo */ | ||
524 | static struct i2c_adapter ivtv_i2c_adap_template = { | ||
525 | .name = "ivtv i2c driver", | ||
526 | .id = I2C_HW_B_CX2341X, /* algo-bit is OR'd with this */ | ||
527 | .algo = NULL, /* set by i2c-algo-bit */ | ||
528 | .algo_data = NULL, /* filled from template */ | ||
529 | .client_register = attach_inform, | ||
530 | .client_unregister = detach_inform, | ||
531 | .owner = THIS_MODULE, | ||
532 | #ifdef I2C_ADAP_CLASS_TV_ANALOG | ||
533 | .class = I2C_ADAP_CLASS_TV_ANALOG, | ||
534 | #endif | ||
535 | }; | ||
536 | |||
537 | static struct i2c_algo_bit_data ivtv_i2c_algo_template = { | ||
538 | NULL, /* ?? */ | ||
539 | ivtv_setsda_old, /* setsda function */ | ||
540 | ivtv_setscl_old, /* " */ | ||
541 | ivtv_getsda_old, /* " */ | ||
542 | ivtv_getscl_old, /* " */ | ||
543 | 10, /* udelay */ | ||
544 | 200 /* timeout */ | ||
545 | }; | ||
546 | |||
547 | static struct i2c_client ivtv_i2c_client_template = { | ||
548 | .name = "ivtv internal", | ||
549 | }; | ||
550 | |||
551 | int ivtv_call_i2c_client(struct ivtv *itv, int addr, unsigned int cmd, void *arg) | ||
552 | { | ||
553 | struct i2c_client *client; | ||
554 | int retval; | ||
555 | int i; | ||
556 | |||
557 | IVTV_DEBUG_I2C("call_i2c_client addr=%02x\n", addr); | ||
558 | for (i = 0; i < I2C_CLIENTS_MAX; i++) { | ||
559 | client = itv->i2c_clients[i]; | ||
560 | if (client == NULL) { | ||
561 | continue; | ||
562 | } | ||
563 | if (client->driver->command == NULL) { | ||
564 | continue; | ||
565 | } | ||
566 | if (addr == client->addr) { | ||
567 | retval = client->driver->command(client, cmd, arg); | ||
568 | return retval; | ||
569 | } | ||
570 | } | ||
571 | if (cmd != VIDIOC_G_CHIP_IDENT) | ||
572 | IVTV_ERR("i2c addr 0x%02x not found for command 0x%x!\n", addr, cmd); | ||
573 | return -ENODEV; | ||
574 | } | ||
575 | |||
576 | /* Find the i2c device based on the driver ID and return | ||
577 | its i2c address or -ENODEV if no matching device was found. */ | ||
578 | static int ivtv_i2c_id_addr(struct ivtv *itv, u32 id) | ||
579 | { | ||
580 | struct i2c_client *client; | ||
581 | int retval = -ENODEV; | ||
582 | int i; | ||
583 | |||
584 | for (i = 0; i < I2C_CLIENTS_MAX; i++) { | ||
585 | client = itv->i2c_clients[i]; | ||
586 | if (client == NULL) | ||
587 | continue; | ||
588 | if (id == client->driver->id) { | ||
589 | retval = client->addr; | ||
590 | break; | ||
591 | } | ||
592 | } | ||
593 | return retval; | ||
594 | } | ||
595 | |||
596 | /* Find the i2c device name matching the DRIVERID */ | ||
597 | static const char *ivtv_i2c_id_name(u32 id) | ||
598 | { | ||
599 | int i; | ||
600 | |||
601 | for (i = 0; i < ARRAY_SIZE(hw_driverids); i++) | ||
602 | if (hw_driverids[i] == id) | ||
603 | return hw_drivernames[i]; | ||
604 | return "unknown device"; | ||
605 | } | ||
606 | |||
607 | /* Find the i2c device name matching the IVTV_HW_ flag */ | ||
608 | static const char *ivtv_i2c_hw_name(u32 hw) | ||
609 | { | ||
610 | int i; | ||
611 | |||
612 | for (i = 0; i < ARRAY_SIZE(hw_driverids); i++) | ||
613 | if (1 << i == hw) | ||
614 | return hw_drivernames[i]; | ||
615 | return "unknown device"; | ||
616 | } | ||
617 | |||
618 | /* Find the i2c device matching the IVTV_HW_ flag and return | ||
619 | its i2c address or -ENODEV if no matching device was found. */ | ||
620 | int ivtv_i2c_hw_addr(struct ivtv *itv, u32 hw) | ||
621 | { | ||
622 | int i; | ||
623 | |||
624 | for (i = 0; i < ARRAY_SIZE(hw_driverids); i++) | ||
625 | if (1 << i == hw) | ||
626 | return ivtv_i2c_id_addr(itv, hw_driverids[i]); | ||
627 | return -ENODEV; | ||
628 | } | ||
629 | |||
630 | /* Calls i2c device based on IVTV_HW_ flag. If hw == 0, then do nothing. | ||
631 | If hw == IVTV_HW_GPIO then call the gpio handler. */ | ||
632 | int ivtv_i2c_hw(struct ivtv *itv, u32 hw, unsigned int cmd, void *arg) | ||
633 | { | ||
634 | int addr; | ||
635 | |||
636 | if (hw == IVTV_HW_GPIO) | ||
637 | return ivtv_gpio(itv, cmd, arg); | ||
638 | if (hw == 0) | ||
639 | return 0; | ||
640 | |||
641 | addr = ivtv_i2c_hw_addr(itv, hw); | ||
642 | if (addr < 0) { | ||
643 | IVTV_ERR("i2c hardware 0x%08x (%s) not found for command 0x%x!\n", | ||
644 | hw, ivtv_i2c_hw_name(hw), cmd); | ||
645 | return addr; | ||
646 | } | ||
647 | return ivtv_call_i2c_client(itv, addr, cmd, arg); | ||
648 | } | ||
649 | |||
650 | /* Calls i2c device based on I2C driver ID. */ | ||
651 | int ivtv_i2c_id(struct ivtv *itv, u32 id, unsigned int cmd, void *arg) | ||
652 | { | ||
653 | int addr; | ||
654 | |||
655 | addr = ivtv_i2c_id_addr(itv, id); | ||
656 | if (addr < 0) { | ||
657 | if (cmd != VIDIOC_G_CHIP_IDENT) | ||
658 | IVTV_ERR("i2c ID 0x%08x (%s) not found for command 0x%x!\n", | ||
659 | id, ivtv_i2c_id_name(id), cmd); | ||
660 | return addr; | ||
661 | } | ||
662 | return ivtv_call_i2c_client(itv, addr, cmd, arg); | ||
663 | } | ||
664 | |||
665 | int ivtv_cx25840(struct ivtv *itv, unsigned int cmd, void *arg) | ||
666 | { | ||
667 | return ivtv_call_i2c_client(itv, IVTV_CX25840_I2C_ADDR, cmd, arg); | ||
668 | } | ||
669 | |||
670 | int ivtv_saa7115(struct ivtv *itv, unsigned int cmd, void *arg) | ||
671 | { | ||
672 | return ivtv_call_i2c_client(itv, IVTV_SAA7115_I2C_ADDR, cmd, arg); | ||
673 | } | ||
674 | |||
675 | int ivtv_saa7127(struct ivtv *itv, unsigned int cmd, void *arg) | ||
676 | { | ||
677 | return ivtv_call_i2c_client(itv, IVTV_SAA7127_I2C_ADDR, cmd, arg); | ||
678 | } | ||
679 | |||
680 | int ivtv_saa717x(struct ivtv *itv, unsigned int cmd, void *arg) | ||
681 | { | ||
682 | return ivtv_call_i2c_client(itv, IVTV_SAA717x_I2C_ADDR, cmd, arg); | ||
683 | } | ||
684 | |||
685 | int ivtv_upd64031a(struct ivtv *itv, unsigned int cmd, void *arg) | ||
686 | { | ||
687 | return ivtv_call_i2c_client(itv, IVTV_UPD64031A_I2C_ADDR, cmd, arg); | ||
688 | } | ||
689 | |||
690 | int ivtv_upd64083(struct ivtv *itv, unsigned int cmd, void *arg) | ||
691 | { | ||
692 | return ivtv_call_i2c_client(itv, IVTV_UPD64083_I2C_ADDR, cmd, arg); | ||
693 | } | ||
694 | |||
695 | /* broadcast cmd for all I2C clients and for the gpio subsystem */ | ||
696 | void ivtv_call_i2c_clients(struct ivtv *itv, unsigned int cmd, void *arg) | ||
697 | { | ||
698 | if (itv->i2c_adap.algo == NULL) { | ||
699 | IVTV_ERR("adapter is not set"); | ||
700 | return; | ||
701 | } | ||
702 | i2c_clients_command(&itv->i2c_adap, cmd, arg); | ||
703 | if (itv->hw_flags & IVTV_HW_GPIO) | ||
704 | ivtv_gpio(itv, cmd, arg); | ||
705 | } | ||
706 | |||
707 | /* init + register i2c algo-bit adapter */ | ||
708 | int __devinit init_ivtv_i2c(struct ivtv *itv) | ||
709 | { | ||
710 | IVTV_DEBUG_I2C("i2c init\n"); | ||
711 | |||
712 | if (itv->options.newi2c > 0) { | ||
713 | memcpy(&itv->i2c_adap, &ivtv_i2c_adap_hw_template, | ||
714 | sizeof(struct i2c_adapter)); | ||
715 | } else { | ||
716 | memcpy(&itv->i2c_adap, &ivtv_i2c_adap_template, | ||
717 | sizeof(struct i2c_adapter)); | ||
718 | memcpy(&itv->i2c_algo, &ivtv_i2c_algo_template, | ||
719 | sizeof(struct i2c_algo_bit_data)); | ||
720 | itv->i2c_algo.data = itv; | ||
721 | itv->i2c_adap.algo_data = &itv->i2c_algo; | ||
722 | } | ||
723 | |||
724 | sprintf(itv->i2c_adap.name + strlen(itv->i2c_adap.name), " #%d", | ||
725 | itv->num); | ||
726 | i2c_set_adapdata(&itv->i2c_adap, itv); | ||
727 | |||
728 | memcpy(&itv->i2c_client, &ivtv_i2c_client_template, | ||
729 | sizeof(struct i2c_client)); | ||
730 | itv->i2c_client.adapter = &itv->i2c_adap; | ||
731 | itv->i2c_adap.dev.parent = &itv->dev->dev; | ||
732 | |||
733 | IVTV_DEBUG_I2C("setting scl and sda to 1\n"); | ||
734 | ivtv_setscl(itv, 1); | ||
735 | ivtv_setsda(itv, 1); | ||
736 | |||
737 | if (itv->options.newi2c > 0) | ||
738 | return i2c_add_adapter(&itv->i2c_adap); | ||
739 | else | ||
740 | return i2c_bit_add_bus(&itv->i2c_adap); | ||
741 | } | ||
742 | |||
743 | void __devexit exit_ivtv_i2c(struct ivtv *itv) | ||
744 | { | ||
745 | IVTV_DEBUG_I2C("i2c exit\n"); | ||
746 | |||
747 | i2c_del_adapter(&itv->i2c_adap); | ||
748 | } | ||
diff --git a/drivers/media/video/ivtv/ivtv-i2c.h b/drivers/media/video/ivtv/ivtv-i2c.h new file mode 100644 index 000000000000..5d210adb5c52 --- /dev/null +++ b/drivers/media/video/ivtv/ivtv-i2c.h | |||
@@ -0,0 +1,36 @@ | |||
1 | /* | ||
2 | I2C functions | ||
3 | Copyright (C) 2003-2004 Kevin Thayer <nufan_wfk at yahoo.com> | ||
4 | Copyright (C) 2005-2007 Hans Verkuil <hverkuil@xs4all.nl> | ||
5 | |||
6 | This program is free software; you can redistribute it and/or modify | ||
7 | it under the terms of the GNU General Public License as published by | ||
8 | the Free Software Foundation; either version 2 of the License, or | ||
9 | (at your option) any later version. | ||
10 | |||
11 | This program is distributed in the hope that it will be useful, | ||
12 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
14 | GNU General Public License for more details. | ||
15 | |||
16 | You should have received a copy of the GNU General Public License | ||
17 | along with this program; if not, write to the Free Software | ||
18 | Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
19 | */ | ||
20 | |||
21 | int ivtv_cx25840(struct ivtv *itv, unsigned int cmd, void *arg); | ||
22 | int ivtv_saa7115(struct ivtv *itv, unsigned int cmd, void *arg); | ||
23 | int ivtv_saa7127(struct ivtv *itv, unsigned int cmd, void *arg); | ||
24 | int ivtv_saa717x(struct ivtv *itv, unsigned int cmd, void *arg); | ||
25 | int ivtv_upd64031a(struct ivtv *itv, unsigned int cmd, void *arg); | ||
26 | int ivtv_upd64083(struct ivtv *itv, unsigned int cmd, void *arg); | ||
27 | |||
28 | int ivtv_i2c_hw_addr(struct ivtv *itv, u32 hw); | ||
29 | int ivtv_i2c_hw(struct ivtv *itv, u32 hw, unsigned int cmd, void *arg); | ||
30 | int ivtv_i2c_id(struct ivtv *itv, u32 id, unsigned int cmd, void *arg); | ||
31 | int ivtv_call_i2c_client(struct ivtv *itv, int addr, unsigned int cmd, void *arg); | ||
32 | void ivtv_call_i2c_clients(struct ivtv *itv, unsigned int cmd, void *arg); | ||
33 | |||
34 | /* init + register i2c algo-bit adapter */ | ||
35 | int __devinit init_ivtv_i2c(struct ivtv *itv); | ||
36 | void __devexit exit_ivtv_i2c(struct ivtv *itv); | ||
diff --git a/drivers/media/video/ivtv/ivtv-ioctl.c b/drivers/media/video/ivtv/ivtv-ioctl.c new file mode 100644 index 000000000000..794a6a02f82f --- /dev/null +++ b/drivers/media/video/ivtv/ivtv-ioctl.c | |||
@@ -0,0 +1,1567 @@ | |||
1 | /* | ||
2 | ioctl system call | ||
3 | Copyright (C) 2003-2004 Kevin Thayer <nufan_wfk at yahoo.com> | ||
4 | Copyright (C) 2005-2007 Hans Verkuil <hverkuil@xs4all.nl> | ||
5 | |||
6 | This program is free software; you can redistribute it and/or modify | ||
7 | it under the terms of the GNU General Public License as published by | ||
8 | the Free Software Foundation; either version 2 of the License, or | ||
9 | (at your option) any later version. | ||
10 | |||
11 | This program is distributed in the hope that it will be useful, | ||
12 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
14 | GNU General Public License for more details. | ||
15 | |||
16 | You should have received a copy of the GNU General Public License | ||
17 | along with this program; if not, write to the Free Software | ||
18 | Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
19 | */ | ||
20 | |||
21 | #include "ivtv-driver.h" | ||
22 | #include "ivtv-version.h" | ||
23 | #include "ivtv-mailbox.h" | ||
24 | #include "ivtv-i2c.h" | ||
25 | #include "ivtv-queue.h" | ||
26 | #include "ivtv-fileops.h" | ||
27 | #include "ivtv-vbi.h" | ||
28 | #include "ivtv-audio.h" | ||
29 | #include "ivtv-video.h" | ||
30 | #include "ivtv-streams.h" | ||
31 | #include "ivtv-yuv.h" | ||
32 | #include "ivtv-ioctl.h" | ||
33 | #include "ivtv-gpio.h" | ||
34 | #include "ivtv-controls.h" | ||
35 | #include "ivtv-cards.h" | ||
36 | #include <media/saa7127.h> | ||
37 | #include <media/tveeprom.h> | ||
38 | #include <media/v4l2-chip-ident.h> | ||
39 | #include <linux/dvb/audio.h> | ||
40 | #include <linux/i2c-id.h> | ||
41 | |||
42 | u16 service2vbi(int type) | ||
43 | { | ||
44 | switch (type) { | ||
45 | case V4L2_SLICED_TELETEXT_B: | ||
46 | return IVTV_SLICED_TYPE_TELETEXT_B; | ||
47 | case V4L2_SLICED_CAPTION_525: | ||
48 | return IVTV_SLICED_TYPE_CAPTION_525; | ||
49 | case V4L2_SLICED_WSS_625: | ||
50 | return IVTV_SLICED_TYPE_WSS_625; | ||
51 | case V4L2_SLICED_VPS: | ||
52 | return IVTV_SLICED_TYPE_VPS; | ||
53 | default: | ||
54 | return 0; | ||
55 | } | ||
56 | } | ||
57 | |||
58 | static int valid_service_line(int field, int line, int is_pal) | ||
59 | { | ||
60 | return (is_pal && line >= 6 && (line != 23 || field == 0)) || | ||
61 | (!is_pal && line >= 10 && line < 22); | ||
62 | } | ||
63 | |||
64 | static u16 select_service_from_set(int field, int line, u16 set, int is_pal) | ||
65 | { | ||
66 | u16 valid_set = (is_pal ? V4L2_SLICED_VBI_625 : V4L2_SLICED_VBI_525); | ||
67 | int i; | ||
68 | |||
69 | set = set & valid_set; | ||
70 | if (set == 0 || !valid_service_line(field, line, is_pal)) { | ||
71 | return 0; | ||
72 | } | ||
73 | if (!is_pal) { | ||
74 | if (line == 21 && (set & V4L2_SLICED_CAPTION_525)) | ||
75 | return V4L2_SLICED_CAPTION_525; | ||
76 | } | ||
77 | else { | ||
78 | if (line == 16 && field == 0 && (set & V4L2_SLICED_VPS)) | ||
79 | return V4L2_SLICED_VPS; | ||
80 | if (line == 23 && field == 0 && (set & V4L2_SLICED_WSS_625)) | ||
81 | return V4L2_SLICED_WSS_625; | ||
82 | if (line == 23) | ||
83 | return 0; | ||
84 | } | ||
85 | for (i = 0; i < 32; i++) { | ||
86 | if ((1 << i) & set) | ||
87 | return 1 << i; | ||
88 | } | ||
89 | return 0; | ||
90 | } | ||
91 | |||
92 | void expand_service_set(struct v4l2_sliced_vbi_format *fmt, int is_pal) | ||
93 | { | ||
94 | u16 set = fmt->service_set; | ||
95 | int f, l; | ||
96 | |||
97 | fmt->service_set = 0; | ||
98 | for (f = 0; f < 2; f++) { | ||
99 | for (l = 0; l < 24; l++) { | ||
100 | fmt->service_lines[f][l] = select_service_from_set(f, l, set, is_pal); | ||
101 | } | ||
102 | } | ||
103 | } | ||
104 | |||
105 | static int check_service_set(struct v4l2_sliced_vbi_format *fmt, int is_pal) | ||
106 | { | ||
107 | int f, l; | ||
108 | u16 set = 0; | ||
109 | |||
110 | for (f = 0; f < 2; f++) { | ||
111 | for (l = 0; l < 24; l++) { | ||
112 | fmt->service_lines[f][l] = select_service_from_set(f, l, fmt->service_lines[f][l], is_pal); | ||
113 | set |= fmt->service_lines[f][l]; | ||
114 | } | ||
115 | } | ||
116 | return set != 0; | ||
117 | } | ||
118 | |||
119 | u16 get_service_set(struct v4l2_sliced_vbi_format *fmt) | ||
120 | { | ||
121 | int f, l; | ||
122 | u16 set = 0; | ||
123 | |||
124 | for (f = 0; f < 2; f++) { | ||
125 | for (l = 0; l < 24; l++) { | ||
126 | set |= fmt->service_lines[f][l]; | ||
127 | } | ||
128 | } | ||
129 | return set; | ||
130 | } | ||
131 | |||
132 | static const struct { | ||
133 | v4l2_std_id std; | ||
134 | char *name; | ||
135 | } enum_stds[] = { | ||
136 | { V4L2_STD_PAL_BG | V4L2_STD_PAL_H, "PAL-BGH" }, | ||
137 | { V4L2_STD_PAL_DK, "PAL-DK" }, | ||
138 | { V4L2_STD_PAL_I, "PAL-I" }, | ||
139 | { V4L2_STD_PAL_M, "PAL-M" }, | ||
140 | { V4L2_STD_PAL_N, "PAL-N" }, | ||
141 | { V4L2_STD_PAL_Nc, "PAL-Nc" }, | ||
142 | { V4L2_STD_SECAM_B | V4L2_STD_SECAM_G | V4L2_STD_SECAM_H, "SECAM-BGH" }, | ||
143 | { V4L2_STD_SECAM_DK, "SECAM-DK" }, | ||
144 | { V4L2_STD_SECAM_L, "SECAM-L" }, | ||
145 | { V4L2_STD_SECAM_LC, "SECAM-L'" }, | ||
146 | { V4L2_STD_NTSC_M, "NTSC-M" }, | ||
147 | { V4L2_STD_NTSC_M_JP, "NTSC-J" }, | ||
148 | { V4L2_STD_NTSC_M_KR, "NTSC-K" }, | ||
149 | }; | ||
150 | |||
151 | static const struct v4l2_standard ivtv_std_60hz = | ||
152 | { | ||
153 | .frameperiod = {.numerator = 1001, .denominator = 30000}, | ||
154 | .framelines = 525, | ||
155 | }; | ||
156 | |||
157 | static const struct v4l2_standard ivtv_std_50hz = | ||
158 | { | ||
159 | .frameperiod = {.numerator = 1, .denominator = 25}, | ||
160 | .framelines = 625, | ||
161 | }; | ||
162 | |||
163 | void ivtv_set_osd_alpha(struct ivtv *itv) | ||
164 | { | ||
165 | ivtv_vapi(itv, CX2341X_OSD_SET_GLOBAL_ALPHA, 3, | ||
166 | itv->osd_global_alpha_state, itv->osd_global_alpha, !itv->osd_local_alpha_state); | ||
167 | ivtv_vapi(itv, CX2341X_OSD_SET_CHROMA_KEY, 2, itv->osd_color_key_state, itv->osd_color_key); | ||
168 | } | ||
169 | |||
170 | int ivtv_set_speed(struct ivtv *itv, int speed) | ||
171 | { | ||
172 | u32 data[CX2341X_MBOX_MAX_DATA]; | ||
173 | struct ivtv_stream *s; | ||
174 | int single_step = (speed == 1 || speed == -1); | ||
175 | DEFINE_WAIT(wait); | ||
176 | |||
177 | if (speed == 0) speed = 1000; | ||
178 | |||
179 | /* No change? */ | ||
180 | if (speed == itv->speed && !single_step) | ||
181 | return 0; | ||
182 | |||
183 | s = &itv->streams[IVTV_DEC_STREAM_TYPE_MPG]; | ||
184 | |||
185 | if (single_step && (speed < 0) == (itv->speed < 0)) { | ||
186 | /* Single step video and no need to change direction */ | ||
187 | ivtv_vapi(itv, CX2341X_DEC_STEP_VIDEO, 1, 0); | ||
188 | itv->speed = speed; | ||
189 | return 0; | ||
190 | } | ||
191 | if (single_step) | ||
192 | /* Need to change direction */ | ||
193 | speed = speed < 0 ? -1000 : 1000; | ||
194 | |||
195 | data[0] = (speed > 1000 || speed < -1000) ? 0x80000000 : 0; | ||
196 | data[0] |= (speed > 1000 || speed < -1500) ? 0x40000000 : 0; | ||
197 | data[1] = (speed < 0); | ||
198 | data[2] = speed < 0 ? 3 : 7; | ||
199 | data[3] = itv->params.video_b_frames; | ||
200 | data[4] = (speed == 1500 || speed == 500) ? itv->speed_mute_audio : 0; | ||
201 | data[5] = 0; | ||
202 | data[6] = 0; | ||
203 | |||
204 | if (speed == 1500 || speed == -1500) data[0] |= 1; | ||
205 | else if (speed == 2000 || speed == -2000) data[0] |= 2; | ||
206 | else if (speed > -1000 && speed < 0) data[0] |= (-1000 / speed); | ||
207 | else if (speed < 1000 && speed > 0) data[0] |= (1000 / speed); | ||
208 | |||
209 | /* If not decoding, just change speed setting */ | ||
210 | if (atomic_read(&itv->decoding) > 0) { | ||
211 | int got_sig = 0; | ||
212 | |||
213 | /* Stop all DMA and decoding activity */ | ||
214 | ivtv_vapi(itv, CX2341X_DEC_PAUSE_PLAYBACK, 1, 0); | ||
215 | |||
216 | /* Wait for any DMA to finish */ | ||
217 | prepare_to_wait(&itv->dma_waitq, &wait, TASK_INTERRUPTIBLE); | ||
218 | while (itv->i_flags & IVTV_F_I_DMA) { | ||
219 | got_sig = signal_pending(current); | ||
220 | if (got_sig) | ||
221 | break; | ||
222 | got_sig = 0; | ||
223 | schedule(); | ||
224 | } | ||
225 | finish_wait(&itv->dma_waitq, &wait); | ||
226 | if (got_sig) | ||
227 | return -EINTR; | ||
228 | |||
229 | /* Change Speed safely */ | ||
230 | ivtv_api(itv, CX2341X_DEC_SET_PLAYBACK_SPEED, 7, data); | ||
231 | IVTV_DEBUG_INFO("Setting Speed to 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x\n", | ||
232 | data[0], data[1], data[2], data[3], data[4], data[5], data[6]); | ||
233 | } | ||
234 | if (single_step) { | ||
235 | speed = (speed < 0) ? -1 : 1; | ||
236 | ivtv_vapi(itv, CX2341X_DEC_STEP_VIDEO, 1, 0); | ||
237 | } | ||
238 | itv->speed = speed; | ||
239 | return 0; | ||
240 | } | ||
241 | |||
242 | static int ivtv_validate_speed(int cur_speed, int new_speed) | ||
243 | { | ||
244 | int fact = new_speed < 0 ? -1 : 1; | ||
245 | int s; | ||
246 | |||
247 | if (new_speed < 0) new_speed = -new_speed; | ||
248 | if (cur_speed < 0) cur_speed = -cur_speed; | ||
249 | |||
250 | if (cur_speed <= new_speed) { | ||
251 | if (new_speed > 1500) return fact * 2000; | ||
252 | if (new_speed > 1000) return fact * 1500; | ||
253 | } | ||
254 | else { | ||
255 | if (new_speed >= 2000) return fact * 2000; | ||
256 | if (new_speed >= 1500) return fact * 1500; | ||
257 | if (new_speed >= 1000) return fact * 1000; | ||
258 | } | ||
259 | if (new_speed == 0) return 1000; | ||
260 | if (new_speed == 1 || new_speed == 1000) return fact * new_speed; | ||
261 | |||
262 | s = new_speed; | ||
263 | new_speed = 1000 / new_speed; | ||
264 | if (1000 / cur_speed == new_speed) | ||
265 | new_speed += (cur_speed < s) ? -1 : 1; | ||
266 | if (new_speed > 60) return 1000 / (fact * 60); | ||
267 | return 1000 / (fact * new_speed); | ||
268 | } | ||
269 | |||
270 | static int ivtv_video_command(struct ivtv *itv, struct ivtv_open_id *id, | ||
271 | struct video_command *vc, int try) | ||
272 | { | ||
273 | struct ivtv_stream *s = &itv->streams[IVTV_DEC_STREAM_TYPE_MPG]; | ||
274 | |||
275 | if (!(itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT)) | ||
276 | return -EINVAL; | ||
277 | |||
278 | switch (vc->cmd) { | ||
279 | case VIDEO_CMD_PLAY: { | ||
280 | vc->flags = 0; | ||
281 | vc->play.speed = ivtv_validate_speed(itv->speed, vc->play.speed); | ||
282 | if (vc->play.speed < 0) | ||
283 | vc->play.format = VIDEO_PLAY_FMT_GOP; | ||
284 | if (try) break; | ||
285 | |||
286 | if (ivtv_set_output_mode(itv, OUT_MPG) != OUT_MPG) | ||
287 | return -EBUSY; | ||
288 | return ivtv_start_decoding(id, vc->play.speed); | ||
289 | } | ||
290 | |||
291 | case VIDEO_CMD_STOP: | ||
292 | vc->flags &= VIDEO_CMD_STOP_IMMEDIATELY|VIDEO_CMD_STOP_TO_BLACK; | ||
293 | if (vc->flags & VIDEO_CMD_STOP_IMMEDIATELY) | ||
294 | vc->stop.pts = 0; | ||
295 | if (try) break; | ||
296 | if (atomic_read(&itv->decoding) == 0) | ||
297 | return 0; | ||
298 | if (itv->output_mode != OUT_MPG) | ||
299 | return -EBUSY; | ||
300 | |||
301 | itv->output_mode = OUT_NONE; | ||
302 | return ivtv_stop_v4l2_decode_stream(s, vc->flags, vc->stop.pts); | ||
303 | |||
304 | case VIDEO_CMD_FREEZE: | ||
305 | vc->flags &= VIDEO_CMD_FREEZE_TO_BLACK; | ||
306 | if (try) break; | ||
307 | if (itv->output_mode != OUT_MPG) | ||
308 | return -EBUSY; | ||
309 | if (atomic_read(&itv->decoding) > 0) { | ||
310 | ivtv_vapi(itv, CX2341X_DEC_PAUSE_PLAYBACK, 1, | ||
311 | (vc->flags & VIDEO_CMD_FREEZE_TO_BLACK) ? 1 : 0); | ||
312 | } | ||
313 | break; | ||
314 | |||
315 | case VIDEO_CMD_CONTINUE: | ||
316 | vc->flags = 0; | ||
317 | if (try) break; | ||
318 | if (itv->output_mode != OUT_MPG) | ||
319 | return -EBUSY; | ||
320 | if (atomic_read(&itv->decoding) > 0) { | ||
321 | ivtv_vapi(itv, CX2341X_DEC_START_PLAYBACK, 2, 0, 0); | ||
322 | } | ||
323 | break; | ||
324 | |||
325 | default: | ||
326 | return -EINVAL; | ||
327 | } | ||
328 | return 0; | ||
329 | } | ||
330 | |||
331 | static int ivtv_itvc(struct ivtv *itv, unsigned int cmd, void *arg) | ||
332 | { | ||
333 | struct v4l2_register *regs = arg; | ||
334 | unsigned long flags; | ||
335 | volatile u8 __iomem *reg_start; | ||
336 | |||
337 | if (!capable(CAP_SYS_ADMIN)) | ||
338 | return -EPERM; | ||
339 | if (regs->reg >= IVTV_REG_OFFSET && regs->reg < IVTV_REG_OFFSET + IVTV_REG_SIZE) | ||
340 | reg_start = itv->reg_mem - IVTV_REG_OFFSET; | ||
341 | else if (itv->has_cx23415 && regs->reg >= IVTV_DECODER_OFFSET && | ||
342 | regs->reg < IVTV_DECODER_OFFSET + IVTV_DECODER_SIZE) | ||
343 | reg_start = itv->dec_mem - IVTV_DECODER_OFFSET; | ||
344 | else if (regs->reg >= 0 && regs->reg < IVTV_ENCODER_SIZE) | ||
345 | reg_start = itv->enc_mem; | ||
346 | else | ||
347 | return -EINVAL; | ||
348 | |||
349 | spin_lock_irqsave(&ivtv_cards_lock, flags); | ||
350 | if (cmd == VIDIOC_DBG_G_REGISTER) { | ||
351 | regs->val = readl(regs->reg + reg_start); | ||
352 | } else { | ||
353 | writel(regs->val, regs->reg + reg_start); | ||
354 | } | ||
355 | spin_unlock_irqrestore(&ivtv_cards_lock, flags); | ||
356 | return 0; | ||
357 | } | ||
358 | |||
359 | static int ivtv_get_fmt(struct ivtv *itv, int streamtype, struct v4l2_format *fmt) | ||
360 | { | ||
361 | switch (fmt->type) { | ||
362 | case V4L2_BUF_TYPE_VIDEO_OUTPUT: | ||
363 | if (!(itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT)) | ||
364 | return -EINVAL; | ||
365 | fmt->fmt.pix.left = itv->main_rect.left; | ||
366 | fmt->fmt.pix.top = itv->main_rect.top; | ||
367 | fmt->fmt.pix.width = itv->main_rect.width; | ||
368 | fmt->fmt.pix.height = itv->main_rect.height; | ||
369 | fmt->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M; | ||
370 | fmt->fmt.pix.field = V4L2_FIELD_INTERLACED; | ||
371 | if (itv->output_mode == OUT_UDMA_YUV) { | ||
372 | switch (itv->yuv_info.lace_mode & IVTV_YUV_MODE_MASK) { | ||
373 | case IVTV_YUV_MODE_INTERLACED: | ||
374 | fmt->fmt.pix.field = (itv->yuv_info.lace_mode & IVTV_YUV_SYNC_MASK) ? | ||
375 | V4L2_FIELD_INTERLACED_BT : V4L2_FIELD_INTERLACED_TB; | ||
376 | break; | ||
377 | case IVTV_YUV_MODE_PROGRESSIVE: | ||
378 | fmt->fmt.pix.field = V4L2_FIELD_NONE; | ||
379 | break; | ||
380 | default: | ||
381 | fmt->fmt.pix.field = V4L2_FIELD_ANY; | ||
382 | break; | ||
383 | } | ||
384 | fmt->fmt.pix.pixelformat = V4L2_PIX_FMT_HM12; | ||
385 | /* YUV size is (Y=(h*w) + UV=(h*(w/2))) */ | ||
386 | fmt->fmt.pix.sizeimage = | ||
387 | fmt->fmt.pix.height * fmt->fmt.pix.width + | ||
388 | fmt->fmt.pix.height * (fmt->fmt.pix.width / 2); | ||
389 | } | ||
390 | else if (itv->output_mode == OUT_YUV || | ||
391 | streamtype == IVTV_ENC_STREAM_TYPE_YUV || | ||
392 | streamtype == IVTV_DEC_STREAM_TYPE_YUV) { | ||
393 | fmt->fmt.pix.pixelformat = V4L2_PIX_FMT_HM12; | ||
394 | /* YUV size is (Y=(h*w) + UV=(h*(w/2))) */ | ||
395 | fmt->fmt.pix.sizeimage = | ||
396 | fmt->fmt.pix.height * fmt->fmt.pix.width + | ||
397 | fmt->fmt.pix.height * (fmt->fmt.pix.width / 2); | ||
398 | } else { | ||
399 | fmt->fmt.pix.pixelformat = V4L2_PIX_FMT_MPEG; | ||
400 | fmt->fmt.pix.sizeimage = 128 * 1024; | ||
401 | } | ||
402 | break; | ||
403 | |||
404 | case V4L2_BUF_TYPE_VIDEO_CAPTURE: | ||
405 | fmt->fmt.pix.left = 0; | ||
406 | fmt->fmt.pix.top = 0; | ||
407 | fmt->fmt.pix.width = itv->params.width; | ||
408 | fmt->fmt.pix.height = itv->params.height; | ||
409 | fmt->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M; | ||
410 | fmt->fmt.pix.field = V4L2_FIELD_INTERLACED; | ||
411 | if (streamtype == IVTV_ENC_STREAM_TYPE_YUV || | ||
412 | streamtype == IVTV_DEC_STREAM_TYPE_YUV) { | ||
413 | fmt->fmt.pix.pixelformat = V4L2_PIX_FMT_HM12; | ||
414 | /* YUV size is (Y=(h*w) + UV=(h*(w/2))) */ | ||
415 | fmt->fmt.pix.sizeimage = | ||
416 | fmt->fmt.pix.height * fmt->fmt.pix.width + | ||
417 | fmt->fmt.pix.height * (fmt->fmt.pix.width / 2); | ||
418 | } else { | ||
419 | fmt->fmt.pix.pixelformat = V4L2_PIX_FMT_MPEG; | ||
420 | fmt->fmt.pix.sizeimage = 128 * 1024; | ||
421 | } | ||
422 | break; | ||
423 | |||
424 | case V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY: | ||
425 | if (!(itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT)) | ||
426 | return -EINVAL; | ||
427 | fmt->fmt.win.chromakey = itv->osd_color_key; | ||
428 | fmt->fmt.win.global_alpha = itv->osd_global_alpha; | ||
429 | break; | ||
430 | |||
431 | case V4L2_BUF_TYPE_VBI_CAPTURE: | ||
432 | fmt->fmt.vbi.sampling_rate = 27000000; | ||
433 | fmt->fmt.vbi.offset = 248; | ||
434 | fmt->fmt.vbi.samples_per_line = itv->vbi.raw_decoder_line_size - 4; | ||
435 | fmt->fmt.vbi.sample_format = V4L2_PIX_FMT_GREY; | ||
436 | fmt->fmt.vbi.start[0] = itv->vbi.start[0]; | ||
437 | fmt->fmt.vbi.start[1] = itv->vbi.start[1]; | ||
438 | fmt->fmt.vbi.count[0] = fmt->fmt.vbi.count[1] = itv->vbi.count; | ||
439 | break; | ||
440 | |||
441 | case V4L2_BUF_TYPE_SLICED_VBI_OUTPUT: | ||
442 | { | ||
443 | struct v4l2_sliced_vbi_format *vbifmt = &fmt->fmt.sliced; | ||
444 | |||
445 | if (!(itv->v4l2_cap & V4L2_CAP_SLICED_VBI_OUTPUT)) | ||
446 | return -EINVAL; | ||
447 | vbifmt->io_size = sizeof(struct v4l2_sliced_vbi_data) * 36; | ||
448 | memset(vbifmt->reserved, 0, sizeof(vbifmt->reserved)); | ||
449 | memset(vbifmt->service_lines, 0, sizeof(vbifmt->service_lines)); | ||
450 | if (itv->is_60hz) { | ||
451 | vbifmt->service_lines[0][21] = V4L2_SLICED_CAPTION_525; | ||
452 | vbifmt->service_lines[1][21] = V4L2_SLICED_CAPTION_525; | ||
453 | } else { | ||
454 | vbifmt->service_lines[0][23] = V4L2_SLICED_WSS_625; | ||
455 | vbifmt->service_lines[0][16] = V4L2_SLICED_VPS; | ||
456 | } | ||
457 | vbifmt->service_set = get_service_set(vbifmt); | ||
458 | break; | ||
459 | } | ||
460 | |||
461 | case V4L2_BUF_TYPE_SLICED_VBI_CAPTURE: | ||
462 | { | ||
463 | struct v4l2_sliced_vbi_format *vbifmt = &fmt->fmt.sliced; | ||
464 | |||
465 | vbifmt->io_size = sizeof(struct v4l2_sliced_vbi_data) * 36; | ||
466 | memset(vbifmt->reserved, 0, sizeof(vbifmt->reserved)); | ||
467 | memset(vbifmt->service_lines, 0, sizeof(vbifmt->service_lines)); | ||
468 | |||
469 | if (streamtype == IVTV_DEC_STREAM_TYPE_VBI) { | ||
470 | vbifmt->service_set = itv->is_50hz ? V4L2_SLICED_VBI_625 : | ||
471 | V4L2_SLICED_VBI_525; | ||
472 | expand_service_set(vbifmt, itv->is_50hz); | ||
473 | break; | ||
474 | } | ||
475 | |||
476 | itv->video_dec_func(itv, VIDIOC_G_FMT, fmt); | ||
477 | vbifmt->service_set = get_service_set(vbifmt); | ||
478 | break; | ||
479 | } | ||
480 | case V4L2_BUF_TYPE_VBI_OUTPUT: | ||
481 | case V4L2_BUF_TYPE_VIDEO_OVERLAY: | ||
482 | default: | ||
483 | return -EINVAL; | ||
484 | } | ||
485 | return 0; | ||
486 | } | ||
487 | |||
488 | static int ivtv_try_or_set_fmt(struct ivtv *itv, int streamtype, | ||
489 | struct v4l2_format *fmt, int set_fmt) | ||
490 | { | ||
491 | struct v4l2_sliced_vbi_format *vbifmt = &fmt->fmt.sliced; | ||
492 | u16 set; | ||
493 | |||
494 | if (fmt->type == V4L2_BUF_TYPE_VIDEO_OUTPUT) { | ||
495 | struct v4l2_rect r; | ||
496 | int field; | ||
497 | |||
498 | if (!(itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT)) | ||
499 | return -EINVAL; | ||
500 | field = fmt->fmt.pix.field; | ||
501 | r.top = fmt->fmt.pix.top; | ||
502 | r.left = fmt->fmt.pix.left; | ||
503 | r.width = fmt->fmt.pix.width; | ||
504 | r.height = fmt->fmt.pix.height; | ||
505 | ivtv_get_fmt(itv, streamtype, fmt); | ||
506 | if (itv->output_mode != OUT_UDMA_YUV) { | ||
507 | /* TODO: would setting the rect also be valid for this mode? */ | ||
508 | fmt->fmt.pix.top = r.top; | ||
509 | fmt->fmt.pix.left = r.left; | ||
510 | fmt->fmt.pix.width = r.width; | ||
511 | fmt->fmt.pix.height = r.height; | ||
512 | } | ||
513 | if (itv->output_mode == OUT_UDMA_YUV) { | ||
514 | /* TODO: add checks for validity */ | ||
515 | fmt->fmt.pix.field = field; | ||
516 | } | ||
517 | if (set_fmt) { | ||
518 | if (itv->output_mode == OUT_UDMA_YUV) { | ||
519 | switch (field) { | ||
520 | case V4L2_FIELD_NONE: | ||
521 | itv->yuv_info.lace_mode = IVTV_YUV_MODE_PROGRESSIVE; | ||
522 | break; | ||
523 | case V4L2_FIELD_ANY: | ||
524 | itv->yuv_info.lace_mode = IVTV_YUV_MODE_AUTO; | ||
525 | break; | ||
526 | case V4L2_FIELD_INTERLACED_BT: | ||
527 | itv->yuv_info.lace_mode = | ||
528 | IVTV_YUV_MODE_INTERLACED|IVTV_YUV_SYNC_ODD; | ||
529 | break; | ||
530 | case V4L2_FIELD_INTERLACED_TB: | ||
531 | default: | ||
532 | itv->yuv_info.lace_mode = IVTV_YUV_MODE_INTERLACED; | ||
533 | break; | ||
534 | } | ||
535 | itv->yuv_info.lace_sync_field = (itv->yuv_info.lace_mode & IVTV_YUV_SYNC_MASK) == IVTV_YUV_SYNC_EVEN ? 0 : 1; | ||
536 | |||
537 | /* Force update of yuv registers */ | ||
538 | itv->yuv_info.yuv_forced_update = 1; | ||
539 | return 0; | ||
540 | } | ||
541 | if (!ivtv_vapi(itv, CX2341X_OSD_SET_FRAMEBUFFER_WINDOW, 4, | ||
542 | r.width, r.height, r.left, r.top)) | ||
543 | itv->main_rect = r; | ||
544 | else | ||
545 | return -EINVAL; | ||
546 | } | ||
547 | return 0; | ||
548 | } | ||
549 | |||
550 | if (fmt->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY) { | ||
551 | if (!(itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT)) | ||
552 | return -EINVAL; | ||
553 | if (set_fmt) { | ||
554 | itv->osd_color_key = fmt->fmt.win.chromakey; | ||
555 | itv->osd_global_alpha = fmt->fmt.win.global_alpha; | ||
556 | ivtv_set_osd_alpha(itv); | ||
557 | } | ||
558 | return 0; | ||
559 | } | ||
560 | |||
561 | /* set window size */ | ||
562 | if (fmt->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) { | ||
563 | int w = fmt->fmt.pix.width; | ||
564 | int h = fmt->fmt.pix.height; | ||
565 | |||
566 | if (w > 720) w = 720; | ||
567 | else if (w < 1) w = 1; | ||
568 | if (h > (itv->is_50hz ? 576 : 480)) h = (itv->is_50hz ? 576 : 480); | ||
569 | else if (h < 2) h = 2; | ||
570 | ivtv_get_fmt(itv, streamtype, fmt); | ||
571 | fmt->fmt.pix.width = w; | ||
572 | fmt->fmt.pix.height = h; | ||
573 | |||
574 | if (!set_fmt || (itv->params.width == w && itv->params.height == h)) | ||
575 | return 0; | ||
576 | if (atomic_read(&itv->capturing) > 0) | ||
577 | return -EBUSY; | ||
578 | |||
579 | itv->params.width = w; | ||
580 | itv->params.height = h; | ||
581 | if (w != 720 || h != (itv->is_50hz ? 576 : 480)) | ||
582 | itv->params.video_temporal_filter = 0; | ||
583 | else | ||
584 | itv->params.video_temporal_filter = 8; | ||
585 | itv->video_dec_func(itv, VIDIOC_S_FMT, fmt); | ||
586 | return ivtv_get_fmt(itv, streamtype, fmt); | ||
587 | } | ||
588 | |||
589 | /* set raw VBI format */ | ||
590 | if (fmt->type == V4L2_BUF_TYPE_VBI_CAPTURE) { | ||
591 | if (set_fmt && streamtype == IVTV_ENC_STREAM_TYPE_VBI && | ||
592 | itv->vbi.sliced_in->service_set && | ||
593 | atomic_read(&itv->capturing) > 0) { | ||
594 | return -EBUSY; | ||
595 | } | ||
596 | if (set_fmt) { | ||
597 | itv->vbi.sliced_in->service_set = 0; | ||
598 | itv->video_dec_func(itv, VIDIOC_S_FMT, &itv->vbi.in); | ||
599 | } | ||
600 | return ivtv_get_fmt(itv, streamtype, fmt); | ||
601 | } | ||
602 | |||
603 | /* set sliced VBI output | ||
604 | In principle the user could request that only certain | ||
605 | VBI types are output and that the others are ignored. | ||
606 | I.e., suppress CC in the even fields or only output | ||
607 | WSS and no VPS. Currently though there is no choice. */ | ||
608 | if (fmt->type == V4L2_BUF_TYPE_SLICED_VBI_OUTPUT) | ||
609 | return ivtv_get_fmt(itv, streamtype, fmt); | ||
610 | |||
611 | /* any else but sliced VBI capture is an error */ | ||
612 | if (fmt->type != V4L2_BUF_TYPE_SLICED_VBI_CAPTURE) | ||
613 | return -EINVAL; | ||
614 | |||
615 | if (streamtype == IVTV_DEC_STREAM_TYPE_VBI) | ||
616 | return ivtv_get_fmt(itv, streamtype, fmt); | ||
617 | |||
618 | /* set sliced VBI capture format */ | ||
619 | vbifmt->io_size = sizeof(struct v4l2_sliced_vbi_data) * 36; | ||
620 | memset(vbifmt->reserved, 0, sizeof(vbifmt->reserved)); | ||
621 | |||
622 | if (vbifmt->service_set) | ||
623 | expand_service_set(vbifmt, itv->is_50hz); | ||
624 | set = check_service_set(vbifmt, itv->is_50hz); | ||
625 | vbifmt->service_set = get_service_set(vbifmt); | ||
626 | |||
627 | if (!set_fmt) | ||
628 | return 0; | ||
629 | if (set == 0) | ||
630 | return -EINVAL; | ||
631 | if (atomic_read(&itv->capturing) > 0 && itv->vbi.sliced_in->service_set == 0) { | ||
632 | return -EBUSY; | ||
633 | } | ||
634 | itv->video_dec_func(itv, VIDIOC_S_FMT, fmt); | ||
635 | memcpy(itv->vbi.sliced_in, vbifmt, sizeof(*itv->vbi.sliced_in)); | ||
636 | return 0; | ||
637 | } | ||
638 | |||
639 | static int ivtv_debug_ioctls(struct file *filp, unsigned int cmd, void *arg) | ||
640 | { | ||
641 | struct ivtv_open_id *id = (struct ivtv_open_id *)filp->private_data; | ||
642 | struct ivtv *itv = id->itv; | ||
643 | struct v4l2_register *reg = arg; | ||
644 | |||
645 | switch (cmd) { | ||
646 | /* ioctls to allow direct access to the encoder registers for testing */ | ||
647 | case VIDIOC_DBG_G_REGISTER: | ||
648 | if (v4l2_chip_match_host(reg->match_type, reg->match_chip)) | ||
649 | return ivtv_itvc(itv, cmd, arg); | ||
650 | if (reg->match_type == V4L2_CHIP_MATCH_I2C_DRIVER) | ||
651 | return ivtv_i2c_id(itv, reg->match_chip, cmd, arg); | ||
652 | return ivtv_call_i2c_client(itv, reg->match_chip, cmd, arg); | ||
653 | |||
654 | case VIDIOC_DBG_S_REGISTER: | ||
655 | if (v4l2_chip_match_host(reg->match_type, reg->match_chip)) | ||
656 | return ivtv_itvc(itv, cmd, arg); | ||
657 | if (reg->match_type == V4L2_CHIP_MATCH_I2C_DRIVER) | ||
658 | return ivtv_i2c_id(itv, reg->match_chip, cmd, arg); | ||
659 | return ivtv_call_i2c_client(itv, reg->match_chip, cmd, arg); | ||
660 | |||
661 | case VIDIOC_G_CHIP_IDENT: { | ||
662 | struct v4l2_chip_ident *chip = arg; | ||
663 | |||
664 | chip->ident = V4L2_IDENT_NONE; | ||
665 | chip->revision = 0; | ||
666 | if (reg->match_type == V4L2_CHIP_MATCH_HOST) { | ||
667 | if (v4l2_chip_match_host(reg->match_type, reg->match_chip)) { | ||
668 | struct v4l2_chip_ident *chip = arg; | ||
669 | |||
670 | chip->ident = itv->has_cx23415 ? V4L2_IDENT_CX23415 : V4L2_IDENT_CX23416; | ||
671 | } | ||
672 | return 0; | ||
673 | } | ||
674 | if (reg->match_type == V4L2_CHIP_MATCH_I2C_DRIVER) | ||
675 | return ivtv_i2c_id(itv, reg->match_chip, cmd, arg); | ||
676 | if (reg->match_type == V4L2_CHIP_MATCH_I2C_ADDR) | ||
677 | return ivtv_call_i2c_client(itv, reg->match_chip, cmd, arg); | ||
678 | return -EINVAL; | ||
679 | } | ||
680 | |||
681 | case VIDIOC_INT_S_AUDIO_ROUTING: { | ||
682 | struct v4l2_routing *route = arg; | ||
683 | |||
684 | ivtv_audio_set_route(itv, route); | ||
685 | break; | ||
686 | } | ||
687 | |||
688 | case VIDIOC_INT_RESET: | ||
689 | ivtv_reset_ir_gpio(itv); | ||
690 | break; | ||
691 | |||
692 | default: | ||
693 | return -EINVAL; | ||
694 | } | ||
695 | return 0; | ||
696 | } | ||
697 | |||
698 | int ivtv_v4l2_ioctls(struct ivtv *itv, struct file *filp, unsigned int cmd, void *arg) | ||
699 | { | ||
700 | struct ivtv_open_id *id = NULL; | ||
701 | |||
702 | if (filp) id = (struct ivtv_open_id *)filp->private_data; | ||
703 | |||
704 | switch (cmd) { | ||
705 | case VIDIOC_G_PRIORITY: | ||
706 | { | ||
707 | enum v4l2_priority *p = arg; | ||
708 | |||
709 | *p = v4l2_prio_max(&itv->prio); | ||
710 | break; | ||
711 | } | ||
712 | |||
713 | case VIDIOC_S_PRIORITY: | ||
714 | { | ||
715 | enum v4l2_priority *prio = arg; | ||
716 | |||
717 | return v4l2_prio_change(&itv->prio, &id->prio, *prio); | ||
718 | } | ||
719 | |||
720 | case VIDIOC_QUERYCAP:{ | ||
721 | struct v4l2_capability *vcap = arg; | ||
722 | |||
723 | memset(vcap, 0, sizeof(*vcap)); | ||
724 | strcpy(vcap->driver, IVTV_DRIVER_NAME); /* driver name */ | ||
725 | strcpy(vcap->card, itv->card_name); /* card type */ | ||
726 | strcpy(vcap->bus_info, pci_name(itv->dev)); /* bus info... */ | ||
727 | vcap->version = IVTV_DRIVER_VERSION; /* version */ | ||
728 | vcap->capabilities = itv->v4l2_cap; /* capabilities */ | ||
729 | |||
730 | /* reserved.. must set to 0! */ | ||
731 | vcap->reserved[0] = vcap->reserved[1] = | ||
732 | vcap->reserved[2] = vcap->reserved[3] = 0; | ||
733 | break; | ||
734 | } | ||
735 | |||
736 | case VIDIOC_ENUMAUDIO:{ | ||
737 | struct v4l2_audio *vin = arg; | ||
738 | |||
739 | return ivtv_get_audio_input(itv, vin->index, vin); | ||
740 | } | ||
741 | |||
742 | case VIDIOC_G_AUDIO:{ | ||
743 | struct v4l2_audio *vin = arg; | ||
744 | |||
745 | vin->index = itv->audio_input; | ||
746 | return ivtv_get_audio_input(itv, vin->index, vin); | ||
747 | } | ||
748 | |||
749 | case VIDIOC_S_AUDIO:{ | ||
750 | struct v4l2_audio *vout = arg; | ||
751 | |||
752 | if (vout->index >= itv->nof_audio_inputs) | ||
753 | return -EINVAL; | ||
754 | itv->audio_input = vout->index; | ||
755 | ivtv_audio_set_io(itv); | ||
756 | break; | ||
757 | } | ||
758 | |||
759 | case VIDIOC_ENUMAUDOUT:{ | ||
760 | struct v4l2_audioout *vin = arg; | ||
761 | |||
762 | /* set it to defaults from our table */ | ||
763 | return ivtv_get_audio_output(itv, vin->index, vin); | ||
764 | } | ||
765 | |||
766 | case VIDIOC_G_AUDOUT:{ | ||
767 | struct v4l2_audioout *vin = arg; | ||
768 | |||
769 | vin->index = 0; | ||
770 | return ivtv_get_audio_output(itv, vin->index, vin); | ||
771 | } | ||
772 | |||
773 | case VIDIOC_S_AUDOUT:{ | ||
774 | struct v4l2_audioout *vout = arg; | ||
775 | |||
776 | return ivtv_get_audio_output(itv, vout->index, vout); | ||
777 | } | ||
778 | |||
779 | case VIDIOC_ENUMINPUT:{ | ||
780 | struct v4l2_input *vin = arg; | ||
781 | |||
782 | /* set it to defaults from our table */ | ||
783 | return ivtv_get_input(itv, vin->index, vin); | ||
784 | } | ||
785 | |||
786 | case VIDIOC_ENUMOUTPUT:{ | ||
787 | struct v4l2_output *vout = arg; | ||
788 | |||
789 | return ivtv_get_output(itv, vout->index, vout); | ||
790 | } | ||
791 | |||
792 | case VIDIOC_TRY_FMT: | ||
793 | case VIDIOC_S_FMT: { | ||
794 | struct v4l2_format *fmt = arg; | ||
795 | |||
796 | return ivtv_try_or_set_fmt(itv, id->type, fmt, cmd == VIDIOC_S_FMT); | ||
797 | } | ||
798 | |||
799 | case VIDIOC_G_FMT: { | ||
800 | struct v4l2_format *fmt = arg; | ||
801 | int type = fmt->type; | ||
802 | |||
803 | memset(fmt, 0, sizeof(*fmt)); | ||
804 | fmt->type = type; | ||
805 | return ivtv_get_fmt(itv, id->type, fmt); | ||
806 | } | ||
807 | |||
808 | case VIDIOC_S_CROP: { | ||
809 | struct v4l2_crop *crop = arg; | ||
810 | |||
811 | if (crop->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) | ||
812 | return -EINVAL; | ||
813 | return itv->video_dec_func(itv, VIDIOC_S_CROP, arg); | ||
814 | } | ||
815 | |||
816 | case VIDIOC_G_CROP: { | ||
817 | struct v4l2_crop *crop = arg; | ||
818 | |||
819 | if (crop->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) | ||
820 | return -EINVAL; | ||
821 | return itv->video_dec_func(itv, VIDIOC_G_CROP, arg); | ||
822 | } | ||
823 | |||
824 | case VIDIOC_ENUM_FMT: { | ||
825 | static struct v4l2_fmtdesc formats[] = { | ||
826 | { 0, 0, 0, | ||
827 | "HM12 (YUV 4:1:1)", V4L2_PIX_FMT_HM12, | ||
828 | { 0, 0, 0, 0 } | ||
829 | }, | ||
830 | { 1, 0, V4L2_FMT_FLAG_COMPRESSED, | ||
831 | "MPEG", V4L2_PIX_FMT_MPEG, | ||
832 | { 0, 0, 0, 0 } | ||
833 | } | ||
834 | }; | ||
835 | struct v4l2_fmtdesc *fmt = arg; | ||
836 | enum v4l2_buf_type type = fmt->type; | ||
837 | |||
838 | switch (type) { | ||
839 | case V4L2_BUF_TYPE_VIDEO_CAPTURE: | ||
840 | break; | ||
841 | case V4L2_BUF_TYPE_VIDEO_OUTPUT: | ||
842 | if (!(itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT)) | ||
843 | return -EINVAL; | ||
844 | break; | ||
845 | default: | ||
846 | return -EINVAL; | ||
847 | } | ||
848 | if (fmt->index > 1) | ||
849 | return -EINVAL; | ||
850 | *fmt = formats[fmt->index]; | ||
851 | fmt->type = type; | ||
852 | return 0; | ||
853 | } | ||
854 | |||
855 | case VIDIOC_G_INPUT:{ | ||
856 | *(int *)arg = itv->active_input; | ||
857 | break; | ||
858 | } | ||
859 | |||
860 | case VIDIOC_S_INPUT:{ | ||
861 | int inp = *(int *)arg; | ||
862 | |||
863 | if (inp < 0 || inp >= itv->nof_inputs) | ||
864 | return -EINVAL; | ||
865 | |||
866 | if (inp == itv->active_input) { | ||
867 | IVTV_DEBUG_INFO("Input unchanged\n"); | ||
868 | break; | ||
869 | } | ||
870 | IVTV_DEBUG_INFO("Changing input from %d to %d\n", | ||
871 | itv->active_input, inp); | ||
872 | |||
873 | itv->active_input = inp; | ||
874 | /* Set the audio input to whatever is appropriate for the | ||
875 | input type. */ | ||
876 | itv->audio_input = itv->card->video_inputs[inp].audio_index; | ||
877 | |||
878 | /* prevent others from messing with the streams until | ||
879 | we're finished changing inputs. */ | ||
880 | ivtv_mute(itv); | ||
881 | ivtv_video_set_io(itv); | ||
882 | ivtv_audio_set_io(itv); | ||
883 | ivtv_unmute(itv); | ||
884 | break; | ||
885 | } | ||
886 | |||
887 | case VIDIOC_G_OUTPUT:{ | ||
888 | if (!(itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT)) | ||
889 | return -EINVAL; | ||
890 | *(int *)arg = itv->active_output; | ||
891 | break; | ||
892 | } | ||
893 | |||
894 | case VIDIOC_S_OUTPUT:{ | ||
895 | int outp = *(int *)arg; | ||
896 | struct v4l2_routing route; | ||
897 | |||
898 | if (outp >= itv->card->nof_outputs) | ||
899 | return -EINVAL; | ||
900 | |||
901 | if (outp == itv->active_output) { | ||
902 | IVTV_DEBUG_INFO("Output unchanged\n"); | ||
903 | break; | ||
904 | } | ||
905 | IVTV_DEBUG_INFO("Changing output from %d to %d\n", | ||
906 | itv->active_output, outp); | ||
907 | |||
908 | itv->active_output = outp; | ||
909 | route.input = SAA7127_INPUT_TYPE_NORMAL; | ||
910 | route.output = itv->card->video_outputs[outp].video_output; | ||
911 | ivtv_saa7127(itv, VIDIOC_INT_S_VIDEO_ROUTING, &route); | ||
912 | break; | ||
913 | } | ||
914 | |||
915 | case VIDIOC_G_FREQUENCY:{ | ||
916 | struct v4l2_frequency *vf = arg; | ||
917 | |||
918 | if (vf->tuner != 0) | ||
919 | return -EINVAL; | ||
920 | ivtv_call_i2c_clients(itv, cmd, arg); | ||
921 | break; | ||
922 | } | ||
923 | |||
924 | case VIDIOC_S_FREQUENCY:{ | ||
925 | struct v4l2_frequency vf = *(struct v4l2_frequency *)arg; | ||
926 | |||
927 | if (vf.tuner != 0) | ||
928 | return -EINVAL; | ||
929 | |||
930 | ivtv_mute(itv); | ||
931 | IVTV_DEBUG_INFO("v4l2 ioctl: set frequency %d\n", vf.frequency); | ||
932 | ivtv_call_i2c_clients(itv, cmd, &vf); | ||
933 | ivtv_unmute(itv); | ||
934 | break; | ||
935 | } | ||
936 | |||
937 | case VIDIOC_ENUMSTD:{ | ||
938 | struct v4l2_standard *vs = arg; | ||
939 | int idx = vs->index; | ||
940 | |||
941 | if (idx < 0 || idx >= ARRAY_SIZE(enum_stds)) | ||
942 | return -EINVAL; | ||
943 | |||
944 | *vs = (enum_stds[idx].std & V4L2_STD_525_60) ? | ||
945 | ivtv_std_60hz : ivtv_std_50hz; | ||
946 | vs->index = idx; | ||
947 | vs->id = enum_stds[idx].std; | ||
948 | strcpy(vs->name, enum_stds[idx].name); | ||
949 | break; | ||
950 | } | ||
951 | |||
952 | case VIDIOC_G_STD:{ | ||
953 | *(v4l2_std_id *) arg = itv->std; | ||
954 | break; | ||
955 | } | ||
956 | |||
957 | case VIDIOC_S_STD: { | ||
958 | v4l2_std_id std = *(v4l2_std_id *) arg; | ||
959 | |||
960 | if ((std & V4L2_STD_ALL) == 0) | ||
961 | return -EINVAL; | ||
962 | |||
963 | if (std == itv->std) | ||
964 | break; | ||
965 | |||
966 | if (test_bit(IVTV_F_I_RADIO_USER, &itv->i_flags) || | ||
967 | atomic_read(&itv->capturing) > 0 || | ||
968 | atomic_read(&itv->decoding) > 0) { | ||
969 | /* Switching standard would turn off the radio or mess | ||
970 | with already running streams, prevent that by | ||
971 | returning EBUSY. */ | ||
972 | return -EBUSY; | ||
973 | } | ||
974 | |||
975 | itv->std = std; | ||
976 | itv->is_60hz = (std & V4L2_STD_525_60) ? 1 : 0; | ||
977 | itv->params.is_50hz = itv->is_50hz = !itv->is_60hz; | ||
978 | itv->params.width = 720; | ||
979 | itv->params.height = itv->is_50hz ? 576 : 480; | ||
980 | itv->vbi.count = itv->is_50hz ? 18 : 12; | ||
981 | itv->vbi.start[0] = itv->is_50hz ? 6 : 10; | ||
982 | itv->vbi.start[1] = itv->is_50hz ? 318 : 273; | ||
983 | if (itv->hw_flags & IVTV_HW_CX25840) { | ||
984 | itv->vbi.sliced_decoder_line_size = itv->is_60hz ? 272 : 284; | ||
985 | } | ||
986 | IVTV_DEBUG_INFO("Switching standard to %llx.\n", itv->std); | ||
987 | |||
988 | /* Tuner */ | ||
989 | ivtv_call_i2c_clients(itv, VIDIOC_S_STD, &itv->std); | ||
990 | |||
991 | if (itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT) { | ||
992 | /* set display standard */ | ||
993 | itv->std_out = std; | ||
994 | itv->is_out_60hz = itv->is_60hz; | ||
995 | itv->is_out_50hz = itv->is_50hz; | ||
996 | ivtv_call_i2c_clients(itv, VIDIOC_INT_S_STD_OUTPUT, &itv->std_out); | ||
997 | ivtv_vapi(itv, CX2341X_DEC_SET_STANDARD, 1, itv->is_out_50hz); | ||
998 | itv->main_rect.left = itv->main_rect.top = 0; | ||
999 | itv->main_rect.width = 720; | ||
1000 | itv->main_rect.height = itv->params.height; | ||
1001 | ivtv_vapi(itv, CX2341X_OSD_SET_FRAMEBUFFER_WINDOW, 4, | ||
1002 | 720, itv->main_rect.height, 0, 0); | ||
1003 | } | ||
1004 | break; | ||
1005 | } | ||
1006 | |||
1007 | case VIDIOC_S_TUNER: { /* Setting tuner can only set audio mode */ | ||
1008 | struct v4l2_tuner *vt = arg; | ||
1009 | |||
1010 | if (vt->index != 0) | ||
1011 | return -EINVAL; | ||
1012 | |||
1013 | ivtv_call_i2c_clients(itv, VIDIOC_S_TUNER, vt); | ||
1014 | break; | ||
1015 | } | ||
1016 | |||
1017 | case VIDIOC_G_TUNER: { | ||
1018 | struct v4l2_tuner *vt = arg; | ||
1019 | |||
1020 | if (vt->index != 0) | ||
1021 | return -EINVAL; | ||
1022 | |||
1023 | memset(vt, 0, sizeof(*vt)); | ||
1024 | ivtv_call_i2c_clients(itv, VIDIOC_G_TUNER, vt); | ||
1025 | |||
1026 | if (test_bit(IVTV_F_I_RADIO_USER, &itv->i_flags)) { | ||
1027 | strcpy(vt->name, "ivtv Radio Tuner"); | ||
1028 | vt->type = V4L2_TUNER_RADIO; | ||
1029 | } else { | ||
1030 | strcpy(vt->name, "ivtv TV Tuner"); | ||
1031 | vt->type = V4L2_TUNER_ANALOG_TV; | ||
1032 | } | ||
1033 | break; | ||
1034 | } | ||
1035 | |||
1036 | case VIDIOC_G_SLICED_VBI_CAP: { | ||
1037 | struct v4l2_sliced_vbi_cap *cap = arg; | ||
1038 | int set = itv->is_50hz ? V4L2_SLICED_VBI_625 : V4L2_SLICED_VBI_525; | ||
1039 | int f, l; | ||
1040 | enum v4l2_buf_type type = cap->type; | ||
1041 | |||
1042 | memset(cap, 0, sizeof(*cap)); | ||
1043 | cap->type = type; | ||
1044 | if (type == V4L2_BUF_TYPE_SLICED_VBI_CAPTURE) { | ||
1045 | for (f = 0; f < 2; f++) { | ||
1046 | for (l = 0; l < 24; l++) { | ||
1047 | if (valid_service_line(f, l, itv->is_50hz)) { | ||
1048 | cap->service_lines[f][l] = set; | ||
1049 | } | ||
1050 | } | ||
1051 | } | ||
1052 | return 0; | ||
1053 | } | ||
1054 | if (type == V4L2_BUF_TYPE_SLICED_VBI_OUTPUT) { | ||
1055 | if (!(itv->v4l2_cap & V4L2_CAP_SLICED_VBI_OUTPUT)) | ||
1056 | return -EINVAL; | ||
1057 | if (itv->is_60hz) { | ||
1058 | cap->service_lines[0][21] = V4L2_SLICED_CAPTION_525; | ||
1059 | cap->service_lines[1][21] = V4L2_SLICED_CAPTION_525; | ||
1060 | } else { | ||
1061 | cap->service_lines[0][23] = V4L2_SLICED_WSS_625; | ||
1062 | cap->service_lines[0][16] = V4L2_SLICED_VPS; | ||
1063 | } | ||
1064 | return 0; | ||
1065 | } | ||
1066 | return -EINVAL; | ||
1067 | } | ||
1068 | |||
1069 | case VIDIOC_G_ENC_INDEX: { | ||
1070 | struct v4l2_enc_idx *idx = arg; | ||
1071 | int i; | ||
1072 | |||
1073 | idx->entries = (itv->pgm_info_write_idx + IVTV_MAX_PGM_INDEX - itv->pgm_info_read_idx) % | ||
1074 | IVTV_MAX_PGM_INDEX; | ||
1075 | if (idx->entries > V4L2_ENC_IDX_ENTRIES) | ||
1076 | idx->entries = V4L2_ENC_IDX_ENTRIES; | ||
1077 | for (i = 0; i < idx->entries; i++) { | ||
1078 | idx->entry[i] = itv->pgm_info[(itv->pgm_info_read_idx + i) % IVTV_MAX_PGM_INDEX]; | ||
1079 | } | ||
1080 | itv->pgm_info_read_idx = (itv->pgm_info_read_idx + idx->entries) % IVTV_MAX_PGM_INDEX; | ||
1081 | break; | ||
1082 | } | ||
1083 | |||
1084 | case VIDIOC_ENCODER_CMD: | ||
1085 | case VIDIOC_TRY_ENCODER_CMD: { | ||
1086 | struct v4l2_encoder_cmd *enc = arg; | ||
1087 | int try = cmd == VIDIOC_TRY_ENCODER_CMD; | ||
1088 | |||
1089 | memset(&enc->raw, 0, sizeof(enc->raw)); | ||
1090 | switch (enc->cmd) { | ||
1091 | case V4L2_ENC_CMD_START: | ||
1092 | enc->flags = 0; | ||
1093 | if (try) | ||
1094 | return 0; | ||
1095 | return ivtv_start_capture(id); | ||
1096 | |||
1097 | case V4L2_ENC_CMD_STOP: | ||
1098 | enc->flags &= V4L2_ENC_CMD_STOP_AT_GOP_END; | ||
1099 | if (try) | ||
1100 | return 0; | ||
1101 | ivtv_stop_capture(id, enc->flags & V4L2_ENC_CMD_STOP_AT_GOP_END); | ||
1102 | return 0; | ||
1103 | |||
1104 | case V4L2_ENC_CMD_PAUSE: | ||
1105 | enc->flags = 0; | ||
1106 | if (try) | ||
1107 | return 0; | ||
1108 | if (!atomic_read(&itv->capturing)) | ||
1109 | return -EPERM; | ||
1110 | if (test_and_set_bit(IVTV_F_I_ENC_PAUSED, &itv->i_flags)) | ||
1111 | return 0; | ||
1112 | ivtv_mute(itv); | ||
1113 | ivtv_vapi(itv, CX2341X_ENC_PAUSE_ENCODER, 1, 0); | ||
1114 | break; | ||
1115 | |||
1116 | case V4L2_ENC_CMD_RESUME: | ||
1117 | enc->flags = 0; | ||
1118 | if (try) | ||
1119 | return 0; | ||
1120 | if (!atomic_read(&itv->capturing)) | ||
1121 | return -EPERM; | ||
1122 | if (!test_and_clear_bit(IVTV_F_I_ENC_PAUSED, &itv->i_flags)) | ||
1123 | return 0; | ||
1124 | ivtv_vapi(itv, CX2341X_ENC_PAUSE_ENCODER, 1, 1); | ||
1125 | ivtv_unmute(itv); | ||
1126 | break; | ||
1127 | default: | ||
1128 | return -EINVAL; | ||
1129 | } | ||
1130 | break; | ||
1131 | } | ||
1132 | |||
1133 | case VIDIOC_G_FBUF: { | ||
1134 | struct v4l2_framebuffer *fb = arg; | ||
1135 | |||
1136 | memset(fb, 0, sizeof(*fb)); | ||
1137 | if (!(itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT_OVERLAY)) | ||
1138 | break; | ||
1139 | fb->capability = V4L2_FBUF_CAP_EXTERNOVERLAY | V4L2_FBUF_CAP_CHROMAKEY | | ||
1140 | V4L2_FBUF_CAP_LOCAL_ALPHA | V4L2_FBUF_CAP_GLOBAL_ALPHA; | ||
1141 | fb->fmt.pixelformat = itv->osd_pixelformat; | ||
1142 | fb->fmt.width = itv->osd_rect.width; | ||
1143 | fb->fmt.height = itv->osd_rect.height; | ||
1144 | fb->fmt.left = itv->osd_rect.left; | ||
1145 | fb->fmt.top = itv->osd_rect.top; | ||
1146 | fb->base = (void *)itv->osd_video_pbase; | ||
1147 | if (itv->osd_global_alpha_state) | ||
1148 | fb->flags |= V4L2_FBUF_FLAG_GLOBAL_ALPHA; | ||
1149 | if (itv->osd_local_alpha_state) | ||
1150 | fb->flags |= V4L2_FBUF_FLAG_LOCAL_ALPHA; | ||
1151 | if (itv->osd_color_key_state) | ||
1152 | fb->flags |= V4L2_FBUF_FLAG_CHROMAKEY; | ||
1153 | break; | ||
1154 | } | ||
1155 | |||
1156 | case VIDIOC_S_FBUF: { | ||
1157 | struct v4l2_framebuffer *fb = arg; | ||
1158 | |||
1159 | if (!(itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT_OVERLAY)) | ||
1160 | break; | ||
1161 | itv->osd_global_alpha_state = (fb->flags & V4L2_FBUF_FLAG_GLOBAL_ALPHA) != 0; | ||
1162 | itv->osd_local_alpha_state = (fb->flags & V4L2_FBUF_FLAG_LOCAL_ALPHA) != 0; | ||
1163 | itv->osd_color_key_state = (fb->flags & V4L2_FBUF_FLAG_CHROMAKEY) != 0; | ||
1164 | break; | ||
1165 | } | ||
1166 | |||
1167 | case VIDIOC_LOG_STATUS: | ||
1168 | { | ||
1169 | int has_output = itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT; | ||
1170 | struct v4l2_input vidin; | ||
1171 | struct v4l2_audio audin; | ||
1172 | int i; | ||
1173 | |||
1174 | IVTV_INFO("================= START STATUS CARD #%d =================\n", itv->num); | ||
1175 | if (itv->hw_flags & IVTV_HW_TVEEPROM) { | ||
1176 | struct tveeprom tv; | ||
1177 | |||
1178 | ivtv_read_eeprom(itv, &tv); | ||
1179 | } | ||
1180 | ivtv_call_i2c_clients(itv, VIDIOC_LOG_STATUS, NULL); | ||
1181 | ivtv_get_input(itv, itv->active_input, &vidin); | ||
1182 | ivtv_get_audio_input(itv, itv->audio_input, &audin); | ||
1183 | IVTV_INFO("Video Input: %s\n", vidin.name); | ||
1184 | IVTV_INFO("Audio Input: %s\n", audin.name); | ||
1185 | if (has_output) { | ||
1186 | struct v4l2_output vidout; | ||
1187 | struct v4l2_audioout audout; | ||
1188 | int mode = itv->output_mode; | ||
1189 | static const char * const output_modes[] = { | ||
1190 | "None", | ||
1191 | "MPEG Streaming", | ||
1192 | "YUV Streaming", | ||
1193 | "YUV Frames", | ||
1194 | "Passthrough", | ||
1195 | }; | ||
1196 | |||
1197 | ivtv_get_output(itv, itv->active_output, &vidout); | ||
1198 | ivtv_get_audio_output(itv, 0, &audout); | ||
1199 | IVTV_INFO("Video Output: %s\n", vidout.name); | ||
1200 | IVTV_INFO("Audio Output: %s\n", audout.name); | ||
1201 | if (mode < 0 || mode > OUT_PASSTHROUGH) | ||
1202 | mode = OUT_NONE; | ||
1203 | IVTV_INFO("Output Mode: %s\n", output_modes[mode]); | ||
1204 | } | ||
1205 | IVTV_INFO("Tuner: %s\n", | ||
1206 | test_bit(IVTV_F_I_RADIO_USER, &itv->i_flags) ? "Radio" : "TV"); | ||
1207 | cx2341x_log_status(&itv->params, itv->name); | ||
1208 | IVTV_INFO("Status flags: 0x%08lx\n", itv->i_flags); | ||
1209 | for (i = 0; i < IVTV_MAX_STREAMS; i++) { | ||
1210 | struct ivtv_stream *s = &itv->streams[i]; | ||
1211 | |||
1212 | if (s->v4l2dev == NULL || s->buffers == 0) | ||
1213 | continue; | ||
1214 | IVTV_INFO("Stream %s: status 0x%04lx, %d%% of %d KiB (%d buffers) in use\n", s->name, s->s_flags, | ||
1215 | (s->buffers - s->q_free.buffers) * 100 / s->buffers, | ||
1216 | (s->buffers * s->buf_size) / 1024, s->buffers); | ||
1217 | } | ||
1218 | IVTV_INFO("Read MPEG/VBI: %lld/%lld bytes\n", itv->mpg_data_received, itv->vbi_data_inserted); | ||
1219 | IVTV_INFO("================== END STATUS CARD #%d ==================\n", itv->num); | ||
1220 | break; | ||
1221 | } | ||
1222 | |||
1223 | default: | ||
1224 | return -EINVAL; | ||
1225 | } | ||
1226 | return 0; | ||
1227 | } | ||
1228 | |||
1229 | static int ivtv_decoder_ioctls(struct file *filp, unsigned int cmd, void *arg) | ||
1230 | { | ||
1231 | struct ivtv_open_id *id = (struct ivtv_open_id *)filp->private_data; | ||
1232 | struct ivtv *itv = id->itv; | ||
1233 | int nonblocking = filp->f_flags & O_NONBLOCK; | ||
1234 | struct ivtv_stream *s = &itv->streams[id->type]; | ||
1235 | |||
1236 | switch (cmd) { | ||
1237 | case IVTV_IOC_DMA_FRAME: { | ||
1238 | struct ivtv_dma_frame *args = arg; | ||
1239 | |||
1240 | IVTV_DEBUG_IOCTL("IVTV_IOC_DMA_FRAME\n"); | ||
1241 | if (!(itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT)) | ||
1242 | return -EINVAL; | ||
1243 | if (args->type != V4L2_BUF_TYPE_VIDEO_OUTPUT) | ||
1244 | return -EINVAL; | ||
1245 | if (itv->output_mode == OUT_UDMA_YUV && args->y_source == NULL) | ||
1246 | return 0; | ||
1247 | if (ivtv_claim_stream(id, id->type)) { | ||
1248 | return -EBUSY; | ||
1249 | } | ||
1250 | if (ivtv_set_output_mode(itv, OUT_UDMA_YUV) != OUT_UDMA_YUV) { | ||
1251 | ivtv_release_stream(s); | ||
1252 | return -EBUSY; | ||
1253 | } | ||
1254 | if (args->y_source == NULL) | ||
1255 | return 0; | ||
1256 | return ivtv_yuv_prep_frame(itv, args); | ||
1257 | } | ||
1258 | |||
1259 | case VIDEO_GET_PTS: { | ||
1260 | u32 data[CX2341X_MBOX_MAX_DATA]; | ||
1261 | u64 *pts = arg; | ||
1262 | |||
1263 | IVTV_DEBUG_IOCTL("VIDEO_GET_PTS\n"); | ||
1264 | if (s->type < IVTV_DEC_STREAM_TYPE_MPG) { | ||
1265 | *pts = s->dma_pts; | ||
1266 | break; | ||
1267 | } | ||
1268 | if (!(itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT)) | ||
1269 | return -EINVAL; | ||
1270 | |||
1271 | if (test_bit(IVTV_F_I_VALID_DEC_TIMINGS, &itv->i_flags)) { | ||
1272 | *pts = (u64) ((u64)itv->last_dec_timing[2] << 32) | | ||
1273 | (u64)itv->last_dec_timing[1]; | ||
1274 | break; | ||
1275 | } | ||
1276 | *pts = 0; | ||
1277 | if (atomic_read(&itv->decoding)) { | ||
1278 | if (ivtv_api(itv, CX2341X_DEC_GET_TIMING_INFO, 5, data)) { | ||
1279 | IVTV_DEBUG_WARN("GET_TIMING: couldn't read clock\n"); | ||
1280 | return -EIO; | ||
1281 | } | ||
1282 | memcpy(itv->last_dec_timing, data, sizeof(itv->last_dec_timing)); | ||
1283 | set_bit(IVTV_F_I_VALID_DEC_TIMINGS, &itv->i_flags); | ||
1284 | *pts = (u64) ((u64) data[2] << 32) | (u64) data[1]; | ||
1285 | /*timing->scr = (u64) (((u64) data[4] << 32) | (u64) (data[3]));*/ | ||
1286 | } | ||
1287 | break; | ||
1288 | } | ||
1289 | |||
1290 | case VIDEO_GET_FRAME_COUNT: { | ||
1291 | u32 data[CX2341X_MBOX_MAX_DATA]; | ||
1292 | u64 *frame = arg; | ||
1293 | |||
1294 | IVTV_DEBUG_IOCTL("VIDEO_GET_FRAME_COUNT\n"); | ||
1295 | if (s->type < IVTV_DEC_STREAM_TYPE_MPG) { | ||
1296 | *frame = 0; | ||
1297 | break; | ||
1298 | } | ||
1299 | if (!(itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT)) | ||
1300 | return -EINVAL; | ||
1301 | |||
1302 | if (test_bit(IVTV_F_I_VALID_DEC_TIMINGS, &itv->i_flags)) { | ||
1303 | *frame = itv->last_dec_timing[0]; | ||
1304 | break; | ||
1305 | } | ||
1306 | *frame = 0; | ||
1307 | if (atomic_read(&itv->decoding)) { | ||
1308 | if (ivtv_api(itv, CX2341X_DEC_GET_TIMING_INFO, 5, data)) { | ||
1309 | IVTV_DEBUG_WARN("GET_TIMING: couldn't read clock\n"); | ||
1310 | return -EIO; | ||
1311 | } | ||
1312 | memcpy(itv->last_dec_timing, data, sizeof(itv->last_dec_timing)); | ||
1313 | set_bit(IVTV_F_I_VALID_DEC_TIMINGS, &itv->i_flags); | ||
1314 | *frame = data[0]; | ||
1315 | } | ||
1316 | break; | ||
1317 | } | ||
1318 | |||
1319 | case VIDEO_PLAY: { | ||
1320 | struct video_command vc; | ||
1321 | |||
1322 | IVTV_DEBUG_IOCTL("VIDEO_PLAY\n"); | ||
1323 | memset(&vc, 0, sizeof(vc)); | ||
1324 | vc.cmd = VIDEO_CMD_PLAY; | ||
1325 | return ivtv_video_command(itv, id, &vc, 0); | ||
1326 | } | ||
1327 | |||
1328 | case VIDEO_STOP: { | ||
1329 | struct video_command vc; | ||
1330 | |||
1331 | IVTV_DEBUG_IOCTL("VIDEO_STOP\n"); | ||
1332 | memset(&vc, 0, sizeof(vc)); | ||
1333 | vc.cmd = VIDEO_CMD_STOP; | ||
1334 | vc.flags = VIDEO_CMD_STOP_TO_BLACK | VIDEO_CMD_STOP_IMMEDIATELY; | ||
1335 | return ivtv_video_command(itv, id, &vc, 0); | ||
1336 | } | ||
1337 | |||
1338 | case VIDEO_FREEZE: { | ||
1339 | struct video_command vc; | ||
1340 | |||
1341 | IVTV_DEBUG_IOCTL("VIDEO_FREEZE\n"); | ||
1342 | memset(&vc, 0, sizeof(vc)); | ||
1343 | vc.cmd = VIDEO_CMD_FREEZE; | ||
1344 | return ivtv_video_command(itv, id, &vc, 0); | ||
1345 | } | ||
1346 | |||
1347 | case VIDEO_CONTINUE: { | ||
1348 | struct video_command vc; | ||
1349 | |||
1350 | IVTV_DEBUG_IOCTL("VIDEO_CONTINUE\n"); | ||
1351 | memset(&vc, 0, sizeof(vc)); | ||
1352 | vc.cmd = VIDEO_CMD_CONTINUE; | ||
1353 | return ivtv_video_command(itv, id, &vc, 0); | ||
1354 | } | ||
1355 | |||
1356 | case VIDEO_COMMAND: | ||
1357 | case VIDEO_TRY_COMMAND: { | ||
1358 | struct video_command *vc = arg; | ||
1359 | int try = (cmd == VIDEO_TRY_COMMAND); | ||
1360 | |||
1361 | if (try) | ||
1362 | IVTV_DEBUG_IOCTL("VIDEO_TRY_COMMAND\n"); | ||
1363 | else | ||
1364 | IVTV_DEBUG_IOCTL("VIDEO_COMMAND\n"); | ||
1365 | return ivtv_video_command(itv, id, vc, try); | ||
1366 | } | ||
1367 | |||
1368 | case VIDEO_GET_EVENT: { | ||
1369 | struct video_event *ev = arg; | ||
1370 | DEFINE_WAIT(wait); | ||
1371 | |||
1372 | IVTV_DEBUG_IOCTL("VIDEO_GET_EVENT\n"); | ||
1373 | if (!(itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT)) | ||
1374 | return -EINVAL; | ||
1375 | memset(ev, 0, sizeof(*ev)); | ||
1376 | set_bit(IVTV_F_I_EV_VSYNC_ENABLED, &itv->i_flags); | ||
1377 | |||
1378 | while (1) { | ||
1379 | if (test_and_clear_bit(IVTV_F_I_EV_DEC_STOPPED, &itv->i_flags)) | ||
1380 | ev->type = VIDEO_EVENT_DECODER_STOPPED; | ||
1381 | else if (test_and_clear_bit(IVTV_F_I_EV_VSYNC, &itv->i_flags)) { | ||
1382 | ev->type = VIDEO_EVENT_VSYNC; | ||
1383 | ev->u.vsync_field = test_bit(IVTV_F_I_EV_VSYNC_FIELD, &itv->i_flags) ? | ||
1384 | VIDEO_VSYNC_FIELD_ODD : VIDEO_VSYNC_FIELD_EVEN; | ||
1385 | if (itv->output_mode == OUT_UDMA_YUV && | ||
1386 | (itv->yuv_info.lace_mode & IVTV_YUV_MODE_MASK) == | ||
1387 | IVTV_YUV_MODE_PROGRESSIVE) { | ||
1388 | ev->u.vsync_field = VIDEO_VSYNC_FIELD_PROGRESSIVE; | ||
1389 | } | ||
1390 | } | ||
1391 | if (ev->type) | ||
1392 | return 0; | ||
1393 | if (nonblocking) | ||
1394 | return -EAGAIN; | ||
1395 | /* wait for event */ | ||
1396 | prepare_to_wait(&itv->event_waitq, &wait, TASK_INTERRUPTIBLE); | ||
1397 | if ((itv->i_flags & (IVTV_F_I_EV_DEC_STOPPED|IVTV_F_I_EV_VSYNC)) == 0) | ||
1398 | schedule(); | ||
1399 | finish_wait(&itv->event_waitq, &wait); | ||
1400 | if (signal_pending(current)) { | ||
1401 | /* return if a signal was received */ | ||
1402 | IVTV_DEBUG_INFO("User stopped wait for event\n"); | ||
1403 | return -EINTR; | ||
1404 | } | ||
1405 | } | ||
1406 | break; | ||
1407 | } | ||
1408 | |||
1409 | default: | ||
1410 | return -EINVAL; | ||
1411 | } | ||
1412 | return 0; | ||
1413 | } | ||
1414 | |||
1415 | static int ivtv_v4l2_do_ioctl(struct inode *inode, struct file *filp, | ||
1416 | unsigned int cmd, void *arg) | ||
1417 | { | ||
1418 | struct ivtv_open_id *id = (struct ivtv_open_id *)filp->private_data; | ||
1419 | struct ivtv *itv = id->itv; | ||
1420 | int ret; | ||
1421 | |||
1422 | /* check priority */ | ||
1423 | switch (cmd) { | ||
1424 | case VIDIOC_S_CTRL: | ||
1425 | case VIDIOC_S_STD: | ||
1426 | case VIDIOC_S_INPUT: | ||
1427 | case VIDIOC_S_OUTPUT: | ||
1428 | case VIDIOC_S_TUNER: | ||
1429 | case VIDIOC_S_FREQUENCY: | ||
1430 | case VIDIOC_S_FMT: | ||
1431 | case VIDIOC_S_CROP: | ||
1432 | case VIDIOC_S_AUDIO: | ||
1433 | case VIDIOC_S_AUDOUT: | ||
1434 | case VIDIOC_S_EXT_CTRLS: | ||
1435 | case VIDIOC_S_FBUF: | ||
1436 | ret = v4l2_prio_check(&itv->prio, &id->prio); | ||
1437 | if (ret) | ||
1438 | return ret; | ||
1439 | } | ||
1440 | |||
1441 | switch (cmd) { | ||
1442 | case VIDIOC_DBG_G_REGISTER: | ||
1443 | case VIDIOC_DBG_S_REGISTER: | ||
1444 | case VIDIOC_G_CHIP_IDENT: | ||
1445 | case VIDIOC_INT_S_AUDIO_ROUTING: | ||
1446 | case VIDIOC_INT_RESET: | ||
1447 | if (ivtv_debug & IVTV_DBGFLG_IOCTL) { | ||
1448 | printk(KERN_INFO "ivtv%d ioctl: ", itv->num); | ||
1449 | v4l_printk_ioctl(cmd); | ||
1450 | } | ||
1451 | return ivtv_debug_ioctls(filp, cmd, arg); | ||
1452 | |||
1453 | case VIDIOC_G_PRIORITY: | ||
1454 | case VIDIOC_S_PRIORITY: | ||
1455 | case VIDIOC_QUERYCAP: | ||
1456 | case VIDIOC_ENUMINPUT: | ||
1457 | case VIDIOC_G_INPUT: | ||
1458 | case VIDIOC_S_INPUT: | ||
1459 | case VIDIOC_ENUMOUTPUT: | ||
1460 | case VIDIOC_G_OUTPUT: | ||
1461 | case VIDIOC_S_OUTPUT: | ||
1462 | case VIDIOC_G_FMT: | ||
1463 | case VIDIOC_S_FMT: | ||
1464 | case VIDIOC_TRY_FMT: | ||
1465 | case VIDIOC_ENUM_FMT: | ||
1466 | case VIDIOC_G_CROP: | ||
1467 | case VIDIOC_S_CROP: | ||
1468 | case VIDIOC_G_FREQUENCY: | ||
1469 | case VIDIOC_S_FREQUENCY: | ||
1470 | case VIDIOC_ENUMSTD: | ||
1471 | case VIDIOC_G_STD: | ||
1472 | case VIDIOC_S_STD: | ||
1473 | case VIDIOC_S_TUNER: | ||
1474 | case VIDIOC_G_TUNER: | ||
1475 | case VIDIOC_ENUMAUDIO: | ||
1476 | case VIDIOC_S_AUDIO: | ||
1477 | case VIDIOC_G_AUDIO: | ||
1478 | case VIDIOC_ENUMAUDOUT: | ||
1479 | case VIDIOC_S_AUDOUT: | ||
1480 | case VIDIOC_G_AUDOUT: | ||
1481 | case VIDIOC_G_SLICED_VBI_CAP: | ||
1482 | case VIDIOC_LOG_STATUS: | ||
1483 | case VIDIOC_G_ENC_INDEX: | ||
1484 | case VIDIOC_ENCODER_CMD: | ||
1485 | case VIDIOC_TRY_ENCODER_CMD: | ||
1486 | case VIDIOC_G_FBUF: | ||
1487 | case VIDIOC_S_FBUF: | ||
1488 | if (ivtv_debug & IVTV_DBGFLG_IOCTL) { | ||
1489 | printk(KERN_INFO "ivtv%d ioctl: ", itv->num); | ||
1490 | v4l_printk_ioctl(cmd); | ||
1491 | } | ||
1492 | return ivtv_v4l2_ioctls(itv, filp, cmd, arg); | ||
1493 | |||
1494 | case VIDIOC_QUERYMENU: | ||
1495 | case VIDIOC_QUERYCTRL: | ||
1496 | case VIDIOC_S_CTRL: | ||
1497 | case VIDIOC_G_CTRL: | ||
1498 | case VIDIOC_S_EXT_CTRLS: | ||
1499 | case VIDIOC_G_EXT_CTRLS: | ||
1500 | case VIDIOC_TRY_EXT_CTRLS: | ||
1501 | if (ivtv_debug & IVTV_DBGFLG_IOCTL) { | ||
1502 | printk(KERN_INFO "ivtv%d ioctl: ", itv->num); | ||
1503 | v4l_printk_ioctl(cmd); | ||
1504 | } | ||
1505 | return ivtv_control_ioctls(itv, cmd, arg); | ||
1506 | |||
1507 | case IVTV_IOC_DMA_FRAME: | ||
1508 | case VIDEO_GET_PTS: | ||
1509 | case VIDEO_GET_FRAME_COUNT: | ||
1510 | case VIDEO_GET_EVENT: | ||
1511 | case VIDEO_PLAY: | ||
1512 | case VIDEO_STOP: | ||
1513 | case VIDEO_FREEZE: | ||
1514 | case VIDEO_CONTINUE: | ||
1515 | case VIDEO_COMMAND: | ||
1516 | case VIDEO_TRY_COMMAND: | ||
1517 | return ivtv_decoder_ioctls(filp, cmd, arg); | ||
1518 | |||
1519 | case 0x00005401: /* Handle isatty() calls */ | ||
1520 | return -EINVAL; | ||
1521 | default: | ||
1522 | return v4l_compat_translate_ioctl(inode, filp, cmd, arg, | ||
1523 | ivtv_v4l2_do_ioctl); | ||
1524 | } | ||
1525 | return 0; | ||
1526 | } | ||
1527 | |||
1528 | int ivtv_v4l2_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, | ||
1529 | unsigned long arg) | ||
1530 | { | ||
1531 | struct ivtv_open_id *id = (struct ivtv_open_id *)filp->private_data; | ||
1532 | struct ivtv *itv = id->itv; | ||
1533 | |||
1534 | /* Filter dvb ioctls that cannot be handled by video_usercopy */ | ||
1535 | switch (cmd) { | ||
1536 | case VIDEO_SELECT_SOURCE: | ||
1537 | IVTV_DEBUG_IOCTL("VIDEO_SELECT_SOURCE\n"); | ||
1538 | if (!(itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT)) | ||
1539 | return -EINVAL; | ||
1540 | return ivtv_passthrough_mode(itv, arg == VIDEO_SOURCE_DEMUX); | ||
1541 | |||
1542 | case AUDIO_SET_MUTE: | ||
1543 | IVTV_DEBUG_IOCTL("AUDIO_SET_MUTE\n"); | ||
1544 | itv->speed_mute_audio = arg; | ||
1545 | return 0; | ||
1546 | |||
1547 | case AUDIO_CHANNEL_SELECT: | ||
1548 | IVTV_DEBUG_IOCTL("AUDIO_CHANNEL_SELECT\n"); | ||
1549 | if (arg > AUDIO_STEREO_SWAPPED) | ||
1550 | return -EINVAL; | ||
1551 | itv->audio_stereo_mode = arg; | ||
1552 | ivtv_vapi(itv, CX2341X_DEC_SET_AUDIO_MODE, 2, itv->audio_bilingual_mode, itv->audio_stereo_mode); | ||
1553 | return 0; | ||
1554 | |||
1555 | case AUDIO_BILINGUAL_CHANNEL_SELECT: | ||
1556 | IVTV_DEBUG_IOCTL("AUDIO_BILINGUAL_CHANNEL_SELECT\n"); | ||
1557 | if (arg > AUDIO_STEREO_SWAPPED) | ||
1558 | return -EINVAL; | ||
1559 | itv->audio_bilingual_mode = arg; | ||
1560 | ivtv_vapi(itv, CX2341X_DEC_SET_AUDIO_MODE, 2, itv->audio_bilingual_mode, itv->audio_stereo_mode); | ||
1561 | return 0; | ||
1562 | |||
1563 | default: | ||
1564 | break; | ||
1565 | } | ||
1566 | return video_usercopy(inode, filp, cmd, arg, ivtv_v4l2_do_ioctl); | ||
1567 | } | ||
diff --git a/drivers/media/video/ivtv/ivtv-ioctl.h b/drivers/media/video/ivtv/ivtv-ioctl.h new file mode 100644 index 000000000000..cbccf7a9f65c --- /dev/null +++ b/drivers/media/video/ivtv/ivtv-ioctl.h | |||
@@ -0,0 +1,28 @@ | |||
1 | /* | ||
2 | ioctl system call | ||
3 | Copyright (C) 2003-2004 Kevin Thayer <nufan_wfk at yahoo.com> | ||
4 | Copyright (C) 2005-2007 Hans Verkuil <hverkuil@xs4all.nl> | ||
5 | |||
6 | This program is free software; you can redistribute it and/or modify | ||
7 | it under the terms of the GNU General Public License as published by | ||
8 | the Free Software Foundation; either version 2 of the License, or | ||
9 | (at your option) any later version. | ||
10 | |||
11 | This program is distributed in the hope that it will be useful, | ||
12 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
14 | GNU General Public License for more details. | ||
15 | |||
16 | You should have received a copy of the GNU General Public License | ||
17 | along with this program; if not, write to the Free Software | ||
18 | Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
19 | */ | ||
20 | |||
21 | u16 service2vbi(int type); | ||
22 | void expand_service_set(struct v4l2_sliced_vbi_format *fmt, int is_pal); | ||
23 | u16 get_service_set(struct v4l2_sliced_vbi_format *fmt); | ||
24 | int ivtv_v4l2_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, | ||
25 | unsigned long arg); | ||
26 | int ivtv_v4l2_ioctls(struct ivtv *itv, struct file *filp, unsigned int cmd, void *arg); | ||
27 | void ivtv_set_osd_alpha(struct ivtv *itv); | ||
28 | int ivtv_set_speed(struct ivtv *itv, int speed); | ||
diff --git a/drivers/media/video/ivtv/ivtv-irq.c b/drivers/media/video/ivtv/ivtv-irq.c new file mode 100644 index 000000000000..c3a047b381b3 --- /dev/null +++ b/drivers/media/video/ivtv/ivtv-irq.c | |||
@@ -0,0 +1,838 @@ | |||
1 | /* interrupt handling | ||
2 | Copyright (C) 2003-2004 Kevin Thayer <nufan_wfk at yahoo.com> | ||
3 | Copyright (C) 2004 Chris Kennedy <c@groovy.org> | ||
4 | Copyright (C) 2005-2007 Hans Verkuil <hverkuil@xs4all.nl> | ||
5 | |||
6 | This program is free software; you can redistribute it and/or modify | ||
7 | it under the terms of the GNU General Public License as published by | ||
8 | the Free Software Foundation; either version 2 of the License, or | ||
9 | (at your option) any later version. | ||
10 | |||
11 | This program is distributed in the hope that it will be useful, | ||
12 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
14 | GNU General Public License for more details. | ||
15 | |||
16 | You should have received a copy of the GNU General Public License | ||
17 | along with this program; if not, write to the Free Software | ||
18 | Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
19 | */ | ||
20 | |||
21 | #include "ivtv-driver.h" | ||
22 | #include "ivtv-firmware.h" | ||
23 | #include "ivtv-fileops.h" | ||
24 | #include "ivtv-queue.h" | ||
25 | #include "ivtv-udma.h" | ||
26 | #include "ivtv-irq.h" | ||
27 | #include "ivtv-ioctl.h" | ||
28 | #include "ivtv-mailbox.h" | ||
29 | #include "ivtv-vbi.h" | ||
30 | #include "ivtv-yuv.h" | ||
31 | |||
32 | #define DMA_MAGIC_COOKIE 0x000001fe | ||
33 | |||
34 | #define SLICED_VBI_PIO 1 | ||
35 | |||
36 | static void ivtv_dma_dec_start(struct ivtv_stream *s); | ||
37 | |||
38 | static const int ivtv_stream_map[] = { | ||
39 | IVTV_ENC_STREAM_TYPE_MPG, | ||
40 | IVTV_ENC_STREAM_TYPE_YUV, | ||
41 | IVTV_ENC_STREAM_TYPE_PCM, | ||
42 | IVTV_ENC_STREAM_TYPE_VBI, | ||
43 | }; | ||
44 | |||
45 | static inline int ivtv_use_pio(struct ivtv_stream *s) | ||
46 | { | ||
47 | struct ivtv *itv = s->itv; | ||
48 | |||
49 | return s->dma == PCI_DMA_NONE || | ||
50 | (SLICED_VBI_PIO && s->type == IVTV_ENC_STREAM_TYPE_VBI && itv->vbi.sliced_in->service_set); | ||
51 | } | ||
52 | |||
53 | void ivtv_irq_work_handler(struct work_struct *work) | ||
54 | { | ||
55 | struct ivtv *itv = container_of(work, struct ivtv, irq_work_queue); | ||
56 | |||
57 | DEFINE_WAIT(wait); | ||
58 | |||
59 | if (test_and_clear_bit(IVTV_F_I_WORK_HANDLER_VBI, &itv->i_flags)) | ||
60 | vbi_work_handler(itv); | ||
61 | |||
62 | if (test_and_clear_bit(IVTV_F_I_WORK_HANDLER_YUV, &itv->i_flags)) | ||
63 | ivtv_yuv_work_handler(itv); | ||
64 | } | ||
65 | |||
66 | /* Determine the required DMA size, setup enough buffers in the predma queue and | ||
67 | actually copy the data from the card to the buffers in case a PIO transfer is | ||
68 | required for this stream. | ||
69 | */ | ||
70 | static int stream_enc_dma_append(struct ivtv_stream *s, u32 data[CX2341X_MBOX_MAX_DATA]) | ||
71 | { | ||
72 | struct ivtv *itv = s->itv; | ||
73 | struct ivtv_buffer *buf; | ||
74 | struct list_head *p; | ||
75 | u32 bytes_needed = 0; | ||
76 | u32 offset, size; | ||
77 | u32 UVoffset = 0, UVsize = 0; | ||
78 | int skip_bufs = s->q_predma.buffers; | ||
79 | int idx = s->SG_length; | ||
80 | int rc; | ||
81 | |||
82 | /* sanity checks */ | ||
83 | if (s->v4l2dev == NULL) { | ||
84 | IVTV_DEBUG_WARN("Stream %s not started\n", s->name); | ||
85 | return -1; | ||
86 | } | ||
87 | if (!test_bit(IVTV_F_S_CLAIMED, &s->s_flags)) { | ||
88 | IVTV_DEBUG_WARN("Stream %s not open\n", s->name); | ||
89 | return -1; | ||
90 | } | ||
91 | |||
92 | /* determine offset, size and PTS for the various streams */ | ||
93 | switch (s->type) { | ||
94 | case IVTV_ENC_STREAM_TYPE_MPG: | ||
95 | offset = data[1]; | ||
96 | size = data[2]; | ||
97 | s->dma_pts = 0; | ||
98 | break; | ||
99 | |||
100 | case IVTV_ENC_STREAM_TYPE_YUV: | ||
101 | offset = data[1]; | ||
102 | size = data[2]; | ||
103 | UVoffset = data[3]; | ||
104 | UVsize = data[4]; | ||
105 | s->dma_pts = ((u64) data[5] << 32) | data[6]; | ||
106 | break; | ||
107 | |||
108 | case IVTV_ENC_STREAM_TYPE_PCM: | ||
109 | offset = data[1] + 12; | ||
110 | size = data[2] - 12; | ||
111 | s->dma_pts = read_dec(offset - 8) | | ||
112 | ((u64)(read_dec(offset - 12)) << 32); | ||
113 | if (itv->has_cx23415) | ||
114 | offset += IVTV_DECODER_OFFSET; | ||
115 | break; | ||
116 | |||
117 | case IVTV_ENC_STREAM_TYPE_VBI: | ||
118 | size = itv->vbi.enc_size * itv->vbi.fpi; | ||
119 | offset = read_enc(itv->vbi.enc_start - 4) + 12; | ||
120 | if (offset == 12) { | ||
121 | IVTV_DEBUG_INFO("VBI offset == 0\n"); | ||
122 | return -1; | ||
123 | } | ||
124 | s->dma_pts = read_enc(offset - 4) | ((u64)read_enc(offset - 8) << 32); | ||
125 | break; | ||
126 | |||
127 | case IVTV_DEC_STREAM_TYPE_VBI: | ||
128 | size = read_dec(itv->vbi.dec_start + 4) + 8; | ||
129 | offset = read_dec(itv->vbi.dec_start) + itv->vbi.dec_start; | ||
130 | s->dma_pts = 0; | ||
131 | offset += IVTV_DECODER_OFFSET; | ||
132 | break; | ||
133 | default: | ||
134 | /* shouldn't happen */ | ||
135 | return -1; | ||
136 | } | ||
137 | |||
138 | /* if this is the start of the DMA then fill in the magic cookie */ | ||
139 | if (s->SG_length == 0) { | ||
140 | if (itv->has_cx23415 && (s->type == IVTV_ENC_STREAM_TYPE_PCM || | ||
141 | s->type == IVTV_DEC_STREAM_TYPE_VBI)) { | ||
142 | s->dma_backup = read_dec(offset - IVTV_DECODER_OFFSET); | ||
143 | write_dec_sync(cpu_to_le32(DMA_MAGIC_COOKIE), offset - IVTV_DECODER_OFFSET); | ||
144 | } | ||
145 | else { | ||
146 | s->dma_backup = read_enc(offset); | ||
147 | write_enc_sync(cpu_to_le32(DMA_MAGIC_COOKIE), offset); | ||
148 | } | ||
149 | s->dma_offset = offset; | ||
150 | } | ||
151 | |||
152 | bytes_needed = size; | ||
153 | if (s->type == IVTV_ENC_STREAM_TYPE_YUV) { | ||
154 | /* The size for the Y samples needs to be rounded upwards to a | ||
155 | multiple of the buf_size. The UV samples then start in the | ||
156 | next buffer. */ | ||
157 | bytes_needed = s->buf_size * ((bytes_needed + s->buf_size - 1) / s->buf_size); | ||
158 | bytes_needed += UVsize; | ||
159 | } | ||
160 | |||
161 | IVTV_DEBUG_DMA("%s %s: 0x%08x bytes at 0x%08x\n", | ||
162 | ivtv_use_pio(s) ? "PIO" : "DMA", s->name, bytes_needed, offset); | ||
163 | |||
164 | rc = ivtv_queue_move(s, &s->q_free, &s->q_full, &s->q_predma, bytes_needed); | ||
165 | if (rc < 0) { /* Insufficient buffers */ | ||
166 | IVTV_DEBUG_WARN("Cannot obtain %d bytes for %s data transfer\n", | ||
167 | bytes_needed, s->name); | ||
168 | return -1; | ||
169 | } | ||
170 | if (rc && !s->buffers_stolen && (s->s_flags & IVTV_F_S_APPL_IO)) { | ||
171 | IVTV_WARN("All %s stream buffers are full. Dropping data.\n", s->name); | ||
172 | IVTV_WARN("Cause: the application is not reading fast enough.\n"); | ||
173 | } | ||
174 | s->buffers_stolen = rc; | ||
175 | |||
176 | /* got the buffers, now fill in SGarray (DMA) or copy the data from the card | ||
177 | to the buffers (PIO). */ | ||
178 | buf = list_entry(s->q_predma.list.next, struct ivtv_buffer, list); | ||
179 | memset(buf->buf, 0, 128); | ||
180 | list_for_each(p, &s->q_predma.list) { | ||
181 | struct ivtv_buffer *buf = list_entry(p, struct ivtv_buffer, list); | ||
182 | |||
183 | if (skip_bufs-- > 0) | ||
184 | continue; | ||
185 | if (!ivtv_use_pio(s)) { | ||
186 | s->SGarray[idx].dst = cpu_to_le32(buf->dma_handle); | ||
187 | s->SGarray[idx].src = cpu_to_le32(offset); | ||
188 | s->SGarray[idx].size = cpu_to_le32(s->buf_size); | ||
189 | } | ||
190 | buf->bytesused = (size < s->buf_size) ? size : s->buf_size; | ||
191 | |||
192 | /* If PIO, then copy the data from the card to the buffer */ | ||
193 | if (s->type == IVTV_DEC_STREAM_TYPE_VBI) { | ||
194 | memcpy_fromio(buf->buf, itv->dec_mem + offset - IVTV_DECODER_OFFSET, buf->bytesused); | ||
195 | } | ||
196 | else if (ivtv_use_pio(s)) { | ||
197 | memcpy_fromio(buf->buf, itv->enc_mem + offset, buf->bytesused); | ||
198 | } | ||
199 | |||
200 | s->q_predma.bytesused += buf->bytesused; | ||
201 | size -= buf->bytesused; | ||
202 | offset += s->buf_size; | ||
203 | |||
204 | /* Sync SG buffers */ | ||
205 | ivtv_buf_sync_for_device(s, buf); | ||
206 | |||
207 | if (size == 0) { /* YUV */ | ||
208 | /* process the UV section */ | ||
209 | offset = UVoffset; | ||
210 | size = UVsize; | ||
211 | } | ||
212 | idx++; | ||
213 | } | ||
214 | s->SG_length = idx; | ||
215 | return 0; | ||
216 | } | ||
217 | |||
218 | static void dma_post(struct ivtv_stream *s) | ||
219 | { | ||
220 | struct ivtv *itv = s->itv; | ||
221 | struct ivtv_buffer *buf = NULL; | ||
222 | struct list_head *p; | ||
223 | u32 offset; | ||
224 | u32 *u32buf; | ||
225 | int x = 0; | ||
226 | |||
227 | if (ivtv_use_pio(s)) { | ||
228 | if (s->q_predma.bytesused) | ||
229 | ivtv_queue_move(s, &s->q_predma, NULL, &s->q_dma, s->q_predma.bytesused); | ||
230 | s->SG_length = 0; | ||
231 | } | ||
232 | IVTV_DEBUG_DMA("%s %s completed (%x)\n", ivtv_use_pio(s) ? "PIO" : "DMA", | ||
233 | s->name, s->dma_offset); | ||
234 | list_for_each(p, &s->q_dma.list) { | ||
235 | buf = list_entry(p, struct ivtv_buffer, list); | ||
236 | u32buf = (u32 *)buf->buf; | ||
237 | |||
238 | /* Sync Buffer */ | ||
239 | ivtv_buf_sync_for_cpu(s, buf); | ||
240 | |||
241 | if (x == 0) { | ||
242 | offset = s->dma_last_offset; | ||
243 | if (u32buf[offset / 4] != DMA_MAGIC_COOKIE) | ||
244 | { | ||
245 | for (offset = 0; offset < 64; offset++) { | ||
246 | if (u32buf[offset] == DMA_MAGIC_COOKIE) { | ||
247 | break; | ||
248 | } | ||
249 | } | ||
250 | offset *= 4; | ||
251 | if (offset == 256) { | ||
252 | IVTV_DEBUG_WARN("%s: Couldn't find start of buffer within the first 256 bytes\n", s->name); | ||
253 | offset = s->dma_last_offset; | ||
254 | } | ||
255 | if (s->dma_last_offset != offset) | ||
256 | IVTV_DEBUG_WARN("%s: offset %d -> %d\n", s->name, s->dma_last_offset, offset); | ||
257 | s->dma_last_offset = offset; | ||
258 | } | ||
259 | if (itv->has_cx23415 && (s->type == IVTV_ENC_STREAM_TYPE_PCM || | ||
260 | s->type == IVTV_DEC_STREAM_TYPE_VBI)) { | ||
261 | write_dec_sync(0, s->dma_offset - IVTV_DECODER_OFFSET); | ||
262 | } | ||
263 | else { | ||
264 | write_enc_sync(0, s->dma_offset); | ||
265 | } | ||
266 | if (offset) { | ||
267 | buf->bytesused -= offset; | ||
268 | memcpy(buf->buf, buf->buf + offset, buf->bytesused + offset); | ||
269 | } | ||
270 | *u32buf = cpu_to_le32(s->dma_backup); | ||
271 | } | ||
272 | x++; | ||
273 | /* flag byteswap ABCD -> DCBA for MPG & VBI data outside irq */ | ||
274 | if (s->type == IVTV_ENC_STREAM_TYPE_MPG || | ||
275 | s->type == IVTV_ENC_STREAM_TYPE_VBI) | ||
276 | set_bit(IVTV_F_B_NEED_BUF_SWAP, &buf->b_flags); | ||
277 | } | ||
278 | if (buf) | ||
279 | buf->bytesused += s->dma_last_offset; | ||
280 | if (buf && s->type == IVTV_DEC_STREAM_TYPE_VBI) { | ||
281 | /* Parse and Groom VBI Data */ | ||
282 | s->q_dma.bytesused -= buf->bytesused; | ||
283 | ivtv_process_vbi_data(itv, buf, 0, s->type); | ||
284 | s->q_dma.bytesused += buf->bytesused; | ||
285 | if (s->id == -1) { | ||
286 | ivtv_queue_move(s, &s->q_dma, NULL, &s->q_free, 0); | ||
287 | return; | ||
288 | } | ||
289 | } | ||
290 | ivtv_queue_move(s, &s->q_dma, NULL, &s->q_full, s->q_dma.bytesused); | ||
291 | if (s->id != -1) | ||
292 | wake_up(&s->waitq); | ||
293 | } | ||
294 | |||
295 | void ivtv_dma_stream_dec_prepare(struct ivtv_stream *s, u32 offset, int lock) | ||
296 | { | ||
297 | struct ivtv *itv = s->itv; | ||
298 | struct ivtv_buffer *buf; | ||
299 | struct list_head *p; | ||
300 | u32 y_size = itv->params.height * itv->params.width; | ||
301 | u32 uv_offset = offset + IVTV_YUV_BUFFER_UV_OFFSET; | ||
302 | int y_done = 0; | ||
303 | int bytes_written = 0; | ||
304 | unsigned long flags = 0; | ||
305 | int idx = 0; | ||
306 | |||
307 | IVTV_DEBUG_DMA("DEC PREPARE DMA %s: %08x %08x\n", s->name, s->q_predma.bytesused, offset); | ||
308 | buf = list_entry(s->q_predma.list.next, struct ivtv_buffer, list); | ||
309 | list_for_each(p, &s->q_predma.list) { | ||
310 | struct ivtv_buffer *buf = list_entry(p, struct ivtv_buffer, list); | ||
311 | |||
312 | /* YUV UV Offset from Y Buffer */ | ||
313 | if (s->type == IVTV_DEC_STREAM_TYPE_YUV && !y_done && bytes_written >= y_size) { | ||
314 | offset = uv_offset; | ||
315 | y_done = 1; | ||
316 | } | ||
317 | s->SGarray[idx].src = cpu_to_le32(buf->dma_handle); | ||
318 | s->SGarray[idx].dst = cpu_to_le32(offset); | ||
319 | s->SGarray[idx].size = cpu_to_le32(buf->bytesused); | ||
320 | |||
321 | offset += buf->bytesused; | ||
322 | bytes_written += buf->bytesused; | ||
323 | |||
324 | /* Sync SG buffers */ | ||
325 | ivtv_buf_sync_for_device(s, buf); | ||
326 | idx++; | ||
327 | } | ||
328 | s->SG_length = idx; | ||
329 | |||
330 | /* Mark last buffer size for Interrupt flag */ | ||
331 | s->SGarray[s->SG_length - 1].size |= cpu_to_le32(0x80000000); | ||
332 | |||
333 | /* Sync Hardware SG List of buffers */ | ||
334 | ivtv_stream_sync_for_device(s); | ||
335 | if (lock) | ||
336 | spin_lock_irqsave(&itv->dma_reg_lock, flags); | ||
337 | if (!test_bit(IVTV_F_I_DMA, &itv->i_flags)) { | ||
338 | ivtv_dma_dec_start(s); | ||
339 | } | ||
340 | else { | ||
341 | set_bit(IVTV_F_S_DMA_PENDING, &s->s_flags); | ||
342 | } | ||
343 | if (lock) | ||
344 | spin_unlock_irqrestore(&itv->dma_reg_lock, flags); | ||
345 | } | ||
346 | |||
347 | /* start the encoder DMA */ | ||
348 | static void ivtv_dma_enc_start(struct ivtv_stream *s) | ||
349 | { | ||
350 | struct ivtv *itv = s->itv; | ||
351 | struct ivtv_stream *s_vbi = &itv->streams[IVTV_ENC_STREAM_TYPE_VBI]; | ||
352 | int i; | ||
353 | |||
354 | if (s->q_predma.bytesused) | ||
355 | ivtv_queue_move(s, &s->q_predma, NULL, &s->q_dma, s->q_predma.bytesused); | ||
356 | IVTV_DEBUG_DMA("start DMA for %s\n", s->name); | ||
357 | s->SGarray[s->SG_length - 1].size = cpu_to_le32(le32_to_cpu(s->SGarray[s->SG_length - 1].size) + 256); | ||
358 | |||
359 | /* If this is an MPEG stream, and VBI data is also pending, then append the | ||
360 | VBI DMA to the MPEG DMA and transfer both sets of data at once. | ||
361 | |||
362 | VBI DMA is a second class citizen compared to MPEG and mixing them together | ||
363 | will confuse the firmware (the end of a VBI DMA is seen as the end of a | ||
364 | MPEG DMA, thus effectively dropping an MPEG frame). So instead we make | ||
365 | sure we only use the MPEG DMA to transfer the VBI DMA if both are in | ||
366 | use. This way no conflicts occur. */ | ||
367 | clear_bit(IVTV_F_S_DMA_HAS_VBI, &s->s_flags); | ||
368 | if (s->type == IVTV_ENC_STREAM_TYPE_MPG && s_vbi->SG_length && | ||
369 | s->SG_length + s_vbi->SG_length <= s->buffers) { | ||
370 | ivtv_queue_move(s_vbi, &s_vbi->q_predma, NULL, &s_vbi->q_dma, s_vbi->q_predma.bytesused); | ||
371 | s_vbi->SGarray[s_vbi->SG_length - 1].size = cpu_to_le32(le32_to_cpu(s_vbi->SGarray[s->SG_length - 1].size) + 256); | ||
372 | for (i = 0; i < s_vbi->SG_length; i++) { | ||
373 | s->SGarray[s->SG_length++] = s_vbi->SGarray[i]; | ||
374 | } | ||
375 | itv->vbi.dma_offset = s_vbi->dma_offset; | ||
376 | s_vbi->SG_length = 0; | ||
377 | set_bit(IVTV_F_S_DMA_HAS_VBI, &s->s_flags); | ||
378 | IVTV_DEBUG_DMA("include DMA for %s\n", s->name); | ||
379 | } | ||
380 | |||
381 | /* Mark last buffer size for Interrupt flag */ | ||
382 | s->SGarray[s->SG_length - 1].size |= cpu_to_le32(0x80000000); | ||
383 | |||
384 | /* Sync Hardware SG List of buffers */ | ||
385 | ivtv_stream_sync_for_device(s); | ||
386 | write_reg(s->SG_handle, IVTV_REG_ENCDMAADDR); | ||
387 | write_reg_sync(read_reg(IVTV_REG_DMAXFER) | 0x02, IVTV_REG_DMAXFER); | ||
388 | set_bit(IVTV_F_I_DMA, &itv->i_flags); | ||
389 | itv->cur_dma_stream = s->type; | ||
390 | itv->dma_timer.expires = jiffies + HZ / 10; | ||
391 | add_timer(&itv->dma_timer); | ||
392 | } | ||
393 | |||
394 | static void ivtv_dma_dec_start(struct ivtv_stream *s) | ||
395 | { | ||
396 | struct ivtv *itv = s->itv; | ||
397 | |||
398 | if (s->q_predma.bytesused) | ||
399 | ivtv_queue_move(s, &s->q_predma, NULL, &s->q_dma, s->q_predma.bytesused); | ||
400 | IVTV_DEBUG_DMA("start DMA for %s\n", s->name); | ||
401 | /* put SG Handle into register 0x0c */ | ||
402 | write_reg(s->SG_handle, IVTV_REG_DECDMAADDR); | ||
403 | write_reg_sync(read_reg(IVTV_REG_DMAXFER) | 0x01, IVTV_REG_DMAXFER); | ||
404 | set_bit(IVTV_F_I_DMA, &itv->i_flags); | ||
405 | itv->cur_dma_stream = s->type; | ||
406 | itv->dma_timer.expires = jiffies + HZ / 10; | ||
407 | add_timer(&itv->dma_timer); | ||
408 | } | ||
409 | |||
410 | static void ivtv_irq_dma_read(struct ivtv *itv) | ||
411 | { | ||
412 | struct ivtv_stream *s = NULL; | ||
413 | struct ivtv_buffer *buf; | ||
414 | int hw_stream_type; | ||
415 | |||
416 | IVTV_DEBUG_IRQ("DEC DMA READ\n"); | ||
417 | del_timer(&itv->dma_timer); | ||
418 | if (read_reg(IVTV_REG_DMASTATUS) & 0x14) { | ||
419 | IVTV_DEBUG_WARN("DEC DMA ERROR %x\n", read_reg(IVTV_REG_DMASTATUS)); | ||
420 | write_reg(read_reg(IVTV_REG_DMASTATUS) & 3, IVTV_REG_DMASTATUS); | ||
421 | } | ||
422 | if (!test_bit(IVTV_F_I_UDMA, &itv->i_flags)) { | ||
423 | if (test_bit(IVTV_F_I_DEC_YUV, &itv->i_flags)) { | ||
424 | s = &itv->streams[IVTV_DEC_STREAM_TYPE_YUV]; | ||
425 | hw_stream_type = 2; | ||
426 | } | ||
427 | else { | ||
428 | s = &itv->streams[IVTV_DEC_STREAM_TYPE_MPG]; | ||
429 | hw_stream_type = 0; | ||
430 | } | ||
431 | IVTV_DEBUG_DMA("DEC DATA READ %s: %d\n", s->name, s->q_dma.bytesused); | ||
432 | |||
433 | ivtv_stream_sync_for_cpu(s); | ||
434 | |||
435 | /* For some reason must kick the firmware, like PIO mode, | ||
436 | I think this tells the firmware we are done and the size | ||
437 | of the xfer so it can calculate what we need next. | ||
438 | I think we can do this part ourselves but would have to | ||
439 | fully calculate xfer info ourselves and not use interrupts | ||
440 | */ | ||
441 | ivtv_vapi(itv, CX2341X_DEC_SCHED_DMA_FROM_HOST, 3, 0, s->q_dma.bytesused, | ||
442 | hw_stream_type); | ||
443 | |||
444 | /* Free last DMA call */ | ||
445 | while ((buf = ivtv_dequeue(s, &s->q_dma)) != NULL) { | ||
446 | ivtv_buf_sync_for_cpu(s, buf); | ||
447 | ivtv_enqueue(s, buf, &s->q_free); | ||
448 | } | ||
449 | wake_up(&s->waitq); | ||
450 | } | ||
451 | clear_bit(IVTV_F_I_UDMA, &itv->i_flags); | ||
452 | clear_bit(IVTV_F_I_DMA, &itv->i_flags); | ||
453 | itv->cur_dma_stream = -1; | ||
454 | wake_up(&itv->dma_waitq); | ||
455 | } | ||
456 | |||
457 | static void ivtv_irq_enc_dma_complete(struct ivtv *itv) | ||
458 | { | ||
459 | u32 data[CX2341X_MBOX_MAX_DATA]; | ||
460 | struct ivtv_stream *s; | ||
461 | |||
462 | del_timer(&itv->dma_timer); | ||
463 | ivtv_api_get_data(&itv->enc_mbox, IVTV_MBOX_DMA_END, data); | ||
464 | IVTV_DEBUG_IRQ("ENC DMA COMPLETE %x %d\n", data[0], data[1]); | ||
465 | if (test_and_clear_bit(IVTV_F_I_ENC_VBI, &itv->i_flags)) | ||
466 | data[1] = 3; | ||
467 | else if (data[1] > 2) | ||
468 | return; | ||
469 | s = &itv->streams[ivtv_stream_map[data[1]]]; | ||
470 | if (data[0] & 0x18) { | ||
471 | IVTV_DEBUG_WARN("ENC DMA ERROR %x\n", data[0]); | ||
472 | write_reg(read_reg(IVTV_REG_DMASTATUS) & 3, IVTV_REG_DMASTATUS); | ||
473 | ivtv_vapi(itv, CX2341X_ENC_SCHED_DMA_TO_HOST, 3, 0, 0, data[1]); | ||
474 | } | ||
475 | s->SG_length = 0; | ||
476 | clear_bit(IVTV_F_I_DMA, &itv->i_flags); | ||
477 | itv->cur_dma_stream = -1; | ||
478 | dma_post(s); | ||
479 | ivtv_stream_sync_for_cpu(s); | ||
480 | if (test_and_clear_bit(IVTV_F_S_DMA_HAS_VBI, &s->s_flags)) { | ||
481 | u32 tmp; | ||
482 | |||
483 | s = &itv->streams[IVTV_ENC_STREAM_TYPE_VBI]; | ||
484 | tmp = s->dma_offset; | ||
485 | s->dma_offset = itv->vbi.dma_offset; | ||
486 | dma_post(s); | ||
487 | s->dma_offset = tmp; | ||
488 | } | ||
489 | wake_up(&itv->dma_waitq); | ||
490 | } | ||
491 | |||
492 | static void ivtv_irq_dma_err(struct ivtv *itv) | ||
493 | { | ||
494 | u32 data[CX2341X_MBOX_MAX_DATA]; | ||
495 | |||
496 | del_timer(&itv->dma_timer); | ||
497 | ivtv_api_get_data(&itv->enc_mbox, IVTV_MBOX_DMA_END, data); | ||
498 | IVTV_DEBUG_WARN("DMA ERROR %08x %08x %08x %d\n", data[0], data[1], | ||
499 | read_reg(IVTV_REG_DMASTATUS), itv->cur_dma_stream); | ||
500 | if (!test_bit(IVTV_F_I_UDMA, &itv->i_flags) && | ||
501 | itv->cur_dma_stream >= 0 && itv->cur_dma_stream < IVTV_MAX_STREAMS) { | ||
502 | struct ivtv_stream *s = &itv->streams[itv->cur_dma_stream]; | ||
503 | |||
504 | /* retry */ | ||
505 | write_reg(read_reg(IVTV_REG_DMASTATUS) & 3, IVTV_REG_DMASTATUS); | ||
506 | if (s->type >= IVTV_DEC_STREAM_TYPE_MPG) | ||
507 | ivtv_dma_dec_start(s); | ||
508 | else | ||
509 | ivtv_dma_enc_start(s); | ||
510 | return; | ||
511 | } | ||
512 | clear_bit(IVTV_F_I_UDMA, &itv->i_flags); | ||
513 | clear_bit(IVTV_F_I_DMA, &itv->i_flags); | ||
514 | itv->cur_dma_stream = -1; | ||
515 | wake_up(&itv->dma_waitq); | ||
516 | } | ||
517 | |||
518 | static void ivtv_irq_enc_start_cap(struct ivtv *itv) | ||
519 | { | ||
520 | u32 data[CX2341X_MBOX_MAX_DATA]; | ||
521 | struct ivtv_stream *s; | ||
522 | |||
523 | /* Get DMA destination and size arguments from card */ | ||
524 | ivtv_api_get_data(&itv->enc_mbox, IVTV_MBOX_DMA, data); | ||
525 | IVTV_DEBUG_IRQ("ENC START CAP %d: %08x %08x\n", data[0], data[1], data[2]); | ||
526 | |||
527 | if (data[0] > 2 || data[1] == 0 || data[2] == 0) { | ||
528 | IVTV_DEBUG_WARN("Unknown input: %08x %08x %08x\n", | ||
529 | data[0], data[1], data[2]); | ||
530 | return; | ||
531 | } | ||
532 | clear_bit(IVTV_F_I_ENC_VBI, &itv->i_flags); | ||
533 | s = &itv->streams[ivtv_stream_map[data[0]]]; | ||
534 | if (!stream_enc_dma_append(s, data)) { | ||
535 | if (ivtv_use_pio(s)) { | ||
536 | dma_post(s); | ||
537 | ivtv_vapi(itv, CX2341X_ENC_SCHED_DMA_TO_HOST, 3, 0, 0, data[0]); | ||
538 | } | ||
539 | else { | ||
540 | set_bit(IVTV_F_S_DMA_PENDING, &s->s_flags); | ||
541 | } | ||
542 | } | ||
543 | } | ||
544 | |||
545 | static void ivtv_irq_enc_vbi_cap(struct ivtv *itv) | ||
546 | { | ||
547 | struct ivtv_stream *s_mpg = &itv->streams[IVTV_ENC_STREAM_TYPE_MPG]; | ||
548 | u32 data[CX2341X_MBOX_MAX_DATA]; | ||
549 | struct ivtv_stream *s; | ||
550 | |||
551 | IVTV_DEBUG_IRQ("ENC START VBI CAP\n"); | ||
552 | s = &itv->streams[IVTV_ENC_STREAM_TYPE_VBI]; | ||
553 | |||
554 | if (ivtv_use_pio(s)) { | ||
555 | if (stream_enc_dma_append(s, data)) | ||
556 | return; | ||
557 | if (s->q_predma.bytesused) | ||
558 | ivtv_queue_move(s, &s->q_predma, NULL, &s->q_dma, s->q_predma.bytesused); | ||
559 | s->SG_length = 0; | ||
560 | dma_post(s); | ||
561 | return; | ||
562 | } | ||
563 | /* If more than two VBI buffers are pending, then | ||
564 | clear the old ones and start with this new one. | ||
565 | This can happen during transition stages when MPEG capturing is | ||
566 | started, but the first interrupts haven't arrived yet. During | ||
567 | that period VBI requests can accumulate without being able to | ||
568 | DMA the data. Since at most four VBI DMA buffers are available, | ||
569 | we just drop the old requests when there are already three | ||
570 | requests queued. */ | ||
571 | if (s->SG_length > 2) { | ||
572 | struct list_head *p; | ||
573 | list_for_each(p, &s->q_predma.list) { | ||
574 | struct ivtv_buffer *buf = list_entry(p, struct ivtv_buffer, list); | ||
575 | ivtv_buf_sync_for_cpu(s, buf); | ||
576 | } | ||
577 | ivtv_queue_move(s, &s->q_predma, NULL, &s->q_free, 0); | ||
578 | s->SG_length = 0; | ||
579 | } | ||
580 | /* if we can append the data, and the MPEG stream isn't capturing, | ||
581 | then start a DMA request for just the VBI data. */ | ||
582 | if (!stream_enc_dma_append(s, data) && | ||
583 | !test_bit(IVTV_F_S_STREAMING, &s_mpg->s_flags)) { | ||
584 | set_bit(IVTV_F_I_ENC_VBI, &itv->i_flags); | ||
585 | set_bit(IVTV_F_S_DMA_PENDING, &s->s_flags); | ||
586 | } | ||
587 | } | ||
588 | |||
589 | static void ivtv_irq_dev_vbi_reinsert(struct ivtv *itv) | ||
590 | { | ||
591 | u32 data[CX2341X_MBOX_MAX_DATA]; | ||
592 | struct ivtv_stream *s = &itv->streams[IVTV_DEC_STREAM_TYPE_VBI]; | ||
593 | |||
594 | IVTV_DEBUG_IRQ("DEC VBI REINSERT\n"); | ||
595 | if (test_bit(IVTV_F_S_CLAIMED, &s->s_flags) && | ||
596 | !stream_enc_dma_append(s, data)) { | ||
597 | dma_post(s); | ||
598 | } | ||
599 | } | ||
600 | |||
601 | static void ivtv_irq_dec_data_req(struct ivtv *itv) | ||
602 | { | ||
603 | u32 data[CX2341X_MBOX_MAX_DATA]; | ||
604 | struct ivtv_stream *s; | ||
605 | |||
606 | /* YUV or MPG */ | ||
607 | ivtv_api_get_data(&itv->dec_mbox, IVTV_MBOX_DMA, data); | ||
608 | |||
609 | if (test_bit(IVTV_F_I_DEC_YUV, &itv->i_flags)) { | ||
610 | itv->dma_data_req_size = itv->params.width * itv->params.height * 3 / 2; | ||
611 | itv->dma_data_req_offset = data[1] ? data[1] : yuv_offset[0]; | ||
612 | s = &itv->streams[IVTV_DEC_STREAM_TYPE_YUV]; | ||
613 | } | ||
614 | else { | ||
615 | itv->dma_data_req_size = data[2] >= 0x10000 ? 0x10000 : data[2]; | ||
616 | itv->dma_data_req_offset = data[1]; | ||
617 | s = &itv->streams[IVTV_DEC_STREAM_TYPE_MPG]; | ||
618 | } | ||
619 | IVTV_DEBUG_IRQ("DEC DATA REQ %s: %d %08x %u\n", s->name, s->q_full.bytesused, | ||
620 | itv->dma_data_req_offset, itv->dma_data_req_size); | ||
621 | if (itv->dma_data_req_size == 0 || s->q_full.bytesused < itv->dma_data_req_size) { | ||
622 | set_bit(IVTV_F_S_NEEDS_DATA, &s->s_flags); | ||
623 | } | ||
624 | else { | ||
625 | clear_bit(IVTV_F_S_NEEDS_DATA, &s->s_flags); | ||
626 | ivtv_queue_move(s, &s->q_full, NULL, &s->q_predma, itv->dma_data_req_size); | ||
627 | ivtv_dma_stream_dec_prepare(s, itv->dma_data_req_offset + IVTV_DECODER_OFFSET, 0); | ||
628 | } | ||
629 | } | ||
630 | |||
631 | static void ivtv_irq_vsync(struct ivtv *itv) | ||
632 | { | ||
633 | /* The vsync interrupt is unusual in that it won't clear until | ||
634 | * the end of the first line for the current field, at which | ||
635 | * point it clears itself. This can result in repeated vsync | ||
636 | * interrupts, or a missed vsync. Read some of the registers | ||
637 | * to determine the line being displayed and ensure we handle | ||
638 | * one vsync per frame. | ||
639 | */ | ||
640 | unsigned int frame = read_reg(0x28c0) & 1; | ||
641 | int last_dma_frame = atomic_read(&itv->yuv_info.next_dma_frame); | ||
642 | |||
643 | if (0) IVTV_DEBUG_IRQ("DEC VSYNC\n"); | ||
644 | |||
645 | if (((frame ^ itv->yuv_info.lace_sync_field) == 0 && ((itv->lastVsyncFrame & 1) ^ itv->yuv_info.lace_sync_field)) || | ||
646 | (frame != (itv->lastVsyncFrame & 1) && !itv->yuv_info.frame_interlaced)) { | ||
647 | int next_dma_frame = last_dma_frame; | ||
648 | |||
649 | if (next_dma_frame >= 0 && next_dma_frame != atomic_read(&itv->yuv_info.next_fill_frame)) { | ||
650 | write_reg(yuv_offset[next_dma_frame] >> 4, 0x82c); | ||
651 | write_reg((yuv_offset[next_dma_frame] + IVTV_YUV_BUFFER_UV_OFFSET) >> 4, 0x830); | ||
652 | write_reg(yuv_offset[next_dma_frame] >> 4, 0x834); | ||
653 | write_reg((yuv_offset[next_dma_frame] + IVTV_YUV_BUFFER_UV_OFFSET) >> 4, 0x838); | ||
654 | next_dma_frame = (next_dma_frame + 1) & 0x3; | ||
655 | atomic_set(&itv->yuv_info.next_dma_frame, next_dma_frame); | ||
656 | } | ||
657 | } | ||
658 | if (frame != (itv->lastVsyncFrame & 1)) { | ||
659 | struct ivtv_stream *s = ivtv_get_output_stream(itv); | ||
660 | int work = 0; | ||
661 | |||
662 | itv->lastVsyncFrame += 1; | ||
663 | if (frame == 0) { | ||
664 | clear_bit(IVTV_F_I_VALID_DEC_TIMINGS, &itv->i_flags); | ||
665 | clear_bit(IVTV_F_I_EV_VSYNC_FIELD, &itv->i_flags); | ||
666 | } | ||
667 | else { | ||
668 | set_bit(IVTV_F_I_EV_VSYNC_FIELD, &itv->i_flags); | ||
669 | } | ||
670 | if (test_bit(IVTV_F_I_EV_VSYNC_ENABLED, &itv->i_flags)) { | ||
671 | set_bit(IVTV_F_I_EV_VSYNC, &itv->i_flags); | ||
672 | wake_up(&itv->event_waitq); | ||
673 | } | ||
674 | wake_up(&itv->vsync_waitq); | ||
675 | if (s) | ||
676 | wake_up(&s->waitq); | ||
677 | |||
678 | /* Send VBI to saa7127 */ | ||
679 | if (frame) { | ||
680 | set_bit(IVTV_F_I_WORK_HANDLER_VBI, &itv->i_flags); | ||
681 | work = 1; | ||
682 | } | ||
683 | |||
684 | /* Check if we need to update the yuv registers */ | ||
685 | if ((itv->yuv_info.yuv_forced_update || itv->yuv_info.new_frame_info[last_dma_frame].update) && last_dma_frame != -1) { | ||
686 | if (!itv->yuv_info.new_frame_info[last_dma_frame].update) | ||
687 | last_dma_frame = (last_dma_frame - 1) & 3; | ||
688 | |||
689 | if (itv->yuv_info.new_frame_info[last_dma_frame].src_w) { | ||
690 | itv->yuv_info.update_frame = last_dma_frame; | ||
691 | itv->yuv_info.new_frame_info[last_dma_frame].update = 0; | ||
692 | itv->yuv_info.yuv_forced_update = 0; | ||
693 | set_bit(IVTV_F_I_WORK_HANDLER_YUV, &itv->i_flags); | ||
694 | work = 1; | ||
695 | } | ||
696 | } | ||
697 | if (work) | ||
698 | queue_work(itv->irq_work_queues, &itv->irq_work_queue); | ||
699 | } | ||
700 | } | ||
701 | |||
702 | #define IVTV_IRQ_DMA (IVTV_IRQ_DMA_READ | IVTV_IRQ_ENC_DMA_COMPLETE | IVTV_IRQ_DMA_ERR | IVTV_IRQ_ENC_START_CAP | IVTV_IRQ_ENC_VBI_CAP | IVTV_IRQ_DEC_DATA_REQ) | ||
703 | |||
704 | irqreturn_t ivtv_irq_handler(int irq, void *dev_id) | ||
705 | { | ||
706 | struct ivtv *itv = (struct ivtv *)dev_id; | ||
707 | u32 combo; | ||
708 | u32 stat; | ||
709 | int i; | ||
710 | u8 vsync_force = 0; | ||
711 | |||
712 | spin_lock(&itv->dma_reg_lock); | ||
713 | /* get contents of irq status register */ | ||
714 | stat = read_reg(IVTV_REG_IRQSTATUS); | ||
715 | |||
716 | combo = ~itv->irqmask & stat; | ||
717 | |||
718 | /* Clear out IRQ */ | ||
719 | if (combo) write_reg(combo, IVTV_REG_IRQSTATUS); | ||
720 | |||
721 | if (0 == combo) { | ||
722 | /* The vsync interrupt is unusual and clears itself. If we | ||
723 | * took too long, we may have missed it. Do some checks | ||
724 | */ | ||
725 | if (~itv->irqmask & IVTV_IRQ_DEC_VSYNC) { | ||
726 | /* vsync is enabled, see if we're in a new field */ | ||
727 | if ((itv->lastVsyncFrame & 1) != (read_reg(0x28c0) & 1)) { | ||
728 | /* New field, looks like we missed it */ | ||
729 | IVTV_DEBUG_YUV("VSync interrupt missed %d\n",read_reg(0x28c0)>>16); | ||
730 | vsync_force = 1; | ||
731 | } | ||
732 | } | ||
733 | |||
734 | if (!vsync_force) { | ||
735 | /* No Vsync expected, wasn't for us */ | ||
736 | spin_unlock(&itv->dma_reg_lock); | ||
737 | return IRQ_NONE; | ||
738 | } | ||
739 | } | ||
740 | |||
741 | /* Exclude interrupts noted below from the output, otherwise the log is flooded with | ||
742 | these messages */ | ||
743 | if (combo & ~0xff6d0400) | ||
744 | IVTV_DEBUG_IRQ("======= valid IRQ bits: 0x%08x ======\n", combo); | ||
745 | |||
746 | if (combo & IVTV_IRQ_DEC_DMA_COMPLETE) { | ||
747 | IVTV_DEBUG_IRQ("DEC DMA COMPLETE\n"); | ||
748 | } | ||
749 | |||
750 | if (combo & IVTV_IRQ_DMA_READ) { | ||
751 | ivtv_irq_dma_read(itv); | ||
752 | } | ||
753 | |||
754 | if (combo & IVTV_IRQ_ENC_DMA_COMPLETE) { | ||
755 | ivtv_irq_enc_dma_complete(itv); | ||
756 | } | ||
757 | |||
758 | if (combo & IVTV_IRQ_DMA_ERR) { | ||
759 | ivtv_irq_dma_err(itv); | ||
760 | } | ||
761 | |||
762 | if (combo & IVTV_IRQ_ENC_START_CAP) { | ||
763 | ivtv_irq_enc_start_cap(itv); | ||
764 | } | ||
765 | |||
766 | if (combo & IVTV_IRQ_ENC_VBI_CAP) { | ||
767 | ivtv_irq_enc_vbi_cap(itv); | ||
768 | } | ||
769 | |||
770 | if (combo & IVTV_IRQ_DEC_VBI_RE_INSERT) { | ||
771 | ivtv_irq_dev_vbi_reinsert(itv); | ||
772 | } | ||
773 | |||
774 | if (combo & IVTV_IRQ_ENC_EOS) { | ||
775 | IVTV_DEBUG_IRQ("ENC EOS\n"); | ||
776 | set_bit(IVTV_F_I_EOS, &itv->i_flags); | ||
777 | wake_up(&itv->cap_w); | ||
778 | } | ||
779 | |||
780 | if (combo & IVTV_IRQ_DEC_DATA_REQ) { | ||
781 | ivtv_irq_dec_data_req(itv); | ||
782 | } | ||
783 | |||
784 | /* Decoder Vertical Sync - We can't rely on 'combo', so check if vsync enabled */ | ||
785 | if (~itv->irqmask & IVTV_IRQ_DEC_VSYNC) { | ||
786 | ivtv_irq_vsync(itv); | ||
787 | } | ||
788 | |||
789 | if (combo & IVTV_IRQ_ENC_VIM_RST) { | ||
790 | IVTV_DEBUG_IRQ("VIM RST\n"); | ||
791 | /*ivtv_vapi(itv, CX2341X_ENC_REFRESH_INPUT, 0); */ | ||
792 | } | ||
793 | |||
794 | if (combo & IVTV_IRQ_DEC_AUD_MODE_CHG) { | ||
795 | IVTV_DEBUG_INFO("Stereo mode changed\n"); | ||
796 | } | ||
797 | |||
798 | if ((combo & IVTV_IRQ_DMA) && !test_bit(IVTV_F_I_DMA, &itv->i_flags)) { | ||
799 | for (i = 0; i < IVTV_MAX_STREAMS; i++) { | ||
800 | int idx = (i + itv->irq_rr_idx++) % IVTV_MAX_STREAMS; | ||
801 | struct ivtv_stream *s = &itv->streams[idx]; | ||
802 | |||
803 | if (!test_and_clear_bit(IVTV_F_S_DMA_PENDING, &s->s_flags)) | ||
804 | continue; | ||
805 | if (s->type >= IVTV_DEC_STREAM_TYPE_MPG) | ||
806 | ivtv_dma_dec_start(s); | ||
807 | else | ||
808 | ivtv_dma_enc_start(s); | ||
809 | break; | ||
810 | } | ||
811 | if (i == IVTV_MAX_STREAMS && test_and_clear_bit(IVTV_F_I_UDMA_PENDING, &itv->i_flags)) { | ||
812 | ivtv_udma_start(itv); | ||
813 | } | ||
814 | } | ||
815 | |||
816 | spin_unlock(&itv->dma_reg_lock); | ||
817 | |||
818 | /* If we've just handled a 'forced' vsync, it's safest to say it | ||
819 | * wasn't ours. Another device may have triggered it at just | ||
820 | * the right time. | ||
821 | */ | ||
822 | return vsync_force ? IRQ_NONE : IRQ_HANDLED; | ||
823 | } | ||
824 | |||
825 | void ivtv_unfinished_dma(unsigned long arg) | ||
826 | { | ||
827 | struct ivtv *itv = (struct ivtv *)arg; | ||
828 | |||
829 | if (!test_bit(IVTV_F_I_DMA, &itv->i_flags)) | ||
830 | return; | ||
831 | IVTV_ERR("DMA TIMEOUT %08x %d\n", read_reg(IVTV_REG_DMASTATUS), itv->cur_dma_stream); | ||
832 | |||
833 | write_reg(read_reg(IVTV_REG_DMASTATUS) & 3, IVTV_REG_DMASTATUS); | ||
834 | clear_bit(IVTV_F_I_UDMA, &itv->i_flags); | ||
835 | clear_bit(IVTV_F_I_DMA, &itv->i_flags); | ||
836 | itv->cur_dma_stream = -1; | ||
837 | wake_up(&itv->dma_waitq); | ||
838 | } | ||
diff --git a/drivers/media/video/ivtv/ivtv-irq.h b/drivers/media/video/ivtv/ivtv-irq.h new file mode 100644 index 000000000000..a43348a30309 --- /dev/null +++ b/drivers/media/video/ivtv/ivtv-irq.h | |||
@@ -0,0 +1,26 @@ | |||
1 | /* | ||
2 | interrupt handling | ||
3 | Copyright (C) 2003-2004 Kevin Thayer <nufan_wfk at yahoo.com> | ||
4 | Copyright (C) 2004 Chris Kennedy <c@groovy.org> | ||
5 | Copyright (C) 2005-2007 Hans Verkuil <hverkuil@xs4all.nl> | ||
6 | |||
7 | This program is free software; you can redistribute it and/or modify | ||
8 | it under the terms of the GNU General Public License as published by | ||
9 | the Free Software Foundation; either version 2 of the License, or | ||
10 | (at your option) any later version. | ||
11 | |||
12 | This program is distributed in the hope that it will be useful, | ||
13 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
15 | GNU General Public License for more details. | ||
16 | |||
17 | You should have received a copy of the GNU General Public License | ||
18 | along with this program; if not, write to the Free Software | ||
19 | Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
20 | */ | ||
21 | |||
22 | irqreturn_t ivtv_irq_handler(int irq, void *dev_id); | ||
23 | |||
24 | void ivtv_irq_work_handler(struct work_struct *work); | ||
25 | void ivtv_dma_stream_dec_prepare(struct ivtv_stream *s, u32 offset, int lock); | ||
26 | void ivtv_unfinished_dma(unsigned long arg); | ||
diff --git a/drivers/media/video/ivtv/ivtv-mailbox.c b/drivers/media/video/ivtv/ivtv-mailbox.c new file mode 100644 index 000000000000..6ae42a3b03cc --- /dev/null +++ b/drivers/media/video/ivtv/ivtv-mailbox.c | |||
@@ -0,0 +1,360 @@ | |||
1 | /* | ||
2 | mailbox functions | ||
3 | Copyright (C) 2003-2004 Kevin Thayer <nufan_wfk at yahoo.com> | ||
4 | Copyright (C) 2004 Chris Kennedy <c@groovy.org> | ||
5 | Copyright (C) 2005-2007 Hans Verkuil <hverkuil@xs4all.nl> | ||
6 | |||
7 | This program is free software; you can redistribute it and/or modify | ||
8 | it under the terms of the GNU General Public License as published by | ||
9 | the Free Software Foundation; either version 2 of the License, or | ||
10 | (at your option) any later version. | ||
11 | |||
12 | This program is distributed in the hope that it will be useful, | ||
13 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
15 | GNU General Public License for more details. | ||
16 | |||
17 | You should have received a copy of the GNU General Public License | ||
18 | along with this program; if not, write to the Free Software | ||
19 | Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
20 | */ | ||
21 | |||
22 | #include <stdarg.h> | ||
23 | |||
24 | #include "ivtv-driver.h" | ||
25 | #include "ivtv-mailbox.h" | ||
26 | |||
27 | /* Firmware mailbox flags*/ | ||
28 | #define IVTV_MBOX_FIRMWARE_DONE 0x00000004 | ||
29 | #define IVTV_MBOX_DRIVER_DONE 0x00000002 | ||
30 | #define IVTV_MBOX_DRIVER_BUSY 0x00000001 | ||
31 | #define IVTV_MBOX_FREE 0x00000000 | ||
32 | |||
33 | /* Firmware mailbox standard timeout */ | ||
34 | #define IVTV_API_STD_TIMEOUT 0x02000000 | ||
35 | |||
36 | #define API_CACHE (1 << 0) /* Allow the command to be stored in the cache */ | ||
37 | #define API_RESULT (1 << 1) /* Allow 1 second for this cmd to end */ | ||
38 | #define API_FAST_RESULT (3 << 1) /* Allow 0.1 second for this cmd to end */ | ||
39 | #define API_DMA (1 << 3) /* DMA mailbox, has special handling */ | ||
40 | #define API_NO_WAIT_MB (1 << 4) /* Command may not wait for a free mailbox */ | ||
41 | #define API_NO_WAIT_RES (1 << 5) /* Command may not wait for the result */ | ||
42 | |||
43 | struct ivtv_api_info { | ||
44 | int flags; /* Flags, see above */ | ||
45 | const char *name; /* The name of the command */ | ||
46 | }; | ||
47 | |||
48 | #define API_ENTRY(x, f) [x] = { (f), #x } | ||
49 | |||
50 | static const struct ivtv_api_info api_info[256] = { | ||
51 | /* MPEG encoder API */ | ||
52 | API_ENTRY(CX2341X_ENC_PING_FW, API_FAST_RESULT), | ||
53 | API_ENTRY(CX2341X_ENC_START_CAPTURE, API_RESULT), | ||
54 | API_ENTRY(CX2341X_ENC_STOP_CAPTURE, API_RESULT), | ||
55 | API_ENTRY(CX2341X_ENC_SET_AUDIO_ID, API_CACHE), | ||
56 | API_ENTRY(CX2341X_ENC_SET_VIDEO_ID, API_CACHE), | ||
57 | API_ENTRY(CX2341X_ENC_SET_PCR_ID, API_CACHE), | ||
58 | API_ENTRY(CX2341X_ENC_SET_FRAME_RATE, API_CACHE), | ||
59 | API_ENTRY(CX2341X_ENC_SET_FRAME_SIZE, API_CACHE), | ||
60 | API_ENTRY(CX2341X_ENC_SET_BIT_RATE, API_CACHE), | ||
61 | API_ENTRY(CX2341X_ENC_SET_GOP_PROPERTIES, API_CACHE), | ||
62 | API_ENTRY(CX2341X_ENC_SET_ASPECT_RATIO, API_CACHE), | ||
63 | API_ENTRY(CX2341X_ENC_SET_DNR_FILTER_MODE, API_CACHE), | ||
64 | API_ENTRY(CX2341X_ENC_SET_DNR_FILTER_PROPS, API_CACHE), | ||
65 | API_ENTRY(CX2341X_ENC_SET_CORING_LEVELS, API_CACHE), | ||
66 | API_ENTRY(CX2341X_ENC_SET_SPATIAL_FILTER_TYPE, API_CACHE), | ||
67 | API_ENTRY(CX2341X_ENC_SET_VBI_LINE, API_RESULT), | ||
68 | API_ENTRY(CX2341X_ENC_SET_STREAM_TYPE, API_CACHE), | ||
69 | API_ENTRY(CX2341X_ENC_SET_OUTPUT_PORT, API_CACHE), | ||
70 | API_ENTRY(CX2341X_ENC_SET_AUDIO_PROPERTIES, API_CACHE), | ||
71 | API_ENTRY(CX2341X_ENC_HALT_FW, API_FAST_RESULT), | ||
72 | API_ENTRY(CX2341X_ENC_GET_VERSION, API_FAST_RESULT), | ||
73 | API_ENTRY(CX2341X_ENC_SET_GOP_CLOSURE, API_CACHE), | ||
74 | API_ENTRY(CX2341X_ENC_GET_SEQ_END, API_RESULT), | ||
75 | API_ENTRY(CX2341X_ENC_SET_PGM_INDEX_INFO, API_FAST_RESULT), | ||
76 | API_ENTRY(CX2341X_ENC_SET_VBI_CONFIG, API_RESULT), | ||
77 | API_ENTRY(CX2341X_ENC_SET_DMA_BLOCK_SIZE, API_CACHE), | ||
78 | API_ENTRY(CX2341X_ENC_GET_PREV_DMA_INFO_MB_10, API_FAST_RESULT), | ||
79 | API_ENTRY(CX2341X_ENC_GET_PREV_DMA_INFO_MB_9, API_FAST_RESULT), | ||
80 | API_ENTRY(CX2341X_ENC_SCHED_DMA_TO_HOST, API_DMA), | ||
81 | API_ENTRY(CX2341X_ENC_INITIALIZE_INPUT, API_RESULT), | ||
82 | API_ENTRY(CX2341X_ENC_SET_FRAME_DROP_RATE, API_CACHE), | ||
83 | API_ENTRY(CX2341X_ENC_PAUSE_ENCODER, API_RESULT), | ||
84 | API_ENTRY(CX2341X_ENC_REFRESH_INPUT, API_NO_WAIT_MB), | ||
85 | API_ENTRY(CX2341X_ENC_SET_COPYRIGHT, API_CACHE), | ||
86 | API_ENTRY(CX2341X_ENC_SET_EVENT_NOTIFICATION, API_RESULT), | ||
87 | API_ENTRY(CX2341X_ENC_SET_NUM_VSYNC_LINES, API_CACHE), | ||
88 | API_ENTRY(CX2341X_ENC_SET_PLACEHOLDER, API_CACHE), | ||
89 | API_ENTRY(CX2341X_ENC_MUTE_VIDEO, API_RESULT), | ||
90 | API_ENTRY(CX2341X_ENC_MUTE_AUDIO, API_RESULT), | ||
91 | API_ENTRY(CX2341X_ENC_SET_VERT_CROP_LINE, API_FAST_RESULT), | ||
92 | API_ENTRY(CX2341X_ENC_MISC, API_FAST_RESULT), | ||
93 | /* Obsolete PULLDOWN API command */ | ||
94 | API_ENTRY(0xb1, API_CACHE), | ||
95 | |||
96 | /* MPEG decoder API */ | ||
97 | API_ENTRY(CX2341X_DEC_PING_FW, API_FAST_RESULT), | ||
98 | API_ENTRY(CX2341X_DEC_START_PLAYBACK, API_RESULT), | ||
99 | API_ENTRY(CX2341X_DEC_STOP_PLAYBACK, API_RESULT), | ||
100 | API_ENTRY(CX2341X_DEC_SET_PLAYBACK_SPEED, API_RESULT), | ||
101 | API_ENTRY(CX2341X_DEC_STEP_VIDEO, API_RESULT), | ||
102 | API_ENTRY(CX2341X_DEC_SET_DMA_BLOCK_SIZE, API_CACHE), | ||
103 | API_ENTRY(CX2341X_DEC_GET_XFER_INFO, API_FAST_RESULT), | ||
104 | API_ENTRY(CX2341X_DEC_GET_DMA_STATUS, API_FAST_RESULT), | ||
105 | API_ENTRY(CX2341X_DEC_SCHED_DMA_FROM_HOST, API_DMA), | ||
106 | API_ENTRY(CX2341X_DEC_PAUSE_PLAYBACK, API_RESULT), | ||
107 | API_ENTRY(CX2341X_DEC_HALT_FW, API_FAST_RESULT), | ||
108 | API_ENTRY(CX2341X_DEC_SET_STANDARD, API_CACHE), | ||
109 | API_ENTRY(CX2341X_DEC_GET_VERSION, API_FAST_RESULT), | ||
110 | API_ENTRY(CX2341X_DEC_SET_STREAM_INPUT, API_CACHE), | ||
111 | API_ENTRY(CX2341X_DEC_GET_TIMING_INFO, API_RESULT /*| API_NO_WAIT_RES*/), | ||
112 | API_ENTRY(CX2341X_DEC_SET_AUDIO_MODE, API_CACHE), | ||
113 | API_ENTRY(CX2341X_DEC_SET_EVENT_NOTIFICATION, API_RESULT), | ||
114 | API_ENTRY(CX2341X_DEC_SET_DISPLAY_BUFFERS, API_CACHE), | ||
115 | API_ENTRY(CX2341X_DEC_EXTRACT_VBI, API_RESULT), | ||
116 | API_ENTRY(CX2341X_DEC_SET_DECODER_SOURCE, API_FAST_RESULT), | ||
117 | API_ENTRY(CX2341X_DEC_SET_PREBUFFERING, API_CACHE), | ||
118 | |||
119 | /* OSD API */ | ||
120 | API_ENTRY(CX2341X_OSD_GET_FRAMEBUFFER, API_FAST_RESULT), | ||
121 | API_ENTRY(CX2341X_OSD_GET_PIXEL_FORMAT, API_FAST_RESULT), | ||
122 | API_ENTRY(CX2341X_OSD_SET_PIXEL_FORMAT, API_CACHE), | ||
123 | API_ENTRY(CX2341X_OSD_GET_STATE, API_FAST_RESULT), | ||
124 | API_ENTRY(CX2341X_OSD_SET_STATE, API_CACHE), | ||
125 | API_ENTRY(CX2341X_OSD_GET_OSD_COORDS, API_FAST_RESULT), | ||
126 | API_ENTRY(CX2341X_OSD_SET_OSD_COORDS, API_CACHE), | ||
127 | API_ENTRY(CX2341X_OSD_GET_SCREEN_COORDS, API_FAST_RESULT), | ||
128 | API_ENTRY(CX2341X_OSD_SET_SCREEN_COORDS, API_CACHE), | ||
129 | API_ENTRY(CX2341X_OSD_GET_GLOBAL_ALPHA, API_FAST_RESULT), | ||
130 | API_ENTRY(CX2341X_OSD_SET_GLOBAL_ALPHA, API_CACHE), | ||
131 | API_ENTRY(CX2341X_OSD_SET_BLEND_COORDS, API_CACHE), | ||
132 | API_ENTRY(CX2341X_OSD_GET_FLICKER_STATE, API_FAST_RESULT), | ||
133 | API_ENTRY(CX2341X_OSD_SET_FLICKER_STATE, API_CACHE), | ||
134 | API_ENTRY(CX2341X_OSD_BLT_COPY, API_RESULT), | ||
135 | API_ENTRY(CX2341X_OSD_BLT_FILL, API_RESULT), | ||
136 | API_ENTRY(CX2341X_OSD_BLT_TEXT, API_RESULT), | ||
137 | API_ENTRY(CX2341X_OSD_SET_FRAMEBUFFER_WINDOW, API_CACHE), | ||
138 | API_ENTRY(CX2341X_OSD_SET_CHROMA_KEY, API_CACHE), | ||
139 | API_ENTRY(CX2341X_OSD_GET_ALPHA_CONTENT_INDEX, API_FAST_RESULT), | ||
140 | API_ENTRY(CX2341X_OSD_SET_ALPHA_CONTENT_INDEX, API_CACHE) | ||
141 | }; | ||
142 | |||
143 | static int try_mailbox(struct ivtv *itv, struct ivtv_mailbox_data *mbdata, int mb) | ||
144 | { | ||
145 | u32 flags = readl(&mbdata->mbox[mb].flags); | ||
146 | int is_free = flags == IVTV_MBOX_FREE || (flags & IVTV_MBOX_FIRMWARE_DONE); | ||
147 | |||
148 | /* if the mailbox is free, then try to claim it */ | ||
149 | if (is_free && !test_and_set_bit(mb, &mbdata->busy)) { | ||
150 | write_sync(IVTV_MBOX_DRIVER_BUSY, &mbdata->mbox[mb].flags); | ||
151 | return 1; | ||
152 | } | ||
153 | return 0; | ||
154 | } | ||
155 | |||
156 | /* Try to find a free mailbox. Note mailbox 0 is reserved for DMA and so is not | ||
157 | attempted here. */ | ||
158 | static int get_mailbox(struct ivtv *itv, struct ivtv_mailbox_data *mbdata, int flags) | ||
159 | { | ||
160 | unsigned long then = jiffies; | ||
161 | int i, mb; | ||
162 | int max_mbox = mbdata->max_mbox; | ||
163 | int retries = 100; | ||
164 | |||
165 | /* All slow commands use the same mailbox, serializing them and also | ||
166 | leaving the other mailbox free for simple fast commands. */ | ||
167 | if ((flags & API_FAST_RESULT) == API_RESULT) | ||
168 | max_mbox = 1; | ||
169 | |||
170 | /* find free non-DMA mailbox */ | ||
171 | for (i = 0; i < retries; i++) { | ||
172 | for (mb = 1; mb <= max_mbox; mb++) | ||
173 | if (try_mailbox(itv, mbdata, mb)) | ||
174 | return mb; | ||
175 | |||
176 | /* Sleep before a retry, if not atomic */ | ||
177 | if (!(flags & API_NO_WAIT_MB)) { | ||
178 | if (jiffies - then > retries * HZ / 100) | ||
179 | break; | ||
180 | ivtv_sleep_timeout(HZ / 100, 0); | ||
181 | } | ||
182 | } | ||
183 | return -ENODEV; | ||
184 | } | ||
185 | |||
186 | static void write_mailbox(volatile struct ivtv_mailbox __iomem *mbox, int cmd, int args, u32 data[]) | ||
187 | { | ||
188 | int i; | ||
189 | |||
190 | write_sync(cmd, &mbox->cmd); | ||
191 | write_sync(IVTV_API_STD_TIMEOUT, &mbox->timeout); | ||
192 | |||
193 | for (i = 0; i < CX2341X_MBOX_MAX_DATA; i++) | ||
194 | write_sync(data[i], &mbox->data[i]); | ||
195 | |||
196 | write_sync(IVTV_MBOX_DRIVER_DONE | IVTV_MBOX_DRIVER_BUSY, &mbox->flags); | ||
197 | } | ||
198 | |||
199 | static void clear_all_mailboxes(struct ivtv *itv, struct ivtv_mailbox_data *mbdata) | ||
200 | { | ||
201 | int i; | ||
202 | |||
203 | for (i = 0; i <= mbdata->max_mbox; i++) { | ||
204 | IVTV_DEBUG_WARN("Clearing mailbox %d: cmd 0x%08x flags 0x%08x\n", | ||
205 | i, readl(&mbdata->mbox[i].cmd), readl(&mbdata->mbox[i].flags)); | ||
206 | write_sync(0, &mbdata->mbox[i].flags); | ||
207 | clear_bit(i, &mbdata->busy); | ||
208 | } | ||
209 | } | ||
210 | |||
211 | static int ivtv_api_call(struct ivtv *itv, int cmd, int args, u32 data[]) | ||
212 | { | ||
213 | struct ivtv_mailbox_data *mbdata = (cmd >= 128) ? &itv->enc_mbox : &itv->dec_mbox; | ||
214 | volatile struct ivtv_mailbox __iomem *mbox; | ||
215 | int api_timeout = HZ; | ||
216 | int flags, mb, i; | ||
217 | unsigned long then; | ||
218 | |||
219 | /* sanity checks */ | ||
220 | if (NULL == mbdata) { | ||
221 | IVTV_ERR("No mailbox allocated\n"); | ||
222 | return -ENODEV; | ||
223 | } | ||
224 | if (args < 0 || args > CX2341X_MBOX_MAX_DATA || | ||
225 | cmd < 0 || cmd > 255 || api_info[cmd].name == NULL) { | ||
226 | IVTV_ERR("Invalid API call: cmd = 0x%02x, args = %d\n", cmd, args); | ||
227 | return -EINVAL; | ||
228 | } | ||
229 | |||
230 | IVTV_DEBUG_API("API Call: %s\n", api_info[cmd].name); | ||
231 | |||
232 | /* clear possibly uninitialized part of data array */ | ||
233 | for (i = args; i < CX2341X_MBOX_MAX_DATA; i++) | ||
234 | data[i] = 0; | ||
235 | |||
236 | /* If this command was issued within the last 30 minutes and with identical | ||
237 | data, then just return 0 as there is no need to issue this command again. | ||
238 | Just an optimization to prevent unnecessary use of mailboxes. */ | ||
239 | if (itv->api_cache[cmd].last_jiffies && | ||
240 | jiffies - itv->api_cache[cmd].last_jiffies < HZ * 1800 && | ||
241 | !memcmp(data, itv->api_cache[cmd].data, sizeof(itv->api_cache[cmd].data))) { | ||
242 | itv->api_cache[cmd].last_jiffies = jiffies; | ||
243 | return 0; | ||
244 | } | ||
245 | |||
246 | flags = api_info[cmd].flags; | ||
247 | |||
248 | if (flags & API_DMA) { | ||
249 | for (i = 0; i < 100; i++) { | ||
250 | mb = i % (mbdata->max_mbox + 1); | ||
251 | if (try_mailbox(itv, mbdata, mb)) { | ||
252 | write_mailbox(&mbdata->mbox[mb], cmd, args, data); | ||
253 | clear_bit(mb, &mbdata->busy); | ||
254 | return 0; | ||
255 | } | ||
256 | IVTV_DEBUG_WARN("%s: mailbox %d not free %08x\n", | ||
257 | api_info[cmd].name, mb, readl(&mbdata->mbox[mb].flags)); | ||
258 | } | ||
259 | IVTV_WARN("Could not find free DMA mailbox for %s\n", api_info[cmd].name); | ||
260 | clear_all_mailboxes(itv, mbdata); | ||
261 | return -EBUSY; | ||
262 | } | ||
263 | |||
264 | if ((flags & API_FAST_RESULT) == API_FAST_RESULT) | ||
265 | api_timeout = HZ / 10; | ||
266 | |||
267 | mb = get_mailbox(itv, mbdata, flags); | ||
268 | if (mb < 0) { | ||
269 | IVTV_DEBUG_WARN("No free mailbox found (%s)\n", api_info[cmd].name); | ||
270 | clear_all_mailboxes(itv, mbdata); | ||
271 | return -EBUSY; | ||
272 | } | ||
273 | mbox = &mbdata->mbox[mb]; | ||
274 | write_mailbox(mbox, cmd, args, data); | ||
275 | if (flags & API_CACHE) { | ||
276 | memcpy(itv->api_cache[cmd].data, data, sizeof(itv->api_cache[cmd].data)); | ||
277 | itv->api_cache[cmd].last_jiffies = jiffies; | ||
278 | } | ||
279 | if ((flags & API_RESULT) == 0) { | ||
280 | clear_bit(mb, &mbdata->busy); | ||
281 | return 0; | ||
282 | } | ||
283 | |||
284 | /* Get results */ | ||
285 | then = jiffies; | ||
286 | |||
287 | while (!(readl(&mbox->flags) & IVTV_MBOX_FIRMWARE_DONE)) { | ||
288 | if (jiffies - then > api_timeout) { | ||
289 | IVTV_DEBUG_WARN("Could not get result (%s)\n", api_info[cmd].name); | ||
290 | /* reset the mailbox, but it is likely too late already */ | ||
291 | write_sync(0, &mbox->flags); | ||
292 | clear_bit(mb, &mbdata->busy); | ||
293 | return -EIO; | ||
294 | } | ||
295 | if (flags & API_NO_WAIT_RES) | ||
296 | mdelay(1); | ||
297 | else | ||
298 | ivtv_sleep_timeout(HZ / 100, 0); | ||
299 | } | ||
300 | if (jiffies - then > HZ / 10) | ||
301 | IVTV_DEBUG_WARN("%s took %lu jiffies (%d per HZ)\n", | ||
302 | api_info[cmd].name, jiffies - then, HZ); | ||
303 | |||
304 | for (i = 0; i < CX2341X_MBOX_MAX_DATA; i++) | ||
305 | data[i] = readl(&mbox->data[i]); | ||
306 | write_sync(0, &mbox->flags); | ||
307 | clear_bit(mb, &mbdata->busy); | ||
308 | return 0; | ||
309 | } | ||
310 | |||
311 | int ivtv_api(struct ivtv *itv, int cmd, int args, u32 data[]) | ||
312 | { | ||
313 | int res = ivtv_api_call(itv, cmd, args, data); | ||
314 | |||
315 | /* Allow a single retry, probably already too late though. | ||
316 | If there is no free mailbox then that is usually an indication | ||
317 | of a more serious problem. */ | ||
318 | return (res == -EBUSY) ? ivtv_api_call(itv, cmd, args, data) : res; | ||
319 | } | ||
320 | |||
321 | int ivtv_api_func(void *priv, int cmd, int in, int out, u32 data[CX2341X_MBOX_MAX_DATA]) | ||
322 | { | ||
323 | return ivtv_api(priv, cmd, in, data); | ||
324 | } | ||
325 | |||
326 | int ivtv_vapi_result(struct ivtv *itv, u32 data[CX2341X_MBOX_MAX_DATA], int cmd, int args, ...) | ||
327 | { | ||
328 | va_list ap; | ||
329 | int i; | ||
330 | |||
331 | va_start(ap, args); | ||
332 | for (i = 0; i < args; i++) { | ||
333 | data[i] = va_arg(ap, u32); | ||
334 | } | ||
335 | va_end(ap); | ||
336 | return ivtv_api(itv, cmd, args, data); | ||
337 | } | ||
338 | |||
339 | int ivtv_vapi(struct ivtv *itv, int cmd, int args, ...) | ||
340 | { | ||
341 | u32 data[CX2341X_MBOX_MAX_DATA]; | ||
342 | va_list ap; | ||
343 | int i; | ||
344 | |||
345 | va_start(ap, args); | ||
346 | for (i = 0; i < args; i++) { | ||
347 | data[i] = va_arg(ap, u32); | ||
348 | } | ||
349 | va_end(ap); | ||
350 | return ivtv_api(itv, cmd, args, data); | ||
351 | } | ||
352 | |||
353 | /* This one is for stuff that can't sleep.. irq handlers, etc.. */ | ||
354 | void ivtv_api_get_data(struct ivtv_mailbox_data *mbdata, int mb, u32 data[]) | ||
355 | { | ||
356 | int i; | ||
357 | |||
358 | for (i = 0; i < CX2341X_MBOX_MAX_DATA; i++) | ||
359 | data[i] = readl(&mbdata->mbox[mb].data[i]); | ||
360 | } | ||
diff --git a/drivers/media/video/ivtv/ivtv-mailbox.h b/drivers/media/video/ivtv/ivtv-mailbox.h new file mode 100644 index 000000000000..79b8aec14370 --- /dev/null +++ b/drivers/media/video/ivtv/ivtv-mailbox.h | |||
@@ -0,0 +1,25 @@ | |||
1 | /* | ||
2 | mailbox functions | ||
3 | Copyright (C) 2003-2004 Kevin Thayer <nufan_wfk at yahoo.com> | ||
4 | Copyright (C) 2005-2007 Hans Verkuil <hverkuil@xs4all.nl> | ||
5 | |||
6 | This program is free software; you can redistribute it and/or modify | ||
7 | it under the terms of the GNU General Public License as published by | ||
8 | the Free Software Foundation; either version 2 of the License, or | ||
9 | (at your option) any later version. | ||
10 | |||
11 | This program is distributed in the hope that it will be useful, | ||
12 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
14 | GNU General Public License for more details. | ||
15 | |||
16 | You should have received a copy of the GNU General Public License | ||
17 | along with this program; if not, write to the Free Software | ||
18 | Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
19 | */ | ||
20 | |||
21 | void ivtv_api_get_data(struct ivtv_mailbox_data *mbox, int mb, u32 data[]); | ||
22 | int ivtv_api(struct ivtv *itv, int cmd, int args, u32 data[]); | ||
23 | int ivtv_vapi_result(struct ivtv *itv, u32 data[CX2341X_MBOX_MAX_DATA], int cmd, int args, ...); | ||
24 | int ivtv_vapi(struct ivtv *itv, int cmd, int args, ...); | ||
25 | int ivtv_api_func(void *priv, int cmd, int in, int out, u32 data[CX2341X_MBOX_MAX_DATA]); | ||
diff --git a/drivers/media/video/ivtv/ivtv-queue.c b/drivers/media/video/ivtv/ivtv-queue.c new file mode 100644 index 000000000000..ccfcef1ad91a --- /dev/null +++ b/drivers/media/video/ivtv/ivtv-queue.c | |||
@@ -0,0 +1,262 @@ | |||
1 | /* | ||
2 | buffer queues. | ||
3 | Copyright (C) 2003-2004 Kevin Thayer <nufan_wfk at yahoo.com> | ||
4 | Copyright (C) 2004 Chris Kennedy <c@groovy.org> | ||
5 | Copyright (C) 2005-2007 Hans Verkuil <hverkuil@xs4all.nl> | ||
6 | |||
7 | This program is free software; you can redistribute it and/or modify | ||
8 | it under the terms of the GNU General Public License as published by | ||
9 | the Free Software Foundation; either version 2 of the License, or | ||
10 | (at your option) any later version. | ||
11 | |||
12 | This program is distributed in the hope that it will be useful, | ||
13 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
15 | GNU General Public License for more details. | ||
16 | |||
17 | You should have received a copy of the GNU General Public License | ||
18 | along with this program; if not, write to the Free Software | ||
19 | Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
20 | */ | ||
21 | |||
22 | #include "ivtv-driver.h" | ||
23 | #include "ivtv-streams.h" | ||
24 | #include "ivtv-queue.h" | ||
25 | #include "ivtv-mailbox.h" | ||
26 | |||
27 | int ivtv_buf_copy_from_user(struct ivtv_stream *s, struct ivtv_buffer *buf, const char __user *src, int copybytes) | ||
28 | { | ||
29 | if (s->buf_size - buf->bytesused < copybytes) | ||
30 | copybytes = s->buf_size - buf->bytesused; | ||
31 | if (copy_from_user(buf->buf + buf->bytesused, src, copybytes)) { | ||
32 | return -EFAULT; | ||
33 | } | ||
34 | buf->bytesused += copybytes; | ||
35 | return copybytes; | ||
36 | } | ||
37 | |||
38 | void ivtv_buf_swap(struct ivtv_buffer *buf) | ||
39 | { | ||
40 | int i; | ||
41 | |||
42 | for (i = 0; i < buf->bytesused; i += 4) | ||
43 | swab32s((u32 *)(buf->buf + i)); | ||
44 | } | ||
45 | |||
46 | void ivtv_queue_init(struct ivtv_queue *q) | ||
47 | { | ||
48 | INIT_LIST_HEAD(&q->list); | ||
49 | q->buffers = 0; | ||
50 | q->length = 0; | ||
51 | q->bytesused = 0; | ||
52 | } | ||
53 | |||
54 | void ivtv_enqueue(struct ivtv_stream *s, struct ivtv_buffer *buf, struct ivtv_queue *q) | ||
55 | { | ||
56 | unsigned long flags = 0; | ||
57 | |||
58 | /* clear the buffer if it is going to be enqueued to the free queue */ | ||
59 | if (q == &s->q_free) { | ||
60 | buf->bytesused = 0; | ||
61 | buf->readpos = 0; | ||
62 | buf->b_flags = 0; | ||
63 | } | ||
64 | spin_lock_irqsave(&s->qlock, flags); | ||
65 | list_add_tail(&buf->list, &q->list); | ||
66 | q->buffers++; | ||
67 | q->length += s->buf_size; | ||
68 | q->bytesused += buf->bytesused - buf->readpos; | ||
69 | spin_unlock_irqrestore(&s->qlock, flags); | ||
70 | } | ||
71 | |||
72 | struct ivtv_buffer *ivtv_dequeue(struct ivtv_stream *s, struct ivtv_queue *q) | ||
73 | { | ||
74 | struct ivtv_buffer *buf = NULL; | ||
75 | unsigned long flags = 0; | ||
76 | |||
77 | spin_lock_irqsave(&s->qlock, flags); | ||
78 | if (!list_empty(&q->list)) { | ||
79 | buf = list_entry(q->list.next, struct ivtv_buffer, list); | ||
80 | list_del_init(q->list.next); | ||
81 | q->buffers--; | ||
82 | q->length -= s->buf_size; | ||
83 | q->bytesused -= buf->bytesused - buf->readpos; | ||
84 | } | ||
85 | spin_unlock_irqrestore(&s->qlock, flags); | ||
86 | return buf; | ||
87 | } | ||
88 | |||
89 | static void ivtv_queue_move_buf(struct ivtv_stream *s, struct ivtv_queue *from, | ||
90 | struct ivtv_queue *to, int clear, int full) | ||
91 | { | ||
92 | struct ivtv_buffer *buf = list_entry(from->list.next, struct ivtv_buffer, list); | ||
93 | |||
94 | list_move_tail(from->list.next, &to->list); | ||
95 | from->buffers--; | ||
96 | from->length -= s->buf_size; | ||
97 | from->bytesused -= buf->bytesused - buf->readpos; | ||
98 | /* special handling for q_free */ | ||
99 | if (clear) | ||
100 | buf->bytesused = buf->readpos = buf->b_flags = 0; | ||
101 | else if (full) { | ||
102 | /* special handling for stolen buffers, assume | ||
103 | all bytes are used. */ | ||
104 | buf->bytesused = s->buf_size; | ||
105 | buf->readpos = buf->b_flags = 0; | ||
106 | } | ||
107 | to->buffers++; | ||
108 | to->length += s->buf_size; | ||
109 | to->bytesused += buf->bytesused - buf->readpos; | ||
110 | } | ||
111 | |||
112 | /* Move 'needed_bytes' worth of buffers from queue 'from' into queue 'to'. | ||
113 | If 'needed_bytes' == 0, then move all buffers from 'from' into 'to'. | ||
114 | If 'steal' != NULL, then buffers may also taken from that queue if | ||
115 | needed. | ||
116 | |||
117 | The buffer is automatically cleared if it goes to the free queue. It is | ||
118 | also cleared if buffers need to be taken from the 'steal' queue and | ||
119 | the 'from' queue is the free queue. | ||
120 | |||
121 | When 'from' is q_free, then needed_bytes is compared to the total | ||
122 | available buffer length, otherwise needed_bytes is compared to the | ||
123 | bytesused value. For the 'steal' queue the total available buffer | ||
124 | length is always used. | ||
125 | |||
126 | -ENOMEM is returned if the buffers could not be obtained, 0 if all | ||
127 | buffers where obtained from the 'from' list and if non-zero then | ||
128 | the number of stolen buffers is returned. */ | ||
129 | int ivtv_queue_move(struct ivtv_stream *s, struct ivtv_queue *from, struct ivtv_queue *steal, | ||
130 | struct ivtv_queue *to, int needed_bytes) | ||
131 | { | ||
132 | unsigned long flags; | ||
133 | int rc = 0; | ||
134 | int from_free = from == &s->q_free; | ||
135 | int to_free = to == &s->q_free; | ||
136 | int bytes_available; | ||
137 | |||
138 | spin_lock_irqsave(&s->qlock, flags); | ||
139 | if (needed_bytes == 0) { | ||
140 | from_free = 1; | ||
141 | needed_bytes = from->length; | ||
142 | } | ||
143 | |||
144 | bytes_available = from_free ? from->length : from->bytesused; | ||
145 | bytes_available += steal ? steal->length : 0; | ||
146 | |||
147 | if (bytes_available < needed_bytes) { | ||
148 | spin_unlock_irqrestore(&s->qlock, flags); | ||
149 | return -ENOMEM; | ||
150 | } | ||
151 | if (from_free) { | ||
152 | u32 old_length = to->length; | ||
153 | |||
154 | while (to->length - old_length < needed_bytes) { | ||
155 | if (list_empty(&from->list)) | ||
156 | from = steal; | ||
157 | if (from == steal) | ||
158 | rc++; /* keep track of 'stolen' buffers */ | ||
159 | ivtv_queue_move_buf(s, from, to, 1, 0); | ||
160 | } | ||
161 | } | ||
162 | else { | ||
163 | u32 old_bytesused = to->bytesused; | ||
164 | |||
165 | while (to->bytesused - old_bytesused < needed_bytes) { | ||
166 | if (list_empty(&from->list)) | ||
167 | from = steal; | ||
168 | if (from == steal) | ||
169 | rc++; /* keep track of 'stolen' buffers */ | ||
170 | ivtv_queue_move_buf(s, from, to, to_free, rc); | ||
171 | } | ||
172 | } | ||
173 | spin_unlock_irqrestore(&s->qlock, flags); | ||
174 | return rc; | ||
175 | } | ||
176 | |||
177 | void ivtv_flush_queues(struct ivtv_stream *s) | ||
178 | { | ||
179 | ivtv_queue_move(s, &s->q_io, NULL, &s->q_free, 0); | ||
180 | ivtv_queue_move(s, &s->q_full, NULL, &s->q_free, 0); | ||
181 | ivtv_queue_move(s, &s->q_dma, NULL, &s->q_free, 0); | ||
182 | ivtv_queue_move(s, &s->q_predma, NULL, &s->q_free, 0); | ||
183 | } | ||
184 | |||
185 | int ivtv_stream_alloc(struct ivtv_stream *s) | ||
186 | { | ||
187 | struct ivtv *itv = s->itv; | ||
188 | int SGsize = sizeof(struct ivtv_SG_element) * s->buffers; | ||
189 | int i; | ||
190 | |||
191 | if (s->buffers == 0) | ||
192 | return 0; | ||
193 | |||
194 | IVTV_DEBUG_INFO("Allocate %s%s stream: %d x %d buffers (%dkB total)\n", | ||
195 | s->dma != PCI_DMA_NONE ? "DMA " : "", | ||
196 | s->name, s->buffers, s->buf_size, s->buffers * s->buf_size / 1024); | ||
197 | |||
198 | /* Allocate DMA SG Arrays */ | ||
199 | if (s->dma != PCI_DMA_NONE) { | ||
200 | s->SGarray = (struct ivtv_SG_element *)kzalloc(SGsize, GFP_KERNEL); | ||
201 | if (s->SGarray == NULL) { | ||
202 | IVTV_ERR("Could not allocate SGarray for %s stream\n", s->name); | ||
203 | return -ENOMEM; | ||
204 | } | ||
205 | s->SG_length = 0; | ||
206 | s->SG_handle = pci_map_single(itv->dev, s->SGarray, SGsize, s->dma); | ||
207 | ivtv_stream_sync_for_cpu(s); | ||
208 | } | ||
209 | |||
210 | /* allocate stream buffers. Initially all buffers are in q_free. */ | ||
211 | for (i = 0; i < s->buffers; i++) { | ||
212 | struct ivtv_buffer *buf = kzalloc(sizeof(struct ivtv_buffer), GFP_KERNEL); | ||
213 | |||
214 | if (buf == NULL) | ||
215 | break; | ||
216 | buf->buf = kmalloc(s->buf_size + 256, GFP_KERNEL); | ||
217 | if (buf->buf == NULL) { | ||
218 | kfree(buf); | ||
219 | break; | ||
220 | } | ||
221 | INIT_LIST_HEAD(&buf->list); | ||
222 | if (s->dma != PCI_DMA_NONE) { | ||
223 | buf->dma_handle = pci_map_single(s->itv->dev, | ||
224 | buf->buf, s->buf_size + 256, s->dma); | ||
225 | ivtv_buf_sync_for_cpu(s, buf); | ||
226 | } | ||
227 | ivtv_enqueue(s, buf, &s->q_free); | ||
228 | } | ||
229 | if (i == s->buffers) | ||
230 | return 0; | ||
231 | IVTV_ERR("Couldn't allocate buffers for %s stream\n", s->name); | ||
232 | ivtv_stream_free(s); | ||
233 | return -ENOMEM; | ||
234 | } | ||
235 | |||
236 | void ivtv_stream_free(struct ivtv_stream *s) | ||
237 | { | ||
238 | struct ivtv_buffer *buf; | ||
239 | |||
240 | /* move all buffers to q_free */ | ||
241 | ivtv_flush_queues(s); | ||
242 | |||
243 | /* empty q_free */ | ||
244 | while ((buf = ivtv_dequeue(s, &s->q_free))) { | ||
245 | if (s->dma != PCI_DMA_NONE) | ||
246 | pci_unmap_single(s->itv->dev, buf->dma_handle, | ||
247 | s->buf_size + 256, s->dma); | ||
248 | kfree(buf->buf); | ||
249 | kfree(buf); | ||
250 | } | ||
251 | |||
252 | /* Free SG Array/Lists */ | ||
253 | if (s->SGarray != NULL) { | ||
254 | if (s->SG_handle != IVTV_DMA_UNMAPPED) { | ||
255 | pci_unmap_single(s->itv->dev, s->SG_handle, | ||
256 | sizeof(struct ivtv_SG_element) * s->buffers, PCI_DMA_TODEVICE); | ||
257 | s->SG_handle = IVTV_DMA_UNMAPPED; | ||
258 | } | ||
259 | s->SGarray = NULL; | ||
260 | s->SG_length = 0; | ||
261 | } | ||
262 | } | ||
diff --git a/drivers/media/video/ivtv/ivtv-queue.h b/drivers/media/video/ivtv/ivtv-queue.h new file mode 100644 index 000000000000..903edd4b4381 --- /dev/null +++ b/drivers/media/video/ivtv/ivtv-queue.h | |||
@@ -0,0 +1,64 @@ | |||
1 | /* | ||
2 | buffer queues. | ||
3 | Copyright (C) 2003-2004 Kevin Thayer <nufan_wfk at yahoo.com> | ||
4 | Copyright (C) 2004 Chris Kennedy <c@groovy.org> | ||
5 | Copyright (C) 2005-2007 Hans Verkuil <hverkuil@xs4all.nl> | ||
6 | |||
7 | This program is free software; you can redistribute it and/or modify | ||
8 | it under the terms of the GNU General Public License as published by | ||
9 | the Free Software Foundation; either version 2 of the License, or | ||
10 | (at your option) any later version. | ||
11 | |||
12 | This program is distributed in the hope that it will be useful, | ||
13 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
15 | GNU General Public License for more details. | ||
16 | |||
17 | You should have received a copy of the GNU General Public License | ||
18 | along with this program; if not, write to the Free Software | ||
19 | Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
20 | */ | ||
21 | |||
22 | #define IVTV_DMA_UNMAPPED ((u32) -1) | ||
23 | |||
24 | /* ivtv_buffer utility functions */ | ||
25 | static inline void ivtv_buf_sync_for_cpu(struct ivtv_stream *s, struct ivtv_buffer *buf) | ||
26 | { | ||
27 | if (s->dma != PCI_DMA_NONE) | ||
28 | pci_dma_sync_single_for_cpu(s->itv->dev, buf->dma_handle, | ||
29 | s->buf_size + 256, s->dma); | ||
30 | } | ||
31 | |||
32 | static inline void ivtv_buf_sync_for_device(struct ivtv_stream *s, struct ivtv_buffer *buf) | ||
33 | { | ||
34 | if (s->dma != PCI_DMA_NONE) | ||
35 | pci_dma_sync_single_for_device(s->itv->dev, buf->dma_handle, | ||
36 | s->buf_size + 256, s->dma); | ||
37 | } | ||
38 | |||
39 | int ivtv_buf_copy_from_user(struct ivtv_stream *s, struct ivtv_buffer *buf, const char __user *src, int copybytes); | ||
40 | void ivtv_buf_swap(struct ivtv_buffer *buf); | ||
41 | |||
42 | /* ivtv_queue utility functions */ | ||
43 | void ivtv_queue_init(struct ivtv_queue *q); | ||
44 | void ivtv_enqueue(struct ivtv_stream *s, struct ivtv_buffer *buf, struct ivtv_queue *q); | ||
45 | struct ivtv_buffer *ivtv_dequeue(struct ivtv_stream *s, struct ivtv_queue *q); | ||
46 | int ivtv_queue_move(struct ivtv_stream *s, struct ivtv_queue *from, struct ivtv_queue *steal, | ||
47 | struct ivtv_queue *to, int needed_bytes); | ||
48 | void ivtv_flush_queues(struct ivtv_stream *s); | ||
49 | |||
50 | /* ivtv_stream utility functions */ | ||
51 | int ivtv_stream_alloc(struct ivtv_stream *s); | ||
52 | void ivtv_stream_free(struct ivtv_stream *s); | ||
53 | |||
54 | static inline void ivtv_stream_sync_for_cpu(struct ivtv_stream *s) | ||
55 | { | ||
56 | pci_dma_sync_single_for_cpu(s->itv->dev, s->SG_handle, | ||
57 | sizeof(struct ivtv_SG_element) * s->buffers, PCI_DMA_TODEVICE); | ||
58 | } | ||
59 | |||
60 | static inline void ivtv_stream_sync_for_device(struct ivtv_stream *s) | ||
61 | { | ||
62 | pci_dma_sync_single_for_device(s->itv->dev, s->SG_handle, | ||
63 | sizeof(struct ivtv_SG_element) * s->buffers, PCI_DMA_TODEVICE); | ||
64 | } | ||
diff --git a/drivers/media/video/ivtv/ivtv-streams.c b/drivers/media/video/ivtv/ivtv-streams.c new file mode 100644 index 000000000000..01a41a844a30 --- /dev/null +++ b/drivers/media/video/ivtv/ivtv-streams.c | |||
@@ -0,0 +1,977 @@ | |||
1 | /* | ||
2 | init/start/stop/exit stream functions | ||
3 | Copyright (C) 2003-2004 Kevin Thayer <nufan_wfk at yahoo.com> | ||
4 | Copyright (C) 2004 Chris Kennedy <c@groovy.org> | ||
5 | Copyright (C) 2005-2007 Hans Verkuil <hverkuil@xs4all.nl> | ||
6 | |||
7 | This program is free software; you can redistribute it and/or modify | ||
8 | it under the terms of the GNU General Public License as published by | ||
9 | the Free Software Foundation; either version 2 of the License, or | ||
10 | (at your option) any later version. | ||
11 | |||
12 | This program is distributed in the hope that it will be useful, | ||
13 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
15 | GNU General Public License for more details. | ||
16 | |||
17 | You should have received a copy of the GNU General Public License | ||
18 | along with this program; if not, write to the Free Software | ||
19 | Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
20 | */ | ||
21 | |||
22 | /* License: GPL | ||
23 | * Author: Kevin Thayer <nufan_wfk at yahoo dot com> | ||
24 | * | ||
25 | * This file will hold API related functions, both internal (firmware api) | ||
26 | * and external (v4l2, etc) | ||
27 | * | ||
28 | * ----- | ||
29 | * MPG600/MPG160 support by T.Adachi <tadachi@tadachi-net.com> | ||
30 | * and Takeru KOMORIYA<komoriya@paken.org> | ||
31 | * | ||
32 | * AVerMedia M179 GPIO info by Chris Pinkham <cpinkham@bc2va.org> | ||
33 | * using information provided by Jiun-Kuei Jung @ AVerMedia. | ||
34 | */ | ||
35 | |||
36 | #include "ivtv-driver.h" | ||
37 | #include "ivtv-fileops.h" | ||
38 | #include "ivtv-i2c.h" | ||
39 | #include "ivtv-queue.h" | ||
40 | #include "ivtv-mailbox.h" | ||
41 | #include "ivtv-audio.h" | ||
42 | #include "ivtv-video.h" | ||
43 | #include "ivtv-vbi.h" | ||
44 | #include "ivtv-ioctl.h" | ||
45 | #include "ivtv-irq.h" | ||
46 | #include "ivtv-streams.h" | ||
47 | #include "ivtv-cards.h" | ||
48 | |||
49 | static struct file_operations ivtv_v4l2_enc_fops = { | ||
50 | .owner = THIS_MODULE, | ||
51 | .read = ivtv_v4l2_read, | ||
52 | .write = ivtv_v4l2_write, | ||
53 | .open = ivtv_v4l2_open, | ||
54 | .ioctl = ivtv_v4l2_ioctl, | ||
55 | .release = ivtv_v4l2_close, | ||
56 | .poll = ivtv_v4l2_enc_poll, | ||
57 | }; | ||
58 | |||
59 | static struct file_operations ivtv_v4l2_dec_fops = { | ||
60 | .owner = THIS_MODULE, | ||
61 | .read = ivtv_v4l2_read, | ||
62 | .write = ivtv_v4l2_write, | ||
63 | .open = ivtv_v4l2_open, | ||
64 | .ioctl = ivtv_v4l2_ioctl, | ||
65 | .release = ivtv_v4l2_close, | ||
66 | .poll = ivtv_v4l2_dec_poll, | ||
67 | }; | ||
68 | |||
69 | static struct { | ||
70 | const char *name; | ||
71 | int vfl_type; | ||
72 | int minor_offset; | ||
73 | int dma, pio; | ||
74 | enum v4l2_buf_type buf_type; | ||
75 | struct file_operations *fops; | ||
76 | } ivtv_stream_info[] = { | ||
77 | { /* IVTV_ENC_STREAM_TYPE_MPG */ | ||
78 | "encoder MPEG", | ||
79 | VFL_TYPE_GRABBER, 0, | ||
80 | PCI_DMA_FROMDEVICE, 0, V4L2_BUF_TYPE_VIDEO_CAPTURE, | ||
81 | &ivtv_v4l2_enc_fops | ||
82 | }, | ||
83 | { /* IVTV_ENC_STREAM_TYPE_YUV */ | ||
84 | "encoder YUV", | ||
85 | VFL_TYPE_GRABBER, IVTV_V4L2_ENC_YUV_OFFSET, | ||
86 | PCI_DMA_FROMDEVICE, 0, V4L2_BUF_TYPE_VIDEO_CAPTURE, | ||
87 | &ivtv_v4l2_enc_fops | ||
88 | }, | ||
89 | { /* IVTV_ENC_STREAM_TYPE_VBI */ | ||
90 | "encoder VBI", | ||
91 | VFL_TYPE_VBI, 0, | ||
92 | PCI_DMA_FROMDEVICE, 0, V4L2_BUF_TYPE_VBI_CAPTURE, | ||
93 | &ivtv_v4l2_enc_fops | ||
94 | }, | ||
95 | { /* IVTV_ENC_STREAM_TYPE_PCM */ | ||
96 | "encoder PCM audio", | ||
97 | VFL_TYPE_GRABBER, IVTV_V4L2_ENC_PCM_OFFSET, | ||
98 | PCI_DMA_FROMDEVICE, 0, V4L2_BUF_TYPE_PRIVATE, | ||
99 | &ivtv_v4l2_enc_fops | ||
100 | }, | ||
101 | { /* IVTV_ENC_STREAM_TYPE_RAD */ | ||
102 | "encoder radio", | ||
103 | VFL_TYPE_RADIO, 0, | ||
104 | PCI_DMA_NONE, 1, V4L2_BUF_TYPE_PRIVATE, | ||
105 | &ivtv_v4l2_enc_fops | ||
106 | }, | ||
107 | { /* IVTV_DEC_STREAM_TYPE_MPG */ | ||
108 | "decoder MPEG", | ||
109 | VFL_TYPE_GRABBER, IVTV_V4L2_DEC_MPG_OFFSET, | ||
110 | PCI_DMA_TODEVICE, 0, V4L2_BUF_TYPE_VIDEO_OUTPUT, | ||
111 | &ivtv_v4l2_dec_fops | ||
112 | }, | ||
113 | { /* IVTV_DEC_STREAM_TYPE_VBI */ | ||
114 | "decoder VBI", | ||
115 | VFL_TYPE_VBI, IVTV_V4L2_DEC_VBI_OFFSET, | ||
116 | PCI_DMA_NONE, 1, V4L2_BUF_TYPE_VBI_CAPTURE, | ||
117 | &ivtv_v4l2_enc_fops | ||
118 | }, | ||
119 | { /* IVTV_DEC_STREAM_TYPE_VOUT */ | ||
120 | "decoder VOUT", | ||
121 | VFL_TYPE_VBI, IVTV_V4L2_DEC_VOUT_OFFSET, | ||
122 | PCI_DMA_NONE, 1, V4L2_BUF_TYPE_VBI_OUTPUT, | ||
123 | &ivtv_v4l2_dec_fops | ||
124 | }, | ||
125 | { /* IVTV_DEC_STREAM_TYPE_YUV */ | ||
126 | "decoder YUV", | ||
127 | VFL_TYPE_GRABBER, IVTV_V4L2_DEC_YUV_OFFSET, | ||
128 | PCI_DMA_TODEVICE, 0, V4L2_BUF_TYPE_VIDEO_OUTPUT, | ||
129 | &ivtv_v4l2_dec_fops | ||
130 | } | ||
131 | }; | ||
132 | |||
133 | static void ivtv_stream_init(struct ivtv *itv, int type) | ||
134 | { | ||
135 | struct ivtv_stream *s = &itv->streams[type]; | ||
136 | struct video_device *dev = s->v4l2dev; | ||
137 | |||
138 | /* we need to keep v4l2dev, so restore it afterwards */ | ||
139 | memset(s, 0, sizeof(*s)); | ||
140 | s->v4l2dev = dev; | ||
141 | |||
142 | /* initialize ivtv_stream fields */ | ||
143 | s->itv = itv; | ||
144 | s->type = type; | ||
145 | s->name = ivtv_stream_info[type].name; | ||
146 | |||
147 | if (ivtv_stream_info[type].pio) | ||
148 | s->dma = PCI_DMA_NONE; | ||
149 | else | ||
150 | s->dma = ivtv_stream_info[type].dma; | ||
151 | s->buf_size = itv->stream_buf_size[type]; | ||
152 | if (s->buf_size) | ||
153 | s->buffers = itv->options.megabytes[type] * 1024 * 1024 / s->buf_size; | ||
154 | spin_lock_init(&s->qlock); | ||
155 | init_waitqueue_head(&s->waitq); | ||
156 | s->id = -1; | ||
157 | s->SG_handle = IVTV_DMA_UNMAPPED; | ||
158 | ivtv_queue_init(&s->q_free); | ||
159 | ivtv_queue_init(&s->q_full); | ||
160 | ivtv_queue_init(&s->q_dma); | ||
161 | ivtv_queue_init(&s->q_predma); | ||
162 | ivtv_queue_init(&s->q_io); | ||
163 | } | ||
164 | |||
165 | static int ivtv_reg_dev(struct ivtv *itv, int type) | ||
166 | { | ||
167 | struct ivtv_stream *s = &itv->streams[type]; | ||
168 | int vfl_type = ivtv_stream_info[type].vfl_type; | ||
169 | int minor_offset = ivtv_stream_info[type].minor_offset; | ||
170 | int minor; | ||
171 | |||
172 | /* These four fields are always initialized. If v4l2dev == NULL, then | ||
173 | this stream is not in use. In that case no other fields but these | ||
174 | four can be used. */ | ||
175 | s->v4l2dev = NULL; | ||
176 | s->itv = itv; | ||
177 | s->type = type; | ||
178 | s->name = ivtv_stream_info[type].name; | ||
179 | |||
180 | /* Check whether the radio is supported */ | ||
181 | if (type == IVTV_ENC_STREAM_TYPE_RAD && !(itv->v4l2_cap & V4L2_CAP_RADIO)) | ||
182 | return 0; | ||
183 | if (type >= IVTV_DEC_STREAM_TYPE_MPG && !(itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT)) | ||
184 | return 0; | ||
185 | |||
186 | if (minor_offset >= 0) | ||
187 | /* card number + user defined offset + device offset */ | ||
188 | minor = itv->num + ivtv_first_minor + minor_offset; | ||
189 | else | ||
190 | minor = -1; | ||
191 | |||
192 | /* User explicitly selected 0 buffers for these streams, so don't | ||
193 | create them. */ | ||
194 | if (minor >= 0 && ivtv_stream_info[type].dma != PCI_DMA_NONE && | ||
195 | itv->options.megabytes[type] == 0) { | ||
196 | IVTV_INFO("Disabled %s device\n", ivtv_stream_info[type].name); | ||
197 | return 0; | ||
198 | } | ||
199 | |||
200 | ivtv_stream_init(itv, type); | ||
201 | |||
202 | /* allocate and initialize the v4l2 video device structure */ | ||
203 | s->v4l2dev = video_device_alloc(); | ||
204 | if (s->v4l2dev == NULL) { | ||
205 | IVTV_ERR("Couldn't allocate v4l2 video_device for %s\n", s->name); | ||
206 | return -ENOMEM; | ||
207 | } | ||
208 | |||
209 | s->v4l2dev->type = VID_TYPE_CAPTURE | VID_TYPE_TUNER | VID_TYPE_TELETEXT | | ||
210 | VID_TYPE_CLIPPING | VID_TYPE_SCALES | VID_TYPE_MPEG_ENCODER; | ||
211 | if (itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT) { | ||
212 | s->v4l2dev->type |= VID_TYPE_MPEG_DECODER; | ||
213 | } | ||
214 | snprintf(s->v4l2dev->name, sizeof(s->v4l2dev->name), "ivtv%d %s", | ||
215 | itv->num, s->name); | ||
216 | |||
217 | s->v4l2dev->minor = minor; | ||
218 | s->v4l2dev->dev = &itv->dev->dev; | ||
219 | s->v4l2dev->fops = ivtv_stream_info[type].fops; | ||
220 | s->v4l2dev->release = video_device_release; | ||
221 | |||
222 | if (minor >= 0) { | ||
223 | /* Register device. First try the desired minor, then any free one. */ | ||
224 | if (video_register_device(s->v4l2dev, vfl_type, minor) && | ||
225 | video_register_device(s->v4l2dev, vfl_type, -1)) { | ||
226 | IVTV_ERR("Couldn't register v4l2 device for %s minor %d\n", | ||
227 | s->name, minor); | ||
228 | video_device_release(s->v4l2dev); | ||
229 | s->v4l2dev = NULL; | ||
230 | return -ENOMEM; | ||
231 | } | ||
232 | } | ||
233 | else { | ||
234 | /* Don't register a 'hidden' stream (OSD) */ | ||
235 | IVTV_INFO("Created framebuffer stream for %s\n", s->name); | ||
236 | return 0; | ||
237 | } | ||
238 | |||
239 | switch (vfl_type) { | ||
240 | case VFL_TYPE_GRABBER: | ||
241 | IVTV_INFO("Registered device video%d for %s (%d MB)\n", | ||
242 | s->v4l2dev->minor, s->name, itv->options.megabytes[type]); | ||
243 | break; | ||
244 | case VFL_TYPE_RADIO: | ||
245 | IVTV_INFO("Registered device radio%d for %s\n", | ||
246 | s->v4l2dev->minor - MINOR_VFL_TYPE_RADIO_MIN, s->name); | ||
247 | break; | ||
248 | case VFL_TYPE_VBI: | ||
249 | if (itv->options.megabytes[type]) | ||
250 | IVTV_INFO("Registered device vbi%d for %s (%d MB)\n", | ||
251 | s->v4l2dev->minor - MINOR_VFL_TYPE_VBI_MIN, | ||
252 | s->name, itv->options.megabytes[type]); | ||
253 | else | ||
254 | IVTV_INFO("Registered device vbi%d for %s\n", | ||
255 | s->v4l2dev->minor - MINOR_VFL_TYPE_VBI_MIN, s->name); | ||
256 | break; | ||
257 | } | ||
258 | return 0; | ||
259 | } | ||
260 | |||
261 | /* Initialize v4l2 variables and register v4l2 devices */ | ||
262 | int ivtv_streams_setup(struct ivtv *itv) | ||
263 | { | ||
264 | int type; | ||
265 | |||
266 | /* Setup V4L2 Devices */ | ||
267 | for (type = 0; type < IVTV_MAX_STREAMS; type++) { | ||
268 | /* Register Device */ | ||
269 | if (ivtv_reg_dev(itv, type)) | ||
270 | break; | ||
271 | |||
272 | if (itv->streams[type].v4l2dev == NULL) | ||
273 | continue; | ||
274 | |||
275 | /* Allocate Stream */ | ||
276 | if (ivtv_stream_alloc(&itv->streams[type])) | ||
277 | break; | ||
278 | } | ||
279 | if (type == IVTV_MAX_STREAMS) { | ||
280 | return 0; | ||
281 | } | ||
282 | |||
283 | /* One or more streams could not be initialized. Clean 'em all up. */ | ||
284 | ivtv_streams_cleanup(itv); | ||
285 | return -ENOMEM; | ||
286 | } | ||
287 | |||
288 | /* Unregister v4l2 devices */ | ||
289 | void ivtv_streams_cleanup(struct ivtv *itv) | ||
290 | { | ||
291 | int type; | ||
292 | |||
293 | /* Teardown all streams */ | ||
294 | for (type = 0; type < IVTV_MAX_STREAMS; type++) { | ||
295 | struct video_device *vdev = itv->streams[type].v4l2dev; | ||
296 | |||
297 | itv->streams[type].v4l2dev = NULL; | ||
298 | if (vdev == NULL) | ||
299 | continue; | ||
300 | |||
301 | ivtv_stream_free(&itv->streams[type]); | ||
302 | /* Free Device */ | ||
303 | if (vdev->minor == -1) /* 'Hidden' never registered stream (OSD) */ | ||
304 | video_device_release(vdev); | ||
305 | else /* All others, just unregister. */ | ||
306 | video_unregister_device(vdev); | ||
307 | } | ||
308 | } | ||
309 | |||
310 | static void ivtv_vbi_setup(struct ivtv *itv) | ||
311 | { | ||
312 | int raw = itv->vbi.sliced_in->service_set == 0; | ||
313 | u32 data[CX2341X_MBOX_MAX_DATA]; | ||
314 | int lines; | ||
315 | int i; | ||
316 | |||
317 | /* If Embed then streamtype must be Program */ | ||
318 | /* TODO: should we really do this? */ | ||
319 | if (0 && !raw && itv->vbi.insert_mpeg) { | ||
320 | itv->params.stream_type = 0; | ||
321 | |||
322 | /* assign stream type */ | ||
323 | ivtv_vapi(itv, CX2341X_ENC_SET_STREAM_TYPE, 1, itv->params.stream_type); | ||
324 | } | ||
325 | |||
326 | /* Reset VBI */ | ||
327 | ivtv_vapi(itv, CX2341X_ENC_SET_VBI_LINE, 5, 0xffff , 0, 0, 0, 0); | ||
328 | |||
329 | if (itv->is_60hz) { | ||
330 | itv->vbi.count = 12; | ||
331 | itv->vbi.start[0] = 10; | ||
332 | itv->vbi.start[1] = 273; | ||
333 | } else { /* PAL/SECAM */ | ||
334 | itv->vbi.count = 18; | ||
335 | itv->vbi.start[0] = 6; | ||
336 | itv->vbi.start[1] = 318; | ||
337 | } | ||
338 | |||
339 | /* setup VBI registers */ | ||
340 | itv->video_dec_func(itv, VIDIOC_S_FMT, &itv->vbi.in); | ||
341 | |||
342 | /* determine number of lines and total number of VBI bytes. | ||
343 | A raw line takes 1443 bytes: 2 * 720 + 4 byte frame header - 1 | ||
344 | The '- 1' byte is probably an unused U or V byte. Or something... | ||
345 | A sliced line takes 51 bytes: 4 byte frame header, 4 byte internal | ||
346 | header, 42 data bytes + checksum (to be confirmed) */ | ||
347 | if (raw) { | ||
348 | lines = itv->vbi.count * 2; | ||
349 | } else { | ||
350 | lines = itv->is_60hz ? 24 : 38; | ||
351 | if (itv->is_60hz && (itv->hw_flags & IVTV_HW_CX25840)) | ||
352 | lines += 2; | ||
353 | } | ||
354 | |||
355 | itv->vbi.enc_size = lines * (raw ? itv->vbi.raw_size : itv->vbi.sliced_size); | ||
356 | |||
357 | /* Note: sliced vs raw flag doesn't seem to have any effect | ||
358 | TODO: check mode (0x02) value with older ivtv versions. */ | ||
359 | data[0] = raw | 0x02 | (0xbd << 8); | ||
360 | |||
361 | /* Every X number of frames a VBI interrupt arrives (frames as in 25 or 30 fps) */ | ||
362 | data[1] = 1; | ||
363 | /* The VBI frames are stored in a ringbuffer with this size (with a VBI frame as unit) */ | ||
364 | data[2] = raw ? 4 : 8; | ||
365 | /* The start/stop codes determine which VBI lines end up in the raw VBI data area. | ||
366 | The codes are from table 24 in the saa7115 datasheet. Each raw/sliced/video line | ||
367 | is framed with codes FF0000XX where XX is the SAV/EAV (Start/End of Active Video) | ||
368 | code. These values for raw VBI are obtained from a driver disassembly. The sliced | ||
369 | start/stop codes was deduced from this, but they do not appear in the driver. | ||
370 | Other code pairs that I found are: 0x250E6249/0x13545454 and 0x25256262/0x38137F54. | ||
371 | However, I have no idea what these values are for. */ | ||
372 | if (itv->hw_flags & IVTV_HW_CX25840) { | ||
373 | /* Setup VBI for the cx25840 digitizer */ | ||
374 | if (raw) { | ||
375 | data[3] = 0x20602060; | ||
376 | data[4] = 0x30703070; | ||
377 | } else { | ||
378 | data[3] = 0xB0F0B0F0; | ||
379 | data[4] = 0xA0E0A0E0; | ||
380 | } | ||
381 | /* Lines per frame */ | ||
382 | data[5] = lines; | ||
383 | /* bytes per line */ | ||
384 | data[6] = (raw ? itv->vbi.raw_size : itv->vbi.sliced_size); | ||
385 | } else { | ||
386 | /* Setup VBI for the saa7115 digitizer */ | ||
387 | if (raw) { | ||
388 | data[3] = 0x25256262; | ||
389 | data[4] = 0x387F7F7F; | ||
390 | } else { | ||
391 | data[3] = 0xABABECEC; | ||
392 | data[4] = 0xB6F1F1F1; | ||
393 | } | ||
394 | /* Lines per frame */ | ||
395 | data[5] = lines; | ||
396 | /* bytes per line */ | ||
397 | data[6] = itv->vbi.enc_size / lines; | ||
398 | } | ||
399 | |||
400 | IVTV_DEBUG_INFO( | ||
401 | "Setup VBI API header 0x%08x pkts %d buffs %d ln %d sz %d\n", | ||
402 | data[0], data[1], data[2], data[5], data[6]); | ||
403 | |||
404 | ivtv_api(itv, CX2341X_ENC_SET_VBI_CONFIG, 7, data); | ||
405 | |||
406 | /* returns the VBI encoder memory area. */ | ||
407 | itv->vbi.enc_start = data[2]; | ||
408 | itv->vbi.fpi = data[0]; | ||
409 | if (!itv->vbi.fpi) | ||
410 | itv->vbi.fpi = 1; | ||
411 | |||
412 | IVTV_DEBUG_INFO("Setup VBI start 0x%08x frames %d fpi %d lines 0x%08x\n", | ||
413 | itv->vbi.enc_start, data[1], itv->vbi.fpi, itv->digitizer); | ||
414 | |||
415 | /* select VBI lines. | ||
416 | Note that the sliced argument seems to have no effect. */ | ||
417 | for (i = 2; i <= 24; i++) { | ||
418 | int valid; | ||
419 | |||
420 | if (itv->is_60hz) { | ||
421 | valid = i >= 10 && i < 22; | ||
422 | } else { | ||
423 | valid = i >= 6 && i < 24; | ||
424 | } | ||
425 | ivtv_vapi(itv, CX2341X_ENC_SET_VBI_LINE, 5, i - 1, | ||
426 | valid, 0 , 0, 0); | ||
427 | ivtv_vapi(itv, CX2341X_ENC_SET_VBI_LINE, 5, (i - 1) | 0x80000000, | ||
428 | valid, 0, 0, 0); | ||
429 | } | ||
430 | |||
431 | /* Remaining VBI questions: | ||
432 | - Is it possible to select particular VBI lines only for inclusion in the MPEG | ||
433 | stream? Currently you can only get the first X lines. | ||
434 | - Is mixed raw and sliced VBI possible? | ||
435 | - What's the meaning of the raw/sliced flag? | ||
436 | - What's the meaning of params 2, 3 & 4 of the Select VBI command? */ | ||
437 | } | ||
438 | |||
439 | int ivtv_start_v4l2_encode_stream(struct ivtv_stream *s) | ||
440 | { | ||
441 | u32 data[CX2341X_MBOX_MAX_DATA]; | ||
442 | struct ivtv *itv = s->itv; | ||
443 | int captype = 0, subtype = 0; | ||
444 | int enable_passthrough = 0; | ||
445 | |||
446 | if (s->v4l2dev == NULL) | ||
447 | return -EINVAL; | ||
448 | |||
449 | IVTV_DEBUG_INFO("Start encoder stream %s\n", s->name); | ||
450 | |||
451 | switch (s->type) { | ||
452 | case IVTV_ENC_STREAM_TYPE_MPG: | ||
453 | captype = 0; | ||
454 | subtype = 3; | ||
455 | |||
456 | /* Stop Passthrough */ | ||
457 | if (itv->output_mode == OUT_PASSTHROUGH) { | ||
458 | ivtv_passthrough_mode(itv, 0); | ||
459 | enable_passthrough = 1; | ||
460 | } | ||
461 | itv->mpg_data_received = itv->vbi_data_inserted = 0; | ||
462 | itv->dualwatch_jiffies = jiffies; | ||
463 | itv->dualwatch_stereo_mode = itv->params.audio_properties & 0x0300; | ||
464 | itv->search_pack_header = 0; | ||
465 | break; | ||
466 | |||
467 | case IVTV_ENC_STREAM_TYPE_YUV: | ||
468 | if (itv->output_mode == OUT_PASSTHROUGH) { | ||
469 | captype = 2; | ||
470 | subtype = 11; /* video+audio+decoder */ | ||
471 | break; | ||
472 | } | ||
473 | captype = 1; | ||
474 | subtype = 1; | ||
475 | break; | ||
476 | case IVTV_ENC_STREAM_TYPE_PCM: | ||
477 | captype = 1; | ||
478 | subtype = 2; | ||
479 | break; | ||
480 | case IVTV_ENC_STREAM_TYPE_VBI: | ||
481 | captype = 1; | ||
482 | subtype = 4; | ||
483 | |||
484 | itv->vbi.frame = 0; | ||
485 | itv->vbi.inserted_frame = 0; | ||
486 | memset(itv->vbi.sliced_mpeg_size, | ||
487 | 0, sizeof(itv->vbi.sliced_mpeg_size)); | ||
488 | break; | ||
489 | default: | ||
490 | return -EINVAL; | ||
491 | } | ||
492 | s->subtype = subtype; | ||
493 | s->buffers_stolen = 0; | ||
494 | |||
495 | /* mute/unmute video */ | ||
496 | ivtv_vapi(itv, CX2341X_ENC_MUTE_VIDEO, 1, test_bit(IVTV_F_I_RADIO_USER, &itv->i_flags) ? 1 : 0); | ||
497 | |||
498 | /* Clear Streamoff flags in case left from last capture */ | ||
499 | clear_bit(IVTV_F_S_STREAMOFF, &s->s_flags); | ||
500 | |||
501 | if (atomic_read(&itv->capturing) == 0) { | ||
502 | /* Always use frame based mode. Experiments have demonstrated that byte | ||
503 | stream based mode results in dropped frames and corruption. Not often, | ||
504 | but occasionally. Many thanks go to Leonard Orb who spent a lot of | ||
505 | effort and time trying to trace the cause of the drop outs. */ | ||
506 | /* 1 frame per DMA */ | ||
507 | /*ivtv_vapi(itv, CX2341X_ENC_SET_DMA_BLOCK_SIZE, 2, 128, 0); */ | ||
508 | ivtv_vapi(itv, CX2341X_ENC_SET_DMA_BLOCK_SIZE, 2, 1, 1); | ||
509 | |||
510 | /* Stuff from Windows, we don't know what it is */ | ||
511 | ivtv_vapi(itv, CX2341X_ENC_SET_VERT_CROP_LINE, 1, 0); | ||
512 | /* According to the docs, this should be correct. However, this is | ||
513 | untested. I don't dare enable this without having tested it. | ||
514 | Only very few old cards actually have this hardware combination. | ||
515 | ivtv_vapi(itv, CX2341X_ENC_SET_VERT_CROP_LINE, 1, | ||
516 | ((itv->hw_flags & IVTV_HW_SAA7114) && itv->is_60hz) ? 10001 : 0); | ||
517 | */ | ||
518 | ivtv_vapi(itv, CX2341X_ENC_MISC, 2, 3, !itv->has_cx23415); | ||
519 | ivtv_vapi(itv, CX2341X_ENC_MISC, 2, 8, 0); | ||
520 | ivtv_vapi(itv, CX2341X_ENC_MISC, 2, 4, 1); | ||
521 | ivtv_vapi(itv, CX2341X_ENC_MISC, 1, 12); | ||
522 | |||
523 | /* assign placeholder */ | ||
524 | ivtv_vapi(itv, CX2341X_ENC_SET_PLACEHOLDER, 12, | ||
525 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); | ||
526 | |||
527 | ivtv_vapi(itv, CX2341X_ENC_SET_NUM_VSYNC_LINES, 2, itv->digitizer, itv->digitizer); | ||
528 | |||
529 | /* Setup VBI */ | ||
530 | if (itv->v4l2_cap & V4L2_CAP_VBI_CAPTURE) { | ||
531 | ivtv_vbi_setup(itv); | ||
532 | } | ||
533 | |||
534 | /* assign program index info. Mask 7: select I/P/B, Num_req: 400 max */ | ||
535 | ivtv_vapi_result(itv, data, CX2341X_ENC_SET_PGM_INDEX_INFO, 2, 7, 400); | ||
536 | itv->pgm_info_offset = data[0]; | ||
537 | itv->pgm_info_num = data[1]; | ||
538 | itv->pgm_info_write_idx = 0; | ||
539 | itv->pgm_info_read_idx = 0; | ||
540 | |||
541 | IVTV_DEBUG_INFO("PGM Index at 0x%08x with %d elements\n", | ||
542 | itv->pgm_info_offset, itv->pgm_info_num); | ||
543 | |||
544 | /* Setup API for Stream */ | ||
545 | cx2341x_update(itv, ivtv_api_func, NULL, &itv->params); | ||
546 | } | ||
547 | |||
548 | /* Vsync Setup */ | ||
549 | if (itv->has_cx23415 && !test_and_set_bit(IVTV_F_I_DIG_RST, &itv->i_flags)) { | ||
550 | /* event notification (on) */ | ||
551 | ivtv_vapi(itv, CX2341X_ENC_SET_EVENT_NOTIFICATION, 4, 0, 1, IVTV_IRQ_ENC_VIM_RST, -1); | ||
552 | ivtv_clear_irq_mask(itv, IVTV_IRQ_ENC_VIM_RST); | ||
553 | } | ||
554 | |||
555 | if (atomic_read(&itv->capturing) == 0) { | ||
556 | /* Clear all Pending Interrupts */ | ||
557 | ivtv_set_irq_mask(itv, IVTV_IRQ_MASK_CAPTURE); | ||
558 | |||
559 | clear_bit(IVTV_F_I_EOS, &itv->i_flags); | ||
560 | |||
561 | /* Initialize Digitizer for Capture */ | ||
562 | ivtv_vapi(itv, CX2341X_ENC_INITIALIZE_INPUT, 0); | ||
563 | |||
564 | ivtv_sleep_timeout(HZ / 10, 0); | ||
565 | } | ||
566 | |||
567 | /* begin_capture */ | ||
568 | if (ivtv_vapi(itv, CX2341X_ENC_START_CAPTURE, 2, captype, subtype)) | ||
569 | { | ||
570 | IVTV_DEBUG_WARN( "Error starting capture!\n"); | ||
571 | return -EINVAL; | ||
572 | } | ||
573 | |||
574 | /* Start Passthrough */ | ||
575 | if (enable_passthrough) { | ||
576 | ivtv_passthrough_mode(itv, 1); | ||
577 | } | ||
578 | |||
579 | if (s->type == IVTV_ENC_STREAM_TYPE_VBI) | ||
580 | ivtv_clear_irq_mask(itv, IVTV_IRQ_ENC_VBI_CAP); | ||
581 | else | ||
582 | ivtv_clear_irq_mask(itv, IVTV_IRQ_MASK_CAPTURE); | ||
583 | |||
584 | /* you're live! sit back and await interrupts :) */ | ||
585 | atomic_inc(&itv->capturing); | ||
586 | return 0; | ||
587 | } | ||
588 | |||
589 | static int ivtv_setup_v4l2_decode_stream(struct ivtv_stream *s) | ||
590 | { | ||
591 | u32 data[CX2341X_MBOX_MAX_DATA]; | ||
592 | struct ivtv *itv = s->itv; | ||
593 | int datatype; | ||
594 | |||
595 | if (s->v4l2dev == NULL) | ||
596 | return -EINVAL; | ||
597 | |||
598 | IVTV_DEBUG_INFO("Setting some initial decoder settings\n"); | ||
599 | |||
600 | /* disable VBI signals, if the MPEG stream contains VBI data, | ||
601 | then that data will be processed automatically for you. */ | ||
602 | ivtv_disable_vbi(itv); | ||
603 | |||
604 | /* set audio mode to left/stereo for dual/stereo mode. */ | ||
605 | ivtv_vapi(itv, CX2341X_DEC_SET_AUDIO_MODE, 2, itv->audio_bilingual_mode, itv->audio_stereo_mode); | ||
606 | |||
607 | /* set number of internal decoder buffers */ | ||
608 | ivtv_vapi(itv, CX2341X_DEC_SET_DISPLAY_BUFFERS, 1, 0); | ||
609 | |||
610 | /* prebuffering */ | ||
611 | ivtv_vapi(itv, CX2341X_DEC_SET_PREBUFFERING, 1, 1); | ||
612 | |||
613 | /* extract from user packets */ | ||
614 | ivtv_vapi_result(itv, data, CX2341X_DEC_EXTRACT_VBI, 1, 1); | ||
615 | itv->vbi.dec_start = data[0]; | ||
616 | |||
617 | IVTV_DEBUG_INFO("Decoder VBI RE-Insert start 0x%08x size 0x%08x\n", | ||
618 | itv->vbi.dec_start, data[1]); | ||
619 | |||
620 | /* set decoder source settings */ | ||
621 | /* Data type: 0 = mpeg from host, | ||
622 | 1 = yuv from encoder, | ||
623 | 2 = yuv_from_host */ | ||
624 | switch (s->type) { | ||
625 | case IVTV_DEC_STREAM_TYPE_YUV: | ||
626 | datatype = itv->output_mode == OUT_PASSTHROUGH ? 1 : 2; | ||
627 | IVTV_DEBUG_INFO("Setup DEC YUV Stream data[0] = %d\n", datatype); | ||
628 | break; | ||
629 | case IVTV_DEC_STREAM_TYPE_MPG: | ||
630 | default: | ||
631 | datatype = 0; | ||
632 | break; | ||
633 | } | ||
634 | if (ivtv_vapi(itv, CX2341X_DEC_SET_DECODER_SOURCE, 4, datatype, | ||
635 | itv->params.width, itv->params.height, itv->params.audio_properties)) { | ||
636 | IVTV_DEBUG_WARN("COULDN'T INITIALIZE DECODER SOURCE\n"); | ||
637 | } | ||
638 | return 0; | ||
639 | } | ||
640 | |||
641 | int ivtv_start_v4l2_decode_stream(struct ivtv_stream *s, int gop_offset) | ||
642 | { | ||
643 | struct ivtv *itv = s->itv; | ||
644 | |||
645 | if (s->v4l2dev == NULL) | ||
646 | return -EINVAL; | ||
647 | |||
648 | if (test_and_set_bit(IVTV_F_S_STREAMING, &s->s_flags)) | ||
649 | return 0; /* already started */ | ||
650 | |||
651 | IVTV_DEBUG_INFO("Starting decode stream %s (gop_offset %d)\n", s->name, gop_offset); | ||
652 | |||
653 | /* Clear Streamoff */ | ||
654 | if (s->type == IVTV_DEC_STREAM_TYPE_YUV) { | ||
655 | /* Initialize Decoder */ | ||
656 | /* Reprogram Decoder YUV Buffers for YUV */ | ||
657 | write_reg(yuv_offset[0] >> 4, 0x82c); | ||
658 | write_reg((yuv_offset[0] + IVTV_YUV_BUFFER_UV_OFFSET) >> 4, 0x830); | ||
659 | write_reg(yuv_offset[0] >> 4, 0x834); | ||
660 | write_reg((yuv_offset[0] + IVTV_YUV_BUFFER_UV_OFFSET) >> 4, 0x838); | ||
661 | |||
662 | write_reg_sync(0x00000000 | (0x0c << 16) | (0x0b << 8), 0x2d24); | ||
663 | |||
664 | write_reg_sync(0x00108080, 0x2898); | ||
665 | /* Enable YUV decoder output */ | ||
666 | write_reg_sync(0x01, IVTV_REG_VDM); | ||
667 | } | ||
668 | |||
669 | ivtv_setup_v4l2_decode_stream(s); | ||
670 | |||
671 | /* set dma size to 65536 bytes */ | ||
672 | ivtv_vapi(itv, CX2341X_DEC_SET_DMA_BLOCK_SIZE, 1, 65536); | ||
673 | |||
674 | clear_bit(IVTV_F_S_STREAMOFF, &s->s_flags); | ||
675 | |||
676 | /* Zero out decoder counters */ | ||
677 | writel(0, &itv->dec_mbox.mbox[IVTV_MBOX_FIELD_DISPLAYED].data[0]); | ||
678 | writel(0, &itv->dec_mbox.mbox[IVTV_MBOX_FIELD_DISPLAYED].data[1]); | ||
679 | writel(0, &itv->dec_mbox.mbox[IVTV_MBOX_FIELD_DISPLAYED].data[2]); | ||
680 | writel(0, &itv->dec_mbox.mbox[IVTV_MBOX_FIELD_DISPLAYED].data[3]); | ||
681 | writel(0, &itv->dec_mbox.mbox[IVTV_MBOX_DMA].data[0]); | ||
682 | writel(0, &itv->dec_mbox.mbox[IVTV_MBOX_DMA].data[1]); | ||
683 | writel(0, &itv->dec_mbox.mbox[IVTV_MBOX_DMA].data[2]); | ||
684 | writel(0, &itv->dec_mbox.mbox[IVTV_MBOX_DMA].data[3]); | ||
685 | |||
686 | /* turn on notification of dual/stereo mode change */ | ||
687 | ivtv_vapi(itv, CX2341X_DEC_SET_EVENT_NOTIFICATION, 4, 0, 1, IVTV_IRQ_DEC_AUD_MODE_CHG, -1); | ||
688 | |||
689 | /* start playback */ | ||
690 | ivtv_vapi(itv, CX2341X_DEC_START_PLAYBACK, 2, gop_offset, 0); | ||
691 | |||
692 | /* Clear the following Interrupt mask bits for decoding */ | ||
693 | ivtv_clear_irq_mask(itv, IVTV_IRQ_MASK_DECODE); | ||
694 | IVTV_DEBUG_IRQ("IRQ Mask is now: 0x%08x\n", itv->irqmask); | ||
695 | |||
696 | /* you're live! sit back and await interrupts :) */ | ||
697 | atomic_inc(&itv->decoding); | ||
698 | return 0; | ||
699 | } | ||
700 | |||
701 | void ivtv_stop_all_captures(struct ivtv *itv) | ||
702 | { | ||
703 | int i; | ||
704 | |||
705 | for (i = IVTV_MAX_STREAMS - 1; i >= 0; i--) { | ||
706 | struct ivtv_stream *s = &itv->streams[i]; | ||
707 | |||
708 | if (s->v4l2dev == NULL) | ||
709 | continue; | ||
710 | if (test_bit(IVTV_F_S_STREAMING, &s->s_flags)) { | ||
711 | ivtv_stop_v4l2_encode_stream(s, 0); | ||
712 | } | ||
713 | } | ||
714 | } | ||
715 | |||
716 | int ivtv_stop_v4l2_encode_stream(struct ivtv_stream *s, int gop_end) | ||
717 | { | ||
718 | struct ivtv *itv = s->itv; | ||
719 | DECLARE_WAITQUEUE(wait, current); | ||
720 | int cap_type; | ||
721 | unsigned long then; | ||
722 | int stopmode; | ||
723 | u32 data[CX2341X_MBOX_MAX_DATA]; | ||
724 | |||
725 | if (s->v4l2dev == NULL) | ||
726 | return -EINVAL; | ||
727 | |||
728 | /* This function assumes that you are allowed to stop the capture | ||
729 | and that we are actually capturing */ | ||
730 | |||
731 | IVTV_DEBUG_INFO("Stop Capture\n"); | ||
732 | |||
733 | if (s->type == IVTV_DEC_STREAM_TYPE_VOUT) | ||
734 | return 0; | ||
735 | if (atomic_read(&itv->capturing) == 0) | ||
736 | return 0; | ||
737 | |||
738 | switch (s->type) { | ||
739 | case IVTV_ENC_STREAM_TYPE_YUV: | ||
740 | cap_type = 1; | ||
741 | break; | ||
742 | case IVTV_ENC_STREAM_TYPE_PCM: | ||
743 | cap_type = 1; | ||
744 | break; | ||
745 | case IVTV_ENC_STREAM_TYPE_VBI: | ||
746 | cap_type = 1; | ||
747 | break; | ||
748 | case IVTV_ENC_STREAM_TYPE_MPG: | ||
749 | default: | ||
750 | cap_type = 0; | ||
751 | break; | ||
752 | } | ||
753 | |||
754 | /* Stop Capture Mode */ | ||
755 | if (s->type == IVTV_ENC_STREAM_TYPE_MPG && gop_end) { | ||
756 | stopmode = 0; | ||
757 | } else { | ||
758 | stopmode = 1; | ||
759 | } | ||
760 | |||
761 | /* end_capture */ | ||
762 | /* when: 0 = end of GOP 1 = NOW!, type: 0 = mpeg, subtype: 3 = video+audio */ | ||
763 | ivtv_vapi(itv, CX2341X_ENC_STOP_CAPTURE, 3, stopmode, cap_type, s->subtype); | ||
764 | |||
765 | /* only run these if we're shutting down the last cap */ | ||
766 | if (atomic_read(&itv->capturing) - 1 == 0) { | ||
767 | /* event notification (off) */ | ||
768 | if (test_and_clear_bit(IVTV_F_I_DIG_RST, &itv->i_flags)) { | ||
769 | /* type: 0 = refresh */ | ||
770 | /* on/off: 0 = off, intr: 0x10000000, mbox_id: -1: none */ | ||
771 | ivtv_vapi(itv, CX2341X_ENC_SET_EVENT_NOTIFICATION, 4, 0, 0, IVTV_IRQ_ENC_VIM_RST, -1); | ||
772 | ivtv_set_irq_mask(itv, IVTV_IRQ_ENC_VIM_RST); | ||
773 | } | ||
774 | } | ||
775 | |||
776 | then = jiffies; | ||
777 | |||
778 | if (!test_bit(IVTV_F_S_PASSTHROUGH, &s->s_flags)) { | ||
779 | if (s->type == IVTV_ENC_STREAM_TYPE_MPG && gop_end) { | ||
780 | /* only run these if we're shutting down the last cap */ | ||
781 | unsigned long duration; | ||
782 | |||
783 | then = jiffies; | ||
784 | add_wait_queue(&itv->cap_w, &wait); | ||
785 | |||
786 | set_current_state(TASK_INTERRUPTIBLE); | ||
787 | |||
788 | /* wait 2s for EOS interrupt */ | ||
789 | while (!test_bit(IVTV_F_I_EOS, &itv->i_flags) && jiffies < then + 2 * HZ) { | ||
790 | schedule_timeout(HZ / 100); | ||
791 | } | ||
792 | |||
793 | /* To convert jiffies to ms, we must multiply by 1000 | ||
794 | * and divide by HZ. To avoid runtime division, we | ||
795 | * convert this to multiplication by 1000/HZ. | ||
796 | * Since integer division truncates, we get the best | ||
797 | * accuracy if we do a rounding calculation of the constant. | ||
798 | * Think of the case where HZ is 1024. | ||
799 | */ | ||
800 | duration = ((1000 + HZ / 2) / HZ) * (jiffies - then); | ||
801 | |||
802 | if (!test_bit(IVTV_F_I_EOS, &itv->i_flags)) { | ||
803 | IVTV_DEBUG_WARN("%s: EOS interrupt not received! stopping anyway.\n", s->name); | ||
804 | IVTV_DEBUG_WARN("%s: waited %lu ms.\n", s->name, duration); | ||
805 | } else { | ||
806 | IVTV_DEBUG_INFO("%s: EOS took %lu ms to occur.\n", s->name, duration); | ||
807 | } | ||
808 | set_current_state(TASK_RUNNING); | ||
809 | remove_wait_queue(&itv->cap_w, &wait); | ||
810 | } | ||
811 | |||
812 | then = jiffies; | ||
813 | /* Make sure DMA is complete */ | ||
814 | add_wait_queue(&s->waitq, &wait); | ||
815 | set_current_state(TASK_INTERRUPTIBLE); | ||
816 | do { | ||
817 | /* check if DMA is pending */ | ||
818 | if ((s->type == IVTV_ENC_STREAM_TYPE_MPG) && /* MPG Only */ | ||
819 | (read_reg(IVTV_REG_DMASTATUS) & 0x02)) { | ||
820 | /* Check for last DMA */ | ||
821 | ivtv_vapi_result(itv, data, CX2341X_ENC_GET_SEQ_END, 2, 0, 0); | ||
822 | |||
823 | if (data[0] == 1) { | ||
824 | IVTV_DEBUG_DMA("%s: Last DMA of size 0x%08x\n", s->name, data[1]); | ||
825 | break; | ||
826 | } | ||
827 | } else if (read_reg(IVTV_REG_DMASTATUS) & 0x02) { | ||
828 | break; | ||
829 | } | ||
830 | |||
831 | ivtv_sleep_timeout(HZ / 100, 1); | ||
832 | } while (then + HZ * 2 > jiffies); | ||
833 | |||
834 | set_current_state(TASK_RUNNING); | ||
835 | remove_wait_queue(&s->waitq, &wait); | ||
836 | } | ||
837 | |||
838 | atomic_dec(&itv->capturing); | ||
839 | |||
840 | /* Clear capture and no-read bits */ | ||
841 | clear_bit(IVTV_F_S_STREAMING, &s->s_flags); | ||
842 | |||
843 | if (s->type == IVTV_ENC_STREAM_TYPE_VBI) | ||
844 | ivtv_set_irq_mask(itv, IVTV_IRQ_ENC_VBI_CAP); | ||
845 | |||
846 | if (atomic_read(&itv->capturing) > 0) { | ||
847 | return 0; | ||
848 | } | ||
849 | |||
850 | /* Set the following Interrupt mask bits for capture */ | ||
851 | ivtv_set_irq_mask(itv, IVTV_IRQ_MASK_CAPTURE); | ||
852 | |||
853 | wake_up(&s->waitq); | ||
854 | |||
855 | return 0; | ||
856 | } | ||
857 | |||
858 | int ivtv_stop_v4l2_decode_stream(struct ivtv_stream *s, int flags, u64 pts) | ||
859 | { | ||
860 | struct ivtv *itv = s->itv; | ||
861 | |||
862 | if (s->v4l2dev == NULL) | ||
863 | return -EINVAL; | ||
864 | |||
865 | if (s->type != IVTV_DEC_STREAM_TYPE_YUV && s->type != IVTV_DEC_STREAM_TYPE_MPG) | ||
866 | return -EINVAL; | ||
867 | |||
868 | if (!test_bit(IVTV_F_S_STREAMING, &s->s_flags)) | ||
869 | return 0; | ||
870 | |||
871 | IVTV_DEBUG_INFO("Stop Decode at %llu, flags: %x\n", pts, flags); | ||
872 | |||
873 | /* Stop Decoder */ | ||
874 | if (!(flags & VIDEO_CMD_STOP_IMMEDIATELY) || pts) { | ||
875 | u32 tmp = 0; | ||
876 | |||
877 | /* Wait until the decoder is no longer running */ | ||
878 | if (pts) { | ||
879 | ivtv_vapi(itv, CX2341X_DEC_STOP_PLAYBACK, 3, | ||
880 | 0, (u32)(pts & 0xffffffff), (u32)(pts >> 32)); | ||
881 | } | ||
882 | while (1) { | ||
883 | u32 data[CX2341X_MBOX_MAX_DATA]; | ||
884 | ivtv_vapi_result(itv, data, CX2341X_DEC_GET_XFER_INFO, 0); | ||
885 | if (s->q_full.buffers + s->q_dma.buffers == 0) { | ||
886 | if (tmp == data[3]) | ||
887 | break; | ||
888 | tmp = data[3]; | ||
889 | } | ||
890 | if (ivtv_sleep_timeout(HZ/10, 1)) | ||
891 | break; | ||
892 | } | ||
893 | } | ||
894 | ivtv_vapi(itv, CX2341X_DEC_STOP_PLAYBACK, 3, flags & VIDEO_CMD_STOP_TO_BLACK, 0, 0); | ||
895 | |||
896 | /* turn off notification of dual/stereo mode change */ | ||
897 | ivtv_vapi(itv, CX2341X_DEC_SET_EVENT_NOTIFICATION, 4, 0, 0, IVTV_IRQ_DEC_AUD_MODE_CHG, -1); | ||
898 | |||
899 | ivtv_set_irq_mask(itv, IVTV_IRQ_MASK_DECODE); | ||
900 | |||
901 | clear_bit(IVTV_F_S_NEEDS_DATA, &s->s_flags); | ||
902 | clear_bit(IVTV_F_S_STREAMING, &s->s_flags); | ||
903 | ivtv_flush_queues(s); | ||
904 | |||
905 | if (!test_bit(IVTV_F_S_PASSTHROUGH, &s->s_flags)) { | ||
906 | /* disable VBI on TV-out */ | ||
907 | ivtv_disable_vbi(itv); | ||
908 | } | ||
909 | |||
910 | /* decrement decoding */ | ||
911 | atomic_dec(&itv->decoding); | ||
912 | |||
913 | set_bit(IVTV_F_I_EV_DEC_STOPPED, &itv->i_flags); | ||
914 | wake_up(&itv->event_waitq); | ||
915 | |||
916 | /* wake up wait queues */ | ||
917 | wake_up(&s->waitq); | ||
918 | |||
919 | return 0; | ||
920 | } | ||
921 | |||
922 | int ivtv_passthrough_mode(struct ivtv *itv, int enable) | ||
923 | { | ||
924 | struct ivtv_stream *yuv_stream = &itv->streams[IVTV_ENC_STREAM_TYPE_YUV]; | ||
925 | struct ivtv_stream *dec_stream = &itv->streams[IVTV_DEC_STREAM_TYPE_YUV]; | ||
926 | |||
927 | if (yuv_stream->v4l2dev == NULL || dec_stream->v4l2dev == NULL) | ||
928 | return -EINVAL; | ||
929 | |||
930 | IVTV_DEBUG_INFO("ivtv ioctl: Select passthrough mode\n"); | ||
931 | |||
932 | /* Prevent others from starting/stopping streams while we | ||
933 | initiate/terminate passthrough mode */ | ||
934 | if (enable) { | ||
935 | if (itv->output_mode == OUT_PASSTHROUGH) { | ||
936 | return 0; | ||
937 | } | ||
938 | if (ivtv_set_output_mode(itv, OUT_PASSTHROUGH) != OUT_PASSTHROUGH) | ||
939 | return -EBUSY; | ||
940 | |||
941 | /* Fully initialize stream, and then unflag init */ | ||
942 | set_bit(IVTV_F_S_PASSTHROUGH, &dec_stream->s_flags); | ||
943 | set_bit(IVTV_F_S_STREAMING, &dec_stream->s_flags); | ||
944 | |||
945 | /* Setup YUV Decoder */ | ||
946 | ivtv_setup_v4l2_decode_stream(dec_stream); | ||
947 | |||
948 | /* Start Decoder */ | ||
949 | ivtv_vapi(itv, CX2341X_DEC_START_PLAYBACK, 2, 0, 1); | ||
950 | atomic_inc(&itv->decoding); | ||
951 | |||
952 | /* Setup capture if not already done */ | ||
953 | if (atomic_read(&itv->capturing) == 0) { | ||
954 | cx2341x_update(itv, ivtv_api_func, NULL, &itv->params); | ||
955 | } | ||
956 | |||
957 | /* Start Passthrough Mode */ | ||
958 | ivtv_vapi(itv, CX2341X_ENC_START_CAPTURE, 2, 2, 11); | ||
959 | atomic_inc(&itv->capturing); | ||
960 | return 0; | ||
961 | } | ||
962 | |||
963 | if (itv->output_mode != OUT_PASSTHROUGH) | ||
964 | return 0; | ||
965 | |||
966 | /* Stop Passthrough Mode */ | ||
967 | ivtv_vapi(itv, CX2341X_ENC_STOP_CAPTURE, 3, 1, 2, 11); | ||
968 | ivtv_vapi(itv, CX2341X_DEC_STOP_PLAYBACK, 3, 1, 0, 0); | ||
969 | |||
970 | atomic_dec(&itv->capturing); | ||
971 | atomic_dec(&itv->decoding); | ||
972 | clear_bit(IVTV_F_S_PASSTHROUGH, &dec_stream->s_flags); | ||
973 | clear_bit(IVTV_F_S_STREAMING, &dec_stream->s_flags); | ||
974 | itv->output_mode = OUT_NONE; | ||
975 | |||
976 | return 0; | ||
977 | } | ||
diff --git a/drivers/media/video/ivtv/ivtv-streams.h b/drivers/media/video/ivtv/ivtv-streams.h new file mode 100644 index 000000000000..8597b75384a7 --- /dev/null +++ b/drivers/media/video/ivtv/ivtv-streams.h | |||
@@ -0,0 +1,31 @@ | |||
1 | /* | ||
2 | init/start/stop/exit stream functions | ||
3 | Copyright (C) 2003-2004 Kevin Thayer <nufan_wfk at yahoo.com> | ||
4 | Copyright (C) 2005-2007 Hans Verkuil <hverkuil@xs4all.nl> | ||
5 | |||
6 | This program is free software; you can redistribute it and/or modify | ||
7 | it under the terms of the GNU General Public License as published by | ||
8 | the Free Software Foundation; either version 2 of the License, or | ||
9 | (at your option) any later version. | ||
10 | |||
11 | This program is distributed in the hope that it will be useful, | ||
12 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
14 | GNU General Public License for more details. | ||
15 | |||
16 | You should have received a copy of the GNU General Public License | ||
17 | along with this program; if not, write to the Free Software | ||
18 | Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
19 | */ | ||
20 | |||
21 | int ivtv_streams_setup(struct ivtv *itv); | ||
22 | void ivtv_streams_cleanup(struct ivtv *itv); | ||
23 | |||
24 | /* Capture related */ | ||
25 | int ivtv_start_v4l2_encode_stream(struct ivtv_stream *s); | ||
26 | int ivtv_stop_v4l2_encode_stream(struct ivtv_stream *s, int gop_end); | ||
27 | int ivtv_start_v4l2_decode_stream(struct ivtv_stream *s, int gop_offset); | ||
28 | int ivtv_stop_v4l2_decode_stream(struct ivtv_stream *s, int flags, u64 pts); | ||
29 | |||
30 | void ivtv_stop_all_captures(struct ivtv *itv); | ||
31 | int ivtv_passthrough_mode(struct ivtv *itv, int enable); | ||
diff --git a/drivers/media/video/ivtv/ivtv-udma.c b/drivers/media/video/ivtv/ivtv-udma.c new file mode 100644 index 000000000000..bd642e1aafc3 --- /dev/null +++ b/drivers/media/video/ivtv/ivtv-udma.c | |||
@@ -0,0 +1,200 @@ | |||
1 | /* | ||
2 | User DMA | ||
3 | |||
4 | Copyright (C) 2003-2004 Kevin Thayer <nufan_wfk at yahoo.com> | ||
5 | Copyright (C) 2004 Chris Kennedy <c@groovy.org> | ||
6 | Copyright (C) 2005-2007 Hans Verkuil <hverkuil@xs4all.nl> | ||
7 | |||
8 | This program is free software; you can redistribute it and/or modify | ||
9 | it under the terms of the GNU General Public License as published by | ||
10 | the Free Software Foundation; either version 2 of the License, or | ||
11 | (at your option) any later version. | ||
12 | |||
13 | This program is distributed in the hope that it will be useful, | ||
14 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
15 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
16 | GNU General Public License for more details. | ||
17 | |||
18 | You should have received a copy of the GNU General Public License | ||
19 | along with this program; if not, write to the Free Software | ||
20 | Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
21 | */ | ||
22 | |||
23 | #include "ivtv-driver.h" | ||
24 | #include "ivtv-streams.h" | ||
25 | #include "ivtv-udma.h" | ||
26 | |||
27 | void ivtv_udma_get_page_info(struct ivtv_dma_page_info *dma_page, unsigned long first, unsigned long size) | ||
28 | { | ||
29 | dma_page->uaddr = first & PAGE_MASK; | ||
30 | dma_page->offset = first & ~PAGE_MASK; | ||
31 | dma_page->tail = 1 + ((first+size-1) & ~PAGE_MASK); | ||
32 | dma_page->first = (first & PAGE_MASK) >> PAGE_SHIFT; | ||
33 | dma_page->last = ((first+size-1) & PAGE_MASK) >> PAGE_SHIFT; | ||
34 | dma_page->page_count = dma_page->last - dma_page->first + 1; | ||
35 | if (dma_page->page_count == 1) dma_page->tail -= dma_page->offset; | ||
36 | } | ||
37 | |||
38 | int ivtv_udma_fill_sg_list (struct ivtv_user_dma *dma, struct ivtv_dma_page_info *dma_page, int map_offset) | ||
39 | { | ||
40 | int i, offset; | ||
41 | |||
42 | offset = dma_page->offset; | ||
43 | |||
44 | /* Fill SG Array with new values */ | ||
45 | for (i = 0; i < dma_page->page_count; i++) { | ||
46 | if (i == dma_page->page_count - 1) { | ||
47 | dma->SGlist[map_offset].length = dma_page->tail; | ||
48 | } | ||
49 | else { | ||
50 | dma->SGlist[map_offset].length = PAGE_SIZE - offset; | ||
51 | } | ||
52 | dma->SGlist[map_offset].offset = offset; | ||
53 | dma->SGlist[map_offset].page = dma->map[map_offset]; | ||
54 | offset = 0; | ||
55 | map_offset++; | ||
56 | } | ||
57 | return map_offset; | ||
58 | } | ||
59 | |||
60 | void ivtv_udma_fill_sg_array (struct ivtv_user_dma *dma, u32 buffer_offset, u32 buffer_offset_2, u32 split) { | ||
61 | int i; | ||
62 | struct scatterlist *sg; | ||
63 | |||
64 | for (i = 0, sg = dma->SGlist; i < dma->SG_length; i++, sg++) { | ||
65 | dma->SGarray[i].size = cpu_to_le32(sg_dma_len(sg)); | ||
66 | dma->SGarray[i].src = cpu_to_le32(sg_dma_address(sg)); | ||
67 | dma->SGarray[i].dst = cpu_to_le32(buffer_offset); | ||
68 | buffer_offset += sg_dma_len(sg); | ||
69 | |||
70 | split -= sg_dma_len(sg); | ||
71 | if (split == 0) | ||
72 | buffer_offset = buffer_offset_2; | ||
73 | } | ||
74 | } | ||
75 | |||
76 | /* User DMA Buffers */ | ||
77 | void ivtv_udma_alloc(struct ivtv *itv) | ||
78 | { | ||
79 | if (itv->udma.SG_handle == 0) { | ||
80 | /* Map DMA Page Array Buffer */ | ||
81 | itv->udma.SG_handle = pci_map_single(itv->dev, itv->udma.SGarray, | ||
82 | sizeof(itv->udma.SGarray), PCI_DMA_TODEVICE); | ||
83 | ivtv_udma_sync_for_cpu(itv); | ||
84 | } | ||
85 | } | ||
86 | |||
87 | int ivtv_udma_setup(struct ivtv *itv, unsigned long ivtv_dest_addr, | ||
88 | void __user *userbuf, int size_in_bytes) | ||
89 | { | ||
90 | struct ivtv_dma_page_info user_dma; | ||
91 | struct ivtv_user_dma *dma = &itv->udma; | ||
92 | int err; | ||
93 | |||
94 | IVTV_DEBUG_DMA("ivtv_udma_setup, dst: 0x%08x\n", (unsigned int)ivtv_dest_addr); | ||
95 | |||
96 | /* Still in USE */ | ||
97 | if (dma->SG_length || dma->page_count) { | ||
98 | IVTV_DEBUG_WARN("ivtv_udma_setup: SG_length %d page_count %d still full?\n", | ||
99 | dma->SG_length, dma->page_count); | ||
100 | return -EBUSY; | ||
101 | } | ||
102 | |||
103 | ivtv_udma_get_page_info(&user_dma, (unsigned long)userbuf, size_in_bytes); | ||
104 | |||
105 | if (user_dma.page_count <= 0) { | ||
106 | IVTV_DEBUG_WARN("ivtv_udma_setup: Error %d page_count from %d bytes %d offset\n", | ||
107 | user_dma.page_count, size_in_bytes, user_dma.offset); | ||
108 | return -EINVAL; | ||
109 | } | ||
110 | |||
111 | /* Get user pages for DMA Xfer */ | ||
112 | down_read(¤t->mm->mmap_sem); | ||
113 | err = get_user_pages(current, current->mm, | ||
114 | user_dma.uaddr, user_dma.page_count, 0, 1, dma->map, NULL); | ||
115 | up_read(¤t->mm->mmap_sem); | ||
116 | |||
117 | if (user_dma.page_count != err) { | ||
118 | IVTV_DEBUG_WARN("failed to map user pages, returned %d instead of %d\n", | ||
119 | err, user_dma.page_count); | ||
120 | return -EINVAL; | ||
121 | } | ||
122 | |||
123 | dma->page_count = user_dma.page_count; | ||
124 | |||
125 | /* Fill SG List with new values */ | ||
126 | ivtv_udma_fill_sg_list(dma, &user_dma, 0); | ||
127 | |||
128 | /* Map SG List */ | ||
129 | dma->SG_length = pci_map_sg(itv->dev, dma->SGlist, dma->page_count, PCI_DMA_TODEVICE); | ||
130 | |||
131 | /* Fill SG Array with new values */ | ||
132 | ivtv_udma_fill_sg_array (dma, ivtv_dest_addr, 0, -1); | ||
133 | |||
134 | /* Tag SG Array with Interrupt Bit */ | ||
135 | dma->SGarray[dma->SG_length - 1].size |= cpu_to_le32(0x80000000); | ||
136 | |||
137 | ivtv_udma_sync_for_device(itv); | ||
138 | return dma->page_count; | ||
139 | } | ||
140 | |||
141 | void ivtv_udma_unmap(struct ivtv *itv) | ||
142 | { | ||
143 | struct ivtv_user_dma *dma = &itv->udma; | ||
144 | int i; | ||
145 | |||
146 | IVTV_DEBUG_INFO("ivtv_unmap_user_dma\n"); | ||
147 | |||
148 | /* Nothing to free */ | ||
149 | if (dma->page_count == 0) | ||
150 | return; | ||
151 | |||
152 | /* Unmap Scatterlist */ | ||
153 | if (dma->SG_length) { | ||
154 | pci_unmap_sg(itv->dev, dma->SGlist, dma->page_count, PCI_DMA_TODEVICE); | ||
155 | dma->SG_length = 0; | ||
156 | } | ||
157 | /* sync DMA */ | ||
158 | ivtv_udma_sync_for_cpu(itv); | ||
159 | |||
160 | /* Release User Pages */ | ||
161 | for (i = 0; i < dma->page_count; i++) { | ||
162 | put_page(dma->map[i]); | ||
163 | } | ||
164 | dma->page_count = 0; | ||
165 | } | ||
166 | |||
167 | void ivtv_udma_free(struct ivtv *itv) | ||
168 | { | ||
169 | /* Unmap SG Array */ | ||
170 | if (itv->udma.SG_handle) { | ||
171 | pci_unmap_single(itv->dev, itv->udma.SG_handle, | ||
172 | sizeof(itv->udma.SGarray), PCI_DMA_TODEVICE); | ||
173 | } | ||
174 | |||
175 | /* Unmap Scatterlist */ | ||
176 | if (itv->udma.SG_length) { | ||
177 | pci_unmap_sg(itv->dev, itv->udma.SGlist, itv->udma.page_count, PCI_DMA_TODEVICE); | ||
178 | } | ||
179 | } | ||
180 | |||
181 | void ivtv_udma_start(struct ivtv *itv) | ||
182 | { | ||
183 | IVTV_DEBUG_DMA("start UDMA\n"); | ||
184 | write_reg(itv->udma.SG_handle, IVTV_REG_DECDMAADDR); | ||
185 | write_reg_sync(read_reg(IVTV_REG_DMAXFER) | 0x01, IVTV_REG_DMAXFER); | ||
186 | set_bit(IVTV_F_I_DMA, &itv->i_flags); | ||
187 | set_bit(IVTV_F_I_UDMA, &itv->i_flags); | ||
188 | } | ||
189 | |||
190 | void ivtv_udma_prepare(struct ivtv *itv) | ||
191 | { | ||
192 | unsigned long flags; | ||
193 | |||
194 | spin_lock_irqsave(&itv->dma_reg_lock, flags); | ||
195 | if (!test_bit(IVTV_F_I_DMA, &itv->i_flags)) | ||
196 | ivtv_udma_start(itv); | ||
197 | else | ||
198 | set_bit(IVTV_F_I_UDMA_PENDING, &itv->i_flags); | ||
199 | spin_unlock_irqrestore(&itv->dma_reg_lock, flags); | ||
200 | } | ||
diff --git a/drivers/media/video/ivtv/ivtv-udma.h b/drivers/media/video/ivtv/ivtv-udma.h new file mode 100644 index 000000000000..e131bccedec0 --- /dev/null +++ b/drivers/media/video/ivtv/ivtv-udma.h | |||
@@ -0,0 +1,43 @@ | |||
1 | /* | ||
2 | Copyright (C) 2003-2004 Kevin Thayer <nufan_wfk at yahoo.com> | ||
3 | Copyright (C) 2004 Chris Kennedy <c@groovy.org> | ||
4 | Copyright (C) 2006-2007 Hans Verkuil <hverkuil@xs4all.nl> | ||
5 | |||
6 | This program is free software; you can redistribute it and/or modify | ||
7 | it under the terms of the GNU General Public License as published by | ||
8 | the Free Software Foundation; either version 2 of the License, or | ||
9 | (at your option) any later version. | ||
10 | |||
11 | This program is distributed in the hope that it will be useful, | ||
12 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
14 | GNU General Public License for more details. | ||
15 | |||
16 | You should have received a copy of the GNU General Public License | ||
17 | along with this program; if not, write to the Free Software | ||
18 | Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
19 | */ | ||
20 | |||
21 | /* User DMA functions */ | ||
22 | void ivtv_udma_get_page_info(struct ivtv_dma_page_info *dma_page, unsigned long first, unsigned long size); | ||
23 | int ivtv_udma_fill_sg_list(struct ivtv_user_dma *dma, struct ivtv_dma_page_info *dma_page, int map_offset); | ||
24 | void ivtv_udma_fill_sg_array(struct ivtv_user_dma *dma, u32 buffer_offset, u32 buffer_offset_2, u32 split); | ||
25 | int ivtv_udma_setup(struct ivtv *itv, unsigned long ivtv_dest_addr, | ||
26 | void __user *userbuf, int size_in_bytes); | ||
27 | void ivtv_udma_unmap(struct ivtv *itv); | ||
28 | void ivtv_udma_free(struct ivtv *itv); | ||
29 | void ivtv_udma_alloc(struct ivtv *itv); | ||
30 | void ivtv_udma_prepare(struct ivtv *itv); | ||
31 | void ivtv_udma_start(struct ivtv *itv); | ||
32 | |||
33 | static inline void ivtv_udma_sync_for_device(struct ivtv *itv) | ||
34 | { | ||
35 | pci_dma_sync_single_for_device((struct pci_dev *)itv->dev, itv->udma.SG_handle, | ||
36 | sizeof(itv->udma.SGarray), PCI_DMA_TODEVICE); | ||
37 | } | ||
38 | |||
39 | static inline void ivtv_udma_sync_for_cpu(struct ivtv *itv) | ||
40 | { | ||
41 | pci_dma_sync_single_for_cpu((struct pci_dev *)itv->dev, itv->udma.SG_handle, | ||
42 | sizeof(itv->udma.SGarray), PCI_DMA_TODEVICE); | ||
43 | } | ||
diff --git a/drivers/media/video/ivtv/ivtv-vbi.c b/drivers/media/video/ivtv/ivtv-vbi.c new file mode 100644 index 000000000000..5efa5a867818 --- /dev/null +++ b/drivers/media/video/ivtv/ivtv-vbi.c | |||
@@ -0,0 +1,538 @@ | |||
1 | /* | ||
2 | Vertical Blank Interval support functions | ||
3 | Copyright (C) 2004-2007 Hans Verkuil <hverkuil@xs4all.nl> | ||
4 | |||
5 | This program is free software; you can redistribute it and/or modify | ||
6 | it under the terms of the GNU General Public License as published by | ||
7 | the Free Software Foundation; either version 2 of the License, or | ||
8 | (at your option) any later version. | ||
9 | |||
10 | This program is distributed in the hope that it will be useful, | ||
11 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
13 | GNU General Public License for more details. | ||
14 | |||
15 | You should have received a copy of the GNU General Public License | ||
16 | along with this program; if not, write to the Free Software | ||
17 | Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
18 | */ | ||
19 | |||
20 | #include "ivtv-driver.h" | ||
21 | #include "ivtv-video.h" | ||
22 | #include "ivtv-vbi.h" | ||
23 | #include "ivtv-ioctl.h" | ||
24 | #include "ivtv-queue.h" | ||
25 | |||
26 | static int odd_parity(u8 c) | ||
27 | { | ||
28 | c ^= (c >> 4); | ||
29 | c ^= (c >> 2); | ||
30 | c ^= (c >> 1); | ||
31 | |||
32 | return c & 1; | ||
33 | } | ||
34 | |||
35 | static void passthrough_vbi_data(struct ivtv *itv, int cnt) | ||
36 | { | ||
37 | int wss = 0; | ||
38 | u8 cc[4] = { 0x80, 0x80, 0x80, 0x80 }; | ||
39 | u8 vps[13]; | ||
40 | int found_cc = 0; | ||
41 | int found_wss = 0; | ||
42 | int found_vps = 0; | ||
43 | int cc_pos = itv->vbi.cc_pos; | ||
44 | int i; | ||
45 | |||
46 | for (i = 0; i < cnt; i++) { | ||
47 | struct v4l2_sliced_vbi_data *d = itv->vbi.sliced_dec_data + i; | ||
48 | |||
49 | if (d->id == V4L2_SLICED_CAPTION_525 && d->line == 21) { | ||
50 | found_cc = 1; | ||
51 | if (d->field) { | ||
52 | cc[2] = d->data[0]; | ||
53 | cc[3] = d->data[1]; | ||
54 | } else { | ||
55 | cc[0] = d->data[0]; | ||
56 | cc[1] = d->data[1]; | ||
57 | } | ||
58 | } | ||
59 | else if (d->id == V4L2_SLICED_VPS && d->line == 16 && d->field == 0) { | ||
60 | memcpy(vps, d->data, sizeof(vps)); | ||
61 | found_vps = 1; | ||
62 | } | ||
63 | else if (d->id == V4L2_SLICED_WSS_625 && d->line == 23 && d->field == 0) { | ||
64 | wss = d->data[0] | d->data[1] << 8; | ||
65 | found_wss = 1; | ||
66 | } | ||
67 | } | ||
68 | |||
69 | if (itv->vbi.wss_found != found_wss || itv->vbi.wss != wss) { | ||
70 | itv->vbi.wss = wss; | ||
71 | itv->vbi.wss_found = found_wss; | ||
72 | set_bit(IVTV_F_I_UPDATE_WSS, &itv->i_flags); | ||
73 | } | ||
74 | |||
75 | if (found_vps || itv->vbi.vps_found) { | ||
76 | itv->vbi.vps[0] = vps[2]; | ||
77 | itv->vbi.vps[1] = vps[8]; | ||
78 | itv->vbi.vps[2] = vps[9]; | ||
79 | itv->vbi.vps[3] = vps[10]; | ||
80 | itv->vbi.vps[4] = vps[11]; | ||
81 | itv->vbi.vps_found = found_vps; | ||
82 | set_bit(IVTV_F_I_UPDATE_VPS, &itv->i_flags); | ||
83 | } | ||
84 | |||
85 | if (found_cc && cc_pos < sizeof(itv->vbi.cc_data_even)) { | ||
86 | itv->vbi.cc_data_odd[cc_pos] = cc[0]; | ||
87 | itv->vbi.cc_data_odd[cc_pos + 1] = cc[1]; | ||
88 | itv->vbi.cc_data_even[cc_pos] = cc[2]; | ||
89 | itv->vbi.cc_data_even[cc_pos + 1] = cc[3]; | ||
90 | itv->vbi.cc_pos = cc_pos + 2; | ||
91 | set_bit(IVTV_F_I_UPDATE_CC, &itv->i_flags); | ||
92 | } | ||
93 | } | ||
94 | |||
95 | static void copy_vbi_data(struct ivtv *itv, int lines, u32 pts_stamp) | ||
96 | { | ||
97 | int line = 0; | ||
98 | int i; | ||
99 | u32 linemask[2] = { 0, 0 }; | ||
100 | unsigned short size; | ||
101 | static const u8 mpeg_hdr_data[] = { | ||
102 | 0x00, 0x00, 0x01, 0xba, 0x44, 0x00, 0x0c, 0x66, | ||
103 | 0x24, 0x01, 0x01, 0xd1, 0xd3, 0xfa, 0xff, 0xff, | ||
104 | 0x00, 0x00, 0x01, 0xbd, 0x00, 0x1a, 0x84, 0x80, | ||
105 | 0x07, 0x21, 0x00, 0x5d, 0x63, 0xa7, 0xff, 0xff | ||
106 | }; | ||
107 | const int sd = sizeof(mpeg_hdr_data); /* start of vbi data */ | ||
108 | int idx = itv->vbi.frame % IVTV_VBI_FRAMES; | ||
109 | u8 *dst = &itv->vbi.sliced_mpeg_data[idx][0]; | ||
110 | |||
111 | for (i = 0; i < lines; i++) { | ||
112 | int f, l; | ||
113 | |||
114 | if (itv->vbi.sliced_data[i].id == 0) | ||
115 | continue; | ||
116 | |||
117 | l = itv->vbi.sliced_data[i].line - 6; | ||
118 | f = itv->vbi.sliced_data[i].field; | ||
119 | if (f) | ||
120 | l += 18; | ||
121 | if (l < 32) | ||
122 | linemask[0] |= (1 << l); | ||
123 | else | ||
124 | linemask[1] |= (1 << (l - 32)); | ||
125 | dst[sd + 12 + line * 43] = service2vbi(itv->vbi.sliced_data[i].id); | ||
126 | memcpy(dst + sd + 12 + line * 43 + 1, itv->vbi.sliced_data[i].data, 42); | ||
127 | line++; | ||
128 | } | ||
129 | memcpy(dst, mpeg_hdr_data, sizeof(mpeg_hdr_data)); | ||
130 | if (line == 36) { | ||
131 | /* All lines are used, so there is no space for the linemask | ||
132 | (the max size of the VBI data is 36 * 43 + 4 bytes). | ||
133 | So in this case we use the magic number 'ITV0'. */ | ||
134 | memcpy(dst + sd, "ITV0", 4); | ||
135 | memcpy(dst + sd + 4, dst + sd + 12, line * 43); | ||
136 | size = 4 + ((43 * line + 3) & ~3); | ||
137 | } else { | ||
138 | memcpy(dst + sd, "itv0", 4); | ||
139 | memcpy(dst + sd + 4, &linemask[0], 8); | ||
140 | size = 12 + ((43 * line + 3) & ~3); | ||
141 | } | ||
142 | dst[4+16] = (size + 10) >> 8; | ||
143 | dst[5+16] = (size + 10) & 0xff; | ||
144 | dst[9+16] = 0x21 | ((pts_stamp >> 29) & 0x6); | ||
145 | dst[10+16] = (pts_stamp >> 22) & 0xff; | ||
146 | dst[11+16] = 1 | ((pts_stamp >> 14) & 0xff); | ||
147 | dst[12+16] = (pts_stamp >> 7) & 0xff; | ||
148 | dst[13+16] = 1 | ((pts_stamp & 0x7f) << 1); | ||
149 | itv->vbi.sliced_mpeg_size[idx] = sd + size; | ||
150 | } | ||
151 | |||
152 | static int ivtv_convert_ivtv_vbi(struct ivtv *itv, u8 *p) | ||
153 | { | ||
154 | u32 linemask[2]; | ||
155 | int i, l, id2; | ||
156 | int line = 0; | ||
157 | |||
158 | if (!memcmp(p, "itv0", 4)) { | ||
159 | memcpy(linemask, p + 4, 8); | ||
160 | p += 12; | ||
161 | } else if (!memcmp(p, "ITV0", 4)) { | ||
162 | linemask[0] = 0xffffffff; | ||
163 | linemask[1] = 0xf; | ||
164 | p += 4; | ||
165 | } else { | ||
166 | /* unknown VBI data stream */ | ||
167 | return 0; | ||
168 | } | ||
169 | for (i = 0; i < 36; i++) { | ||
170 | int err = 0; | ||
171 | |||
172 | if (i < 32 && !(linemask[0] & (1 << i))) | ||
173 | continue; | ||
174 | if (i >= 32 && !(linemask[1] & (1 << (i - 32)))) | ||
175 | continue; | ||
176 | id2 = *p & 0xf; | ||
177 | switch (id2) { | ||
178 | case IVTV_SLICED_TYPE_TELETEXT_B: | ||
179 | id2 = V4L2_SLICED_TELETEXT_B; | ||
180 | break; | ||
181 | case IVTV_SLICED_TYPE_CAPTION_525: | ||
182 | id2 = V4L2_SLICED_CAPTION_525; | ||
183 | err = !odd_parity(p[1]) || !odd_parity(p[2]); | ||
184 | break; | ||
185 | case IVTV_SLICED_TYPE_VPS: | ||
186 | id2 = V4L2_SLICED_VPS; | ||
187 | break; | ||
188 | case IVTV_SLICED_TYPE_WSS_625: | ||
189 | id2 = V4L2_SLICED_WSS_625; | ||
190 | break; | ||
191 | default: | ||
192 | id2 = 0; | ||
193 | break; | ||
194 | } | ||
195 | if (err == 0) { | ||
196 | l = (i < 18) ? i + 6 : i - 18 + 6; | ||
197 | itv->vbi.sliced_dec_data[line].line = l; | ||
198 | itv->vbi.sliced_dec_data[line].field = i >= 18; | ||
199 | itv->vbi.sliced_dec_data[line].id = id2; | ||
200 | memcpy(itv->vbi.sliced_dec_data[line].data, p + 1, 42); | ||
201 | line++; | ||
202 | } | ||
203 | p += 43; | ||
204 | } | ||
205 | while (line < 36) { | ||
206 | itv->vbi.sliced_dec_data[line].id = 0; | ||
207 | itv->vbi.sliced_dec_data[line].line = 0; | ||
208 | itv->vbi.sliced_dec_data[line].field = 0; | ||
209 | line++; | ||
210 | } | ||
211 | return line * sizeof(itv->vbi.sliced_dec_data[0]); | ||
212 | } | ||
213 | |||
214 | ssize_t ivtv_write_vbi(struct ivtv *itv, const char __user *ubuf, size_t count) | ||
215 | { | ||
216 | /* Should be a __user pointer, but sparse doesn't parse this bit correctly. */ | ||
217 | const struct v4l2_sliced_vbi_data *p = (const struct v4l2_sliced_vbi_data *)ubuf; | ||
218 | u8 cc[4] = { 0x80, 0x80, 0x80, 0x80 }; | ||
219 | int found_cc = 0; | ||
220 | int cc_pos = itv->vbi.cc_pos; | ||
221 | |||
222 | if (itv->vbi.service_set_out == 0) | ||
223 | return -EPERM; | ||
224 | |||
225 | while (count >= sizeof(struct v4l2_sliced_vbi_data)) { | ||
226 | switch (p->id) { | ||
227 | case V4L2_SLICED_CAPTION_525: | ||
228 | if (p->id == V4L2_SLICED_CAPTION_525 && | ||
229 | p->line == 21 && | ||
230 | (itv->vbi.service_set_out & | ||
231 | V4L2_SLICED_CAPTION_525) == 0) { | ||
232 | break; | ||
233 | } | ||
234 | found_cc = 1; | ||
235 | if (p->field) { | ||
236 | cc[2] = p->data[0]; | ||
237 | cc[3] = p->data[1]; | ||
238 | } else { | ||
239 | cc[0] = p->data[0]; | ||
240 | cc[1] = p->data[1]; | ||
241 | } | ||
242 | break; | ||
243 | |||
244 | case V4L2_SLICED_VPS: | ||
245 | if (p->line == 16 && p->field == 0 && | ||
246 | (itv->vbi.service_set_out & V4L2_SLICED_VPS)) { | ||
247 | itv->vbi.vps[0] = p->data[2]; | ||
248 | itv->vbi.vps[1] = p->data[8]; | ||
249 | itv->vbi.vps[2] = p->data[9]; | ||
250 | itv->vbi.vps[3] = p->data[10]; | ||
251 | itv->vbi.vps[4] = p->data[11]; | ||
252 | itv->vbi.vps_found = 1; | ||
253 | set_bit(IVTV_F_I_UPDATE_VPS, &itv->i_flags); | ||
254 | } | ||
255 | break; | ||
256 | |||
257 | case V4L2_SLICED_WSS_625: | ||
258 | if (p->line == 23 && p->field == 0 && | ||
259 | (itv->vbi.service_set_out & V4L2_SLICED_WSS_625)) { | ||
260 | /* No lock needed for WSS */ | ||
261 | itv->vbi.wss = p->data[0] | (p->data[1] << 8); | ||
262 | itv->vbi.wss_found = 1; | ||
263 | set_bit(IVTV_F_I_UPDATE_WSS, &itv->i_flags); | ||
264 | } | ||
265 | break; | ||
266 | |||
267 | default: | ||
268 | break; | ||
269 | } | ||
270 | count -= sizeof(*p); | ||
271 | p++; | ||
272 | } | ||
273 | |||
274 | if (found_cc && cc_pos < sizeof(itv->vbi.cc_data_even)) { | ||
275 | itv->vbi.cc_data_odd[cc_pos] = cc[0]; | ||
276 | itv->vbi.cc_data_odd[cc_pos + 1] = cc[1]; | ||
277 | itv->vbi.cc_data_even[cc_pos] = cc[2]; | ||
278 | itv->vbi.cc_data_even[cc_pos + 1] = cc[3]; | ||
279 | itv->vbi.cc_pos = cc_pos + 2; | ||
280 | set_bit(IVTV_F_I_UPDATE_CC, &itv->i_flags); | ||
281 | } | ||
282 | |||
283 | return (const char __user *)p - ubuf; | ||
284 | } | ||
285 | |||
286 | /* Compress raw VBI format, removes leading SAV codes and surplus space after the | ||
287 | field. | ||
288 | Returns new compressed size. */ | ||
289 | static u32 compress_raw_buf(struct ivtv *itv, u8 *buf, u32 size) | ||
290 | { | ||
291 | u32 line_size = itv->vbi.raw_decoder_line_size; | ||
292 | u32 lines = itv->vbi.count; | ||
293 | u8 sav1 = itv->vbi.raw_decoder_sav_odd_field; | ||
294 | u8 sav2 = itv->vbi.raw_decoder_sav_even_field; | ||
295 | u8 *q = buf; | ||
296 | u8 *p; | ||
297 | int i; | ||
298 | |||
299 | for (i = 0; i < lines; i++) { | ||
300 | p = buf + i * line_size; | ||
301 | |||
302 | /* Look for SAV code */ | ||
303 | if (p[0] != 0xff || p[1] || p[2] || (p[3] != sav1 && p[3] != sav2)) { | ||
304 | break; | ||
305 | } | ||
306 | memcpy(q, p + 4, line_size - 4); | ||
307 | q += line_size - 4; | ||
308 | } | ||
309 | return lines * (line_size - 4); | ||
310 | } | ||
311 | |||
312 | |||
313 | /* Compressed VBI format, all found sliced blocks put next to one another | ||
314 | Returns new compressed size */ | ||
315 | static u32 compress_sliced_buf(struct ivtv *itv, u32 line, u8 *buf, u32 size, u8 sav) | ||
316 | { | ||
317 | u32 line_size = itv->vbi.sliced_decoder_line_size; | ||
318 | struct v4l2_decode_vbi_line vbi; | ||
319 | int i; | ||
320 | |||
321 | /* find the first valid line */ | ||
322 | for (i = 0; i < size; i++, buf++) { | ||
323 | if (buf[0] == 0xff && !buf[1] && !buf[2] && buf[3] == sav) | ||
324 | break; | ||
325 | } | ||
326 | |||
327 | size -= i; | ||
328 | if (size < line_size) { | ||
329 | return line; | ||
330 | } | ||
331 | for (i = 0; i < size / line_size; i++) { | ||
332 | u8 *p = buf + i * line_size; | ||
333 | |||
334 | /* Look for SAV code */ | ||
335 | if (p[0] != 0xff || p[1] || p[2] || p[3] != sav) { | ||
336 | continue; | ||
337 | } | ||
338 | vbi.p = p + 4; | ||
339 | itv->video_dec_func(itv, VIDIOC_INT_DECODE_VBI_LINE, &vbi); | ||
340 | if (vbi.type) { | ||
341 | itv->vbi.sliced_data[line].id = vbi.type; | ||
342 | itv->vbi.sliced_data[line].field = vbi.is_second_field; | ||
343 | itv->vbi.sliced_data[line].line = vbi.line; | ||
344 | memcpy(itv->vbi.sliced_data[line].data, vbi.p, 42); | ||
345 | line++; | ||
346 | } | ||
347 | } | ||
348 | return line; | ||
349 | } | ||
350 | |||
351 | void ivtv_process_vbi_data(struct ivtv *itv, struct ivtv_buffer *buf, | ||
352 | u64 pts_stamp, int streamtype) | ||
353 | { | ||
354 | u8 *p = (u8 *) buf->buf; | ||
355 | u32 size = buf->bytesused; | ||
356 | int y; | ||
357 | |||
358 | /* Raw VBI data */ | ||
359 | if (streamtype == IVTV_ENC_STREAM_TYPE_VBI && itv->vbi.sliced_in->service_set == 0) { | ||
360 | u8 type; | ||
361 | |||
362 | ivtv_buf_swap(buf); | ||
363 | |||
364 | type = p[3]; | ||
365 | |||
366 | size = buf->bytesused = compress_raw_buf(itv, p, size); | ||
367 | |||
368 | /* second field of the frame? */ | ||
369 | if (type == itv->vbi.raw_decoder_sav_even_field) { | ||
370 | /* Dirty hack needed for backwards | ||
371 | compatibility of old VBI software. */ | ||
372 | p += size - 4; | ||
373 | memcpy(p, &itv->vbi.frame, 4); | ||
374 | itv->vbi.frame++; | ||
375 | } | ||
376 | return; | ||
377 | } | ||
378 | |||
379 | /* Sliced VBI data with data insertion */ | ||
380 | if (streamtype == IVTV_ENC_STREAM_TYPE_VBI) { | ||
381 | int lines; | ||
382 | |||
383 | ivtv_buf_swap(buf); | ||
384 | |||
385 | /* first field */ | ||
386 | lines = compress_sliced_buf(itv, 0, p, size / 2, | ||
387 | itv->vbi.sliced_decoder_sav_odd_field); | ||
388 | /* second field */ | ||
389 | /* experimentation shows that the second half does not always begin | ||
390 | at the exact address. So start a bit earlier (hence 32). */ | ||
391 | lines = compress_sliced_buf(itv, lines, p + size / 2 - 32, size / 2 + 32, | ||
392 | itv->vbi.sliced_decoder_sav_even_field); | ||
393 | /* always return at least one empty line */ | ||
394 | if (lines == 0) { | ||
395 | itv->vbi.sliced_data[0].id = 0; | ||
396 | itv->vbi.sliced_data[0].line = 0; | ||
397 | itv->vbi.sliced_data[0].field = 0; | ||
398 | lines = 1; | ||
399 | } | ||
400 | buf->bytesused = size = lines * sizeof(itv->vbi.sliced_data[0]); | ||
401 | memcpy(p, &itv->vbi.sliced_data[0], size); | ||
402 | |||
403 | if (itv->vbi.insert_mpeg) { | ||
404 | copy_vbi_data(itv, lines, pts_stamp); | ||
405 | } | ||
406 | itv->vbi.frame++; | ||
407 | return; | ||
408 | } | ||
409 | |||
410 | /* Sliced VBI re-inserted from an MPEG stream */ | ||
411 | if (streamtype == IVTV_DEC_STREAM_TYPE_VBI) { | ||
412 | /* If the size is not 4-byte aligned, then the starting address | ||
413 | for the swapping is also shifted. After swapping the data the | ||
414 | real start address of the VBI data is exactly 4 bytes after the | ||
415 | original start. It's a bit fiddly but it works like a charm. | ||
416 | Non-4-byte alignment happens when an lseek is done on the input | ||
417 | mpeg file to a non-4-byte aligned position. So on arrival here | ||
418 | the VBI data is also non-4-byte aligned. */ | ||
419 | int offset = size & 3; | ||
420 | int cnt; | ||
421 | |||
422 | if (offset) { | ||
423 | p += 4 - offset; | ||
424 | } | ||
425 | /* Swap Buffer */ | ||
426 | for (y = 0; y < size; y += 4) { | ||
427 | swab32s((u32 *)(p + y)); | ||
428 | } | ||
429 | |||
430 | cnt = ivtv_convert_ivtv_vbi(itv, p + offset); | ||
431 | memcpy(buf->buf, itv->vbi.sliced_dec_data, cnt); | ||
432 | buf->bytesused = cnt; | ||
433 | |||
434 | passthrough_vbi_data(itv, cnt / sizeof(itv->vbi.sliced_dec_data[0])); | ||
435 | return; | ||
436 | } | ||
437 | } | ||
438 | |||
439 | void ivtv_disable_vbi(struct ivtv *itv) | ||
440 | { | ||
441 | clear_bit(IVTV_F_I_UPDATE_WSS, &itv->i_flags); | ||
442 | clear_bit(IVTV_F_I_UPDATE_VPS, &itv->i_flags); | ||
443 | clear_bit(IVTV_F_I_UPDATE_CC, &itv->i_flags); | ||
444 | ivtv_set_wss(itv, 0, 0); | ||
445 | ivtv_set_cc(itv, 0, 0, 0, 0, 0); | ||
446 | ivtv_set_vps(itv, 0, 0, 0, 0, 0, 0); | ||
447 | itv->vbi.vps_found = itv->vbi.wss_found = 0; | ||
448 | itv->vbi.wss = 0; | ||
449 | itv->vbi.cc_pos = 0; | ||
450 | } | ||
451 | |||
452 | |||
453 | void vbi_work_handler(struct ivtv *itv) | ||
454 | { | ||
455 | struct v4l2_sliced_vbi_data data; | ||
456 | |||
457 | /* Lock */ | ||
458 | if (itv->output_mode == OUT_PASSTHROUGH) { | ||
459 | /* Note: currently only the saa7115 is used in a PVR350, | ||
460 | so these commands are for now saa7115 specific. */ | ||
461 | if (itv->is_50hz) { | ||
462 | data.id = V4L2_SLICED_WSS_625; | ||
463 | data.field = 0; | ||
464 | |||
465 | if (itv->video_dec_func(itv, VIDIOC_INT_G_VBI_DATA, &data) == 0) { | ||
466 | ivtv_set_wss(itv, 1, data.data[0] & 0xf); | ||
467 | itv->vbi.wss_no_update = 0; | ||
468 | } else if (itv->vbi.wss_no_update == 4) { | ||
469 | ivtv_set_wss(itv, 1, 0x8); /* 4x3 full format */ | ||
470 | } else { | ||
471 | itv->vbi.wss_no_update++; | ||
472 | } | ||
473 | } | ||
474 | else { | ||
475 | u8 c1 = 0, c2 = 0, c3 = 0, c4 = 0; | ||
476 | int mode = 0; | ||
477 | |||
478 | data.id = V4L2_SLICED_CAPTION_525; | ||
479 | data.field = 0; | ||
480 | if (itv->video_dec_func(itv, VIDIOC_INT_G_VBI_DATA, &data) == 0) { | ||
481 | mode |= 1; | ||
482 | c1 = data.data[0]; | ||
483 | c2 = data.data[1]; | ||
484 | } | ||
485 | data.field = 1; | ||
486 | if (itv->video_dec_func(itv, VIDIOC_INT_G_VBI_DATA, &data) == 0) { | ||
487 | mode |= 2; | ||
488 | c3 = data.data[0]; | ||
489 | c4 = data.data[1]; | ||
490 | } | ||
491 | if (mode) { | ||
492 | itv->vbi.cc_no_update = 0; | ||
493 | ivtv_set_cc(itv, mode, c1, c2, c3, c4); | ||
494 | } else if (itv->vbi.cc_no_update == 4) { | ||
495 | ivtv_set_cc(itv, 0, 0, 0, 0, 0); | ||
496 | } else { | ||
497 | itv->vbi.cc_no_update++; | ||
498 | } | ||
499 | } | ||
500 | return; | ||
501 | } | ||
502 | |||
503 | if (test_and_clear_bit(IVTV_F_I_UPDATE_WSS, &itv->i_flags)) { | ||
504 | /* Lock */ | ||
505 | ivtv_set_wss(itv, itv->vbi.wss_found, itv->vbi.wss & 0xf); | ||
506 | } | ||
507 | |||
508 | if (test_and_clear_bit(IVTV_F_I_UPDATE_CC, &itv->i_flags)) { | ||
509 | if (itv->vbi.cc_pos == 0) { | ||
510 | ivtv_set_cc(itv, 3, 0x80, 0x80, 0x80, 0x80); | ||
511 | } | ||
512 | while (itv->vbi.cc_pos) { | ||
513 | u8 cc_odd0 = itv->vbi.cc_data_odd[0]; | ||
514 | u8 cc_odd1 = itv->vbi.cc_data_odd[1]; | ||
515 | u8 cc_even0 = itv->vbi.cc_data_even[0]; | ||
516 | u8 cc_even1 = itv->vbi.cc_data_even[1]; | ||
517 | |||
518 | memcpy(itv->vbi.cc_data_odd, itv->vbi.cc_data_odd + 2, sizeof(itv->vbi.cc_data_odd) - 2); | ||
519 | memcpy(itv->vbi.cc_data_even, itv->vbi.cc_data_even + 2, sizeof(itv->vbi.cc_data_even) - 2); | ||
520 | itv->vbi.cc_pos -= 2; | ||
521 | if (itv->vbi.cc_pos && cc_odd0 == 0x80 && cc_odd1 == 0x80) | ||
522 | continue; | ||
523 | |||
524 | /* Send to Saa7127 */ | ||
525 | ivtv_set_cc(itv, 3, cc_odd0, cc_odd1, cc_even0, cc_even1); | ||
526 | if (itv->vbi.cc_pos == 0) | ||
527 | set_bit(IVTV_F_I_UPDATE_CC, &itv->i_flags); | ||
528 | break; | ||
529 | } | ||
530 | } | ||
531 | |||
532 | if (test_and_clear_bit(IVTV_F_I_UPDATE_VPS, &itv->i_flags)) { | ||
533 | /* Lock */ | ||
534 | ivtv_set_vps(itv, itv->vbi.vps_found, | ||
535 | itv->vbi.vps[0], itv->vbi.vps[1], | ||
536 | itv->vbi.vps[2], itv->vbi.vps[3], itv->vbi.vps[4]); | ||
537 | } | ||
538 | } | ||
diff --git a/drivers/media/video/ivtv/ivtv-vbi.h b/drivers/media/video/ivtv/ivtv-vbi.h new file mode 100644 index 000000000000..cdaea697b3ec --- /dev/null +++ b/drivers/media/video/ivtv/ivtv-vbi.h | |||
@@ -0,0 +1,26 @@ | |||
1 | /* | ||
2 | Vertical Blank Interval support functions | ||
3 | Copyright (C) 2004-2007 Hans Verkuil <hverkuil@xs4all.nl> | ||
4 | |||
5 | This program is free software; you can redistribute it and/or modify | ||
6 | it under the terms of the GNU General Public License as published by | ||
7 | the Free Software Foundation; either version 2 of the License, or | ||
8 | (at your option) any later version. | ||
9 | |||
10 | This program is distributed in the hope that it will be useful, | ||
11 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
13 | GNU General Public License for more details. | ||
14 | |||
15 | You should have received a copy of the GNU General Public License | ||
16 | along with this program; if not, write to the Free Software | ||
17 | Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
18 | */ | ||
19 | |||
20 | ssize_t ivtv_write_vbi(struct ivtv *itv, const char __user *ubuf, size_t count); | ||
21 | void ivtv_process_vbi_data(struct ivtv *itv, struct ivtv_buffer *buf, | ||
22 | u64 pts_stamp, int streamtype); | ||
23 | int ivtv_used_line(struct ivtv *itv, int line, int field); | ||
24 | void ivtv_disable_vbi(struct ivtv *itv); | ||
25 | void ivtv_set_vbi(unsigned long arg); | ||
26 | void vbi_work_handler(struct ivtv *itv); | ||
diff --git a/drivers/media/video/ivtv/ivtv-version.h b/drivers/media/video/ivtv/ivtv-version.h new file mode 100644 index 000000000000..85530a3cd369 --- /dev/null +++ b/drivers/media/video/ivtv/ivtv-version.h | |||
@@ -0,0 +1,26 @@ | |||
1 | /* | ||
2 | ivtv driver version information | ||
3 | Copyright (C) 2005-2007 Hans Verkuil <hverkuil@xs4all.nl> | ||
4 | |||
5 | This program is free software; you can redistribute it and/or modify | ||
6 | it under the terms of the GNU General Public License as published by | ||
7 | the Free Software Foundation; either version 2 of the License, or | ||
8 | (at your option) any later version. | ||
9 | |||
10 | This program is distributed in the hope that it will be useful, | ||
11 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
13 | GNU General Public License for more details. | ||
14 | |||
15 | You should have received a copy of the GNU General Public License | ||
16 | along with this program; if not, write to the Free Software | ||
17 | Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
18 | */ | ||
19 | |||
20 | #define IVTV_DRIVER_NAME "ivtv" | ||
21 | #define IVTV_DRIVER_VERSION_MAJOR 1 | ||
22 | #define IVTV_DRIVER_VERSION_MINOR 0 | ||
23 | #define IVTV_DRIVER_VERSION_PATCHLEVEL 0 | ||
24 | |||
25 | #define IVTV_VERSION __stringify(IVTV_DRIVER_VERSION_MAJOR) "." __stringify(IVTV_DRIVER_VERSION_MINOR) "." __stringify(IVTV_DRIVER_VERSION_PATCHLEVEL) | ||
26 | #define IVTV_DRIVER_VERSION KERNEL_VERSION(IVTV_DRIVER_VERSION_MAJOR,IVTV_DRIVER_VERSION_MINOR,IVTV_DRIVER_VERSION_PATCHLEVEL) | ||
diff --git a/drivers/media/video/ivtv/ivtv-video.c b/drivers/media/video/ivtv/ivtv-video.c new file mode 100644 index 000000000000..5858b197d510 --- /dev/null +++ b/drivers/media/video/ivtv/ivtv-video.c | |||
@@ -0,0 +1,142 @@ | |||
1 | /* | ||
2 | saa7127 interface functions | ||
3 | Copyright (C) 2004-2007 Hans Verkuil <hverkuil@xs4all.nl> | ||
4 | |||
5 | This program is free software; you can redistribute it and/or modify | ||
6 | it under the terms of the GNU General Public License as published by | ||
7 | the Free Software Foundation; either version 2 of the License, or | ||
8 | (at your option) any later version. | ||
9 | |||
10 | This program is distributed in the hope that it will be useful, | ||
11 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
13 | GNU General Public License for more details. | ||
14 | |||
15 | You should have received a copy of the GNU General Public License | ||
16 | along with this program; if not, write to the Free Software | ||
17 | Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
18 | */ | ||
19 | |||
20 | #include "ivtv-driver.h" | ||
21 | #include "ivtv-video.h" | ||
22 | #include "ivtv-i2c.h" | ||
23 | #include "ivtv-gpio.h" | ||
24 | #include "ivtv-cards.h" | ||
25 | #include <media/upd64031a.h> | ||
26 | #include <media/upd64083.h> | ||
27 | |||
28 | void ivtv_set_vps(struct ivtv *itv, int enabled, u8 vps1, u8 vps2, u8 vps3, | ||
29 | u8 vps4, u8 vps5) | ||
30 | { | ||
31 | struct v4l2_sliced_vbi_data data; | ||
32 | |||
33 | if (!(itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT)) | ||
34 | return; | ||
35 | data.id = V4L2_SLICED_VPS; | ||
36 | data.field = 0; | ||
37 | data.line = enabled ? 16 : 0; | ||
38 | data.data[4] = vps1; | ||
39 | data.data[10] = vps2; | ||
40 | data.data[11] = vps3; | ||
41 | data.data[12] = vps4; | ||
42 | data.data[13] = vps5; | ||
43 | ivtv_saa7127(itv, VIDIOC_INT_S_VBI_DATA, &data); | ||
44 | } | ||
45 | |||
46 | void ivtv_set_cc(struct ivtv *itv, int mode, u8 cc1, u8 cc2, u8 cc3, u8 cc4) | ||
47 | { | ||
48 | struct v4l2_sliced_vbi_data data; | ||
49 | |||
50 | if (!(itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT)) | ||
51 | return; | ||
52 | data.id = V4L2_SLICED_CAPTION_525; | ||
53 | data.field = 0; | ||
54 | data.line = (mode & 1) ? 21 : 0; | ||
55 | data.data[0] = cc1; | ||
56 | data.data[1] = cc2; | ||
57 | ivtv_saa7127(itv, VIDIOC_INT_S_VBI_DATA, &data); | ||
58 | data.field = 1; | ||
59 | data.line = (mode & 2) ? 21 : 0; | ||
60 | data.data[0] = cc3; | ||
61 | data.data[1] = cc4; | ||
62 | ivtv_saa7127(itv, VIDIOC_INT_S_VBI_DATA, &data); | ||
63 | } | ||
64 | |||
65 | void ivtv_set_wss(struct ivtv *itv, int enabled, int mode) | ||
66 | { | ||
67 | struct v4l2_sliced_vbi_data data; | ||
68 | |||
69 | if (!(itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT)) | ||
70 | return; | ||
71 | /* When using a 50 Hz system, always turn on the | ||
72 | wide screen signal with 4x3 ratio as the default. | ||
73 | Turning this signal on and off can confuse certain | ||
74 | TVs. As far as I can tell there is no reason not to | ||
75 | transmit this signal. */ | ||
76 | if ((itv->std & V4L2_STD_625_50) && !enabled) { | ||
77 | enabled = 1; | ||
78 | mode = 0x08; /* 4x3 full format */ | ||
79 | } | ||
80 | data.id = V4L2_SLICED_WSS_625; | ||
81 | data.field = 0; | ||
82 | data.line = enabled ? 23 : 0; | ||
83 | data.data[0] = mode & 0xff; | ||
84 | data.data[1] = (mode >> 8) & 0xff; | ||
85 | ivtv_saa7127(itv, VIDIOC_INT_S_VBI_DATA, &data); | ||
86 | } | ||
87 | |||
88 | void ivtv_video_set_io(struct ivtv *itv) | ||
89 | { | ||
90 | struct v4l2_routing route; | ||
91 | int inp = itv->active_input; | ||
92 | u32 type; | ||
93 | |||
94 | route.input = itv->card->video_inputs[inp].video_input; | ||
95 | route.output = 0; | ||
96 | itv->video_dec_func(itv, VIDIOC_INT_S_VIDEO_ROUTING, &route); | ||
97 | |||
98 | type = itv->card->video_inputs[inp].video_type; | ||
99 | |||
100 | if (type == IVTV_CARD_INPUT_VID_TUNER) { | ||
101 | route.input = 0; /* Tuner */ | ||
102 | } else if (type < IVTV_CARD_INPUT_COMPOSITE1) { | ||
103 | route.input = 2; /* S-Video */ | ||
104 | } else { | ||
105 | route.input = 1; /* Composite */ | ||
106 | } | ||
107 | |||
108 | if (itv->card->hw_video & IVTV_HW_GPIO) | ||
109 | ivtv_gpio(itv, VIDIOC_INT_S_VIDEO_ROUTING, &route); | ||
110 | |||
111 | if (itv->card->hw_video & IVTV_HW_UPD64031A) { | ||
112 | if (type == IVTV_CARD_INPUT_VID_TUNER || | ||
113 | type >= IVTV_CARD_INPUT_COMPOSITE1) { | ||
114 | /* Composite: GR on, connect to 3DYCS */ | ||
115 | route.input = UPD64031A_GR_ON | UPD64031A_3DYCS_COMPOSITE; | ||
116 | } else { | ||
117 | /* S-Video: GR bypassed, turn it off */ | ||
118 | route.input = UPD64031A_GR_OFF | UPD64031A_3DYCS_DISABLE; | ||
119 | } | ||
120 | route.input |= itv->card->gr_config; | ||
121 | |||
122 | ivtv_upd64031a(itv, VIDIOC_INT_S_VIDEO_ROUTING, &route); | ||
123 | } | ||
124 | |||
125 | if (itv->card->hw_video & IVTV_HW_UPD6408X) { | ||
126 | route.input = UPD64083_YCS_MODE; | ||
127 | if (type > IVTV_CARD_INPUT_VID_TUNER && | ||
128 | type < IVTV_CARD_INPUT_COMPOSITE1) { | ||
129 | /* S-Video uses YCNR mode and internal Y-ADC, the upd64031a | ||
130 | is not used. */ | ||
131 | route.input |= UPD64083_YCNR_MODE; | ||
132 | } | ||
133 | else if (itv->card->hw_video & IVTV_HW_UPD64031A) { | ||
134 | /* Use upd64031a output for tuner and composite(CX23416GYC only) inputs */ | ||
135 | if ((type == IVTV_CARD_INPUT_VID_TUNER)|| | ||
136 | (itv->card->type == IVTV_CARD_CX23416GYC)) { | ||
137 | route.input |= UPD64083_EXT_Y_ADC; | ||
138 | } | ||
139 | } | ||
140 | ivtv_upd64083(itv, VIDIOC_INT_S_VIDEO_ROUTING, &route); | ||
141 | } | ||
142 | } | ||
diff --git a/drivers/media/video/ivtv/ivtv-video.h b/drivers/media/video/ivtv/ivtv-video.h new file mode 100644 index 000000000000..c8ade5d3c413 --- /dev/null +++ b/drivers/media/video/ivtv/ivtv-video.h | |||
@@ -0,0 +1,24 @@ | |||
1 | /* | ||
2 | saa7127 interface functions | ||
3 | Copyright (C) 2004-2007 Hans Verkuil <hverkuil@xs4all.nl> | ||
4 | |||
5 | This program is free software; you can redistribute it and/or modify | ||
6 | it under the terms of the GNU General Public License as published by | ||
7 | the Free Software Foundation; either version 2 of the License, or | ||
8 | (at your option) any later version. | ||
9 | |||
10 | This program is distributed in the hope that it will be useful, | ||
11 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
13 | GNU General Public License for more details. | ||
14 | |||
15 | You should have received a copy of the GNU General Public License | ||
16 | along with this program; if not, write to the Free Software | ||
17 | Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
18 | */ | ||
19 | |||
20 | void ivtv_set_wss(struct ivtv *itv, int enabled, int mode); | ||
21 | void ivtv_set_cc(struct ivtv *itv, int mode, u8 cc1, u8 cc2, u8 cc3, u8 cc4); | ||
22 | void ivtv_set_vps(struct ivtv *itv, int enabled, u8 vps1, u8 vps2, u8 vps3, | ||
23 | u8 vps4, u8 vps5); | ||
24 | void ivtv_video_set_io(struct ivtv *itv); | ||
diff --git a/drivers/media/video/ivtv/ivtv-yuv.c b/drivers/media/video/ivtv/ivtv-yuv.c new file mode 100644 index 000000000000..bcea09542e5a --- /dev/null +++ b/drivers/media/video/ivtv/ivtv-yuv.c | |||
@@ -0,0 +1,1129 @@ | |||
1 | /* | ||
2 | yuv support | ||
3 | |||
4 | Copyright (C) 2007 Ian Armstrong <ian@iarmst.demon.co.uk> | ||
5 | |||
6 | This program is free software; you can redistribute it and/or modify | ||
7 | it under the terms of the GNU General Public License as published by | ||
8 | the Free Software Foundation; either version 2 of the License, or | ||
9 | (at your option) any later version. | ||
10 | |||
11 | This program is distributed in the hope that it will be useful, | ||
12 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
14 | GNU General Public License for more details. | ||
15 | |||
16 | You should have received a copy of the GNU General Public License | ||
17 | along with this program; if not, write to the Free Software | ||
18 | Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
19 | */ | ||
20 | |||
21 | #include "ivtv-driver.h" | ||
22 | #include "ivtv-queue.h" | ||
23 | #include "ivtv-udma.h" | ||
24 | #include "ivtv-irq.h" | ||
25 | #include "ivtv-yuv.h" | ||
26 | |||
27 | static int ivtv_yuv_prep_user_dma(struct ivtv *itv, struct ivtv_user_dma *dma, | ||
28 | struct ivtv_dma_frame *args) | ||
29 | { | ||
30 | struct ivtv_dma_page_info y_dma; | ||
31 | struct ivtv_dma_page_info uv_dma; | ||
32 | |||
33 | int i; | ||
34 | int y_pages, uv_pages; | ||
35 | |||
36 | unsigned long y_buffer_offset, uv_buffer_offset; | ||
37 | int y_decode_height, uv_decode_height, y_size; | ||
38 | int frame = atomic_read(&itv->yuv_info.next_fill_frame); | ||
39 | |||
40 | y_buffer_offset = IVTV_DEC_MEM_START + yuv_offset[frame]; | ||
41 | uv_buffer_offset = y_buffer_offset + IVTV_YUV_BUFFER_UV_OFFSET; | ||
42 | |||
43 | y_decode_height = uv_decode_height = args->src.height + args->src.top; | ||
44 | |||
45 | if (y_decode_height < 512-16) | ||
46 | y_buffer_offset += 720 * 16; | ||
47 | |||
48 | if (y_decode_height & 15) | ||
49 | y_decode_height = (y_decode_height + 16) & ~15; | ||
50 | |||
51 | if (uv_decode_height & 31) | ||
52 | uv_decode_height = (uv_decode_height + 32) & ~31; | ||
53 | |||
54 | y_size = 720 * y_decode_height; | ||
55 | |||
56 | /* Still in USE */ | ||
57 | if (dma->SG_length || dma->page_count) { | ||
58 | IVTV_DEBUG_WARN("prep_user_dma: SG_length %d page_count %d still full?\n", | ||
59 | dma->SG_length, dma->page_count); | ||
60 | return -EBUSY; | ||
61 | } | ||
62 | |||
63 | ivtv_udma_get_page_info (&y_dma, (unsigned long)args->y_source, 720 * y_decode_height); | ||
64 | ivtv_udma_get_page_info (&uv_dma, (unsigned long)args->uv_source, 360 * uv_decode_height); | ||
65 | |||
66 | /* Get user pages for DMA Xfer */ | ||
67 | down_read(¤t->mm->mmap_sem); | ||
68 | y_pages = get_user_pages(current, current->mm, y_dma.uaddr, y_dma.page_count, 0, 1, &dma->map[0], NULL); | ||
69 | uv_pages = get_user_pages(current, current->mm, uv_dma.uaddr, uv_dma.page_count, 0, 1, &dma->map[y_pages], NULL); | ||
70 | up_read(¤t->mm->mmap_sem); | ||
71 | |||
72 | dma->page_count = y_dma.page_count + uv_dma.page_count; | ||
73 | |||
74 | if (y_pages + uv_pages != dma->page_count) { | ||
75 | IVTV_DEBUG_WARN("failed to map user pages, returned %d instead of %d\n", | ||
76 | y_pages + uv_pages, dma->page_count); | ||
77 | |||
78 | for (i = 0; i < dma->page_count; i++) { | ||
79 | put_page(dma->map[i]); | ||
80 | } | ||
81 | dma->page_count = 0; | ||
82 | return -EINVAL; | ||
83 | } | ||
84 | |||
85 | /* Fill & map SG List */ | ||
86 | ivtv_udma_fill_sg_list (dma, &uv_dma, ivtv_udma_fill_sg_list (dma, &y_dma, 0)); | ||
87 | dma->SG_length = pci_map_sg(itv->dev, dma->SGlist, dma->page_count, PCI_DMA_TODEVICE); | ||
88 | |||
89 | /* Fill SG Array with new values */ | ||
90 | ivtv_udma_fill_sg_array (dma, y_buffer_offset, uv_buffer_offset, y_size); | ||
91 | |||
92 | /* If we've offset the y plane, ensure top area is blanked */ | ||
93 | if (args->src.height + args->src.top < 512-16) { | ||
94 | if (itv->yuv_info.blanking_dmaptr) { | ||
95 | dma->SGarray[dma->SG_length].size = cpu_to_le32(720*16); | ||
96 | dma->SGarray[dma->SG_length].src = cpu_to_le32(itv->yuv_info.blanking_dmaptr); | ||
97 | dma->SGarray[dma->SG_length].dst = cpu_to_le32(IVTV_DEC_MEM_START + yuv_offset[frame]); | ||
98 | dma->SG_length++; | ||
99 | } | ||
100 | } | ||
101 | |||
102 | /* Tag SG Array with Interrupt Bit */ | ||
103 | dma->SGarray[dma->SG_length - 1].size |= cpu_to_le32(0x80000000); | ||
104 | |||
105 | ivtv_udma_sync_for_device(itv); | ||
106 | return 0; | ||
107 | } | ||
108 | |||
109 | /* We rely on a table held in the firmware - Quick check. */ | ||
110 | int ivtv_yuv_filter_check(struct ivtv *itv) | ||
111 | { | ||
112 | int i, offset_y, offset_uv; | ||
113 | |||
114 | for (i=0, offset_y = 16, offset_uv = 4; i<16; i++, offset_y += 24, offset_uv += 12) { | ||
115 | if ((read_dec(IVTV_YUV_HORIZONTAL_FILTER_OFFSET + offset_y) != i << 16) || | ||
116 | (read_dec(IVTV_YUV_VERTICAL_FILTER_OFFSET + offset_uv) != i << 16)) { | ||
117 | IVTV_WARN ("YUV filter table not found in firmware.\n"); | ||
118 | return -1; | ||
119 | } | ||
120 | } | ||
121 | return 0; | ||
122 | } | ||
123 | |||
124 | static void ivtv_yuv_filter(struct ivtv *itv, int h_filter, int v_filter_1, int v_filter_2) | ||
125 | { | ||
126 | int filter_index, filter_line; | ||
127 | |||
128 | /* If any filter is -1, then don't update it */ | ||
129 | if (h_filter > -1) { | ||
130 | if (h_filter > 4) h_filter = 4; | ||
131 | filter_index = h_filter * 384; | ||
132 | filter_line = 0; | ||
133 | while (filter_line < 16) { | ||
134 | write_reg(read_dec(IVTV_YUV_HORIZONTAL_FILTER_OFFSET + filter_index), 0x02804); | ||
135 | write_reg(read_dec(IVTV_YUV_HORIZONTAL_FILTER_OFFSET + filter_index), 0x0281c); | ||
136 | filter_index += 4; | ||
137 | write_reg(read_dec(IVTV_YUV_HORIZONTAL_FILTER_OFFSET + filter_index), 0x02808); | ||
138 | write_reg(read_dec(IVTV_YUV_HORIZONTAL_FILTER_OFFSET + filter_index), 0x02820); | ||
139 | filter_index += 4; | ||
140 | write_reg(read_dec(IVTV_YUV_HORIZONTAL_FILTER_OFFSET + filter_index), 0x0280c); | ||
141 | write_reg(read_dec(IVTV_YUV_HORIZONTAL_FILTER_OFFSET + filter_index), 0x02824); | ||
142 | filter_index += 4; | ||
143 | write_reg(read_dec(IVTV_YUV_HORIZONTAL_FILTER_OFFSET + filter_index), 0x02810); | ||
144 | write_reg(read_dec(IVTV_YUV_HORIZONTAL_FILTER_OFFSET + filter_index), 0x02828); | ||
145 | filter_index += 4; | ||
146 | write_reg(read_dec(IVTV_YUV_HORIZONTAL_FILTER_OFFSET + filter_index), 0x02814); | ||
147 | write_reg(read_dec(IVTV_YUV_HORIZONTAL_FILTER_OFFSET + filter_index), 0x0282c); | ||
148 | filter_index += 8; | ||
149 | write_reg(0, 0x02818); | ||
150 | write_reg(0, 0x02830); | ||
151 | filter_line ++; | ||
152 | } | ||
153 | IVTV_DEBUG_YUV("h_filter -> %d\n",h_filter); | ||
154 | } | ||
155 | |||
156 | if (v_filter_1 > -1) { | ||
157 | if (v_filter_1 > 4) v_filter_1 = 4; | ||
158 | filter_index = v_filter_1 * 192; | ||
159 | filter_line = 0; | ||
160 | while (filter_line < 16) { | ||
161 | write_reg(read_dec(IVTV_YUV_VERTICAL_FILTER_OFFSET + filter_index), 0x02900); | ||
162 | filter_index += 4; | ||
163 | write_reg(read_dec(IVTV_YUV_VERTICAL_FILTER_OFFSET + filter_index), 0x02904); | ||
164 | filter_index += 8; | ||
165 | write_reg(0, 0x02908); | ||
166 | filter_line ++; | ||
167 | } | ||
168 | IVTV_DEBUG_YUV("v_filter_1 -> %d\n",v_filter_1); | ||
169 | } | ||
170 | |||
171 | if (v_filter_2 > -1) { | ||
172 | if (v_filter_2 > 4) v_filter_2 = 4; | ||
173 | filter_index = v_filter_2 * 192; | ||
174 | filter_line = 0; | ||
175 | while (filter_line < 16) { | ||
176 | write_reg(read_dec(IVTV_YUV_VERTICAL_FILTER_OFFSET + filter_index), 0x0290c); | ||
177 | filter_index += 4; | ||
178 | write_reg(read_dec(IVTV_YUV_VERTICAL_FILTER_OFFSET + filter_index), 0x02910); | ||
179 | filter_index += 8; | ||
180 | write_reg(0, 0x02914); | ||
181 | filter_line ++; | ||
182 | } | ||
183 | IVTV_DEBUG_YUV("v_filter_2 -> %d\n",v_filter_2); | ||
184 | } | ||
185 | } | ||
186 | |||
187 | static void ivtv_yuv_handle_horizontal(struct ivtv *itv, struct yuv_frame_info *window) | ||
188 | { | ||
189 | u32 reg_2834, reg_2838, reg_283c; | ||
190 | u32 reg_2844, reg_2854, reg_285c; | ||
191 | u32 reg_2864, reg_2874, reg_2890; | ||
192 | u32 reg_2870, reg_2870_base, reg_2870_offset; | ||
193 | int x_cutoff; | ||
194 | int h_filter; | ||
195 | u32 master_width; | ||
196 | |||
197 | IVTV_DEBUG_WARN( "Need to adjust to width %d src_w %d dst_w %d src_x %d dst_x %d\n", | ||
198 | window->tru_w, window->src_w, window->dst_w,window->src_x, window->dst_x); | ||
199 | |||
200 | /* How wide is the src image */ | ||
201 | x_cutoff = window->src_w + window->src_x; | ||
202 | |||
203 | /* Set the display width */ | ||
204 | reg_2834 = window->dst_w; | ||
205 | reg_2838 = reg_2834; | ||
206 | |||
207 | /* Set the display position */ | ||
208 | reg_2890 = window->dst_x; | ||
209 | |||
210 | /* Index into the image horizontally */ | ||
211 | reg_2870 = 0; | ||
212 | |||
213 | /* 2870 is normally fudged to align video coords with osd coords. | ||
214 | If running full screen, it causes an unwanted left shift | ||
215 | Remove the fudge if we almost fill the screen. | ||
216 | Gradually adjust the offset to avoid the video 'snapping' | ||
217 | left/right if it gets dragged through this region. | ||
218 | Only do this if osd is full width. */ | ||
219 | if (window->vis_w == 720) { | ||
220 | if ((window->tru_x - window->pan_x > -1) && (window->tru_x - window->pan_x <= 40) && (window->dst_w >= 680)){ | ||
221 | reg_2870 = 10 - (window->tru_x - window->pan_x) / 4; | ||
222 | } | ||
223 | else if ((window->tru_x - window->pan_x < 0) && (window->tru_x - window->pan_x >= -20) && (window->dst_w >= 660)) { | ||
224 | reg_2870 = (10 + (window->tru_x - window->pan_x) / 2); | ||
225 | } | ||
226 | |||
227 | if (window->dst_w >= window->src_w) | ||
228 | reg_2870 = reg_2870 << 16 | reg_2870; | ||
229 | else | ||
230 | reg_2870 = ((reg_2870 & ~1) << 15) | (reg_2870 & ~1); | ||
231 | } | ||
232 | |||
233 | if (window->dst_w < window->src_w) | ||
234 | reg_2870 = 0x000d000e - reg_2870; | ||
235 | else | ||
236 | reg_2870 = 0x0012000e - reg_2870; | ||
237 | |||
238 | /* We're also using 2870 to shift the image left (src_x & negative dst_x) */ | ||
239 | reg_2870_offset = (window->src_x*((window->dst_w << 21)/window->src_w))>>19; | ||
240 | |||
241 | if (window->dst_w >= window->src_w) { | ||
242 | x_cutoff &= ~1; | ||
243 | master_width = (window->src_w * 0x00200000) / (window->dst_w); | ||
244 | if (master_width * window->dst_w != window->src_w * 0x00200000) master_width ++; | ||
245 | reg_2834 = (reg_2834 << 16) | x_cutoff; | ||
246 | reg_2838 = (reg_2838 << 16) | x_cutoff; | ||
247 | reg_283c = master_width >> 2; | ||
248 | reg_2844 = master_width >> 2; | ||
249 | reg_2854 = master_width; | ||
250 | reg_285c = master_width >> 1; | ||
251 | reg_2864 = master_width >> 1; | ||
252 | |||
253 | /* We also need to factor in the scaling | ||
254 | (src_w - dst_w) / (src_w / 4) */ | ||
255 | if (window->dst_w > window->src_w) | ||
256 | reg_2870_base = ((window->dst_w - window->src_w)<<16) / (window->src_w <<14); | ||
257 | else | ||
258 | reg_2870_base = 0; | ||
259 | |||
260 | reg_2870 += (((reg_2870_offset << 14) & 0xFFFF0000) | reg_2870_offset >> 2) + (reg_2870_base << 17 | reg_2870_base); | ||
261 | reg_2874 = 0; | ||
262 | } | ||
263 | else if (window->dst_w < window->src_w / 2) { | ||
264 | master_width = (window->src_w * 0x00080000) / window->dst_w; | ||
265 | if (master_width * window->dst_w != window->src_w * 0x00080000) master_width ++; | ||
266 | reg_2834 = (reg_2834 << 16) | x_cutoff; | ||
267 | reg_2838 = (reg_2838 << 16) | x_cutoff; | ||
268 | reg_283c = master_width >> 2; | ||
269 | reg_2844 = master_width >> 1; | ||
270 | reg_2854 = master_width; | ||
271 | reg_285c = master_width >> 1; | ||
272 | reg_2864 = master_width >> 1; | ||
273 | reg_2870 += (((reg_2870_offset << 15) & 0xFFFF0000) | reg_2870_offset); | ||
274 | reg_2870 += (5 - (((window->src_w + window->src_w / 2) - 1) / window->dst_w)) << 16; | ||
275 | reg_2874 = 0x00000012; | ||
276 | } | ||
277 | else { | ||
278 | master_width = (window->src_w * 0x00100000) / window->dst_w; | ||
279 | if (master_width * window->dst_w != window->src_w * 0x00100000) master_width ++; | ||
280 | reg_2834 = (reg_2834 << 16) | x_cutoff; | ||
281 | reg_2838 = (reg_2838 << 16) | x_cutoff; | ||
282 | reg_283c = master_width >> 2; | ||
283 | reg_2844 = master_width >> 1; | ||
284 | reg_2854 = master_width; | ||
285 | reg_285c = master_width >> 1; | ||
286 | reg_2864 = master_width >> 1; | ||
287 | reg_2870 += (((reg_2870_offset << 14) & 0xFFFF0000) | reg_2870_offset >> 1); | ||
288 | reg_2870 += (5 - (((window->src_w * 3) - 1) / window->dst_w)) << 16; | ||
289 | reg_2874 = 0x00000001; | ||
290 | } | ||
291 | |||
292 | /* Select the horizontal filter */ | ||
293 | if (window->src_w == window->dst_w) { | ||
294 | /* An exact size match uses filter 0 */ | ||
295 | h_filter = 0; | ||
296 | } | ||
297 | else { | ||
298 | /* Figure out which filter to use */ | ||
299 | h_filter = ((window->src_w << 16) / window->dst_w) >> 15; | ||
300 | h_filter = (h_filter >> 1) + (h_filter & 1); | ||
301 | /* Only an exact size match can use filter 0 */ | ||
302 | if (h_filter == 0) h_filter = 1; | ||
303 | } | ||
304 | |||
305 | write_reg(reg_2834, 0x02834); | ||
306 | write_reg(reg_2838, 0x02838); | ||
307 | IVTV_DEBUG_YUV("Update reg 0x2834 %08x->%08x 0x2838 %08x->%08x\n",itv->yuv_info.reg_2834, reg_2834, itv->yuv_info.reg_2838, reg_2838); | ||
308 | |||
309 | write_reg(reg_283c, 0x0283c); | ||
310 | write_reg(reg_2844, 0x02844); | ||
311 | |||
312 | IVTV_DEBUG_YUV("Update reg 0x283c %08x->%08x 0x2844 %08x->%08x\n",itv->yuv_info.reg_283c, reg_283c, itv->yuv_info.reg_2844, reg_2844); | ||
313 | |||
314 | write_reg(0x00080514, 0x02840); | ||
315 | write_reg(0x00100514, 0x02848); | ||
316 | IVTV_DEBUG_YUV("Update reg 0x2840 %08x->%08x 0x2848 %08x->%08x\n",itv->yuv_info.reg_2840, 0x00080514, itv->yuv_info.reg_2848, 0x00100514); | ||
317 | |||
318 | write_reg(reg_2854, 0x02854); | ||
319 | IVTV_DEBUG_YUV("Update reg 0x2854 %08x->%08x \n",itv->yuv_info.reg_2854, reg_2854); | ||
320 | |||
321 | write_reg(reg_285c, 0x0285c); | ||
322 | write_reg(reg_2864, 0x02864); | ||
323 | IVTV_DEBUG_YUV("Update reg 0x285c %08x->%08x 0x2864 %08x->%08x\n",itv->yuv_info.reg_285c, reg_285c, itv->yuv_info.reg_2864, reg_2864); | ||
324 | |||
325 | write_reg(reg_2874, 0x02874); | ||
326 | IVTV_DEBUG_YUV("Update reg 0x2874 %08x->%08x\n",itv->yuv_info.reg_2874, reg_2874); | ||
327 | |||
328 | write_reg(reg_2870, 0x02870); | ||
329 | IVTV_DEBUG_YUV("Update reg 0x2870 %08x->%08x\n",itv->yuv_info.reg_2870, reg_2870); | ||
330 | |||
331 | write_reg( reg_2890,0x02890); | ||
332 | IVTV_DEBUG_YUV("Update reg 0x2890 %08x->%08x\n",itv->yuv_info.reg_2890, reg_2890); | ||
333 | |||
334 | /* Only update the filter if we really need to */ | ||
335 | if (h_filter != itv->yuv_info.h_filter) { | ||
336 | ivtv_yuv_filter (itv,h_filter,-1,-1); | ||
337 | itv->yuv_info.h_filter = h_filter; | ||
338 | } | ||
339 | } | ||
340 | |||
341 | static void ivtv_yuv_handle_vertical(struct ivtv *itv, struct yuv_frame_info *window) | ||
342 | { | ||
343 | u32 master_height; | ||
344 | u32 reg_2918, reg_291c, reg_2920, reg_2928; | ||
345 | u32 reg_2930, reg_2934, reg_293c; | ||
346 | u32 reg_2940, reg_2944, reg_294c; | ||
347 | u32 reg_2950, reg_2954, reg_2958, reg_295c; | ||
348 | u32 reg_2960, reg_2964, reg_2968, reg_296c; | ||
349 | u32 reg_289c; | ||
350 | u32 src_y_major_y, src_y_minor_y; | ||
351 | u32 src_y_major_uv, src_y_minor_uv; | ||
352 | u32 reg_2964_base, reg_2968_base; | ||
353 | int v_filter_1, v_filter_2; | ||
354 | |||
355 | IVTV_DEBUG_WARN("Need to adjust to height %d src_h %d dst_h %d src_y %d dst_y %d\n", | ||
356 | window->tru_h, window->src_h, window->dst_h,window->src_y, window->dst_y); | ||
357 | |||
358 | /* What scaling mode is being used... */ | ||
359 | if (window->interlaced_y) { | ||
360 | IVTV_DEBUG_YUV("Scaling mode Y: Interlaced\n"); | ||
361 | } | ||
362 | else { | ||
363 | IVTV_DEBUG_YUV("Scaling mode Y: Progressive\n"); | ||
364 | } | ||
365 | |||
366 | if (window->interlaced_uv) { | ||
367 | IVTV_DEBUG_YUV("Scaling mode UV: Interlaced\n"); | ||
368 | } | ||
369 | else { | ||
370 | IVTV_DEBUG_YUV("Scaling mode UV: Progressive\n"); | ||
371 | } | ||
372 | |||
373 | /* What is the source video being treated as... */ | ||
374 | if (itv->yuv_info.frame_interlaced) { | ||
375 | IVTV_DEBUG_WARN("Source video: Interlaced\n"); | ||
376 | } | ||
377 | else { | ||
378 | IVTV_DEBUG_WARN("Source video: Non-interlaced\n"); | ||
379 | } | ||
380 | |||
381 | /* We offset into the image using two different index methods, so split | ||
382 | the y source coord into two parts. */ | ||
383 | if (window->src_y < 8) { | ||
384 | src_y_minor_uv = window->src_y; | ||
385 | src_y_major_uv = 0; | ||
386 | } | ||
387 | else { | ||
388 | src_y_minor_uv = 8; | ||
389 | src_y_major_uv = window->src_y - 8; | ||
390 | } | ||
391 | |||
392 | src_y_minor_y = src_y_minor_uv; | ||
393 | src_y_major_y = src_y_major_uv; | ||
394 | |||
395 | if (window->offset_y) src_y_minor_y += 16; | ||
396 | |||
397 | if (window->interlaced_y) | ||
398 | reg_2918 = (window->dst_h << 16) | (window->src_h + src_y_minor_y); | ||
399 | else | ||
400 | reg_2918 = (window->dst_h << 16) | ((window->src_h + src_y_minor_y) << 1); | ||
401 | |||
402 | if (window->interlaced_uv) | ||
403 | reg_291c = (window->dst_h << 16) | ((window->src_h + src_y_minor_uv) >> 1); | ||
404 | else | ||
405 | reg_291c = (window->dst_h << 16) | (window->src_h + src_y_minor_uv); | ||
406 | |||
407 | reg_2964_base = (src_y_minor_y * ((window->dst_h << 16)/window->src_h)) >> 14; | ||
408 | reg_2968_base = (src_y_minor_uv * ((window->dst_h << 16)/window->src_h)) >> 14; | ||
409 | |||
410 | if (window->dst_h / 2 >= window->src_h && !window->interlaced_y) { | ||
411 | master_height = (window->src_h * 0x00400000) / window->dst_h; | ||
412 | if ((window->src_h * 0x00400000) - (master_height * window->dst_h) >= window->dst_h / 2) master_height ++; | ||
413 | reg_2920 = master_height >> 2; | ||
414 | reg_2928 = master_height >> 3; | ||
415 | reg_2930 = master_height; | ||
416 | reg_2940 = master_height >> 1; | ||
417 | reg_2964_base >>= 3; | ||
418 | reg_2968_base >>= 3; | ||
419 | reg_296c = 0x00000000; | ||
420 | } | ||
421 | else if (window->dst_h >= window->src_h) { | ||
422 | master_height = (window->src_h * 0x00400000) / window->dst_h; | ||
423 | master_height = (master_height >> 1) + (master_height & 1); | ||
424 | reg_2920 = master_height >> 2; | ||
425 | reg_2928 = master_height >> 2; | ||
426 | reg_2930 = master_height; | ||
427 | reg_2940 = master_height >> 1; | ||
428 | reg_296c = 0x00000000; | ||
429 | if (window->interlaced_y) { | ||
430 | reg_2964_base >>= 3; | ||
431 | } | ||
432 | else { | ||
433 | reg_296c ++; | ||
434 | reg_2964_base >>= 2; | ||
435 | } | ||
436 | if (window->interlaced_uv) reg_2928 >>= 1; | ||
437 | reg_2968_base >>= 3; | ||
438 | } | ||
439 | else if (window->dst_h >= window->src_h / 2) { | ||
440 | master_height = (window->src_h * 0x00200000) / window->dst_h; | ||
441 | master_height = (master_height >> 1) + (master_height & 1); | ||
442 | reg_2920 = master_height >> 2; | ||
443 | reg_2928 = master_height >> 2; | ||
444 | reg_2930 = master_height; | ||
445 | reg_2940 = master_height; | ||
446 | reg_296c = 0x00000101; | ||
447 | if (window->interlaced_y) { | ||
448 | reg_2964_base >>= 2; | ||
449 | } | ||
450 | else { | ||
451 | reg_296c ++; | ||
452 | reg_2964_base >>= 1; | ||
453 | } | ||
454 | if (window->interlaced_uv) reg_2928 >>= 1; | ||
455 | reg_2968_base >>= 2; | ||
456 | } | ||
457 | else { | ||
458 | master_height = (window->src_h * 0x00100000) / window->dst_h; | ||
459 | master_height = (master_height >> 1) + (master_height & 1); | ||
460 | reg_2920 = master_height >> 2; | ||
461 | reg_2928 = master_height >> 2; | ||
462 | reg_2930 = master_height; | ||
463 | reg_2940 = master_height; | ||
464 | reg_2964_base >>= 1; | ||
465 | reg_2968_base >>= 2; | ||
466 | reg_296c = 0x00000102; | ||
467 | } | ||
468 | |||
469 | /* FIXME These registers change depending on scaled / unscaled output | ||
470 | We really need to work out what they should be */ | ||
471 | if (window->src_h == window->dst_h){ | ||
472 | reg_2934 = 0x00020000; | ||
473 | reg_293c = 0x00100000; | ||
474 | reg_2944 = 0x00040000; | ||
475 | reg_294c = 0x000b0000; | ||
476 | } | ||
477 | else { | ||
478 | reg_2934 = 0x00000FF0; | ||
479 | reg_293c = 0x00000FF0; | ||
480 | reg_2944 = 0x00000FF0; | ||
481 | reg_294c = 0x00000FF0; | ||
482 | } | ||
483 | |||
484 | /* The first line to be displayed */ | ||
485 | reg_2950 = 0x00010000 + src_y_major_y; | ||
486 | if (window->interlaced_y) reg_2950 += 0x00010000; | ||
487 | reg_2954 = reg_2950 + 1; | ||
488 | |||
489 | reg_2958 = 0x00010000 + (src_y_major_y >> 1); | ||
490 | if (window->interlaced_uv) reg_2958 += 0x00010000; | ||
491 | reg_295c = reg_2958 + 1; | ||
492 | |||
493 | if (itv->yuv_info.decode_height == 480) | ||
494 | reg_289c = 0x011e0017; | ||
495 | else | ||
496 | reg_289c = 0x01500017; | ||
497 | |||
498 | if (window->dst_y < 0) | ||
499 | reg_289c = (reg_289c - ((window->dst_y & ~1)<<15))-(window->dst_y >>1); | ||
500 | else | ||
501 | reg_289c = (reg_289c + ((window->dst_y & ~1)<<15))+(window->dst_y >>1); | ||
502 | |||
503 | /* How much of the source to decode. | ||
504 | Take into account the source offset */ | ||
505 | reg_2960 = ((src_y_minor_y + window->src_h + src_y_major_y) - 1 ) | | ||
506 | ((((src_y_minor_uv + window->src_h + src_y_major_uv) - 1) & ~1) << 15); | ||
507 | |||
508 | /* Calculate correct value for register 2964 */ | ||
509 | if (window->src_h == window->dst_h) | ||
510 | reg_2964 = 1; | ||
511 | else { | ||
512 | reg_2964 = 2 + ((window->dst_h << 1) / window->src_h); | ||
513 | reg_2964 = (reg_2964 >> 1) + (reg_2964 & 1); | ||
514 | } | ||
515 | reg_2968 = (reg_2964 << 16) + reg_2964 + (reg_2964 >> 1); | ||
516 | reg_2964 = (reg_2964 << 16) + reg_2964 + (reg_2964 * 46 / 94); | ||
517 | |||
518 | /* Okay, we've wasted time working out the correct value, | ||
519 | but if we use it, it fouls the the window alignment. | ||
520 | Fudge it to what we want... */ | ||
521 | reg_2964 = 0x00010001 + ((reg_2964 & 0x0000FFFF) - (reg_2964 >> 16)); | ||
522 | reg_2968 = 0x00010001 + ((reg_2968 & 0x0000FFFF) - (reg_2968 >> 16)); | ||
523 | |||
524 | /* Deviate further from what it should be. I find the flicker headache | ||
525 | inducing so try to reduce it slightly. Leave 2968 as-is otherwise | ||
526 | colours foul. */ | ||
527 | if ((reg_2964 != 0x00010001) && (window->dst_h / 2 <= window->src_h)) | ||
528 | reg_2964 = (reg_2964 & 0xFFFF0000) + ((reg_2964 & 0x0000FFFF)/2); | ||
529 | |||
530 | if (!window->interlaced_y) reg_2964 -= 0x00010001; | ||
531 | if (!window->interlaced_uv) reg_2968 -= 0x00010001; | ||
532 | |||
533 | reg_2964 += ((reg_2964_base << 16) | reg_2964_base); | ||
534 | reg_2968 += ((reg_2968_base << 16) | reg_2968_base); | ||
535 | |||
536 | /* Select the vertical filter */ | ||
537 | if (window->src_h == window->dst_h) { | ||
538 | /* An exact size match uses filter 0/1 */ | ||
539 | v_filter_1 = 0; | ||
540 | v_filter_2 = 1; | ||
541 | } | ||
542 | else { | ||
543 | /* Figure out which filter to use */ | ||
544 | v_filter_1 = ((window->src_h << 16) / window->dst_h) >> 15; | ||
545 | v_filter_1 = (v_filter_1 >> 1) + (v_filter_1 & 1); | ||
546 | /* Only an exact size match can use filter 0 */ | ||
547 | if (v_filter_1 == 0) v_filter_1 = 1; | ||
548 | v_filter_2 = v_filter_1; | ||
549 | } | ||
550 | |||
551 | write_reg(reg_2934, 0x02934); | ||
552 | write_reg(reg_293c, 0x0293c); | ||
553 | IVTV_DEBUG_YUV("Update reg 0x2934 %08x->%08x 0x293c %08x->%08x\n",itv->yuv_info.reg_2934, reg_2934, itv->yuv_info.reg_293c, reg_293c); | ||
554 | write_reg(reg_2944, 0x02944); | ||
555 | write_reg(reg_294c, 0x0294c); | ||
556 | IVTV_DEBUG_YUV("Update reg 0x2944 %08x->%08x 0x294c %08x->%08x\n",itv->yuv_info.reg_2944, reg_2944, itv->yuv_info.reg_294c, reg_294c); | ||
557 | |||
558 | /* Ensure 2970 is 0 (does it ever change ?) */ | ||
559 | /* write_reg(0,0x02970); */ | ||
560 | /* IVTV_DEBUG_YUV("Update reg 0x2970 %08x->%08x\n",itv->yuv_info.reg_2970, 0); */ | ||
561 | |||
562 | write_reg(reg_2930, 0x02938); | ||
563 | write_reg(reg_2930, 0x02930); | ||
564 | IVTV_DEBUG_YUV("Update reg 0x2930 %08x->%08x 0x2938 %08x->%08x\n",itv->yuv_info.reg_2930, reg_2930, itv->yuv_info.reg_2938, reg_2930); | ||
565 | |||
566 | write_reg(reg_2928, 0x02928); | ||
567 | write_reg(reg_2928+0x514, 0x0292C); | ||
568 | IVTV_DEBUG_YUV("Update reg 0x2928 %08x->%08x 0x292c %08x->%08x\n",itv->yuv_info.reg_2928, reg_2928, itv->yuv_info.reg_292c, reg_2928+0x514); | ||
569 | |||
570 | write_reg(reg_2920, 0x02920); | ||
571 | write_reg(reg_2920+0x514, 0x02924); | ||
572 | IVTV_DEBUG_YUV("Update reg 0x2920 %08x->%08x 0x2924 %08x->%08x\n",itv->yuv_info.reg_2920, reg_2920, itv->yuv_info.reg_2924, 0x514+reg_2920); | ||
573 | |||
574 | write_reg (reg_2918,0x02918); | ||
575 | write_reg (reg_291c,0x0291C); | ||
576 | IVTV_DEBUG_YUV("Update reg 0x2918 %08x->%08x 0x291C %08x->%08x\n",itv->yuv_info.reg_2918,reg_2918,itv->yuv_info.reg_291c,reg_291c); | ||
577 | |||
578 | write_reg(reg_296c, 0x0296c); | ||
579 | IVTV_DEBUG_YUV("Update reg 0x296c %08x->%08x\n",itv->yuv_info.reg_296c, reg_296c); | ||
580 | |||
581 | write_reg(reg_2940, 0x02948); | ||
582 | write_reg(reg_2940, 0x02940); | ||
583 | IVTV_DEBUG_YUV("Update reg 0x2940 %08x->%08x 0x2948 %08x->%08x\n",itv->yuv_info.reg_2940, reg_2940, itv->yuv_info.reg_2948, reg_2940); | ||
584 | |||
585 | write_reg(reg_2950, 0x02950); | ||
586 | write_reg(reg_2954, 0x02954); | ||
587 | IVTV_DEBUG_YUV("Update reg 0x2950 %08x->%08x 0x2954 %08x->%08x\n",itv->yuv_info.reg_2950, reg_2950, itv->yuv_info.reg_2954, reg_2954); | ||
588 | |||
589 | write_reg(reg_2958, 0x02958); | ||
590 | write_reg(reg_295c, 0x0295C); | ||
591 | IVTV_DEBUG_YUV("Update reg 0x2958 %08x->%08x 0x295C %08x->%08x\n",itv->yuv_info.reg_2958, reg_2958, itv->yuv_info.reg_295c, reg_295c); | ||
592 | |||
593 | write_reg(reg_2960, 0x02960); | ||
594 | IVTV_DEBUG_YUV("Update reg 0x2960 %08x->%08x \n",itv->yuv_info.reg_2960, reg_2960); | ||
595 | |||
596 | write_reg(reg_2964, 0x02964); | ||
597 | write_reg(reg_2968, 0x02968); | ||
598 | IVTV_DEBUG_YUV("Update reg 0x2964 %08x->%08x 0x2968 %08x->%08x\n",itv->yuv_info.reg_2964, reg_2964, itv->yuv_info.reg_2968, reg_2968); | ||
599 | |||
600 | write_reg( reg_289c,0x0289c); | ||
601 | IVTV_DEBUG_YUV("Update reg 0x289c %08x->%08x\n",itv->yuv_info.reg_289c, reg_289c); | ||
602 | |||
603 | /* Only update filter 1 if we really need to */ | ||
604 | if (v_filter_1 != itv->yuv_info.v_filter_1) { | ||
605 | ivtv_yuv_filter (itv,-1,v_filter_1,-1); | ||
606 | itv->yuv_info.v_filter_1 = v_filter_1; | ||
607 | } | ||
608 | |||
609 | /* Only update filter 2 if we really need to */ | ||
610 | if (v_filter_2 != itv->yuv_info.v_filter_2) { | ||
611 | ivtv_yuv_filter (itv,-1,-1,v_filter_2); | ||
612 | itv->yuv_info.v_filter_2 = v_filter_2; | ||
613 | } | ||
614 | |||
615 | itv->yuv_info.frame_interlaced_last = itv->yuv_info.frame_interlaced; | ||
616 | } | ||
617 | |||
618 | /* Modify the supplied coordinate information to fit the visible osd area */ | ||
619 | static u32 ivtv_yuv_window_setup (struct ivtv *itv, struct yuv_frame_info *window) | ||
620 | { | ||
621 | int osd_crop, lace_threshold; | ||
622 | u32 osd_scale; | ||
623 | u32 yuv_update = 0; | ||
624 | |||
625 | lace_threshold = itv->yuv_info.lace_threshold; | ||
626 | if (lace_threshold < 0) | ||
627 | lace_threshold = itv->yuv_info.decode_height - 1; | ||
628 | |||
629 | /* Work out the lace settings */ | ||
630 | switch (itv->yuv_info.lace_mode) { | ||
631 | case IVTV_YUV_MODE_PROGRESSIVE: /* Progressive mode */ | ||
632 | itv->yuv_info.frame_interlaced = 0; | ||
633 | if (window->tru_h < 512 || (window->tru_h > 576 && window->tru_h < 1021)) | ||
634 | window->interlaced_y = 0; | ||
635 | else | ||
636 | window->interlaced_y = 1; | ||
637 | |||
638 | if (window->tru_h < 1021 && (window->dst_h >= window->src_h /2)) | ||
639 | window->interlaced_uv = 0; | ||
640 | else | ||
641 | window->interlaced_uv = 1; | ||
642 | break; | ||
643 | |||
644 | case IVTV_YUV_MODE_AUTO: | ||
645 | if (window->tru_h <= lace_threshold || window->tru_h > 576 || window->tru_w > 720){ | ||
646 | itv->yuv_info.frame_interlaced = 0; | ||
647 | if ((window->tru_h < 512) || | ||
648 | (window->tru_h > 576 && window->tru_h < 1021) || | ||
649 | (window->tru_w > 720 && window->tru_h < 1021)) | ||
650 | window->interlaced_y = 0; | ||
651 | else | ||
652 | window->interlaced_y = 1; | ||
653 | |||
654 | if (window->tru_h < 1021 && (window->dst_h >= window->src_h /2)) | ||
655 | window->interlaced_uv = 0; | ||
656 | else | ||
657 | window->interlaced_uv = 1; | ||
658 | } | ||
659 | else { | ||
660 | itv->yuv_info.frame_interlaced = 1; | ||
661 | window->interlaced_y = 1; | ||
662 | window->interlaced_uv = 1; | ||
663 | } | ||
664 | break; | ||
665 | |||
666 | case IVTV_YUV_MODE_INTERLACED: /* Interlace mode */ | ||
667 | default: | ||
668 | itv->yuv_info.frame_interlaced = 1; | ||
669 | window->interlaced_y = 1; | ||
670 | window->interlaced_uv = 1; | ||
671 | break; | ||
672 | } | ||
673 | |||
674 | /* Sorry, but no negative coords for src */ | ||
675 | if (window->src_x < 0) window->src_x = 0; | ||
676 | if (window->src_y < 0) window->src_y = 0; | ||
677 | |||
678 | /* Can only reduce width down to 1/4 original size */ | ||
679 | if ((osd_crop = window->src_w - ( 4 * window->dst_w )) > 0) { | ||
680 | window->src_x += osd_crop / 2; | ||
681 | window->src_w = (window->src_w - osd_crop) & ~3; | ||
682 | window->dst_w = window->src_w / 4; | ||
683 | window->dst_w += window->dst_w & 1; | ||
684 | } | ||
685 | |||
686 | /* Can only reduce height down to 1/4 original size */ | ||
687 | if (window->src_h / window->dst_h >= 2) { | ||
688 | /* Overflow may be because we're running progressive, so force mode switch */ | ||
689 | window->interlaced_y = 1; | ||
690 | /* Make sure we're still within limits for interlace */ | ||
691 | if ((osd_crop = window->src_h - ( 4 * window->dst_h )) > 0) { | ||
692 | /* If we reach here we'll have to force the height. */ | ||
693 | window->src_y += osd_crop / 2; | ||
694 | window->src_h = (window->src_h - osd_crop) & ~3; | ||
695 | window->dst_h = window->src_h / 4; | ||
696 | window->dst_h += window->dst_h & 1; | ||
697 | } | ||
698 | } | ||
699 | |||
700 | /* If there's nothing to safe to display, we may as well stop now */ | ||
701 | if ((int)window->dst_w <= 2 || (int)window->dst_h <= 2 || (int)window->src_w <= 2 || (int)window->src_h <= 2) { | ||
702 | return 0; | ||
703 | } | ||
704 | |||
705 | /* Ensure video remains inside OSD area */ | ||
706 | osd_scale = (window->src_h << 16) / window->dst_h; | ||
707 | |||
708 | if ((osd_crop = window->pan_y - window->dst_y) > 0) { | ||
709 | /* Falls off the upper edge - crop */ | ||
710 | window->src_y += (osd_scale * osd_crop) >> 16; | ||
711 | window->src_h -= (osd_scale * osd_crop) >> 16; | ||
712 | window->dst_h -= osd_crop; | ||
713 | window->dst_y = 0; | ||
714 | } | ||
715 | else { | ||
716 | window->dst_y -= window->pan_y; | ||
717 | } | ||
718 | |||
719 | if ((osd_crop = window->dst_h + window->dst_y - window->vis_h) > 0) { | ||
720 | /* Falls off the lower edge - crop */ | ||
721 | window->dst_h -= osd_crop; | ||
722 | window->src_h -= (osd_scale * osd_crop) >> 16; | ||
723 | } | ||
724 | |||
725 | osd_scale = (window->src_w << 16) / window->dst_w; | ||
726 | |||
727 | if ((osd_crop = window->pan_x - window->dst_x) > 0) { | ||
728 | /* Fall off the left edge - crop */ | ||
729 | window->src_x += (osd_scale * osd_crop) >> 16; | ||
730 | window->src_w -= (osd_scale * osd_crop) >> 16; | ||
731 | window->dst_w -= osd_crop; | ||
732 | window->dst_x = 0; | ||
733 | } | ||
734 | else { | ||
735 | window->dst_x -= window->pan_x; | ||
736 | } | ||
737 | |||
738 | if ((osd_crop = window->dst_w + window->dst_x - window->vis_w) > 0) { | ||
739 | /* Falls off the right edge - crop */ | ||
740 | window->dst_w -= osd_crop; | ||
741 | window->src_w -= (osd_scale * osd_crop) >> 16; | ||
742 | } | ||
743 | |||
744 | /* The OSD can be moved. Track to it */ | ||
745 | window->dst_x += itv->yuv_info.osd_x_offset; | ||
746 | window->dst_y += itv->yuv_info.osd_y_offset; | ||
747 | |||
748 | /* Width & height for both src & dst must be even. | ||
749 | Same for coordinates. */ | ||
750 | window->dst_w &= ~1; | ||
751 | window->dst_x &= ~1; | ||
752 | |||
753 | window->src_w += window->src_x & 1; | ||
754 | window->src_x &= ~1; | ||
755 | |||
756 | window->src_w &= ~1; | ||
757 | window->dst_w &= ~1; | ||
758 | |||
759 | window->dst_h &= ~1; | ||
760 | window->dst_y &= ~1; | ||
761 | |||
762 | window->src_h += window->src_y & 1; | ||
763 | window->src_y &= ~1; | ||
764 | |||
765 | window->src_h &= ~1; | ||
766 | window->dst_h &= ~1; | ||
767 | |||
768 | /* Due to rounding, we may have reduced the output size to <1/4 of the source | ||
769 | Check again, but this time just resize. Don't change source coordinates */ | ||
770 | if (window->dst_w < window->src_w / 4) { | ||
771 | window->src_w &= ~3; | ||
772 | window->dst_w = window->src_w / 4; | ||
773 | window->dst_w += window->dst_w & 1; | ||
774 | } | ||
775 | if (window->dst_h < window->src_h / 4) { | ||
776 | window->src_h &= ~3; | ||
777 | window->dst_h = window->src_h / 4; | ||
778 | window->dst_h += window->dst_h & 1; | ||
779 | } | ||
780 | |||
781 | /* Check again. If there's nothing to safe to display, stop now */ | ||
782 | if ((int)window->dst_w <= 2 || (int)window->dst_h <= 2 || (int)window->src_w <= 2 || (int)window->src_h <= 2) { | ||
783 | return 0; | ||
784 | } | ||
785 | |||
786 | /* Both x offset & width are linked, so they have to be done together */ | ||
787 | if ((itv->yuv_info.old_frame_info.dst_w != window->dst_w) || | ||
788 | (itv->yuv_info.old_frame_info.src_w != window->src_w) || | ||
789 | (itv->yuv_info.old_frame_info.dst_x != window->dst_x) || | ||
790 | (itv->yuv_info.old_frame_info.src_x != window->src_x) || | ||
791 | (itv->yuv_info.old_frame_info.pan_x != window->pan_x) || | ||
792 | (itv->yuv_info.old_frame_info.vis_w != window->vis_w)) { | ||
793 | yuv_update |= IVTV_YUV_UPDATE_HORIZONTAL; | ||
794 | } | ||
795 | |||
796 | if ((itv->yuv_info.old_frame_info.src_h != window->src_h) || | ||
797 | (itv->yuv_info.old_frame_info.dst_h != window->dst_h) || | ||
798 | (itv->yuv_info.old_frame_info.dst_y != window->dst_y) || | ||
799 | (itv->yuv_info.old_frame_info.src_y != window->src_y) || | ||
800 | (itv->yuv_info.old_frame_info.pan_y != window->pan_y) || | ||
801 | (itv->yuv_info.old_frame_info.vis_h != window->vis_h) || | ||
802 | (itv->yuv_info.old_frame_info.interlaced_y != window->interlaced_y) || | ||
803 | (itv->yuv_info.old_frame_info.interlaced_uv != window->interlaced_uv)) { | ||
804 | yuv_update |= IVTV_YUV_UPDATE_VERTICAL; | ||
805 | } | ||
806 | |||
807 | return yuv_update; | ||
808 | } | ||
809 | |||
810 | /* Update the scaling register to the requested value */ | ||
811 | void ivtv_yuv_work_handler (struct ivtv *itv) | ||
812 | { | ||
813 | struct yuv_frame_info window; | ||
814 | u32 yuv_update; | ||
815 | |||
816 | int frame = itv->yuv_info.update_frame; | ||
817 | |||
818 | /* IVTV_DEBUG_YUV("Update yuv registers for frame %d\n",frame); */ | ||
819 | memcpy(&window, &itv->yuv_info.new_frame_info[frame], sizeof (window)); | ||
820 | |||
821 | /* Update the osd pan info */ | ||
822 | window.pan_x = itv->yuv_info.osd_x_pan; | ||
823 | window.pan_y = itv->yuv_info.osd_y_pan; | ||
824 | window.vis_w = itv->yuv_info.osd_vis_w; | ||
825 | window.vis_h = itv->yuv_info.osd_vis_h; | ||
826 | |||
827 | /* Calculate the display window coordinates. Exit if nothing left */ | ||
828 | if (!(yuv_update = ivtv_yuv_window_setup (itv, &window))) | ||
829 | return; | ||
830 | |||
831 | /* Update horizontal settings */ | ||
832 | if (yuv_update & IVTV_YUV_UPDATE_HORIZONTAL) | ||
833 | ivtv_yuv_handle_horizontal(itv, &window); | ||
834 | |||
835 | if (yuv_update & IVTV_YUV_UPDATE_VERTICAL) | ||
836 | ivtv_yuv_handle_vertical(itv, &window); | ||
837 | |||
838 | memcpy(&itv->yuv_info.old_frame_info, &window, sizeof (itv->yuv_info.old_frame_info)); | ||
839 | } | ||
840 | |||
841 | static void ivtv_yuv_init (struct ivtv *itv) | ||
842 | { | ||
843 | IVTV_DEBUG_YUV("ivtv_yuv_init\n"); | ||
844 | |||
845 | /* Take a snapshot of the current register settings */ | ||
846 | itv->yuv_info.reg_2834 = read_reg(0x02834); | ||
847 | itv->yuv_info.reg_2838 = read_reg(0x02838); | ||
848 | itv->yuv_info.reg_283c = read_reg(0x0283c); | ||
849 | itv->yuv_info.reg_2840 = read_reg(0x02840); | ||
850 | itv->yuv_info.reg_2844 = read_reg(0x02844); | ||
851 | itv->yuv_info.reg_2848 = read_reg(0x02848); | ||
852 | itv->yuv_info.reg_2854 = read_reg(0x02854); | ||
853 | itv->yuv_info.reg_285c = read_reg(0x0285c); | ||
854 | itv->yuv_info.reg_2864 = read_reg(0x02864); | ||
855 | itv->yuv_info.reg_2870 = read_reg(0x02870); | ||
856 | itv->yuv_info.reg_2874 = read_reg(0x02874); | ||
857 | itv->yuv_info.reg_2898 = read_reg(0x02898); | ||
858 | itv->yuv_info.reg_2890 = read_reg(0x02890); | ||
859 | |||
860 | itv->yuv_info.reg_289c = read_reg(0x0289c); | ||
861 | itv->yuv_info.reg_2918 = read_reg(0x02918); | ||
862 | itv->yuv_info.reg_291c = read_reg(0x0291c); | ||
863 | itv->yuv_info.reg_2920 = read_reg(0x02920); | ||
864 | itv->yuv_info.reg_2924 = read_reg(0x02924); | ||
865 | itv->yuv_info.reg_2928 = read_reg(0x02928); | ||
866 | itv->yuv_info.reg_292c = read_reg(0x0292c); | ||
867 | itv->yuv_info.reg_2930 = read_reg(0x02930); | ||
868 | itv->yuv_info.reg_2934 = read_reg(0x02934); | ||
869 | itv->yuv_info.reg_2938 = read_reg(0x02938); | ||
870 | itv->yuv_info.reg_293c = read_reg(0x0293c); | ||
871 | itv->yuv_info.reg_2940 = read_reg(0x02940); | ||
872 | itv->yuv_info.reg_2944 = read_reg(0x02944); | ||
873 | itv->yuv_info.reg_2948 = read_reg(0x02948); | ||
874 | itv->yuv_info.reg_294c = read_reg(0x0294c); | ||
875 | itv->yuv_info.reg_2950 = read_reg(0x02950); | ||
876 | itv->yuv_info.reg_2954 = read_reg(0x02954); | ||
877 | itv->yuv_info.reg_2958 = read_reg(0x02958); | ||
878 | itv->yuv_info.reg_295c = read_reg(0x0295c); | ||
879 | itv->yuv_info.reg_2960 = read_reg(0x02960); | ||
880 | itv->yuv_info.reg_2964 = read_reg(0x02964); | ||
881 | itv->yuv_info.reg_2968 = read_reg(0x02968); | ||
882 | itv->yuv_info.reg_296c = read_reg(0x0296c); | ||
883 | itv->yuv_info.reg_2970 = read_reg(0x02970); | ||
884 | |||
885 | itv->yuv_info.v_filter_1 = -1; | ||
886 | itv->yuv_info.v_filter_2 = -1; | ||
887 | itv->yuv_info.h_filter = -1; | ||
888 | |||
889 | /* Set some valid size info */ | ||
890 | itv->yuv_info.osd_x_offset = read_reg(0x02a04) & 0x00000FFF; | ||
891 | itv->yuv_info.osd_y_offset = (read_reg(0x02a04) >> 16) & 0x00000FFF; | ||
892 | |||
893 | /* Bit 2 of reg 2878 indicates current decoder output format | ||
894 | 0 : NTSC 1 : PAL */ | ||
895 | if (read_reg(0x2878) & 4) | ||
896 | itv->yuv_info.decode_height = 576; | ||
897 | else | ||
898 | itv->yuv_info.decode_height = 480; | ||
899 | |||
900 | /* If no visible size set, assume full size */ | ||
901 | if (!itv->yuv_info.osd_vis_w) itv->yuv_info.osd_vis_w = 720 - itv->yuv_info.osd_x_offset; | ||
902 | if (!itv->yuv_info.osd_vis_h) itv->yuv_info.osd_vis_h = itv->yuv_info.decode_height - itv->yuv_info.osd_y_offset; | ||
903 | |||
904 | /* We need a buffer for blanking when Y plane is offset - non-fatal if we can't get one */ | ||
905 | itv->yuv_info.blanking_ptr = kzalloc(720*16,GFP_KERNEL); | ||
906 | if (itv->yuv_info.blanking_ptr) { | ||
907 | itv->yuv_info.blanking_dmaptr = pci_map_single(itv->dev, itv->yuv_info.blanking_ptr, 720*16, PCI_DMA_TODEVICE); | ||
908 | } | ||
909 | else { | ||
910 | itv->yuv_info.blanking_dmaptr = 0; | ||
911 | IVTV_DEBUG_WARN ("Failed to allocate yuv blanking buffer\n"); | ||
912 | } | ||
913 | |||
914 | IVTV_DEBUG_WARN("Enable video output\n"); | ||
915 | write_reg_sync(0x00108080, 0x2898); | ||
916 | |||
917 | /* Enable YUV decoder output */ | ||
918 | write_reg_sync(0x01, IVTV_REG_VDM); | ||
919 | |||
920 | set_bit(IVTV_F_I_DECODING_YUV, &itv->i_flags); | ||
921 | atomic_set(&itv->yuv_info.next_dma_frame,0); | ||
922 | } | ||
923 | |||
924 | int ivtv_yuv_prep_frame(struct ivtv *itv, struct ivtv_dma_frame *args) | ||
925 | { | ||
926 | DEFINE_WAIT(wait); | ||
927 | int rc = 0; | ||
928 | int got_sig = 0; | ||
929 | int frame, next_fill_frame, last_fill_frame; | ||
930 | |||
931 | IVTV_DEBUG_INFO("yuv_prep_frame\n"); | ||
932 | |||
933 | if (atomic_read(&itv->yuv_info.next_dma_frame) == -1) ivtv_yuv_init(itv); | ||
934 | |||
935 | frame = atomic_read(&itv->yuv_info.next_fill_frame); | ||
936 | next_fill_frame = (frame + 1) & 0x3; | ||
937 | last_fill_frame = (atomic_read(&itv->yuv_info.next_dma_frame)+1) & 0x3; | ||
938 | |||
939 | if (next_fill_frame != last_fill_frame && last_fill_frame != frame) { | ||
940 | /* Buffers are full - Overwrite the last frame */ | ||
941 | next_fill_frame = frame; | ||
942 | frame = (frame - 1) & 3; | ||
943 | } | ||
944 | |||
945 | /* Take a snapshot of the yuv coordinate information */ | ||
946 | itv->yuv_info.new_frame_info[frame].src_x = args->src.left; | ||
947 | itv->yuv_info.new_frame_info[frame].src_y = args->src.top; | ||
948 | itv->yuv_info.new_frame_info[frame].src_w = args->src.width; | ||
949 | itv->yuv_info.new_frame_info[frame].src_h = args->src.height; | ||
950 | itv->yuv_info.new_frame_info[frame].dst_x = args->dst.left; | ||
951 | itv->yuv_info.new_frame_info[frame].dst_y = args->dst.top; | ||
952 | itv->yuv_info.new_frame_info[frame].dst_w = args->dst.width; | ||
953 | itv->yuv_info.new_frame_info[frame].dst_h = args->dst.height; | ||
954 | itv->yuv_info.new_frame_info[frame].tru_x = args->dst.left; | ||
955 | itv->yuv_info.new_frame_info[frame].tru_w = args->src_width; | ||
956 | itv->yuv_info.new_frame_info[frame].tru_h = args->src_height; | ||
957 | |||
958 | /* Are we going to offset the Y plane */ | ||
959 | if (args->src.height + args->src.top < 512-16) | ||
960 | itv->yuv_info.new_frame_info[frame].offset_y = 1; | ||
961 | else | ||
962 | itv->yuv_info.new_frame_info[frame].offset_y = 0; | ||
963 | |||
964 | /* Snapshot the osd pan info */ | ||
965 | itv->yuv_info.new_frame_info[frame].pan_x = itv->yuv_info.osd_x_pan; | ||
966 | itv->yuv_info.new_frame_info[frame].pan_y = itv->yuv_info.osd_y_pan; | ||
967 | itv->yuv_info.new_frame_info[frame].vis_w = itv->yuv_info.osd_vis_w; | ||
968 | itv->yuv_info.new_frame_info[frame].vis_h = itv->yuv_info.osd_vis_h; | ||
969 | |||
970 | itv->yuv_info.new_frame_info[frame].update = 0; | ||
971 | itv->yuv_info.new_frame_info[frame].interlaced_y = 0; | ||
972 | itv->yuv_info.new_frame_info[frame].interlaced_uv = 0; | ||
973 | |||
974 | if (memcmp (&itv->yuv_info.old_frame_info_args, &itv->yuv_info.new_frame_info[frame], | ||
975 | sizeof (itv->yuv_info.new_frame_info[frame]))) { | ||
976 | memcpy(&itv->yuv_info.old_frame_info_args, &itv->yuv_info.new_frame_info[frame], sizeof (itv->yuv_info.old_frame_info_args)); | ||
977 | itv->yuv_info.new_frame_info[frame].update = 1; | ||
978 | /* IVTV_DEBUG_YUV ("Requesting register update for frame %d\n",frame); */ | ||
979 | } | ||
980 | |||
981 | /* DMA the frame */ | ||
982 | mutex_lock(&itv->udma.lock); | ||
983 | |||
984 | if ((rc = ivtv_yuv_prep_user_dma(itv, &itv->udma, args)) != 0) { | ||
985 | mutex_unlock(&itv->udma.lock); | ||
986 | return rc; | ||
987 | } | ||
988 | |||
989 | ivtv_udma_prepare(itv); | ||
990 | prepare_to_wait(&itv->dma_waitq, &wait, TASK_INTERRUPTIBLE); | ||
991 | /* if no UDMA is pending and no UDMA is in progress, then the DMA | ||
992 | is finished */ | ||
993 | while (itv->i_flags & (IVTV_F_I_UDMA_PENDING | IVTV_F_I_UDMA)) { | ||
994 | /* don't interrupt if the DMA is in progress but break off | ||
995 | a still pending DMA. */ | ||
996 | got_sig = signal_pending(current); | ||
997 | if (got_sig && test_and_clear_bit(IVTV_F_I_UDMA_PENDING, &itv->i_flags)) | ||
998 | break; | ||
999 | got_sig = 0; | ||
1000 | schedule(); | ||
1001 | } | ||
1002 | finish_wait(&itv->dma_waitq, &wait); | ||
1003 | |||
1004 | /* Unmap Last DMA Xfer */ | ||
1005 | ivtv_udma_unmap(itv); | ||
1006 | |||
1007 | if (got_sig) { | ||
1008 | IVTV_DEBUG_INFO("User stopped YUV UDMA\n"); | ||
1009 | mutex_unlock(&itv->udma.lock); | ||
1010 | return -EINTR; | ||
1011 | } | ||
1012 | |||
1013 | atomic_set(&itv->yuv_info.next_fill_frame, next_fill_frame); | ||
1014 | |||
1015 | mutex_unlock(&itv->udma.lock); | ||
1016 | return rc; | ||
1017 | } | ||
1018 | |||
1019 | void ivtv_yuv_close(struct ivtv *itv) | ||
1020 | { | ||
1021 | int h_filter, v_filter_1, v_filter_2; | ||
1022 | |||
1023 | IVTV_DEBUG_YUV("ivtv_yuv_close\n"); | ||
1024 | ivtv_waitq(&itv->vsync_waitq); | ||
1025 | |||
1026 | atomic_set(&itv->yuv_info.next_dma_frame, -1); | ||
1027 | atomic_set(&itv->yuv_info.next_fill_frame, 0); | ||
1028 | |||
1029 | /* Reset registers we have changed so mpeg playback works */ | ||
1030 | |||
1031 | /* If we fully restore this register, the display may remain active. | ||
1032 | Restore, but set one bit to blank the video. Firmware will always | ||
1033 | clear this bit when needed, so not a problem. */ | ||
1034 | write_reg(itv->yuv_info.reg_2898 | 0x01000000, 0x2898); | ||
1035 | |||
1036 | write_reg(itv->yuv_info.reg_2834, 0x02834); | ||
1037 | write_reg(itv->yuv_info.reg_2838, 0x02838); | ||
1038 | write_reg(itv->yuv_info.reg_283c, 0x0283c); | ||
1039 | write_reg(itv->yuv_info.reg_2840, 0x02840); | ||
1040 | write_reg(itv->yuv_info.reg_2844, 0x02844); | ||
1041 | write_reg(itv->yuv_info.reg_2848, 0x02848); | ||
1042 | write_reg(itv->yuv_info.reg_2854, 0x02854); | ||
1043 | write_reg(itv->yuv_info.reg_285c, 0x0285c); | ||
1044 | write_reg(itv->yuv_info.reg_2864, 0x02864); | ||
1045 | write_reg(itv->yuv_info.reg_2870, 0x02870); | ||
1046 | write_reg(itv->yuv_info.reg_2874, 0x02874); | ||
1047 | write_reg(itv->yuv_info.reg_2890, 0x02890); | ||
1048 | write_reg(itv->yuv_info.reg_289c, 0x0289c); | ||
1049 | |||
1050 | write_reg(itv->yuv_info.reg_2918, 0x02918); | ||
1051 | write_reg(itv->yuv_info.reg_291c, 0x0291c); | ||
1052 | write_reg(itv->yuv_info.reg_2920, 0x02920); | ||
1053 | write_reg(itv->yuv_info.reg_2924, 0x02924); | ||
1054 | write_reg(itv->yuv_info.reg_2928, 0x02928); | ||
1055 | write_reg(itv->yuv_info.reg_292c, 0x0292c); | ||
1056 | write_reg(itv->yuv_info.reg_2930, 0x02930); | ||
1057 | write_reg(itv->yuv_info.reg_2934, 0x02934); | ||
1058 | write_reg(itv->yuv_info.reg_2938, 0x02938); | ||
1059 | write_reg(itv->yuv_info.reg_293c, 0x0293c); | ||
1060 | write_reg(itv->yuv_info.reg_2940, 0x02940); | ||
1061 | write_reg(itv->yuv_info.reg_2944, 0x02944); | ||
1062 | write_reg(itv->yuv_info.reg_2948, 0x02948); | ||
1063 | write_reg(itv->yuv_info.reg_294c, 0x0294c); | ||
1064 | write_reg(itv->yuv_info.reg_2950, 0x02950); | ||
1065 | write_reg(itv->yuv_info.reg_2954, 0x02954); | ||
1066 | write_reg(itv->yuv_info.reg_2958, 0x02958); | ||
1067 | write_reg(itv->yuv_info.reg_295c, 0x0295c); | ||
1068 | write_reg(itv->yuv_info.reg_2960, 0x02960); | ||
1069 | write_reg(itv->yuv_info.reg_2964, 0x02964); | ||
1070 | write_reg(itv->yuv_info.reg_2968, 0x02968); | ||
1071 | write_reg(itv->yuv_info.reg_296c, 0x0296c); | ||
1072 | write_reg(itv->yuv_info.reg_2970, 0x02970); | ||
1073 | |||
1074 | /* Prepare to restore filters */ | ||
1075 | |||
1076 | /* First the horizontal filter */ | ||
1077 | if ((itv->yuv_info.reg_2834 & 0x0000FFFF) == (itv->yuv_info.reg_2834 >> 16)) { | ||
1078 | /* An exact size match uses filter 0 */ | ||
1079 | h_filter = 0; | ||
1080 | } | ||
1081 | else { | ||
1082 | /* Figure out which filter to use */ | ||
1083 | h_filter = ((itv->yuv_info.reg_2834 << 16) / (itv->yuv_info.reg_2834 >> 16)) >> 15; | ||
1084 | h_filter = (h_filter >> 1) + (h_filter & 1); | ||
1085 | /* Only an exact size match can use filter 0. */ | ||
1086 | if (h_filter < 1) h_filter = 1; | ||
1087 | } | ||
1088 | |||
1089 | /* Now the vertical filter */ | ||
1090 | if ((itv->yuv_info.reg_2918 & 0x0000FFFF) == (itv->yuv_info.reg_2918 >> 16)) { | ||
1091 | /* An exact size match uses filter 0/1 */ | ||
1092 | v_filter_1 = 0; | ||
1093 | v_filter_2 = 1; | ||
1094 | } | ||
1095 | else { | ||
1096 | /* Figure out which filter to use */ | ||
1097 | v_filter_1 = ((itv->yuv_info.reg_2918 << 16) / (itv->yuv_info.reg_2918 >> 16)) >> 15; | ||
1098 | v_filter_1 = (v_filter_1 >> 1) + (v_filter_1 & 1); | ||
1099 | /* Only an exact size match can use filter 0 */ | ||
1100 | if (v_filter_1 == 0) v_filter_1 = 1; | ||
1101 | v_filter_2 = v_filter_1; | ||
1102 | } | ||
1103 | |||
1104 | /* Now restore the filters */ | ||
1105 | ivtv_yuv_filter (itv,h_filter,v_filter_1,v_filter_2); | ||
1106 | |||
1107 | /* and clear a few registers */ | ||
1108 | write_reg(0, 0x02814); | ||
1109 | write_reg(0, 0x0282c); | ||
1110 | write_reg(0, 0x02904); | ||
1111 | write_reg(0, 0x02910); | ||
1112 | |||
1113 | /* Release the blanking buffer */ | ||
1114 | if (itv->yuv_info.blanking_ptr) { | ||
1115 | kfree (itv->yuv_info.blanking_ptr); | ||
1116 | itv->yuv_info.blanking_ptr = NULL; | ||
1117 | pci_unmap_single(itv->dev, itv->yuv_info.blanking_dmaptr, 720*16, PCI_DMA_TODEVICE); | ||
1118 | } | ||
1119 | |||
1120 | /* Invalidate the old dimension information */ | ||
1121 | itv->yuv_info.old_frame_info.src_w = 0; | ||
1122 | itv->yuv_info.old_frame_info.src_h = 0; | ||
1123 | itv->yuv_info.old_frame_info_args.src_w = 0; | ||
1124 | itv->yuv_info.old_frame_info_args.src_h = 0; | ||
1125 | |||
1126 | /* All done. */ | ||
1127 | clear_bit(IVTV_F_I_DECODING_YUV, &itv->i_flags); | ||
1128 | } | ||
1129 | |||
diff --git a/drivers/media/video/ivtv/ivtv-yuv.h b/drivers/media/video/ivtv/ivtv-yuv.h new file mode 100644 index 000000000000..88972d3f77c4 --- /dev/null +++ b/drivers/media/video/ivtv/ivtv-yuv.h | |||
@@ -0,0 +1,24 @@ | |||
1 | /* | ||
2 | yuv support | ||
3 | |||
4 | Copyright (C) 2007 Ian Armstrong <ian@iarmst.demon.co.uk> | ||
5 | |||
6 | This program is free software; you can redistribute it and/or modify | ||
7 | it under the terms of the GNU General Public License as published by | ||
8 | the Free Software Foundation; either version 2 of the License, or | ||
9 | (at your option) any later version. | ||
10 | |||
11 | This program is distributed in the hope that it will be useful, | ||
12 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
14 | GNU General Public License for more details. | ||
15 | |||
16 | You should have received a copy of the GNU General Public License | ||
17 | along with this program; if not, write to the Free Software | ||
18 | Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
19 | */ | ||
20 | |||
21 | int ivtv_yuv_filter_check(struct ivtv *itv); | ||
22 | int ivtv_yuv_prep_frame(struct ivtv *itv, struct ivtv_dma_frame *args); | ||
23 | void ivtv_yuv_close(struct ivtv *itv); | ||
24 | void ivtv_yuv_work_handler (struct ivtv *itv); | ||
diff --git a/drivers/media/video/msp3400-driver.c b/drivers/media/video/msp3400-driver.c index ba1af3c8525e..3bb7d6634862 100644 --- a/drivers/media/video/msp3400-driver.c +++ b/drivers/media/video/msp3400-driver.c | |||
@@ -773,6 +773,9 @@ static int msp_command(struct i2c_client *client, unsigned int cmd, void *arg) | |||
773 | break; | 773 | break; |
774 | } | 774 | } |
775 | 775 | ||
776 | case VIDIOC_G_CHIP_IDENT: | ||
777 | return v4l2_chip_ident_i2c_client(client, arg, state->ident, (state->rev1 << 16) | state->rev2); | ||
778 | |||
776 | default: | 779 | default: |
777 | /* unknown */ | 780 | /* unknown */ |
778 | return -EINVAL; | 781 | return -EINVAL; |
@@ -872,6 +875,8 @@ static int msp_attach(struct i2c_adapter *adapter, int address, int kind) | |||
872 | snprintf(client->name, sizeof(client->name), "MSP%d4%02d%c-%c%d", | 875 | snprintf(client->name, sizeof(client->name), "MSP%d4%02d%c-%c%d", |
873 | msp_family, msp_product, | 876 | msp_family, msp_product, |
874 | msp_revision, msp_hard, msp_rom); | 877 | msp_revision, msp_hard, msp_rom); |
878 | /* Rev B=2, C=3, D=4, G=7 */ | ||
879 | state->ident = msp_family * 10000 + 4000 + msp_product * 10 + msp_revision - '@'; | ||
875 | 880 | ||
876 | /* Has NICAM support: all mspx41x and mspx45x products have NICAM */ | 881 | /* Has NICAM support: all mspx41x and mspx45x products have NICAM */ |
877 | state->has_nicam = msp_prod_hi == 1 || msp_prod_hi == 5; | 882 | state->has_nicam = msp_prod_hi == 1 || msp_prod_hi == 5; |
diff --git a/drivers/media/video/msp3400-driver.h b/drivers/media/video/msp3400-driver.h index 7531efa1615e..ab69a290e5dc 100644 --- a/drivers/media/video/msp3400-driver.h +++ b/drivers/media/video/msp3400-driver.h | |||
@@ -50,6 +50,7 @@ extern int msp_stereo_thresh; | |||
50 | 50 | ||
51 | struct msp_state { | 51 | struct msp_state { |
52 | int rev1, rev2; | 52 | int rev1, rev2; |
53 | int ident; | ||
53 | u8 has_nicam; | 54 | u8 has_nicam; |
54 | u8 has_radio; | 55 | u8 has_radio; |
55 | u8 has_headphones; | 56 | u8 has_headphones; |
diff --git a/drivers/media/video/ov7670.c b/drivers/media/video/ov7670.c index 5ed0adc4ca26..03bc369a9e49 100644 --- a/drivers/media/video/ov7670.c +++ b/drivers/media/video/ov7670.c | |||
@@ -5,6 +5,8 @@ | |||
5 | * by Jonathan Corbet with substantial inspiration from Mark | 5 | * by Jonathan Corbet with substantial inspiration from Mark |
6 | * McClelland's ovcamchip code. | 6 | * McClelland's ovcamchip code. |
7 | * | 7 | * |
8 | * Copyright 2006-7 Jonathan Corbet <corbet@lwn.net> | ||
9 | * | ||
8 | * This file may be distributed under the terms of the GNU General | 10 | * This file may be distributed under the terms of the GNU General |
9 | * Public License, version 2. | 11 | * Public License, version 2. |
10 | */ | 12 | */ |
@@ -15,6 +17,7 @@ | |||
15 | #include <linux/delay.h> | 17 | #include <linux/delay.h> |
16 | #include <linux/videodev.h> | 18 | #include <linux/videodev.h> |
17 | #include <media/v4l2-common.h> | 19 | #include <media/v4l2-common.h> |
20 | #include <media/v4l2-chip-ident.h> | ||
18 | #include <linux/i2c.h> | 21 | #include <linux/i2c.h> |
19 | 22 | ||
20 | 23 | ||
@@ -162,6 +165,10 @@ MODULE_LICENSE("GPL"); | |||
162 | 165 | ||
163 | #define REG_GFIX 0x69 /* Fix gain control */ | 166 | #define REG_GFIX 0x69 /* Fix gain control */ |
164 | 167 | ||
168 | #define REG_REG76 0x76 /* OV's name */ | ||
169 | #define R76_BLKPCOR 0x80 /* Black pixel correction enable */ | ||
170 | #define R76_WHTPCOR 0x40 /* White pixel correction enable */ | ||
171 | |||
165 | #define REG_RGB444 0x8c /* RGB 444 control */ | 172 | #define REG_RGB444 0x8c /* RGB 444 control */ |
166 | #define R444_ENABLE 0x02 /* Turn on RGB444, overrides 5x5 */ | 173 | #define R444_ENABLE 0x02 /* Turn on RGB444, overrides 5x5 */ |
167 | #define R444_RGBX 0x01 /* Empty nibble at end */ | 174 | #define R444_RGBX 0x01 /* Empty nibble at end */ |
@@ -255,7 +262,7 @@ static struct regval_list ov7670_default_regs[] = { | |||
255 | 262 | ||
256 | /* Almost all of these are magic "reserved" values. */ | 263 | /* Almost all of these are magic "reserved" values. */ |
257 | { REG_COM5, 0x61 }, { REG_COM6, 0x4b }, | 264 | { REG_COM5, 0x61 }, { REG_COM6, 0x4b }, |
258 | { 0x16, 0x02 }, { REG_MVFP, 0x07|MVFP_MIRROR }, | 265 | { 0x16, 0x02 }, { REG_MVFP, 0x07 }, |
259 | { 0x21, 0x02 }, { 0x22, 0x91 }, | 266 | { 0x21, 0x02 }, { 0x22, 0x91 }, |
260 | { 0x29, 0x07 }, { 0x33, 0x0b }, | 267 | { 0x29, 0x07 }, { 0x33, 0x0b }, |
261 | { 0x35, 0x0b }, { 0x37, 0x1d }, | 268 | { 0x35, 0x0b }, { 0x37, 0x1d }, |
@@ -380,6 +387,13 @@ static struct regval_list ov7670_fmt_rgb444[] = { | |||
380 | { 0xff, 0xff }, | 387 | { 0xff, 0xff }, |
381 | }; | 388 | }; |
382 | 389 | ||
390 | static struct regval_list ov7670_fmt_raw[] = { | ||
391 | { REG_COM7, COM7_BAYER }, | ||
392 | { REG_COM13, 0x08 }, /* No gamma, magic rsvd bit */ | ||
393 | { REG_COM16, 0x3d }, /* Edge enhancement, denoise */ | ||
394 | { REG_REG76, 0xe1 }, /* Pix correction, magic rsvd */ | ||
395 | { 0xff, 0xff }, | ||
396 | }; | ||
383 | 397 | ||
384 | 398 | ||
385 | 399 | ||
@@ -483,32 +497,39 @@ static struct ov7670_format_struct { | |||
483 | __u32 pixelformat; | 497 | __u32 pixelformat; |
484 | struct regval_list *regs; | 498 | struct regval_list *regs; |
485 | int cmatrix[CMATRIX_LEN]; | 499 | int cmatrix[CMATRIX_LEN]; |
500 | int bpp; /* Bytes per pixel */ | ||
486 | } ov7670_formats[] = { | 501 | } ov7670_formats[] = { |
487 | { | 502 | { |
488 | .desc = "YUYV 4:2:2", | 503 | .desc = "YUYV 4:2:2", |
489 | .pixelformat = V4L2_PIX_FMT_YUYV, | 504 | .pixelformat = V4L2_PIX_FMT_YUYV, |
490 | .regs = ov7670_fmt_yuv422, | 505 | .regs = ov7670_fmt_yuv422, |
491 | .cmatrix = { 128, -128, 0, -34, -94, 128 }, | 506 | .cmatrix = { 128, -128, 0, -34, -94, 128 }, |
507 | .bpp = 2, | ||
492 | }, | 508 | }, |
493 | { | 509 | { |
494 | .desc = "RGB 444", | 510 | .desc = "RGB 444", |
495 | .pixelformat = V4L2_PIX_FMT_RGB444, | 511 | .pixelformat = V4L2_PIX_FMT_RGB444, |
496 | .regs = ov7670_fmt_rgb444, | 512 | .regs = ov7670_fmt_rgb444, |
497 | .cmatrix = { 179, -179, 0, -61, -176, 228 }, | 513 | .cmatrix = { 179, -179, 0, -61, -176, 228 }, |
514 | .bpp = 2, | ||
498 | }, | 515 | }, |
499 | { | 516 | { |
500 | .desc = "RGB 565", | 517 | .desc = "RGB 565", |
501 | .pixelformat = V4L2_PIX_FMT_RGB565, | 518 | .pixelformat = V4L2_PIX_FMT_RGB565, |
502 | .regs = ov7670_fmt_rgb565, | 519 | .regs = ov7670_fmt_rgb565, |
503 | .cmatrix = { 179, -179, 0, -61, -176, 228 }, | 520 | .cmatrix = { 179, -179, 0, -61, -176, 228 }, |
521 | .bpp = 2, | ||
522 | }, | ||
523 | { | ||
524 | .desc = "Raw RGB Bayer", | ||
525 | .pixelformat = V4L2_PIX_FMT_SBGGR8, | ||
526 | .regs = ov7670_fmt_raw, | ||
527 | .cmatrix = { 0, 0, 0, 0, 0, 0 }, | ||
528 | .bpp = 1 | ||
504 | }, | 529 | }, |
505 | }; | 530 | }; |
506 | #define N_OV7670_FMTS (sizeof(ov7670_formats)/sizeof(ov7670_formats[0])) | 531 | #define N_OV7670_FMTS ARRAY_SIZE(ov7670_formats) |
507 | 532 | ||
508 | /* | ||
509 | * All formats we support are 2 bytes/pixel. | ||
510 | */ | ||
511 | #define BYTES_PER_PIXEL 2 | ||
512 | 533 | ||
513 | /* | 534 | /* |
514 | * Then there is the issue of window sizes. Try to capture the info here. | 535 | * Then there is the issue of window sizes. Try to capture the info here. |
@@ -685,7 +706,7 @@ static int ov7670_try_fmt(struct i2c_client *c, struct v4l2_format *fmt, | |||
685 | */ | 706 | */ |
686 | pix->width = wsize->width; | 707 | pix->width = wsize->width; |
687 | pix->height = wsize->height; | 708 | pix->height = wsize->height; |
688 | pix->bytesperline = pix->width*BYTES_PER_PIXEL; | 709 | pix->bytesperline = pix->width*ov7670_formats[index].bpp; |
689 | pix->sizeimage = pix->height*pix->bytesperline; | 710 | pix->sizeimage = pix->height*pix->bytesperline; |
690 | return 0; | 711 | return 0; |
691 | } | 712 | } |
@@ -1270,9 +1291,8 @@ static int ov7670_command(struct i2c_client *client, unsigned int cmd, | |||
1270 | void *arg) | 1291 | void *arg) |
1271 | { | 1292 | { |
1272 | switch (cmd) { | 1293 | switch (cmd) { |
1273 | case VIDIOC_INT_G_CHIP_IDENT: | 1294 | case VIDIOC_G_CHIP_IDENT: |
1274 | * (enum v4l2_chip_ident *) arg = V4L2_IDENT_OV7670; | 1295 | return v4l2_chip_ident_i2c_client(client, arg, V4L2_IDENT_OV7670, 0); |
1275 | return 0; | ||
1276 | 1296 | ||
1277 | case VIDIOC_INT_RESET: | 1297 | case VIDIOC_INT_RESET: |
1278 | ov7670_reset(client); | 1298 | ov7670_reset(client); |
diff --git a/drivers/media/video/planb.c b/drivers/media/video/planb.c index e6e61df0d071..1455a8f4e930 100644 --- a/drivers/media/video/planb.c +++ b/drivers/media/video/planb.c | |||
@@ -2210,7 +2210,7 @@ static int find_planb(void) | |||
2210 | "membase 0x%x (base reg. 0x%x)\n", | 2210 | "membase 0x%x (base reg. 0x%x)\n", |
2211 | bus, PCI_SLOT(dev_fn), PCI_FUNC(dev_fn), old_base, confreg); | 2211 | bus, PCI_SLOT(dev_fn), PCI_FUNC(dev_fn), old_base, confreg); |
2212 | 2212 | ||
2213 | pdev = pci_find_slot (bus, dev_fn); | 2213 | pdev = pci_get_bus_and_slot(bus, dev_fn); |
2214 | if (!pdev) { | 2214 | if (!pdev) { |
2215 | printk(KERN_ERR "planb: cannot find slot\n"); | 2215 | printk(KERN_ERR "planb: cannot find slot\n"); |
2216 | goto err_out; | 2216 | goto err_out; |
@@ -2240,6 +2240,7 @@ static int find_planb(void) | |||
2240 | pb->planb_base = planb_regs; | 2240 | pb->planb_base = planb_regs; |
2241 | pb->planb_base_phys = (struct planb_registers *)new_base; | 2241 | pb->planb_base_phys = (struct planb_registers *)new_base; |
2242 | pb->irq = irq; | 2242 | pb->irq = irq; |
2243 | pb->dev = pdev; | ||
2243 | 2244 | ||
2244 | return planb_num; | 2245 | return planb_num; |
2245 | 2246 | ||
@@ -2247,6 +2248,7 @@ err_out_disable: | |||
2247 | pci_disable_device(pdev); | 2248 | pci_disable_device(pdev); |
2248 | err_out: | 2249 | err_out: |
2249 | /* FIXME handle error */ /* comment moved from pci_find_slot, above */ | 2250 | /* FIXME handle error */ /* comment moved from pci_find_slot, above */ |
2251 | pci_dev_put(pdev); | ||
2250 | return 0; | 2252 | return 0; |
2251 | } | 2253 | } |
2252 | 2254 | ||
@@ -2274,6 +2276,8 @@ static void release_planb(void) | |||
2274 | printk(KERN_INFO "PlanB: unregistering with v4l\n"); | 2276 | printk(KERN_INFO "PlanB: unregistering with v4l\n"); |
2275 | video_unregister_device(&pb->video_dev); | 2277 | video_unregister_device(&pb->video_dev); |
2276 | 2278 | ||
2279 | pci_dev_put(pb->dev); | ||
2280 | |||
2277 | /* note that iounmap() does nothing on the PPC right now */ | 2281 | /* note that iounmap() does nothing on the PPC right now */ |
2278 | iounmap ((void *)pb->planb_base); | 2282 | iounmap ((void *)pb->planb_base); |
2279 | } | 2283 | } |
diff --git a/drivers/media/video/planb.h b/drivers/media/video/planb.h index 92823211d0c5..e21b5735c103 100644 --- a/drivers/media/video/planb.h +++ b/drivers/media/video/planb.h | |||
@@ -177,6 +177,7 @@ struct planb { | |||
177 | struct mutex lock; | 177 | struct mutex lock; |
178 | unsigned int irq; /* interrupt number */ | 178 | unsigned int irq; /* interrupt number */ |
179 | volatile unsigned int intr_mask; | 179 | volatile unsigned int intr_mask; |
180 | struct pci_dev *dev; /* Our PCI device */ | ||
180 | 181 | ||
181 | int overlay; /* overlay running? */ | 182 | int overlay; /* overlay running? */ |
182 | struct planb_window win; | 183 | struct planb_window win; |
diff --git a/drivers/media/video/pvrusb2/pvrusb2-encoder.c b/drivers/media/video/pvrusb2/pvrusb2-encoder.c index 5786faf9b3b8..5669c8ca9ca3 100644 --- a/drivers/media/video/pvrusb2/pvrusb2-encoder.c +++ b/drivers/media/video/pvrusb2/pvrusb2-encoder.c | |||
@@ -324,7 +324,7 @@ static int pvr2_encoder_vcmd(struct pvr2_hdw *hdw, int cmd, | |||
324 | 324 | ||
325 | /* This implements some extra setup for the encoder that seems to be | 325 | /* This implements some extra setup for the encoder that seems to be |
326 | specific to the PVR USB2 hardware. */ | 326 | specific to the PVR USB2 hardware. */ |
327 | int pvr2_encoder_prep_config(struct pvr2_hdw *hdw) | 327 | static int pvr2_encoder_prep_config(struct pvr2_hdw *hdw) |
328 | { | 328 | { |
329 | int ret = 0; | 329 | int ret = 0; |
330 | int encMisc3Arg = 0; | 330 | int encMisc3Arg = 0; |
diff --git a/drivers/media/video/pvrusb2/pvrusb2-hdw-internal.h b/drivers/media/video/pvrusb2/pvrusb2-hdw-internal.h index 16bd74199601..ce66ab8ff2d8 100644 --- a/drivers/media/video/pvrusb2/pvrusb2-hdw-internal.h +++ b/drivers/media/video/pvrusb2/pvrusb2-hdw-internal.h | |||
@@ -283,6 +283,8 @@ struct pvr2_hdw { | |||
283 | int unit_number; /* ID for driver instance */ | 283 | int unit_number; /* ID for driver instance */ |
284 | unsigned long serial_number; /* ID for hardware itself */ | 284 | unsigned long serial_number; /* ID for hardware itself */ |
285 | 285 | ||
286 | char bus_info[32]; /* Bus location info */ | ||
287 | |||
286 | /* Minor numbers used by v4l logic (yes, this is a hack, as there | 288 | /* Minor numbers used by v4l logic (yes, this is a hack, as there |
287 | should be no v4l junk here). Probably a better way to do this. */ | 289 | should be no v4l junk here). Probably a better way to do this. */ |
288 | int v4l_minor_number_video; | 290 | int v4l_minor_number_video; |
diff --git a/drivers/media/video/pvrusb2/pvrusb2-hdw.c b/drivers/media/video/pvrusb2/pvrusb2-hdw.c index 9916cf32494d..acf651e01f94 100644 --- a/drivers/media/video/pvrusb2/pvrusb2-hdw.c +++ b/drivers/media/video/pvrusb2/pvrusb2-hdw.c | |||
@@ -1008,6 +1008,13 @@ unsigned long pvr2_hdw_get_sn(struct pvr2_hdw *hdw) | |||
1008 | return hdw->serial_number; | 1008 | return hdw->serial_number; |
1009 | } | 1009 | } |
1010 | 1010 | ||
1011 | |||
1012 | const char *pvr2_hdw_get_bus_info(struct pvr2_hdw *hdw) | ||
1013 | { | ||
1014 | return hdw->bus_info; | ||
1015 | } | ||
1016 | |||
1017 | |||
1011 | unsigned long pvr2_hdw_get_cur_freq(struct pvr2_hdw *hdw) | 1018 | unsigned long pvr2_hdw_get_cur_freq(struct pvr2_hdw *hdw) |
1012 | { | 1019 | { |
1013 | return hdw->freqSelector ? hdw->freqValTelevision : hdw->freqValRadio; | 1020 | return hdw->freqSelector ? hdw->freqValTelevision : hdw->freqValRadio; |
@@ -2105,6 +2112,11 @@ struct pvr2_hdw *pvr2_hdw_create(struct usb_interface *intf, | |||
2105 | hdw->usb_intf = intf; | 2112 | hdw->usb_intf = intf; |
2106 | hdw->usb_dev = interface_to_usbdev(intf); | 2113 | hdw->usb_dev = interface_to_usbdev(intf); |
2107 | 2114 | ||
2115 | scnprintf(hdw->bus_info,sizeof(hdw->bus_info), | ||
2116 | "usb %s address %d", | ||
2117 | hdw->usb_dev->dev.bus_id, | ||
2118 | hdw->usb_dev->devnum); | ||
2119 | |||
2108 | ifnum = hdw->usb_intf->cur_altsetting->desc.bInterfaceNumber; | 2120 | ifnum = hdw->usb_intf->cur_altsetting->desc.bInterfaceNumber; |
2109 | usb_set_interface(hdw->usb_dev,ifnum,0); | 2121 | usb_set_interface(hdw->usb_dev,ifnum,0); |
2110 | 2122 | ||
@@ -3275,7 +3287,9 @@ int pvr2_hdw_register_access(struct pvr2_hdw *hdw, | |||
3275 | mutex_lock(&hdw->i2c_list_lock); do { | 3287 | mutex_lock(&hdw->i2c_list_lock); do { |
3276 | list_for_each(item,&hdw->i2c_clients) { | 3288 | list_for_each(item,&hdw->i2c_clients) { |
3277 | cp = list_entry(item,struct pvr2_i2c_client,list); | 3289 | cp = list_entry(item,struct pvr2_i2c_client,list); |
3278 | if (!v4l2_chip_match_i2c_client(cp->client, req.match_type, req.match_chip)) { | 3290 | if (!v4l2_chip_match_i2c_client( |
3291 | cp->client, | ||
3292 | req.match_type, req.match_chip)) { | ||
3279 | continue; | 3293 | continue; |
3280 | } | 3294 | } |
3281 | stat = pvr2_i2c_client_cmd( | 3295 | stat = pvr2_i2c_client_cmd( |
diff --git a/drivers/media/video/pvrusb2/pvrusb2-hdw.h b/drivers/media/video/pvrusb2/pvrusb2-hdw.h index 0c9cca43ff85..4dba8d006324 100644 --- a/drivers/media/video/pvrusb2/pvrusb2-hdw.h +++ b/drivers/media/video/pvrusb2/pvrusb2-hdw.h | |||
@@ -124,6 +124,9 @@ struct usb_device *pvr2_hdw_get_dev(struct pvr2_hdw *); | |||
124 | /* Retrieve serial number of device */ | 124 | /* Retrieve serial number of device */ |
125 | unsigned long pvr2_hdw_get_sn(struct pvr2_hdw *); | 125 | unsigned long pvr2_hdw_get_sn(struct pvr2_hdw *); |
126 | 126 | ||
127 | /* Retrieve bus location info of device */ | ||
128 | const char *pvr2_hdw_get_bus_info(struct pvr2_hdw *); | ||
129 | |||
127 | /* Called when hardware has been unplugged */ | 130 | /* Called when hardware has been unplugged */ |
128 | void pvr2_hdw_disconnect(struct pvr2_hdw *); | 131 | void pvr2_hdw_disconnect(struct pvr2_hdw *); |
129 | 132 | ||
diff --git a/drivers/media/video/pvrusb2/pvrusb2-sysfs.c b/drivers/media/video/pvrusb2/pvrusb2-sysfs.c index 91396fd573e4..a741c556a39a 100644 --- a/drivers/media/video/pvrusb2/pvrusb2-sysfs.c +++ b/drivers/media/video/pvrusb2/pvrusb2-sysfs.c | |||
@@ -42,9 +42,11 @@ struct pvr2_sysfs { | |||
42 | struct class_device_attribute attr_v4l_minor_number; | 42 | struct class_device_attribute attr_v4l_minor_number; |
43 | struct class_device_attribute attr_v4l_radio_minor_number; | 43 | struct class_device_attribute attr_v4l_radio_minor_number; |
44 | struct class_device_attribute attr_unit_number; | 44 | struct class_device_attribute attr_unit_number; |
45 | struct class_device_attribute attr_bus_info; | ||
45 | int v4l_minor_number_created_ok; | 46 | int v4l_minor_number_created_ok; |
46 | int v4l_radio_minor_number_created_ok; | 47 | int v4l_radio_minor_number_created_ok; |
47 | int unit_number_created_ok; | 48 | int unit_number_created_ok; |
49 | int bus_info_created_ok; | ||
48 | }; | 50 | }; |
49 | 51 | ||
50 | #ifdef CONFIG_VIDEO_PVRUSB2_DEBUGIFC | 52 | #ifdef CONFIG_VIDEO_PVRUSB2_DEBUGIFC |
@@ -705,6 +707,10 @@ static void class_dev_destroy(struct pvr2_sysfs *sfp) | |||
705 | pvr2_sysfs_tear_down_debugifc(sfp); | 707 | pvr2_sysfs_tear_down_debugifc(sfp); |
706 | #endif /* CONFIG_VIDEO_PVRUSB2_DEBUGIFC */ | 708 | #endif /* CONFIG_VIDEO_PVRUSB2_DEBUGIFC */ |
707 | pvr2_sysfs_tear_down_controls(sfp); | 709 | pvr2_sysfs_tear_down_controls(sfp); |
710 | if (sfp->bus_info_created_ok) { | ||
711 | class_device_remove_file(sfp->class_dev, | ||
712 | &sfp->attr_bus_info); | ||
713 | } | ||
708 | if (sfp->v4l_minor_number_created_ok) { | 714 | if (sfp->v4l_minor_number_created_ok) { |
709 | class_device_remove_file(sfp->class_dev, | 715 | class_device_remove_file(sfp->class_dev, |
710 | &sfp->attr_v4l_minor_number); | 716 | &sfp->attr_v4l_minor_number); |
@@ -735,6 +741,16 @@ static ssize_t v4l_minor_number_show(struct class_device *class_dev,char *buf) | |||
735 | } | 741 | } |
736 | 742 | ||
737 | 743 | ||
744 | static ssize_t bus_info_show(struct class_device *class_dev,char *buf) | ||
745 | { | ||
746 | struct pvr2_sysfs *sfp; | ||
747 | sfp = (struct pvr2_sysfs *)class_dev->class_data; | ||
748 | if (!sfp) return -EINVAL; | ||
749 | return scnprintf(buf,PAGE_SIZE,"%s\n", | ||
750 | pvr2_hdw_get_bus_info(sfp->channel.hdw)); | ||
751 | } | ||
752 | |||
753 | |||
738 | static ssize_t v4l_radio_minor_number_show(struct class_device *class_dev, | 754 | static ssize_t v4l_radio_minor_number_show(struct class_device *class_dev, |
739 | char *buf) | 755 | char *buf) |
740 | { | 756 | { |
@@ -836,6 +852,20 @@ static void class_dev_create(struct pvr2_sysfs *sfp, | |||
836 | sfp->unit_number_created_ok = !0; | 852 | sfp->unit_number_created_ok = !0; |
837 | } | 853 | } |
838 | 854 | ||
855 | sfp->attr_bus_info.attr.owner = THIS_MODULE; | ||
856 | sfp->attr_bus_info.attr.name = "bus_info_str"; | ||
857 | sfp->attr_bus_info.attr.mode = S_IRUGO; | ||
858 | sfp->attr_bus_info.show = bus_info_show; | ||
859 | sfp->attr_bus_info.store = NULL; | ||
860 | ret = class_device_create_file(sfp->class_dev, | ||
861 | &sfp->attr_bus_info); | ||
862 | if (ret < 0) { | ||
863 | printk(KERN_WARNING "%s: class_device_create_file error: %d\n", | ||
864 | __FUNCTION__, ret); | ||
865 | } else { | ||
866 | sfp->bus_info_created_ok = !0; | ||
867 | } | ||
868 | |||
839 | pvr2_sysfs_add_controls(sfp); | 869 | pvr2_sysfs_add_controls(sfp); |
840 | #ifdef CONFIG_VIDEO_PVRUSB2_DEBUGIFC | 870 | #ifdef CONFIG_VIDEO_PVRUSB2_DEBUGIFC |
841 | pvr2_sysfs_add_debugifc(sfp); | 871 | pvr2_sysfs_add_debugifc(sfp); |
diff --git a/drivers/media/video/pvrusb2/pvrusb2-v4l2.c b/drivers/media/video/pvrusb2/pvrusb2-v4l2.c index 25d3830b482a..4563b3df8a0d 100644 --- a/drivers/media/video/pvrusb2/pvrusb2-v4l2.c +++ b/drivers/media/video/pvrusb2/pvrusb2-v4l2.c | |||
@@ -203,6 +203,8 @@ static int pvr2_v4l2_do_ioctl(struct inode *inode, struct file *file, | |||
203 | struct v4l2_capability *cap = arg; | 203 | struct v4l2_capability *cap = arg; |
204 | 204 | ||
205 | memcpy(cap, &pvr_capability, sizeof(struct v4l2_capability)); | 205 | memcpy(cap, &pvr_capability, sizeof(struct v4l2_capability)); |
206 | strlcpy(cap->bus_info,pvr2_hdw_get_bus_info(hdw), | ||
207 | sizeof(cap->bus_info)); | ||
206 | 208 | ||
207 | ret = 0; | 209 | ret = 0; |
208 | break; | 210 | break; |
diff --git a/drivers/media/video/pwc/pwc-ctrl.c b/drivers/media/video/pwc/pwc-ctrl.c index 0bd115588f31..338ced7188f2 100644 --- a/drivers/media/video/pwc/pwc-ctrl.c +++ b/drivers/media/video/pwc/pwc-ctrl.c | |||
@@ -140,6 +140,8 @@ static const char *size2name[PSZ_MAX] = | |||
140 | An alternate value of 0 means this mode is not available at all. | 140 | An alternate value of 0 means this mode is not available at all. |
141 | */ | 141 | */ |
142 | 142 | ||
143 | #define PWC_FPS_MAX_NALA 8 | ||
144 | |||
143 | struct Nala_table_entry { | 145 | struct Nala_table_entry { |
144 | char alternate; /* USB alternate setting */ | 146 | char alternate; /* USB alternate setting */ |
145 | int compressed; /* Compressed yes/no */ | 147 | int compressed; /* Compressed yes/no */ |
@@ -147,7 +149,9 @@ struct Nala_table_entry { | |||
147 | unsigned char mode[3]; /* precomputed mode table */ | 149 | unsigned char mode[3]; /* precomputed mode table */ |
148 | }; | 150 | }; |
149 | 151 | ||
150 | static struct Nala_table_entry Nala_table[PSZ_MAX][8] = | 152 | static unsigned int Nala_fps_vector[PWC_FPS_MAX_NALA] = { 4, 5, 7, 10, 12, 15, 20, 24 }; |
153 | |||
154 | static struct Nala_table_entry Nala_table[PSZ_MAX][PWC_FPS_MAX_NALA] = | ||
151 | { | 155 | { |
152 | #include "pwc-nala.h" | 156 | #include "pwc-nala.h" |
153 | }; | 157 | }; |
@@ -423,6 +427,59 @@ int pwc_set_video_mode(struct pwc_device *pdev, int width, int height, int frame | |||
423 | return 0; | 427 | return 0; |
424 | } | 428 | } |
425 | 429 | ||
430 | static unsigned int pwc_get_fps_Nala(struct pwc_device *pdev, unsigned int index, unsigned int size) | ||
431 | { | ||
432 | unsigned int i; | ||
433 | |||
434 | for (i = 0; i < PWC_FPS_MAX_NALA; i++) { | ||
435 | if (Nala_table[size][i].alternate) { | ||
436 | if (index--==0) return Nala_fps_vector[i]; | ||
437 | } | ||
438 | } | ||
439 | return 0; | ||
440 | } | ||
441 | |||
442 | static unsigned int pwc_get_fps_Kiara(struct pwc_device *pdev, unsigned int index, unsigned int size) | ||
443 | { | ||
444 | unsigned int i; | ||
445 | |||
446 | for (i = 0; i < PWC_FPS_MAX_KIARA; i++) { | ||
447 | if (Kiara_table[size][i][3].alternate) { | ||
448 | if (index--==0) return Kiara_fps_vector[i]; | ||
449 | } | ||
450 | } | ||
451 | return 0; | ||
452 | } | ||
453 | |||
454 | static unsigned int pwc_get_fps_Timon(struct pwc_device *pdev, unsigned int index, unsigned int size) | ||
455 | { | ||
456 | unsigned int i; | ||
457 | |||
458 | for (i=0; i < PWC_FPS_MAX_TIMON; i++) { | ||
459 | if (Timon_table[size][i][3].alternate) { | ||
460 | if (index--==0) return Timon_fps_vector[i]; | ||
461 | } | ||
462 | } | ||
463 | return 0; | ||
464 | } | ||
465 | |||
466 | unsigned int pwc_get_fps(struct pwc_device *pdev, unsigned int index, unsigned int size) | ||
467 | { | ||
468 | unsigned int ret; | ||
469 | |||
470 | if (DEVICE_USE_CODEC1(pdev->type)) { | ||
471 | ret = pwc_get_fps_Nala(pdev, index, size); | ||
472 | |||
473 | } else if (DEVICE_USE_CODEC3(pdev->type)) { | ||
474 | ret = pwc_get_fps_Kiara(pdev, index, size); | ||
475 | |||
476 | } else { | ||
477 | ret = pwc_get_fps_Timon(pdev, index, size); | ||
478 | } | ||
479 | |||
480 | return ret; | ||
481 | } | ||
482 | |||
426 | #define BLACK_Y 0 | 483 | #define BLACK_Y 0 |
427 | #define BLACK_U 128 | 484 | #define BLACK_U 128 |
428 | #define BLACK_V 128 | 485 | #define BLACK_V 128 |
@@ -1343,7 +1400,7 @@ int pwc_ioctl(struct pwc_device *pdev, unsigned int cmd, void *arg) | |||
1343 | ret = pwc_read_red_gain(pdev, &ARGR(wb).read_red); | 1400 | ret = pwc_read_red_gain(pdev, &ARGR(wb).read_red); |
1344 | if (ret < 0) | 1401 | if (ret < 0) |
1345 | break; | 1402 | break; |
1346 | ret =pwc_read_blue_gain(pdev, &ARGR(wb).read_blue); | 1403 | ret = pwc_read_blue_gain(pdev, &ARGR(wb).read_blue); |
1347 | if (ret < 0) | 1404 | if (ret < 0) |
1348 | break; | 1405 | break; |
1349 | } | 1406 | } |
diff --git a/drivers/media/video/pwc/pwc-if.c b/drivers/media/video/pwc/pwc-if.c index 27ed76986ca2..085332a503de 100644 --- a/drivers/media/video/pwc/pwc-if.c +++ b/drivers/media/video/pwc/pwc-if.c | |||
@@ -95,8 +95,8 @@ static const struct usb_device_id pwc_device_table [] = { | |||
95 | { USB_DEVICE(0x046D, 0x08B3) }, /* Logitech QuickCam Zoom (old model) */ | 95 | { USB_DEVICE(0x046D, 0x08B3) }, /* Logitech QuickCam Zoom (old model) */ |
96 | { USB_DEVICE(0x046D, 0x08B4) }, /* Logitech QuickCam Zoom (new model) */ | 96 | { USB_DEVICE(0x046D, 0x08B4) }, /* Logitech QuickCam Zoom (new model) */ |
97 | { USB_DEVICE(0x046D, 0x08B5) }, /* Logitech QuickCam Orbit/Sphere */ | 97 | { USB_DEVICE(0x046D, 0x08B5) }, /* Logitech QuickCam Orbit/Sphere */ |
98 | { USB_DEVICE(0x046D, 0x08B6) }, /* Logitech (reserved) */ | 98 | { USB_DEVICE(0x046D, 0x08B6) }, /* Cisco VT Camera */ |
99 | { USB_DEVICE(0x046D, 0x08B7) }, /* Logitech (reserved) */ | 99 | { USB_DEVICE(0x046D, 0x08B7) }, /* Logitech ViewPort AV 100 */ |
100 | { USB_DEVICE(0x046D, 0x08B8) }, /* Logitech (reserved) */ | 100 | { USB_DEVICE(0x046D, 0x08B8) }, /* Logitech (reserved) */ |
101 | { USB_DEVICE(0x055D, 0x9000) }, /* Samsung MPC-C10 */ | 101 | { USB_DEVICE(0x055D, 0x9000) }, /* Samsung MPC-C10 */ |
102 | { USB_DEVICE(0x055D, 0x9001) }, /* Samsung MPC-C30 */ | 102 | { USB_DEVICE(0x055D, 0x9001) }, /* Samsung MPC-C30 */ |
@@ -1493,7 +1493,7 @@ static int usb_pwc_probe(struct usb_interface *intf, const struct usb_device_id | |||
1493 | case 0x0329: | 1493 | case 0x0329: |
1494 | PWC_INFO("Philips SPC 900NC USB webcam detected.\n"); | 1494 | PWC_INFO("Philips SPC 900NC USB webcam detected.\n"); |
1495 | name = "Philips SPC 900NC webcam"; | 1495 | name = "Philips SPC 900NC webcam"; |
1496 | type_id = 720; | 1496 | type_id = 740; |
1497 | break; | 1497 | break; |
1498 | default: | 1498 | default: |
1499 | return -ENODEV; | 1499 | return -ENODEV; |
@@ -1547,8 +1547,16 @@ static int usb_pwc_probe(struct usb_interface *intf, const struct usb_device_id | |||
1547 | features |= FEATURE_MOTOR_PANTILT; | 1547 | features |= FEATURE_MOTOR_PANTILT; |
1548 | break; | 1548 | break; |
1549 | case 0x08b6: | 1549 | case 0x08b6: |
1550 | PWC_INFO("Logitech/Cisco VT Camera webcam detected.\n"); | ||
1551 | name = "Cisco VT Camera"; | ||
1552 | type_id = 740; /* CCD sensor */ | ||
1553 | break; | ||
1550 | case 0x08b7: | 1554 | case 0x08b7: |
1551 | case 0x08b8: | 1555 | PWC_INFO("Logitech ViewPort AV 100 webcam detected.\n"); |
1556 | name = "Logitech ViewPort AV 100"; | ||
1557 | type_id = 740; /* CCD sensor */ | ||
1558 | break; | ||
1559 | case 0x08b8: /* Where this released? */ | ||
1552 | PWC_INFO("Logitech QuickCam detected (reserved ID).\n"); | 1560 | PWC_INFO("Logitech QuickCam detected (reserved ID).\n"); |
1553 | name = "Logitech QuickCam (res.)"; | 1561 | name = "Logitech QuickCam (res.)"; |
1554 | type_id = 730; /* Assuming CMOS */ | 1562 | type_id = 730; /* Assuming CMOS */ |
diff --git a/drivers/media/video/pwc/pwc-ioctl.h b/drivers/media/video/pwc/pwc-ioctl.h index 784bc72521fa..cec660299768 100644 --- a/drivers/media/video/pwc/pwc-ioctl.h +++ b/drivers/media/video/pwc/pwc-ioctl.h | |||
@@ -2,7 +2,7 @@ | |||
2 | #define PWC_IOCTL_H | 2 | #define PWC_IOCTL_H |
3 | 3 | ||
4 | /* (C) 2001-2004 Nemosoft Unv. | 4 | /* (C) 2001-2004 Nemosoft Unv. |
5 | (C) 2004 Luc Saillard (luc@saillard.org) | 5 | (C) 2004-2006 Luc Saillard (luc@saillard.org) |
6 | 6 | ||
7 | NOTE: this version of pwc is an unofficial (modified) release of pwc & pcwx | 7 | NOTE: this version of pwc is an unofficial (modified) release of pwc & pcwx |
8 | driver and thus may have bugs that are not present in the original version. | 8 | driver and thus may have bugs that are not present in the original version. |
@@ -25,7 +25,7 @@ | |||
25 | Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | 25 | Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
26 | */ | 26 | */ |
27 | 27 | ||
28 | /* This is pwc-ioctl.h belonging to PWC 8.12.1 | 28 | /* This is pwc-ioctl.h belonging to PWC 10.0.10 |
29 | It contains structures and defines to communicate from user space | 29 | It contains structures and defines to communicate from user space |
30 | directly to the driver. | 30 | directly to the driver. |
31 | */ | 31 | */ |
@@ -51,6 +51,9 @@ | |||
51 | ... the function | 51 | ... the function |
52 | */ | 52 | */ |
53 | 53 | ||
54 | #include <linux/types.h> | ||
55 | #include <linux/version.h> | ||
56 | |||
54 | 57 | ||
55 | /* Enumeration of image sizes */ | 58 | /* Enumeration of image sizes */ |
56 | #define PSZ_SQCIF 0x00 | 59 | #define PSZ_SQCIF 0x00 |
@@ -65,6 +68,8 @@ | |||
65 | /* The frame rate is encoded in the video_window.flags parameter using | 68 | /* The frame rate is encoded in the video_window.flags parameter using |
66 | the upper 16 bits, since some flags are defined nowadays. The following | 69 | the upper 16 bits, since some flags are defined nowadays. The following |
67 | defines provide a mask and shift to filter out this value. | 70 | defines provide a mask and shift to filter out this value. |
71 | This value can also be passing using the private flag when using v4l2 and | ||
72 | VIDIOC_S_FMT ioctl. | ||
68 | 73 | ||
69 | In 'Snapshot' mode the camera freezes its automatic exposure and colour | 74 | In 'Snapshot' mode the camera freezes its automatic exposure and colour |
70 | balance controls. | 75 | balance controls. |
@@ -73,6 +78,8 @@ | |||
73 | #define PWC_FPS_MASK 0x00FF0000 | 78 | #define PWC_FPS_MASK 0x00FF0000 |
74 | #define PWC_FPS_FRMASK 0x003F0000 | 79 | #define PWC_FPS_FRMASK 0x003F0000 |
75 | #define PWC_FPS_SNAPSHOT 0x00400000 | 80 | #define PWC_FPS_SNAPSHOT 0x00400000 |
81 | #define PWC_QLT_MASK 0x03000000 | ||
82 | #define PWC_QLT_SHIFT 24 | ||
76 | 83 | ||
77 | 84 | ||
78 | /* structure for transferring x & y coordinates */ | 85 | /* structure for transferring x & y coordinates */ |
@@ -289,4 +296,29 @@ struct pwc_table_init_buffer { | |||
289 | }; | 296 | }; |
290 | #define VIDIOCPWCGVIDTABLE _IOR('v', 216, struct pwc_table_init_buffer) | 297 | #define VIDIOCPWCGVIDTABLE _IOR('v', 216, struct pwc_table_init_buffer) |
291 | 298 | ||
299 | /* | ||
300 | * This is private command used when communicating with v4l2. | ||
301 | * In the future all private ioctl will be remove/replace to | ||
302 | * use interface offer by v4l2. | ||
303 | */ | ||
304 | |||
305 | #define V4L2_CID_PRIVATE_SAVE_USER (V4L2_CID_PRIVATE_BASE + 0) | ||
306 | #define V4L2_CID_PRIVATE_RESTORE_USER (V4L2_CID_PRIVATE_BASE + 1) | ||
307 | #define V4L2_CID_PRIVATE_RESTORE_FACTORY (V4L2_CID_PRIVATE_BASE + 2) | ||
308 | #define V4L2_CID_PRIVATE_COLOUR_MODE (V4L2_CID_PRIVATE_BASE + 3) | ||
309 | #define V4L2_CID_PRIVATE_AUTOCONTOUR (V4L2_CID_PRIVATE_BASE + 4) | ||
310 | #define V4L2_CID_PRIVATE_CONTOUR (V4L2_CID_PRIVATE_BASE + 5) | ||
311 | #define V4L2_CID_PRIVATE_BACKLIGHT (V4L2_CID_PRIVATE_BASE + 6) | ||
312 | #define V4L2_CID_PRIVATE_FLICKERLESS (V4L2_CID_PRIVATE_BASE + 7) | ||
313 | #define V4L2_CID_PRIVATE_NOISE_REDUCTION (V4L2_CID_PRIVATE_BASE + 8) | ||
314 | |||
315 | struct pwc_raw_frame { | ||
316 | __le16 type; /* type of the webcam */ | ||
317 | __le16 vbandlength; /* Size of 4lines compressed (used by the decompressor) */ | ||
318 | __u8 cmd[4]; /* the four byte of the command (in case of nala, | ||
319 | only the first 3 bytes is filled) */ | ||
320 | __u8 rawframe[0]; /* frame_size = H/4*vbandlength */ | ||
321 | } __attribute__ ((packed)); | ||
322 | |||
323 | |||
292 | #endif | 324 | #endif |
diff --git a/drivers/media/video/pwc/pwc-kiara.c b/drivers/media/video/pwc/pwc-kiara.c index fec39cc5a9f1..f4ae83c0cf2b 100644 --- a/drivers/media/video/pwc/pwc-kiara.c +++ b/drivers/media/video/pwc/pwc-kiara.c | |||
@@ -42,6 +42,8 @@ | |||
42 | #include "pwc-kiara.h" | 42 | #include "pwc-kiara.h" |
43 | #include "pwc-uncompress.h" | 43 | #include "pwc-uncompress.h" |
44 | 44 | ||
45 | const unsigned int Kiara_fps_vector[PWC_FPS_MAX_KIARA] = { 5, 10, 15, 20, 25, 30 }; | ||
46 | |||
45 | const struct Kiara_table_entry Kiara_table[PSZ_MAX][6][4] = | 47 | const struct Kiara_table_entry Kiara_table[PSZ_MAX][6][4] = |
46 | { | 48 | { |
47 | /* SQCIF */ | 49 | /* SQCIF */ |
diff --git a/drivers/media/video/pwc/pwc-kiara.h b/drivers/media/video/pwc/pwc-kiara.h index 0bdb22547d86..047dad8c15f7 100644 --- a/drivers/media/video/pwc/pwc-kiara.h +++ b/drivers/media/video/pwc/pwc-kiara.h | |||
@@ -29,6 +29,8 @@ | |||
29 | 29 | ||
30 | #include <media/pwc-ioctl.h> | 30 | #include <media/pwc-ioctl.h> |
31 | 31 | ||
32 | #define PWC_FPS_MAX_KIARA 6 | ||
33 | |||
32 | struct Kiara_table_entry | 34 | struct Kiara_table_entry |
33 | { | 35 | { |
34 | char alternate; /* USB alternate interface */ | 36 | char alternate; /* USB alternate interface */ |
@@ -37,8 +39,9 @@ struct Kiara_table_entry | |||
37 | unsigned char mode[12]; /* precomputed mode settings for cam */ | 39 | unsigned char mode[12]; /* precomputed mode settings for cam */ |
38 | }; | 40 | }; |
39 | 41 | ||
40 | extern const struct Kiara_table_entry Kiara_table[PSZ_MAX][6][4]; | 42 | extern const struct Kiara_table_entry Kiara_table[PSZ_MAX][PWC_FPS_MAX_KIARA][4]; |
41 | extern const unsigned int KiaraRomTable[8][2][16][8]; | 43 | extern const unsigned int KiaraRomTable[8][2][16][8]; |
44 | extern const unsigned int Kiara_fps_vector[PWC_FPS_MAX_KIARA]; | ||
42 | 45 | ||
43 | #endif | 46 | #endif |
44 | 47 | ||
diff --git a/drivers/media/video/pwc/pwc-timon.c b/drivers/media/video/pwc/pwc-timon.c index be65bdcd195b..c56c174b161c 100644 --- a/drivers/media/video/pwc/pwc-timon.c +++ b/drivers/media/video/pwc/pwc-timon.c | |||
@@ -40,7 +40,9 @@ | |||
40 | 40 | ||
41 | #include "pwc-timon.h" | 41 | #include "pwc-timon.h" |
42 | 42 | ||
43 | const struct Timon_table_entry Timon_table[PSZ_MAX][6][4] = | 43 | const unsigned int Timon_fps_vector[PWC_FPS_MAX_TIMON] = { 5, 10, 15, 20, 25, 30 }; |
44 | |||
45 | const struct Timon_table_entry Timon_table[PSZ_MAX][PWC_FPS_MAX_TIMON][4] = | ||
44 | { | 46 | { |
45 | /* SQCIF */ | 47 | /* SQCIF */ |
46 | { | 48 | { |
diff --git a/drivers/media/video/pwc/pwc-timon.h b/drivers/media/video/pwc/pwc-timon.h index eef9e2cd4320..a6e22224c95f 100644 --- a/drivers/media/video/pwc/pwc-timon.h +++ b/drivers/media/video/pwc/pwc-timon.h | |||
@@ -44,6 +44,8 @@ | |||
44 | 44 | ||
45 | #include <media/pwc-ioctl.h> | 45 | #include <media/pwc-ioctl.h> |
46 | 46 | ||
47 | #define PWC_FPS_MAX_TIMON 6 | ||
48 | |||
47 | struct Timon_table_entry | 49 | struct Timon_table_entry |
48 | { | 50 | { |
49 | char alternate; /* USB alternate interface */ | 51 | char alternate; /* USB alternate interface */ |
@@ -52,9 +54,9 @@ struct Timon_table_entry | |||
52 | unsigned char mode[13]; /* precomputed mode settings for cam */ | 54 | unsigned char mode[13]; /* precomputed mode settings for cam */ |
53 | }; | 55 | }; |
54 | 56 | ||
55 | extern const struct Timon_table_entry Timon_table[PSZ_MAX][6][4]; | 57 | extern const struct Timon_table_entry Timon_table[PSZ_MAX][PWC_FPS_MAX_TIMON][4]; |
56 | extern const unsigned int TimonRomTable [16][2][16][8]; | 58 | extern const unsigned int TimonRomTable [16][2][16][8]; |
57 | 59 | extern const unsigned int Timon_fps_vector[PWC_FPS_MAX_TIMON]; | |
58 | 60 | ||
59 | #endif | 61 | #endif |
60 | 62 | ||
diff --git a/drivers/media/video/pwc/pwc-v4l.c b/drivers/media/video/pwc/pwc-v4l.c index d5e6bc850643..32fbe1ae6251 100644 --- a/drivers/media/video/pwc/pwc-v4l.c +++ b/drivers/media/video/pwc/pwc-v4l.c | |||
@@ -1168,7 +1168,7 @@ int pwc_video_do_ioctl(struct inode *inode, struct file *file, | |||
1168 | buf->sequence = 0; | 1168 | buf->sequence = 0; |
1169 | buf->memory = V4L2_MEMORY_MMAP; | 1169 | buf->memory = V4L2_MEMORY_MMAP; |
1170 | buf->m.offset = pdev->fill_image * pdev->len_per_image; | 1170 | buf->m.offset = pdev->fill_image * pdev->len_per_image; |
1171 | buf->length = buf->bytesused; | 1171 | buf->length = pdev->len_per_image; |
1172 | pwc_next_image(pdev); | 1172 | pwc_next_image(pdev); |
1173 | 1173 | ||
1174 | PWC_DEBUG_IOCTL("VIDIOC_DQBUF: buf->index=%d\n",buf->index); | 1174 | PWC_DEBUG_IOCTL("VIDIOC_DQBUF: buf->index=%d\n",buf->index); |
@@ -1193,6 +1193,64 @@ int pwc_video_do_ioctl(struct inode *inode, struct file *file, | |||
1193 | return 0; | 1193 | return 0; |
1194 | } | 1194 | } |
1195 | 1195 | ||
1196 | case VIDIOC_ENUM_FRAMESIZES: | ||
1197 | { | ||
1198 | struct v4l2_frmsizeenum *fsize = arg; | ||
1199 | unsigned int i = 0, index = fsize->index; | ||
1200 | |||
1201 | if (fsize->pixel_format == V4L2_PIX_FMT_YUV420) { | ||
1202 | for (i = 0; i < PSZ_MAX; i++) { | ||
1203 | if (pdev->image_mask & (1UL << i)) { | ||
1204 | if (!index--) { | ||
1205 | fsize->type = V4L2_FRMSIZE_TYPE_DISCRETE; | ||
1206 | fsize->discrete.width = pwc_image_sizes[i].x; | ||
1207 | fsize->discrete.height = pwc_image_sizes[i].y; | ||
1208 | return 0; | ||
1209 | } | ||
1210 | } | ||
1211 | } | ||
1212 | } else if (fsize->index == 0 && | ||
1213 | ((fsize->pixel_format == V4L2_PIX_FMT_PWC1 && DEVICE_USE_CODEC1(pdev->type)) || | ||
1214 | (fsize->pixel_format == V4L2_PIX_FMT_PWC2 && DEVICE_USE_CODEC23(pdev->type)))) { | ||
1215 | |||
1216 | fsize->type = V4L2_FRMSIZE_TYPE_DISCRETE; | ||
1217 | fsize->discrete.width = pdev->abs_max.x; | ||
1218 | fsize->discrete.height = pdev->abs_max.y; | ||
1219 | return 0; | ||
1220 | } | ||
1221 | return -EINVAL; | ||
1222 | } | ||
1223 | |||
1224 | case VIDIOC_ENUM_FRAMEINTERVALS: | ||
1225 | { | ||
1226 | struct v4l2_frmivalenum *fival = arg; | ||
1227 | int size = -1; | ||
1228 | unsigned int i; | ||
1229 | |||
1230 | for (i = 0; i < PSZ_MAX; i++) { | ||
1231 | if (pwc_image_sizes[i].x == fival->width && | ||
1232 | pwc_image_sizes[i].y == fival->height) { | ||
1233 | size = i; | ||
1234 | break; | ||
1235 | } | ||
1236 | } | ||
1237 | |||
1238 | /* TODO: Support raw format */ | ||
1239 | if (size < 0 || fival->pixel_format != V4L2_PIX_FMT_YUV420) { | ||
1240 | return -EINVAL; | ||
1241 | } | ||
1242 | |||
1243 | i = pwc_get_fps(pdev, fival->index, size); | ||
1244 | if (!i) | ||
1245 | return -EINVAL; | ||
1246 | |||
1247 | fival->type = V4L2_FRMIVAL_TYPE_DISCRETE; | ||
1248 | fival->discrete.numerator = 1; | ||
1249 | fival->discrete.denominator = i; | ||
1250 | |||
1251 | return 0; | ||
1252 | } | ||
1253 | |||
1196 | default: | 1254 | default: |
1197 | return pwc_ioctl(pdev, cmd, arg); | 1255 | return pwc_ioctl(pdev, cmd, arg); |
1198 | } /* ..switch */ | 1256 | } /* ..switch */ |
diff --git a/drivers/media/video/pwc/pwc.h b/drivers/media/video/pwc/pwc.h index e778a2b8c280..acbb9312960a 100644 --- a/drivers/media/video/pwc/pwc.h +++ b/drivers/media/video/pwc/pwc.h | |||
@@ -44,7 +44,7 @@ | |||
44 | #define PWC_MINOR 0 | 44 | #define PWC_MINOR 0 |
45 | #define PWC_EXTRAMINOR 12 | 45 | #define PWC_EXTRAMINOR 12 |
46 | #define PWC_VERSION_CODE KERNEL_VERSION(PWC_MAJOR,PWC_MINOR,PWC_EXTRAMINOR) | 46 | #define PWC_VERSION_CODE KERNEL_VERSION(PWC_MAJOR,PWC_MINOR,PWC_EXTRAMINOR) |
47 | #define PWC_VERSION "10.0.12" | 47 | #define PWC_VERSION "10.0.13" |
48 | #define PWC_NAME "pwc" | 48 | #define PWC_NAME "pwc" |
49 | #define PFX PWC_NAME ": " | 49 | #define PFX PWC_NAME ": " |
50 | 50 | ||
@@ -85,7 +85,7 @@ | |||
85 | #define PWC_INFO(fmt, args...) printk(KERN_INFO PFX fmt, ##args) | 85 | #define PWC_INFO(fmt, args...) printk(KERN_INFO PFX fmt, ##args) |
86 | #define PWC_TRACE(fmt, args...) PWC_DEBUG(TRACE, fmt, ##args) | 86 | #define PWC_TRACE(fmt, args...) PWC_DEBUG(TRACE, fmt, ##args) |
87 | 87 | ||
88 | #else /* if ! CONFIG_PWC_DEBUG */ | 88 | #else /* if ! CONFIG_USB_PWC_DEBUG */ |
89 | 89 | ||
90 | #define PWC_ERROR(fmt, args...) printk(KERN_ERR PFX fmt, ##args) | 90 | #define PWC_ERROR(fmt, args...) printk(KERN_ERR PFX fmt, ##args) |
91 | #define PWC_WARNING(fmt, args...) printk(KERN_WARNING PFX fmt, ##args) | 91 | #define PWC_WARNING(fmt, args...) printk(KERN_WARNING PFX fmt, ##args) |
@@ -287,6 +287,7 @@ void pwc_construct(struct pwc_device *pdev); | |||
287 | /** Functions in pwc-ctrl.c */ | 287 | /** Functions in pwc-ctrl.c */ |
288 | /* Request a certain video mode. Returns < 0 if not possible */ | 288 | /* Request a certain video mode. Returns < 0 if not possible */ |
289 | extern int pwc_set_video_mode(struct pwc_device *pdev, int width, int height, int frames, int compression, int snapshot); | 289 | extern int pwc_set_video_mode(struct pwc_device *pdev, int width, int height, int frames, int compression, int snapshot); |
290 | extern unsigned int pwc_get_fps(struct pwc_device *pdev, unsigned int index, unsigned int size); | ||
290 | /* Calculate the number of bytes per image (not frame) */ | 291 | /* Calculate the number of bytes per image (not frame) */ |
291 | extern int pwc_mpt_reset(struct pwc_device *pdev, int flags); | 292 | extern int pwc_mpt_reset(struct pwc_device *pdev, int flags); |
292 | extern int pwc_mpt_set_angle(struct pwc_device *pdev, int pan, int tilt); | 293 | extern int pwc_mpt_set_angle(struct pwc_device *pdev, int pan, int tilt); |
diff --git a/drivers/media/video/saa7115.c b/drivers/media/video/saa7115.c index 4d5bbd859de1..2d18f0069821 100644 --- a/drivers/media/video/saa7115.c +++ b/drivers/media/video/saa7115.c | |||
@@ -45,6 +45,7 @@ | |||
45 | #include <linux/i2c.h> | 45 | #include <linux/i2c.h> |
46 | #include <linux/videodev2.h> | 46 | #include <linux/videodev2.h> |
47 | #include <media/v4l2-common.h> | 47 | #include <media/v4l2-common.h> |
48 | #include <media/v4l2-chip-ident.h> | ||
48 | #include <media/saa7115.h> | 49 | #include <media/saa7115.h> |
49 | #include <asm/div64.h> | 50 | #include <asm/div64.h> |
50 | 51 | ||
@@ -80,7 +81,7 @@ struct saa711x_state { | |||
80 | int sat; | 81 | int sat; |
81 | int width; | 82 | int width; |
82 | int height; | 83 | int height; |
83 | enum v4l2_chip_ident ident; | 84 | u32 ident; |
84 | u32 audclk_freq; | 85 | u32 audclk_freq; |
85 | u32 crystal_freq; | 86 | u32 crystal_freq; |
86 | u8 ucgc; | 87 | u8 ucgc; |
@@ -1232,7 +1233,6 @@ static void saa711x_decode_vbi_line(struct i2c_client *client, | |||
1232 | static int saa711x_command(struct i2c_client *client, unsigned int cmd, void *arg) | 1233 | static int saa711x_command(struct i2c_client *client, unsigned int cmd, void *arg) |
1233 | { | 1234 | { |
1234 | struct saa711x_state *state = i2c_get_clientdata(client); | 1235 | struct saa711x_state *state = i2c_get_clientdata(client); |
1235 | int *iarg = arg; | ||
1236 | 1236 | ||
1237 | /* ioctls to allow direct access to the saa7115 registers for testing */ | 1237 | /* ioctls to allow direct access to the saa7115 registers for testing */ |
1238 | switch (cmd) { | 1238 | switch (cmd) { |
@@ -1437,9 +1437,8 @@ static int saa711x_command(struct i2c_client *client, unsigned int cmd, void *ar | |||
1437 | } | 1437 | } |
1438 | #endif | 1438 | #endif |
1439 | 1439 | ||
1440 | case VIDIOC_INT_G_CHIP_IDENT: | 1440 | case VIDIOC_G_CHIP_IDENT: |
1441 | *iarg = state->ident; | 1441 | return v4l2_chip_ident_i2c_client(client, arg, state->ident, 0); |
1442 | break; | ||
1443 | 1442 | ||
1444 | default: | 1443 | default: |
1445 | return -EINVAL; | 1444 | return -EINVAL; |
@@ -1487,6 +1486,7 @@ static int saa711x_attach(struct i2c_adapter *adapter, int address, int kind) | |||
1487 | if (memcmp(name, "1f711", 5)) { | 1486 | if (memcmp(name, "1f711", 5)) { |
1488 | v4l_dbg(1, debug, client, "chip found @ 0x%x (ID %s) does not match a known saa711x chip.\n", | 1487 | v4l_dbg(1, debug, client, "chip found @ 0x%x (ID %s) does not match a known saa711x chip.\n", |
1489 | address << 1, name); | 1488 | address << 1, name); |
1489 | kfree(client); | ||
1490 | return 0; | 1490 | return 0; |
1491 | } | 1491 | } |
1492 | 1492 | ||
diff --git a/drivers/media/video/saa7127.c b/drivers/media/video/saa7127.c index 654863db1591..9f986930490f 100644 --- a/drivers/media/video/saa7127.c +++ b/drivers/media/video/saa7127.c | |||
@@ -54,6 +54,7 @@ | |||
54 | #include <linux/i2c.h> | 54 | #include <linux/i2c.h> |
55 | #include <linux/videodev2.h> | 55 | #include <linux/videodev2.h> |
56 | #include <media/v4l2-common.h> | 56 | #include <media/v4l2-common.h> |
57 | #include <media/v4l2-chip-ident.h> | ||
57 | #include <media/saa7127.h> | 58 | #include <media/saa7127.h> |
58 | 59 | ||
59 | static int debug = 0; | 60 | static int debug = 0; |
@@ -234,7 +235,7 @@ static struct i2c_reg_value saa7127_init_config_50hz[] = { | |||
234 | 235 | ||
235 | struct saa7127_state { | 236 | struct saa7127_state { |
236 | v4l2_std_id std; | 237 | v4l2_std_id std; |
237 | enum v4l2_chip_ident ident; | 238 | u32 ident; |
238 | enum saa7127_input_type input_type; | 239 | enum saa7127_input_type input_type; |
239 | enum saa7127_output_type output_type; | 240 | enum saa7127_output_type output_type; |
240 | int video_enable; | 241 | int video_enable; |
@@ -550,12 +551,12 @@ static int saa7127_command(struct i2c_client *client, | |||
550 | struct v4l2_routing *route = arg; | 551 | struct v4l2_routing *route = arg; |
551 | 552 | ||
552 | switch (cmd) { | 553 | switch (cmd) { |
553 | case VIDIOC_S_STD: | 554 | case VIDIOC_INT_S_STD_OUTPUT: |
554 | if (state->std == *(v4l2_std_id *)arg) | 555 | if (state->std == *(v4l2_std_id *)arg) |
555 | break; | 556 | break; |
556 | return saa7127_set_std(client, *(v4l2_std_id *)arg); | 557 | return saa7127_set_std(client, *(v4l2_std_id *)arg); |
557 | 558 | ||
558 | case VIDIOC_G_STD: | 559 | case VIDIOC_INT_G_STD_OUTPUT: |
559 | *(v4l2_std_id *)arg = state->std; | 560 | *(v4l2_std_id *)arg = state->std; |
560 | break; | 561 | break; |
561 | 562 | ||
@@ -650,9 +651,8 @@ static int saa7127_command(struct i2c_client *client, | |||
650 | break; | 651 | break; |
651 | } | 652 | } |
652 | 653 | ||
653 | case VIDIOC_INT_G_CHIP_IDENT: | 654 | case VIDIOC_G_CHIP_IDENT: |
654 | *(enum v4l2_chip_ident *)arg = state->ident; | 655 | return v4l2_chip_ident_i2c_client(client, arg, state->ident, 0); |
655 | break; | ||
656 | 656 | ||
657 | default: | 657 | default: |
658 | return -EINVAL; | 658 | return -EINVAL; |
diff --git a/drivers/media/video/saa7134/Kconfig b/drivers/media/video/saa7134/Kconfig index 59da79ce2efd..309dca368f4a 100644 --- a/drivers/media/video/saa7134/Kconfig +++ b/drivers/media/video/saa7134/Kconfig | |||
@@ -46,6 +46,7 @@ config VIDEO_SAA7134_DVB | |||
46 | select DVB_NXT200X if !DVB_FE_CUSTOMISE | 46 | select DVB_NXT200X if !DVB_FE_CUSTOMISE |
47 | select DVB_TDA10086 if !DVB_FE_CUSTOMISE | 47 | select DVB_TDA10086 if !DVB_FE_CUSTOMISE |
48 | select DVB_TDA826X if !DVB_FE_CUSTOMISE | 48 | select DVB_TDA826X if !DVB_FE_CUSTOMISE |
49 | select DVB_TDA827X if !DVB_FE_CUSTOMISE | ||
49 | select DVB_ISL6421 if !DVB_FE_CUSTOMISE | 50 | select DVB_ISL6421 if !DVB_FE_CUSTOMISE |
50 | ---help--- | 51 | ---help--- |
51 | This adds support for DVB cards based on the | 52 | This adds support for DVB cards based on the |
diff --git a/drivers/media/video/saa7134/saa7134-cards.c b/drivers/media/video/saa7134/saa7134-cards.c index 89f32107f46b..4ea479baee74 100644 --- a/drivers/media/video/saa7134/saa7134-cards.c +++ b/drivers/media/video/saa7134/saa7134-cards.c | |||
@@ -1543,12 +1543,12 @@ struct saa7134_board saa7134_boards[] = { | |||
1543 | },{ | 1543 | },{ |
1544 | .name = name_comp1, | 1544 | .name = name_comp1, |
1545 | .vmux = 0, | 1545 | .vmux = 0, |
1546 | .amux = LINE2, | 1546 | .amux = LINE1, |
1547 | .gpio = 0x02, | 1547 | .gpio = 0x02, |
1548 | },{ | 1548 | },{ |
1549 | .name = name_svideo, | 1549 | .name = name_svideo, |
1550 | .vmux = 6, | 1550 | .vmux = 6, |
1551 | .amux = LINE2, | 1551 | .amux = LINE1, |
1552 | .gpio = 0x02, | 1552 | .gpio = 0x02, |
1553 | }}, | 1553 | }}, |
1554 | .radio = { | 1554 | .radio = { |
@@ -1778,17 +1778,19 @@ struct saa7134_board saa7134_boards[] = { | |||
1778 | [SAA7134_BOARD_FLYDVBTDUO] = { | 1778 | [SAA7134_BOARD_FLYDVBTDUO] = { |
1779 | /* LifeView FlyDVB-T DUO */ | 1779 | /* LifeView FlyDVB-T DUO */ |
1780 | /* "Nico Sabbi <nsabbi@tiscali.it> Hartmut Hackmann hartmut.hackmann@t-online.de*/ | 1780 | /* "Nico Sabbi <nsabbi@tiscali.it> Hartmut Hackmann hartmut.hackmann@t-online.de*/ |
1781 | .name = "LifeView FlyDVB-T DUO", | 1781 | .name = "LifeView FlyDVB-T DUO / MSI TV@nywhere Duo", |
1782 | .audio_clock = 0x00200000, | 1782 | .audio_clock = 0x00200000, |
1783 | .tuner_type = TUNER_PHILIPS_TDA8290, | 1783 | .tuner_type = TUNER_PHILIPS_TDA8290, |
1784 | .radio_type = UNSET, | 1784 | .radio_type = UNSET, |
1785 | .tuner_addr = ADDR_UNSET, | 1785 | .tuner_addr = ADDR_UNSET, |
1786 | .radio_addr = ADDR_UNSET, | 1786 | .radio_addr = ADDR_UNSET, |
1787 | .gpiomask = 0x00200000, | ||
1787 | .mpeg = SAA7134_MPEG_DVB, | 1788 | .mpeg = SAA7134_MPEG_DVB, |
1788 | .inputs = {{ | 1789 | .inputs = {{ |
1789 | .name = name_tv, | 1790 | .name = name_tv, |
1790 | .vmux = 1, | 1791 | .vmux = 1, |
1791 | .amux = TV, | 1792 | .amux = TV, |
1793 | .gpio = 0x200000, /* GPIO21=High for TV input */ | ||
1792 | .tv = 1, | 1794 | .tv = 1, |
1793 | },{ | 1795 | },{ |
1794 | .name = name_comp1, /* Composite signal on S-Video input */ | 1796 | .name = name_comp1, /* Composite signal on S-Video input */ |
@@ -1803,6 +1805,11 @@ struct saa7134_board saa7134_boards[] = { | |||
1803 | .vmux = 8, | 1805 | .vmux = 8, |
1804 | .amux = LINE2, | 1806 | .amux = LINE2, |
1805 | }}, | 1807 | }}, |
1808 | .radio = { | ||
1809 | .name = name_radio, | ||
1810 | .amux = TV, | ||
1811 | .gpio = 0x000000, /* GPIO21=Low for FM radio antenna */ | ||
1812 | }, | ||
1806 | }, | 1813 | }, |
1807 | [SAA7134_BOARD_PHILIPS_TOUGH] = { | 1814 | [SAA7134_BOARD_PHILIPS_TOUGH] = { |
1808 | .name = "Philips TOUGH DVB-T reference design", | 1815 | .name = "Philips TOUGH DVB-T reference design", |
@@ -2546,8 +2553,9 @@ struct saa7134_board saa7134_boards[] = { | |||
2546 | .radio_type = UNSET, | 2553 | .radio_type = UNSET, |
2547 | .tuner_addr = ADDR_UNSET, | 2554 | .tuner_addr = ADDR_UNSET, |
2548 | .radio_addr = ADDR_UNSET, | 2555 | .radio_addr = ADDR_UNSET, |
2556 | .tuner_config = 0, | ||
2549 | .mpeg = SAA7134_MPEG_DVB, | 2557 | .mpeg = SAA7134_MPEG_DVB, |
2550 | .gpiomask = 1 << 21, | 2558 | .gpiomask = 0x0200000, |
2551 | .inputs = {{ | 2559 | .inputs = {{ |
2552 | .name = name_tv, | 2560 | .name = name_tv, |
2553 | .vmux = 1, | 2561 | .vmux = 1, |
@@ -2624,7 +2632,7 @@ struct saa7134_board saa7134_boards[] = { | |||
2624 | }}, | 2632 | }}, |
2625 | .radio = { | 2633 | .radio = { |
2626 | .name = name_radio, | 2634 | .name = name_radio, |
2627 | .amux = LINE1, | 2635 | .amux = TV, |
2628 | .gpio = 0x0200000, | 2636 | .gpio = 0x0200000, |
2629 | }, | 2637 | }, |
2630 | }, | 2638 | }, |
@@ -3043,6 +3051,7 @@ struct saa7134_board saa7134_boards[] = { | |||
3043 | .radio_type = UNSET, | 3051 | .radio_type = UNSET, |
3044 | .tuner_addr = ADDR_UNSET, | 3052 | .tuner_addr = ADDR_UNSET, |
3045 | .radio_addr = ADDR_UNSET, | 3053 | .radio_addr = ADDR_UNSET, |
3054 | .tuner_config = 1, | ||
3046 | .mpeg = SAA7134_MPEG_DVB, | 3055 | .mpeg = SAA7134_MPEG_DVB, |
3047 | .gpiomask = 0x000200000, | 3056 | .gpiomask = 0x000200000, |
3048 | .inputs = {{ | 3057 | .inputs = {{ |
@@ -3289,6 +3298,115 @@ struct saa7134_board saa7134_boards[] = { | |||
3289 | .amux = LINE1, | 3298 | .amux = LINE1, |
3290 | }}, | 3299 | }}, |
3291 | }, | 3300 | }, |
3301 | [SAA7134_BOARD_PHILIPS_TIGER_S] = { | ||
3302 | .name = "Philips Tiger - S Reference design", | ||
3303 | .audio_clock = 0x00187de7, | ||
3304 | .tuner_type = TUNER_PHILIPS_TDA8290, | ||
3305 | .radio_type = UNSET, | ||
3306 | .tuner_addr = ADDR_UNSET, | ||
3307 | .radio_addr = ADDR_UNSET, | ||
3308 | .tuner_config = 2, | ||
3309 | .mpeg = SAA7134_MPEG_DVB, | ||
3310 | .gpiomask = 0x0200000, | ||
3311 | .inputs = {{ | ||
3312 | .name = name_tv, | ||
3313 | .vmux = 1, | ||
3314 | .amux = TV, | ||
3315 | .tv = 1, | ||
3316 | },{ | ||
3317 | .name = name_comp1, | ||
3318 | .vmux = 3, | ||
3319 | .amux = LINE1, | ||
3320 | },{ | ||
3321 | .name = name_svideo, | ||
3322 | .vmux = 8, | ||
3323 | .amux = LINE1, | ||
3324 | }}, | ||
3325 | .radio = { | ||
3326 | .name = name_radio, | ||
3327 | .amux = TV, | ||
3328 | .gpio = 0x0200000, | ||
3329 | }, | ||
3330 | }, | ||
3331 | [SAA7134_BOARD_AVERMEDIA_M102] = { | ||
3332 | .name = "Avermedia M102", | ||
3333 | .audio_clock = 0x00187de7, | ||
3334 | .tuner_type = TUNER_PHILIPS_TDA8290, | ||
3335 | .radio_type = UNSET, | ||
3336 | .tuner_addr = ADDR_UNSET, | ||
3337 | .radio_addr = ADDR_UNSET, | ||
3338 | .gpiomask = 1<<21, | ||
3339 | .inputs = {{ | ||
3340 | .name = name_tv, | ||
3341 | .vmux = 1, | ||
3342 | .amux = TV, | ||
3343 | .tv = 1, | ||
3344 | },{ | ||
3345 | .name = name_comp1, | ||
3346 | .vmux = 0, | ||
3347 | .amux = LINE2, | ||
3348 | },{ | ||
3349 | .name = name_svideo, | ||
3350 | .vmux = 6, | ||
3351 | .amux = LINE2, | ||
3352 | }}, | ||
3353 | }, | ||
3354 | [SAA7134_BOARD_ASUS_P7131_4871] = { | ||
3355 | .name = "ASUS P7131 4871", | ||
3356 | .audio_clock = 0x00187de7, | ||
3357 | .tuner_type = TUNER_PHILIPS_TDA8290, | ||
3358 | .radio_type = UNSET, | ||
3359 | .tuner_addr = ADDR_UNSET, | ||
3360 | .radio_addr = ADDR_UNSET, | ||
3361 | .tuner_config = 2, | ||
3362 | .mpeg = SAA7134_MPEG_DVB, | ||
3363 | .gpiomask = 0x0200000, | ||
3364 | .inputs = {{ | ||
3365 | .name = name_tv, | ||
3366 | .vmux = 1, | ||
3367 | .amux = TV, | ||
3368 | .tv = 1, | ||
3369 | .gpio = 0x0200000, | ||
3370 | }}, | ||
3371 | }, | ||
3372 | [SAA7134_BOARD_ASUSTeK_P7131_HYBRID_LNA] = { | ||
3373 | .name = "ASUSTeK P7131 Hybrid", | ||
3374 | .audio_clock = 0x00187de7, | ||
3375 | .tuner_type = TUNER_PHILIPS_TDA8290, | ||
3376 | .radio_type = UNSET, | ||
3377 | .tuner_addr = ADDR_UNSET, | ||
3378 | .radio_addr = ADDR_UNSET, | ||
3379 | .tuner_config = 2, | ||
3380 | .gpiomask = 1 << 21, | ||
3381 | .mpeg = SAA7134_MPEG_DVB, | ||
3382 | .inputs = {{ | ||
3383 | .name = name_tv, | ||
3384 | .vmux = 1, | ||
3385 | .amux = TV, | ||
3386 | .tv = 1, | ||
3387 | .gpio = 0x0000000, | ||
3388 | },{ | ||
3389 | .name = name_comp1, | ||
3390 | .vmux = 3, | ||
3391 | .amux = LINE2, | ||
3392 | .gpio = 0x0200000, | ||
3393 | },{ | ||
3394 | .name = name_comp2, | ||
3395 | .vmux = 0, | ||
3396 | .amux = LINE2, | ||
3397 | .gpio = 0x0200000, | ||
3398 | },{ | ||
3399 | .name = name_svideo, | ||
3400 | .vmux = 8, | ||
3401 | .amux = LINE2, | ||
3402 | .gpio = 0x0200000, | ||
3403 | }}, | ||
3404 | .radio = { | ||
3405 | .name = name_radio, | ||
3406 | .amux = TV, | ||
3407 | .gpio = 0x0200000, | ||
3408 | }, | ||
3409 | }, | ||
3292 | }; | 3410 | }; |
3293 | 3411 | ||
3294 | const unsigned int saa7134_bcount = ARRAY_SIZE(saa7134_boards); | 3412 | const unsigned int saa7134_bcount = ARRAY_SIZE(saa7134_boards); |
@@ -3914,7 +4032,7 @@ struct pci_device_id saa7134_pci_tbl[] = { | |||
3914 | .device = PCI_DEVICE_ID_PHILIPS_SAA7133, | 4032 | .device = PCI_DEVICE_ID_PHILIPS_SAA7133, |
3915 | .subvendor = 0x1043, | 4033 | .subvendor = 0x1043, |
3916 | .subdevice = 0x4876, | 4034 | .subdevice = 0x4876, |
3917 | .driver_data = SAA7134_BOARD_ASUSTeK_P7131_DUAL, | 4035 | .driver_data = SAA7134_BOARD_ASUSTeK_P7131_HYBRID_LNA, |
3918 | },{ | 4036 | },{ |
3919 | .vendor = PCI_VENDOR_ID_PHILIPS, | 4037 | .vendor = PCI_VENDOR_ID_PHILIPS, |
3920 | .device = PCI_DEVICE_ID_PHILIPS_SAA7133, | 4038 | .device = PCI_DEVICE_ID_PHILIPS_SAA7133, |
@@ -3958,6 +4076,30 @@ struct pci_device_id saa7134_pci_tbl[] = { | |||
3958 | .subdevice = 0x1175, | 4076 | .subdevice = 0x1175, |
3959 | .driver_data = SAA7134_BOARD_CINERGY_HT_PCI, | 4077 | .driver_data = SAA7134_BOARD_CINERGY_HT_PCI, |
3960 | },{ | 4078 | },{ |
4079 | .vendor = PCI_VENDOR_ID_PHILIPS, | ||
4080 | .device = PCI_DEVICE_ID_PHILIPS_SAA7133, | ||
4081 | .subvendor = 0x1461, /* Avermedia Technologies Inc */ | ||
4082 | .subdevice = 0xf31e, | ||
4083 | .driver_data = SAA7134_BOARD_AVERMEDIA_M102, | ||
4084 | },{ | ||
4085 | .vendor = PCI_VENDOR_ID_PHILIPS, | ||
4086 | .device = PCI_DEVICE_ID_PHILIPS_SAA7133, | ||
4087 | .subvendor = 0x4E42, /* MSI */ | ||
4088 | .subdevice = 0x0306, /* TV@nywhere DUO */ | ||
4089 | .driver_data = SAA7134_BOARD_FLYDVBTDUO, | ||
4090 | },{ | ||
4091 | .vendor = PCI_VENDOR_ID_PHILIPS, | ||
4092 | .device = PCI_DEVICE_ID_PHILIPS_SAA7133, | ||
4093 | .subvendor = 0x1043, | ||
4094 | .subdevice = 0x4871, | ||
4095 | .driver_data = SAA7134_BOARD_ASUS_P7131_4871, | ||
4096 | },{ | ||
4097 | .vendor = PCI_VENDOR_ID_PHILIPS, | ||
4098 | .device = PCI_DEVICE_ID_PHILIPS_SAA7133, | ||
4099 | .subvendor = 0x1043, | ||
4100 | .subdevice = 0x4857, | ||
4101 | .driver_data = SAA7134_BOARD_ASUSTeK_P7131_DUAL, | ||
4102 | },{ | ||
3961 | /* --- boards without eeprom + subsystem ID --- */ | 4103 | /* --- boards without eeprom + subsystem ID --- */ |
3962 | .vendor = PCI_VENDOR_ID_PHILIPS, | 4104 | .vendor = PCI_VENDOR_ID_PHILIPS, |
3963 | .device = PCI_DEVICE_ID_PHILIPS_SAA7134, | 4105 | .device = PCI_DEVICE_ID_PHILIPS_SAA7134, |
@@ -3971,7 +4113,6 @@ struct pci_device_id saa7134_pci_tbl[] = { | |||
3971 | .subdevice = 0, | 4113 | .subdevice = 0, |
3972 | .driver_data = SAA7134_BOARD_NOAUTO, | 4114 | .driver_data = SAA7134_BOARD_NOAUTO, |
3973 | },{ | 4115 | },{ |
3974 | |||
3975 | /* --- default catch --- */ | 4116 | /* --- default catch --- */ |
3976 | .vendor = PCI_VENDOR_ID_PHILIPS, | 4117 | .vendor = PCI_VENDOR_ID_PHILIPS, |
3977 | .device = PCI_DEVICE_ID_PHILIPS_SAA7130, | 4118 | .device = PCI_DEVICE_ID_PHILIPS_SAA7130, |
@@ -4063,6 +4204,7 @@ int saa7134_board_init1(struct saa7134_dev *dev) | |||
4063 | case SAA7134_BOARD_SEDNA_PC_TV_CARDBUS: | 4204 | case SAA7134_BOARD_SEDNA_PC_TV_CARDBUS: |
4064 | case SAA7134_BOARD_FLYDVBT_LR301: | 4205 | case SAA7134_BOARD_FLYDVBT_LR301: |
4065 | case SAA7134_BOARD_ASUSTeK_P7131_DUAL: | 4206 | case SAA7134_BOARD_ASUSTeK_P7131_DUAL: |
4207 | case SAA7134_BOARD_ASUSTeK_P7131_HYBRID_LNA: | ||
4066 | case SAA7134_BOARD_FLYDVBTDUO: | 4208 | case SAA7134_BOARD_FLYDVBTDUO: |
4067 | case SAA7134_BOARD_PROTEUS_2309: | 4209 | case SAA7134_BOARD_PROTEUS_2309: |
4068 | case SAA7134_BOARD_AVERMEDIA_A16AR: | 4210 | case SAA7134_BOARD_AVERMEDIA_A16AR: |
@@ -4103,8 +4245,8 @@ int saa7134_board_init1(struct saa7134_dev *dev) | |||
4103 | break; | 4245 | break; |
4104 | case SAA7134_BOARD_ADS_DUO_CARDBUS_PTV331: | 4246 | case SAA7134_BOARD_ADS_DUO_CARDBUS_PTV331: |
4105 | case SAA7134_BOARD_FLYDVBT_HYBRID_CARDBUS: | 4247 | case SAA7134_BOARD_FLYDVBT_HYBRID_CARDBUS: |
4106 | saa_writeb(SAA7134_GPIO_GPMODE3, 0x08); | 4248 | saa_andorl(SAA7134_GPIO_GPMODE0 >> 2, 0x08000000, 0x08000000); |
4107 | saa_writeb(SAA7134_GPIO_GPSTATUS3, 0x00); | 4249 | saa_andorl(SAA7134_GPIO_GPSTATUS0 >> 2, 0x08000000, 0x00000000); |
4108 | break; | 4250 | break; |
4109 | case SAA7134_BOARD_AVERMEDIA_CARDBUS: | 4251 | case SAA7134_BOARD_AVERMEDIA_CARDBUS: |
4110 | /* power-up tuner chip */ | 4252 | /* power-up tuner chip */ |
@@ -4137,6 +4279,11 @@ int saa7134_board_init1(struct saa7134_dev *dev) | |||
4137 | "%s: Dual decoder functionality is disabled for now, use the other chip.\n", | 4279 | "%s: Dual decoder functionality is disabled for now, use the other chip.\n", |
4138 | dev->name,card(dev).name,dev->name,dev->name); | 4280 | dev->name,card(dev).name,dev->name,dev->name); |
4139 | break; | 4281 | break; |
4282 | case SAA7134_BOARD_AVERMEDIA_M102: | ||
4283 | /* enable tuner */ | ||
4284 | saa_andorl(SAA7134_GPIO_GPMODE0 >> 2, 0x8c040007, 0x8c040007); | ||
4285 | saa_andorl(SAA7134_GPIO_GPSTATUS0 >> 2, 0x0c0007cd, 0x0c0007cd); | ||
4286 | break; | ||
4140 | } | 4287 | } |
4141 | return 0; | 4288 | return 0; |
4142 | } | 4289 | } |
@@ -4146,6 +4293,9 @@ int saa7134_board_init2(struct saa7134_dev *dev) | |||
4146 | { | 4293 | { |
4147 | unsigned char buf; | 4294 | unsigned char buf; |
4148 | int board; | 4295 | int board; |
4296 | struct tuner_setup tun_setup; | ||
4297 | tun_setup.config = 0; | ||
4298 | tun_setup.tuner_callback = saa7134_tuner_callback; | ||
4149 | 4299 | ||
4150 | switch (dev->board) { | 4300 | switch (dev->board) { |
4151 | case SAA7134_BOARD_BMK_MPEX_NOTUNER: | 4301 | case SAA7134_BOARD_BMK_MPEX_NOTUNER: |
@@ -4162,8 +4312,6 @@ int saa7134_board_init2(struct saa7134_dev *dev) | |||
4162 | dev->tuner_type = saa7134_boards[dev->board].tuner_type; | 4312 | dev->tuner_type = saa7134_boards[dev->board].tuner_type; |
4163 | 4313 | ||
4164 | if (TUNER_ABSENT != dev->tuner_type) { | 4314 | if (TUNER_ABSENT != dev->tuner_type) { |
4165 | struct tuner_setup tun_setup; | ||
4166 | |||
4167 | tun_setup.mode_mask = T_RADIO | T_ANALOG_TV | T_DIGITAL_TV; | 4315 | tun_setup.mode_mask = T_RADIO | T_ANALOG_TV | T_DIGITAL_TV; |
4168 | tun_setup.type = dev->tuner_type; | 4316 | tun_setup.type = dev->tuner_type; |
4169 | tun_setup.addr = ADDR_UNSET; | 4317 | tun_setup.addr = ADDR_UNSET; |
@@ -4173,7 +4321,6 @@ int saa7134_board_init2(struct saa7134_dev *dev) | |||
4173 | break; | 4321 | break; |
4174 | case SAA7134_BOARD_MD7134: | 4322 | case SAA7134_BOARD_MD7134: |
4175 | { | 4323 | { |
4176 | struct tuner_setup tun_setup; | ||
4177 | u8 subaddr; | 4324 | u8 subaddr; |
4178 | u8 data[3]; | 4325 | u8 data[3]; |
4179 | int ret, tuner_t; | 4326 | int ret, tuner_t; |
@@ -4245,7 +4392,6 @@ int saa7134_board_init2(struct saa7134_dev *dev) | |||
4245 | * the channel decoder. We have to make it transparent to find it | 4392 | * the channel decoder. We have to make it transparent to find it |
4246 | */ | 4393 | */ |
4247 | { | 4394 | { |
4248 | struct tuner_setup tun_setup; | ||
4249 | u8 data[] = { 0x07, 0x02}; | 4395 | u8 data[] = { 0x07, 0x02}; |
4250 | struct i2c_msg msg = {.addr=0x08, .flags=0, .buf=data, .len = sizeof(data)}; | 4396 | struct i2c_msg msg = {.addr=0x08, .flags=0, .buf=data, .len = sizeof(data)}; |
4251 | i2c_transfer(&dev->i2c_adap, &msg, 1); | 4397 | i2c_transfer(&dev->i2c_adap, &msg, 1); |
@@ -4258,16 +4404,38 @@ int saa7134_board_init2(struct saa7134_dev *dev) | |||
4258 | } | 4404 | } |
4259 | break; | 4405 | break; |
4260 | case SAA7134_BOARD_PHILIPS_TIGER: | 4406 | case SAA7134_BOARD_PHILIPS_TIGER: |
4407 | case SAA7134_BOARD_PHILIPS_TIGER_S: | ||
4408 | { | ||
4409 | u8 data[] = { 0x3c, 0x33, 0x60}; | ||
4410 | struct i2c_msg msg = {.addr=0x08, .flags=0, .buf=data, .len = sizeof(data)}; | ||
4411 | if(dev->autodetected && (dev->eedata[0x49] == 0x50)) { | ||
4412 | dev->board = SAA7134_BOARD_PHILIPS_TIGER_S; | ||
4413 | printk(KERN_INFO "%s: Reconfigured board as %s\n", | ||
4414 | dev->name, saa7134_boards[dev->board].name); | ||
4415 | } | ||
4416 | if(dev->board == SAA7134_BOARD_PHILIPS_TIGER_S) { | ||
4417 | tun_setup.mode_mask = T_ANALOG_TV | T_DIGITAL_TV; | ||
4418 | tun_setup.type = TUNER_PHILIPS_TDA8290; | ||
4419 | tun_setup.addr = 0x4b; | ||
4420 | tun_setup.config = 2; | ||
4421 | |||
4422 | saa7134_i2c_call_clients (dev, TUNER_SET_TYPE_ADDR,&tun_setup); | ||
4423 | data[2] = 0x68; | ||
4424 | } | ||
4425 | i2c_transfer(&dev->i2c_adap, &msg, 1); | ||
4426 | } | ||
4427 | break; | ||
4261 | case SAA7134_BOARD_PINNACLE_PCTV_310i: | 4428 | case SAA7134_BOARD_PINNACLE_PCTV_310i: |
4262 | case SAA7134_BOARD_TEVION_DVBT_220RF: | 4429 | case SAA7134_BOARD_TEVION_DVBT_220RF: |
4263 | case SAA7134_BOARD_ASUSTeK_P7131_DUAL: | 4430 | case SAA7134_BOARD_ASUSTeK_P7131_DUAL: |
4431 | case SAA7134_BOARD_ASUSTeK_P7131_HYBRID_LNA: | ||
4264 | case SAA7134_BOARD_MEDION_MD8800_QUADRO: | 4432 | case SAA7134_BOARD_MEDION_MD8800_QUADRO: |
4265 | case SAA7134_BOARD_HAUPPAUGE_HVR1110: | 4433 | case SAA7134_BOARD_HAUPPAUGE_HVR1110: |
4266 | /* this is a hybrid board, initialize to analog mode | 4434 | /* this is a hybrid board, initialize to analog mode |
4267 | * and configure firmware eeprom address | 4435 | * and configure firmware eeprom address |
4268 | */ | 4436 | */ |
4269 | { | 4437 | { |
4270 | u8 data[] = { 0x3c, 0x33, 0x68}; | 4438 | u8 data[] = { 0x3c, 0x33, 0x60}; |
4271 | struct i2c_msg msg = {.addr=0x08, .flags=0, .buf=data, .len = sizeof(data)}; | 4439 | struct i2c_msg msg = {.addr=0x08, .flags=0, .buf=data, .len = sizeof(data)}; |
4272 | i2c_transfer(&dev->i2c_adap, &msg, 1); | 4440 | i2c_transfer(&dev->i2c_adap, &msg, 1); |
4273 | } | 4441 | } |
@@ -4281,18 +4449,18 @@ int saa7134_board_init2(struct saa7134_dev *dev) | |||
4281 | break; | 4449 | break; |
4282 | case SAA7134_BOARD_ADS_DUO_CARDBUS_PTV331: | 4450 | case SAA7134_BOARD_ADS_DUO_CARDBUS_PTV331: |
4283 | case SAA7134_BOARD_FLYDVBT_HYBRID_CARDBUS: | 4451 | case SAA7134_BOARD_FLYDVBT_HYBRID_CARDBUS: |
4284 | /* make the tda10046 find its eeprom */ | 4452 | /* initialize analog mode */ |
4285 | { | 4453 | { |
4286 | u8 data[] = { 0x3c, 0x33, 0x62}; | 4454 | u8 data[] = { 0x3c, 0x33, 0x6a}; |
4287 | struct i2c_msg msg = {.addr=0x08, .flags=0, .buf=data, .len = sizeof(data)}; | 4455 | struct i2c_msg msg = {.addr=0x08, .flags=0, .buf=data, .len = sizeof(data)}; |
4288 | i2c_transfer(&dev->i2c_adap, &msg, 1); | 4456 | i2c_transfer(&dev->i2c_adap, &msg, 1); |
4289 | } | 4457 | } |
4290 | break; | 4458 | break; |
4291 | case SAA7134_BOARD_CINERGY_HT_PCMCIA: | 4459 | case SAA7134_BOARD_CINERGY_HT_PCMCIA: |
4292 | case SAA7134_BOARD_CINERGY_HT_PCI: | 4460 | case SAA7134_BOARD_CINERGY_HT_PCI: |
4293 | /* make the tda10046 find its eeprom */ | 4461 | /* initialize analog mode */ |
4294 | { | 4462 | { |
4295 | u8 data[] = { 0x3c, 0x33, 0x60}; | 4463 | u8 data[] = { 0x3c, 0x33, 0x68}; |
4296 | struct i2c_msg msg = {.addr=0x08, .flags=0, .buf=data, .len = sizeof(data)}; | 4464 | struct i2c_msg msg = {.addr=0x08, .flags=0, .buf=data, .len = sizeof(data)}; |
4297 | i2c_transfer(&dev->i2c_adap, &msg, 1); | 4465 | i2c_transfer(&dev->i2c_adap, &msg, 1); |
4298 | } | 4466 | } |
diff --git a/drivers/media/video/saa7134/saa7134-core.c b/drivers/media/video/saa7134/saa7134-core.c index ed038fff3b4f..25f84701a8e8 100644 --- a/drivers/media/video/saa7134/saa7134-core.c +++ b/drivers/media/video/saa7134/saa7134-core.c | |||
@@ -117,6 +117,64 @@ void saa7134_track_gpio(struct saa7134_dev *dev, char *msg) | |||
117 | dev->name, mode, (~mode) & status, mode & status, msg); | 117 | dev->name, mode, (~mode) & status, mode & status, msg); |
118 | } | 118 | } |
119 | 119 | ||
120 | void saa7134_set_gpio(struct saa7134_dev *dev, int bit_no, int value) | ||
121 | { | ||
122 | u32 index, bitval; | ||
123 | |||
124 | index = 1 << bit_no; | ||
125 | switch (value) { | ||
126 | case 0: /* static value */ | ||
127 | case 1: dprintk("setting GPIO%d to static %d\n", bit_no, value); | ||
128 | /* turn sync mode off if necessary */ | ||
129 | if (index & 0x00c00000) | ||
130 | saa_andorb(SAA7134_VIDEO_PORT_CTRL6, 0x0f, 0x00); | ||
131 | if (value) | ||
132 | bitval = index; | ||
133 | else | ||
134 | bitval = 0; | ||
135 | saa_andorl(SAA7134_GPIO_GPMODE0 >> 2, index, index); | ||
136 | saa_andorl(SAA7134_GPIO_GPSTATUS0 >> 2, index, bitval); | ||
137 | break; | ||
138 | case 3: /* tristate */ | ||
139 | dprintk("setting GPIO%d to tristate\n", bit_no); | ||
140 | saa_andorl(SAA7134_GPIO_GPMODE0 >> 2, index, 0); | ||
141 | break; | ||
142 | } | ||
143 | } | ||
144 | |||
145 | int saa7134_tuner_callback(void *ptr, int command, int arg) | ||
146 | { | ||
147 | u8 sync_control; | ||
148 | struct saa7134_dev *dev = ptr; | ||
149 | |||
150 | switch (dev->tuner_type) { | ||
151 | case TUNER_PHILIPS_TDA8290: | ||
152 | switch (command) { | ||
153 | case 0: /* switch LNA gain through GPIO 22*/ | ||
154 | saa7134_set_gpio(dev, 22, arg) ; | ||
155 | break; | ||
156 | case 1: /* vsync output at GPIO22. 50 / 60Hz */ | ||
157 | dprintk("setting GPIO22 to vsync %d\n", arg); | ||
158 | saa_andorb(SAA7134_VIDEO_PORT_CTRL3, 0x80, 0x80); | ||
159 | saa_andorb(SAA7134_VIDEO_PORT_CTRL6, 0x0f, 0x03); | ||
160 | if (arg == 1) | ||
161 | sync_control = 11; | ||
162 | else | ||
163 | sync_control = 17; | ||
164 | saa_writeb(SAA7134_VGATE_START, sync_control); | ||
165 | saa_writeb(SAA7134_VGATE_STOP, sync_control + 1); | ||
166 | saa_andorb(SAA7134_MISC_VGATE_MSB, 0x03, 0x00); | ||
167 | break; | ||
168 | default: | ||
169 | return -EINVAL; | ||
170 | } | ||
171 | break; | ||
172 | default: | ||
173 | return -ENODEV; | ||
174 | } | ||
175 | return 0; | ||
176 | } | ||
177 | |||
120 | /* ------------------------------------------------------------------ */ | 178 | /* ------------------------------------------------------------------ */ |
121 | 179 | ||
122 | 180 | ||
@@ -124,55 +182,28 @@ void saa7134_track_gpio(struct saa7134_dev *dev, char *msg) | |||
124 | /* delayed request_module */ | 182 | /* delayed request_module */ |
125 | 183 | ||
126 | #if defined(CONFIG_MODULES) && defined(MODULE) | 184 | #if defined(CONFIG_MODULES) && defined(MODULE) |
127 | static int need_empress; | ||
128 | static int need_dvb; | ||
129 | static int need_alsa; | ||
130 | static int need_oss; | ||
131 | 185 | ||
132 | static int pending_call(struct notifier_block *self, unsigned long state, | ||
133 | void *module) | ||
134 | { | ||
135 | if (module != THIS_MODULE || state != MODULE_STATE_LIVE) | ||
136 | return NOTIFY_DONE; | ||
137 | 186 | ||
138 | if (need_empress) | 187 | static void request_module_async(struct work_struct *work){ |
188 | struct saa7134_dev* dev = container_of(work, struct saa7134_dev, request_module_wk); | ||
189 | if (card_is_empress(dev)) | ||
139 | request_module("saa7134-empress"); | 190 | request_module("saa7134-empress"); |
140 | if (need_dvb) | 191 | if (card_is_dvb(dev)) |
141 | request_module("saa7134-dvb"); | 192 | request_module("saa7134-dvb"); |
142 | if (need_alsa) | 193 | if (alsa) |
143 | request_module("saa7134-alsa"); | 194 | request_module("saa7134-alsa"); |
144 | if (need_oss) | 195 | if (oss) |
145 | request_module("saa7134-oss"); | 196 | request_module("saa7134-oss"); |
146 | return NOTIFY_DONE; | ||
147 | } | 197 | } |
148 | 198 | ||
149 | static int pending_registered; | 199 | static void request_submodules(struct saa7134_dev *dev) |
150 | static struct notifier_block pending_notifier = { | ||
151 | .notifier_call = pending_call, | ||
152 | }; | ||
153 | |||
154 | static void request_module_depend(char *name, int *flag) | ||
155 | { | 200 | { |
156 | int err; | 201 | INIT_WORK(&dev->request_module_wk, request_module_async); |
157 | switch (THIS_MODULE->state) { | 202 | schedule_work(&dev->request_module_wk); |
158 | case MODULE_STATE_COMING: | ||
159 | if (!pending_registered) { | ||
160 | err = register_module_notifier(&pending_notifier); | ||
161 | pending_registered = 1; | ||
162 | } | ||
163 | *flag = 1; | ||
164 | break; | ||
165 | case MODULE_STATE_LIVE: | ||
166 | request_module(name); | ||
167 | break; | ||
168 | default: | ||
169 | /* nothing */; | ||
170 | break; | ||
171 | } | ||
172 | } | 203 | } |
173 | 204 | ||
174 | #else | 205 | #else |
175 | #define request_module_depend(name,flag) | 206 | #define request_submodules(dev) |
176 | #endif /* CONFIG_MODULES */ | 207 | #endif /* CONFIG_MODULES */ |
177 | 208 | ||
178 | /* ------------------------------------------------------------------ */ | 209 | /* ------------------------------------------------------------------ */ |
@@ -703,7 +734,6 @@ static int saa7134_hwfini(struct saa7134_dev *dev) | |||
703 | saa7134_ts_fini(dev); | 734 | saa7134_ts_fini(dev); |
704 | saa7134_input_fini(dev); | 735 | saa7134_input_fini(dev); |
705 | saa7134_vbi_fini(dev); | 736 | saa7134_vbi_fini(dev); |
706 | saa7134_video_fini(dev); | ||
707 | saa7134_tvaudio_fini(dev); | 737 | saa7134_tvaudio_fini(dev); |
708 | return 0; | 738 | return 0; |
709 | } | 739 | } |
@@ -944,18 +974,9 @@ static int __devinit saa7134_initdev(struct pci_dev *pci_dev, | |||
944 | request_module("tuner"); | 974 | request_module("tuner"); |
945 | if (card_is_empress(dev)) { | 975 | if (card_is_empress(dev)) { |
946 | request_module("saa6752hs"); | 976 | request_module("saa6752hs"); |
947 | request_module_depend("saa7134-empress",&need_empress); | ||
948 | } | 977 | } |
949 | 978 | ||
950 | if (card_is_dvb(dev)) | 979 | request_submodules(dev); |
951 | request_module_depend("saa7134-dvb",&need_dvb); | ||
952 | |||
953 | |||
954 | if (alsa) | ||
955 | request_module_depend("saa7134-alsa",&need_alsa); | ||
956 | |||
957 | if (oss) | ||
958 | request_module_depend("saa7134-oss",&need_oss); | ||
959 | 980 | ||
960 | v4l2_prio_init(&dev->prio); | 981 | v4l2_prio_init(&dev->prio); |
961 | 982 | ||
@@ -1013,6 +1034,9 @@ static int __devinit saa7134_initdev(struct pci_dev *pci_dev, | |||
1013 | saa7134_dmasound_init(dev); | 1034 | saa7134_dmasound_init(dev); |
1014 | } | 1035 | } |
1015 | 1036 | ||
1037 | if (TUNER_ABSENT != dev->tuner_type) | ||
1038 | saa7134_i2c_call_clients(dev, TUNER_SET_STANDBY, NULL); | ||
1039 | |||
1016 | return 0; | 1040 | return 0; |
1017 | 1041 | ||
1018 | fail4: | 1042 | fail4: |
@@ -1152,10 +1176,6 @@ static int saa7134_init(void) | |||
1152 | 1176 | ||
1153 | static void saa7134_fini(void) | 1177 | static void saa7134_fini(void) |
1154 | { | 1178 | { |
1155 | #if defined(CONFIG_MODULES) && defined(MODULE) | ||
1156 | if (pending_registered) | ||
1157 | unregister_module_notifier(&pending_notifier); | ||
1158 | #endif /* CONFIG_MODULES */ | ||
1159 | pci_unregister_driver(&saa7134_pci_driver); | 1179 | pci_unregister_driver(&saa7134_pci_driver); |
1160 | } | 1180 | } |
1161 | 1181 | ||
@@ -1164,6 +1184,7 @@ module_exit(saa7134_fini); | |||
1164 | 1184 | ||
1165 | /* ----------------------------------------------------------- */ | 1185 | /* ----------------------------------------------------------- */ |
1166 | 1186 | ||
1187 | EXPORT_SYMBOL(saa7134_set_gpio); | ||
1167 | EXPORT_SYMBOL(saa7134_i2c_call_clients); | 1188 | EXPORT_SYMBOL(saa7134_i2c_call_clients); |
1168 | EXPORT_SYMBOL(saa7134_devlist); | 1189 | EXPORT_SYMBOL(saa7134_devlist); |
1169 | EXPORT_SYMBOL(saa7134_boards); | 1190 | EXPORT_SYMBOL(saa7134_boards); |
diff --git a/drivers/media/video/saa7134/saa7134-dvb.c b/drivers/media/video/saa7134/saa7134-dvb.c index e3059fd33951..65aec881bbde 100644 --- a/drivers/media/video/saa7134/saa7134-dvb.c +++ b/drivers/media/video/saa7134/saa7134-dvb.c | |||
@@ -41,7 +41,9 @@ | |||
41 | 41 | ||
42 | #include "tda10086.h" | 42 | #include "tda10086.h" |
43 | #include "tda826x.h" | 43 | #include "tda826x.h" |
44 | #include "tda827x.h" | ||
44 | #include "isl6421.h" | 45 | #include "isl6421.h" |
46 | |||
45 | MODULE_AUTHOR("Gerd Knorr <kraxel@bytesex.org> [SuSE Labs]"); | 47 | MODULE_AUTHOR("Gerd Knorr <kraxel@bytesex.org> [SuSE Labs]"); |
46 | MODULE_LICENSE("GPL"); | 48 | MODULE_LICENSE("GPL"); |
47 | 49 | ||
@@ -54,7 +56,21 @@ static int use_frontend = 0; | |||
54 | module_param(use_frontend, int, 0644); | 56 | module_param(use_frontend, int, 0644); |
55 | MODULE_PARM_DESC(use_frontend,"for cards with multiple frontends (0: terrestrial, 1: satellite)"); | 57 | MODULE_PARM_DESC(use_frontend,"for cards with multiple frontends (0: terrestrial, 1: satellite)"); |
56 | 58 | ||
57 | /* ------------------------------------------------------------------ */ | 59 | static int debug = 0; |
60 | module_param(debug, int, 0644); | ||
61 | MODULE_PARM_DESC(debug, "Turn on/off module debugging (default:off)."); | ||
62 | |||
63 | #define dprintk(fmt, arg...) do { if (debug) \ | ||
64 | printk(KERN_DEBUG "%s/dvb: " fmt, dev->name , ## arg); } while(0) | ||
65 | |||
66 | /* Print a warning */ | ||
67 | #define wprintk(fmt, arg...) \ | ||
68 | printk(KERN_WARNING "%s/dvb: " fmt, dev->name, ## arg) | ||
69 | |||
70 | /* ------------------------------------------------------------------ | ||
71 | * mt352 based DVB-T cards | ||
72 | */ | ||
73 | |||
58 | static int pinnacle_antenna_pwr(struct saa7134_dev *dev, int on) | 74 | static int pinnacle_antenna_pwr(struct saa7134_dev *dev, int on) |
59 | { | 75 | { |
60 | u32 ok; | 76 | u32 ok; |
@@ -75,8 +91,7 @@ static int pinnacle_antenna_pwr(struct saa7134_dev *dev, int on) | |||
75 | saa_setl(SAA7134_GPIO_GPSTATUS0 >> 2, (1 << 28)); | 91 | saa_setl(SAA7134_GPIO_GPSTATUS0 >> 2, (1 << 28)); |
76 | udelay(10); | 92 | udelay(10); |
77 | ok = saa_readl(SAA7134_GPIO_GPSTATUS0) & (1 << 27); | 93 | ok = saa_readl(SAA7134_GPIO_GPSTATUS0) & (1 << 27); |
78 | printk("%s: %s %s\n", dev->name, __FUNCTION__, | 94 | dprintk("%s %s\n", __FUNCTION__, ok ? "on" : "off"); |
79 | ok ? "on" : "off"); | ||
80 | 95 | ||
81 | if (!ok) | 96 | if (!ok) |
82 | saa_clearl(SAA7134_GPIO_GPSTATUS0 >> 2, (1 << 26)); | 97 | saa_clearl(SAA7134_GPIO_GPSTATUS0 >> 2, (1 << 26)); |
@@ -96,7 +111,7 @@ static int mt352_pinnacle_init(struct dvb_frontend* fe) | |||
96 | static u8 irq_cfg [] = { INTERRUPT_EN_0, 0x00, 0x00, 0x00, 0x00 }; | 111 | static u8 irq_cfg [] = { INTERRUPT_EN_0, 0x00, 0x00, 0x00, 0x00 }; |
97 | struct saa7134_dev *dev= fe->dvb->priv; | 112 | struct saa7134_dev *dev= fe->dvb->priv; |
98 | 113 | ||
99 | printk("%s: %s called\n",dev->name,__FUNCTION__); | 114 | dprintk("%s called\n", __FUNCTION__); |
100 | 115 | ||
101 | mt352_write(fe, clock_config, sizeof(clock_config)); | 116 | mt352_write(fe, clock_config, sizeof(clock_config)); |
102 | udelay(200); | 117 | udelay(200); |
@@ -185,10 +200,26 @@ static struct mt352_config avermedia_777 = { | |||
185 | .demod_init = mt352_aver777_init, | 200 | .demod_init = mt352_aver777_init, |
186 | }; | 201 | }; |
187 | 202 | ||
188 | /* ------------------------------------------------------------------ */ | 203 | /* ================================================================== |
189 | static int philips_tda6651_pll_set(u8 addr, struct dvb_frontend *fe, struct dvb_frontend_parameters *params) | 204 | * tda1004x based DVB-T cards, helper functions |
205 | */ | ||
206 | |||
207 | static int philips_tda1004x_request_firmware(struct dvb_frontend *fe, | ||
208 | const struct firmware **fw, char *name) | ||
209 | { | ||
210 | struct saa7134_dev *dev = fe->dvb->priv; | ||
211 | return request_firmware(fw, name, &dev->pci->dev); | ||
212 | } | ||
213 | |||
214 | /* ------------------------------------------------------------------ | ||
215 | * these tuners are tu1216, td1316(a) | ||
216 | */ | ||
217 | |||
218 | static int philips_tda6651_pll_set(struct dvb_frontend *fe, struct dvb_frontend_parameters *params) | ||
190 | { | 219 | { |
191 | struct saa7134_dev *dev = fe->dvb->priv; | 220 | struct saa7134_dev *dev = fe->dvb->priv; |
221 | struct tda1004x_state *state = fe->demodulator_priv; | ||
222 | u8 addr = state->config->tuner_address; | ||
192 | u8 tuner_buf[4]; | 223 | u8 tuner_buf[4]; |
193 | struct i2c_msg tuner_msg = {.addr = addr,.flags = 0,.buf = tuner_buf,.len = | 224 | struct i2c_msg tuner_msg = {.addr = addr,.flags = 0,.buf = tuner_buf,.len = |
194 | sizeof(tuner_buf) }; | 225 | sizeof(tuner_buf) }; |
@@ -263,15 +294,20 @@ static int philips_tda6651_pll_set(u8 addr, struct dvb_frontend *fe, struct dvb_ | |||
263 | 294 | ||
264 | if (fe->ops.i2c_gate_ctrl) | 295 | if (fe->ops.i2c_gate_ctrl) |
265 | fe->ops.i2c_gate_ctrl(fe, 1); | 296 | fe->ops.i2c_gate_ctrl(fe, 1); |
266 | if (i2c_transfer(&dev->i2c_adap, &tuner_msg, 1) != 1) | 297 | if (i2c_transfer(&dev->i2c_adap, &tuner_msg, 1) != 1) { |
298 | wprintk("could not write to tuner at addr: 0x%02x\n", | ||
299 | addr << 1); | ||
267 | return -EIO; | 300 | return -EIO; |
301 | } | ||
268 | msleep(1); | 302 | msleep(1); |
269 | return 0; | 303 | return 0; |
270 | } | 304 | } |
271 | 305 | ||
272 | static int philips_tda6651_pll_init(u8 addr, struct dvb_frontend *fe) | 306 | static int philips_tu1216_init(struct dvb_frontend *fe) |
273 | { | 307 | { |
274 | struct saa7134_dev *dev = fe->dvb->priv; | 308 | struct saa7134_dev *dev = fe->dvb->priv; |
309 | struct tda1004x_state *state = fe->demodulator_priv; | ||
310 | u8 addr = state->config->tuner_address; | ||
275 | static u8 tu1216_init[] = { 0x0b, 0xf5, 0x85, 0xab }; | 311 | static u8 tu1216_init[] = { 0x0b, 0xf5, 0x85, 0xab }; |
276 | struct i2c_msg tuner_msg = {.addr = addr,.flags = 0,.buf = tu1216_init,.len = sizeof(tu1216_init) }; | 312 | struct i2c_msg tuner_msg = {.addr = addr,.flags = 0,.buf = tu1216_init,.len = sizeof(tu1216_init) }; |
277 | 313 | ||
@@ -287,46 +323,17 @@ static int philips_tda6651_pll_init(u8 addr, struct dvb_frontend *fe) | |||
287 | 323 | ||
288 | /* ------------------------------------------------------------------ */ | 324 | /* ------------------------------------------------------------------ */ |
289 | 325 | ||
290 | static int philips_tu1216_tuner_60_init(struct dvb_frontend *fe) | ||
291 | { | ||
292 | return philips_tda6651_pll_init(0x60, fe); | ||
293 | } | ||
294 | |||
295 | static int philips_tu1216_tuner_60_set_params(struct dvb_frontend *fe, struct dvb_frontend_parameters *params) | ||
296 | { | ||
297 | return philips_tda6651_pll_set(0x60, fe, params); | ||
298 | } | ||
299 | |||
300 | static int philips_tda1004x_request_firmware(struct dvb_frontend *fe, | ||
301 | const struct firmware **fw, char *name) | ||
302 | { | ||
303 | struct saa7134_dev *dev = fe->dvb->priv; | ||
304 | return request_firmware(fw, name, &dev->pci->dev); | ||
305 | } | ||
306 | |||
307 | static struct tda1004x_config philips_tu1216_60_config = { | 326 | static struct tda1004x_config philips_tu1216_60_config = { |
308 | |||
309 | .demod_address = 0x8, | 327 | .demod_address = 0x8, |
310 | .invert = 1, | 328 | .invert = 1, |
311 | .invert_oclk = 0, | 329 | .invert_oclk = 0, |
312 | .xtal_freq = TDA10046_XTAL_4M, | 330 | .xtal_freq = TDA10046_XTAL_4M, |
313 | .agc_config = TDA10046_AGC_DEFAULT, | 331 | .agc_config = TDA10046_AGC_DEFAULT, |
314 | .if_freq = TDA10046_FREQ_3617, | 332 | .if_freq = TDA10046_FREQ_3617, |
315 | .request_firmware = philips_tda1004x_request_firmware, | 333 | .tuner_address = 0x60, |
334 | .request_firmware = philips_tda1004x_request_firmware | ||
316 | }; | 335 | }; |
317 | 336 | ||
318 | /* ------------------------------------------------------------------ */ | ||
319 | |||
320 | static int philips_tu1216_tuner_61_init(struct dvb_frontend *fe) | ||
321 | { | ||
322 | return philips_tda6651_pll_init(0x61, fe); | ||
323 | } | ||
324 | |||
325 | static int philips_tu1216_tuner_61_set_params(struct dvb_frontend *fe, struct dvb_frontend_parameters *params) | ||
326 | { | ||
327 | return philips_tda6651_pll_set(0x61, fe, params); | ||
328 | } | ||
329 | |||
330 | static struct tda1004x_config philips_tu1216_61_config = { | 337 | static struct tda1004x_config philips_tu1216_61_config = { |
331 | 338 | ||
332 | .demod_address = 0x8, | 339 | .demod_address = 0x8, |
@@ -335,7 +342,8 @@ static struct tda1004x_config philips_tu1216_61_config = { | |||
335 | .xtal_freq = TDA10046_XTAL_4M, | 342 | .xtal_freq = TDA10046_XTAL_4M, |
336 | .agc_config = TDA10046_AGC_DEFAULT, | 343 | .agc_config = TDA10046_AGC_DEFAULT, |
337 | .if_freq = TDA10046_FREQ_3617, | 344 | .if_freq = TDA10046_FREQ_3617, |
338 | .request_firmware = philips_tda1004x_request_firmware, | 345 | .tuner_address = 0x61, |
346 | .request_firmware = philips_tda1004x_request_firmware | ||
339 | }; | 347 | }; |
340 | 348 | ||
341 | /* ------------------------------------------------------------------ */ | 349 | /* ------------------------------------------------------------------ */ |
@@ -343,24 +351,42 @@ static struct tda1004x_config philips_tu1216_61_config = { | |||
343 | static int philips_td1316_tuner_init(struct dvb_frontend *fe) | 351 | static int philips_td1316_tuner_init(struct dvb_frontend *fe) |
344 | { | 352 | { |
345 | struct saa7134_dev *dev = fe->dvb->priv; | 353 | struct saa7134_dev *dev = fe->dvb->priv; |
354 | struct tda1004x_state *state = fe->demodulator_priv; | ||
355 | u8 addr = state->config->tuner_address; | ||
346 | static u8 msg[] = { 0x0b, 0xf5, 0x86, 0xab }; | 356 | static u8 msg[] = { 0x0b, 0xf5, 0x86, 0xab }; |
347 | struct i2c_msg init_msg = {.addr = 0x61,.flags = 0,.buf = msg,.len = sizeof(msg) }; | 357 | struct i2c_msg init_msg = {.addr = addr,.flags = 0,.buf = msg,.len = sizeof(msg) }; |
348 | 358 | ||
349 | /* setup PLL configuration */ | 359 | /* setup PLL configuration */ |
350 | if (fe->ops.i2c_gate_ctrl) | 360 | if (fe->ops.i2c_gate_ctrl) |
351 | fe->ops.i2c_gate_ctrl(fe, 1); | 361 | fe->ops.i2c_gate_ctrl(fe, 1); |
352 | if (i2c_transfer(&dev->i2c_adap, &init_msg, 1) != 1) | 362 | if (i2c_transfer(&dev->i2c_adap, &init_msg, 1) != 1) |
353 | return -EIO; | 363 | return -EIO; |
354 | if (fe->ops.i2c_gate_ctrl) | ||
355 | fe->ops.i2c_gate_ctrl(fe, 0); | ||
356 | return 0; | 364 | return 0; |
357 | } | 365 | } |
358 | 366 | ||
359 | static int philips_td1316_tuner_set_params(struct dvb_frontend *fe, struct dvb_frontend_parameters *params) | 367 | static int philips_td1316_tuner_set_params(struct dvb_frontend *fe, struct dvb_frontend_parameters *params) |
360 | { | 368 | { |
361 | return philips_tda6651_pll_set(0x61, fe, params); | 369 | return philips_tda6651_pll_set(fe, params); |
362 | } | 370 | } |
363 | 371 | ||
372 | static int philips_td1316_tuner_sleep(struct dvb_frontend *fe) | ||
373 | { | ||
374 | struct saa7134_dev *dev = fe->dvb->priv; | ||
375 | struct tda1004x_state *state = fe->demodulator_priv; | ||
376 | u8 addr = state->config->tuner_address; | ||
377 | static u8 msg[] = { 0x0b, 0xdc, 0x86, 0xa4 }; | ||
378 | struct i2c_msg analog_msg = {.addr = addr,.flags = 0,.buf = msg,.len = sizeof(msg) }; | ||
379 | |||
380 | /* switch the tuner to analog mode */ | ||
381 | if (fe->ops.i2c_gate_ctrl) | ||
382 | fe->ops.i2c_gate_ctrl(fe, 1); | ||
383 | if (i2c_transfer(&dev->i2c_adap, &analog_msg, 1) != 1) | ||
384 | return -EIO; | ||
385 | return 0; | ||
386 | } | ||
387 | |||
388 | /* ------------------------------------------------------------------ */ | ||
389 | |||
364 | static int philips_europa_tuner_init(struct dvb_frontend *fe) | 390 | static int philips_europa_tuner_init(struct dvb_frontend *fe) |
365 | { | 391 | { |
366 | struct saa7134_dev *dev = fe->dvb->priv; | 392 | struct saa7134_dev *dev = fe->dvb->priv; |
@@ -380,18 +406,14 @@ static int philips_europa_tuner_init(struct dvb_frontend *fe) | |||
380 | static int philips_europa_tuner_sleep(struct dvb_frontend *fe) | 406 | static int philips_europa_tuner_sleep(struct dvb_frontend *fe) |
381 | { | 407 | { |
382 | struct saa7134_dev *dev = fe->dvb->priv; | 408 | struct saa7134_dev *dev = fe->dvb->priv; |
383 | /* this message actually turns the tuner back to analog mode */ | ||
384 | static u8 msg[] = { 0x0b, 0xdc, 0x86, 0xa4 }; | ||
385 | struct i2c_msg analog_msg = {.addr = 0x61,.flags = 0,.buf = msg,.len = sizeof(msg) }; | ||
386 | 409 | ||
387 | i2c_transfer(&dev->i2c_adap, &analog_msg, 1); | 410 | static u8 msg[] = { 0x00, 0x14 }; |
388 | msleep(1); | 411 | struct i2c_msg analog_msg = {.addr = 0x43,.flags = 0,.buf = msg,.len = sizeof(msg) }; |
412 | |||
413 | if (philips_td1316_tuner_sleep(fe)) | ||
414 | return -EIO; | ||
389 | 415 | ||
390 | /* switch the board to analog mode */ | 416 | /* switch the board to analog mode */ |
391 | analog_msg.addr = 0x43; | ||
392 | analog_msg.len = 0x02; | ||
393 | msg[0] = 0x00; | ||
394 | msg[1] = 0x14; | ||
395 | if (fe->ops.i2c_gate_ctrl) | 417 | if (fe->ops.i2c_gate_ctrl) |
396 | fe->ops.i2c_gate_ctrl(fe, 1); | 418 | fe->ops.i2c_gate_ctrl(fe, 1); |
397 | i2c_transfer(&dev->i2c_adap, &analog_msg, 1); | 419 | i2c_transfer(&dev->i2c_adap, &analog_msg, 1); |
@@ -416,7 +438,8 @@ static struct tda1004x_config philips_europa_config = { | |||
416 | .xtal_freq = TDA10046_XTAL_4M, | 438 | .xtal_freq = TDA10046_XTAL_4M, |
417 | .agc_config = TDA10046_AGC_IFO_AUTO_POS, | 439 | .agc_config = TDA10046_AGC_IFO_AUTO_POS, |
418 | .if_freq = TDA10046_FREQ_052, | 440 | .if_freq = TDA10046_FREQ_052, |
419 | .request_firmware = NULL, | 441 | .tuner_address = 0x61, |
442 | .request_firmware = philips_tda1004x_request_firmware | ||
420 | }; | 443 | }; |
421 | 444 | ||
422 | /* ------------------------------------------------------------------ */ | 445 | /* ------------------------------------------------------------------ */ |
@@ -424,9 +447,11 @@ static struct tda1004x_config philips_europa_config = { | |||
424 | static int philips_fmd1216_tuner_init(struct dvb_frontend *fe) | 447 | static int philips_fmd1216_tuner_init(struct dvb_frontend *fe) |
425 | { | 448 | { |
426 | struct saa7134_dev *dev = fe->dvb->priv; | 449 | struct saa7134_dev *dev = fe->dvb->priv; |
450 | struct tda1004x_state *state = fe->demodulator_priv; | ||
451 | u8 addr = state->config->tuner_address; | ||
427 | /* this message is to set up ATC and ALC */ | 452 | /* this message is to set up ATC and ALC */ |
428 | static u8 fmd1216_init[] = { 0x0b, 0xdc, 0x9c, 0xa0 }; | 453 | static u8 fmd1216_init[] = { 0x0b, 0xdc, 0x9c, 0xa0 }; |
429 | struct i2c_msg tuner_msg = {.addr = 0x61,.flags = 0,.buf = fmd1216_init,.len = sizeof(fmd1216_init) }; | 454 | struct i2c_msg tuner_msg = {.addr = addr,.flags = 0,.buf = fmd1216_init,.len = sizeof(fmd1216_init) }; |
430 | 455 | ||
431 | if (fe->ops.i2c_gate_ctrl) | 456 | if (fe->ops.i2c_gate_ctrl) |
432 | fe->ops.i2c_gate_ctrl(fe, 1); | 457 | fe->ops.i2c_gate_ctrl(fe, 1); |
@@ -440,9 +465,11 @@ static int philips_fmd1216_tuner_init(struct dvb_frontend *fe) | |||
440 | static int philips_fmd1216_tuner_sleep(struct dvb_frontend *fe) | 465 | static int philips_fmd1216_tuner_sleep(struct dvb_frontend *fe) |
441 | { | 466 | { |
442 | struct saa7134_dev *dev = fe->dvb->priv; | 467 | struct saa7134_dev *dev = fe->dvb->priv; |
468 | struct tda1004x_state *state = fe->demodulator_priv; | ||
469 | u8 addr = state->config->tuner_address; | ||
443 | /* this message actually turns the tuner back to analog mode */ | 470 | /* this message actually turns the tuner back to analog mode */ |
444 | static u8 fmd1216_init[] = { 0x0b, 0xdc, 0x9c, 0x60 }; | 471 | u8 fmd1216_init[] = { 0x0b, 0xdc, 0x9c, 0x60 }; |
445 | struct i2c_msg tuner_msg = {.addr = 0x61,.flags = 0,.buf = fmd1216_init,.len = sizeof(fmd1216_init) }; | 472 | struct i2c_msg tuner_msg = {.addr = addr,.flags = 0,.buf = fmd1216_init,.len = sizeof(fmd1216_init) }; |
446 | 473 | ||
447 | if (fe->ops.i2c_gate_ctrl) | 474 | if (fe->ops.i2c_gate_ctrl) |
448 | fe->ops.i2c_gate_ctrl(fe, 1); | 475 | fe->ops.i2c_gate_ctrl(fe, 1); |
@@ -460,8 +487,10 @@ static int philips_fmd1216_tuner_sleep(struct dvb_frontend *fe) | |||
460 | static int philips_fmd1216_tuner_set_params(struct dvb_frontend *fe, struct dvb_frontend_parameters *params) | 487 | static int philips_fmd1216_tuner_set_params(struct dvb_frontend *fe, struct dvb_frontend_parameters *params) |
461 | { | 488 | { |
462 | struct saa7134_dev *dev = fe->dvb->priv; | 489 | struct saa7134_dev *dev = fe->dvb->priv; |
490 | struct tda1004x_state *state = fe->demodulator_priv; | ||
491 | u8 addr = state->config->tuner_address; | ||
463 | u8 tuner_buf[4]; | 492 | u8 tuner_buf[4]; |
464 | struct i2c_msg tuner_msg = {.addr = 0x61,.flags = 0,.buf = tuner_buf,.len = | 493 | struct i2c_msg tuner_msg = {.addr = addr,.flags = 0,.buf = tuner_buf,.len = |
465 | sizeof(tuner_buf) }; | 494 | sizeof(tuner_buf) }; |
466 | int tuner_frequency = 0; | 495 | int tuner_frequency = 0; |
467 | int divider = 0; | 496 | int divider = 0; |
@@ -536,8 +565,11 @@ static int philips_fmd1216_tuner_set_params(struct dvb_frontend *fe, struct dvb_ | |||
536 | 565 | ||
537 | if (fe->ops.i2c_gate_ctrl) | 566 | if (fe->ops.i2c_gate_ctrl) |
538 | fe->ops.i2c_gate_ctrl(fe, 1); | 567 | fe->ops.i2c_gate_ctrl(fe, 1); |
539 | if (i2c_transfer(&dev->i2c_adap, &tuner_msg, 1) != 1) | 568 | if (i2c_transfer(&dev->i2c_adap, &tuner_msg, 1) != 1) { |
569 | wprintk("could not write to tuner at addr: 0x%02x\n", | ||
570 | addr << 1); | ||
540 | return -EIO; | 571 | return -EIO; |
572 | } | ||
541 | return 0; | 573 | return 0; |
542 | } | 574 | } |
543 | 575 | ||
@@ -548,582 +580,365 @@ static struct tda1004x_config medion_cardbus = { | |||
548 | .xtal_freq = TDA10046_XTAL_16M, | 580 | .xtal_freq = TDA10046_XTAL_16M, |
549 | .agc_config = TDA10046_AGC_IFO_AUTO_NEG, | 581 | .agc_config = TDA10046_AGC_IFO_AUTO_NEG, |
550 | .if_freq = TDA10046_FREQ_3613, | 582 | .if_freq = TDA10046_FREQ_3613, |
551 | .request_firmware = NULL, | 583 | .tuner_address = 0x61, |
584 | .request_firmware = philips_tda1004x_request_firmware | ||
552 | }; | 585 | }; |
553 | 586 | ||
554 | /* ------------------------------------------------------------------ */ | 587 | /* ------------------------------------------------------------------ |
555 | 588 | * tda 1004x based cards with philips silicon tuner | |
556 | struct tda827x_data { | 589 | */ |
557 | u32 lomax; | ||
558 | u8 spd; | ||
559 | u8 bs; | ||
560 | u8 bp; | ||
561 | u8 cp; | ||
562 | u8 gc3; | ||
563 | u8 div1p5; | ||
564 | }; | ||
565 | |||
566 | static struct tda827x_data tda827x_dvbt[] = { | ||
567 | { .lomax = 62000000, .spd = 3, .bs = 2, .bp = 0, .cp = 0, .gc3 = 3, .div1p5 = 1}, | ||
568 | { .lomax = 66000000, .spd = 3, .bs = 3, .bp = 0, .cp = 0, .gc3 = 3, .div1p5 = 1}, | ||
569 | { .lomax = 76000000, .spd = 3, .bs = 1, .bp = 0, .cp = 0, .gc3 = 3, .div1p5 = 0}, | ||
570 | { .lomax = 84000000, .spd = 3, .bs = 2, .bp = 0, .cp = 0, .gc3 = 3, .div1p5 = 0}, | ||
571 | { .lomax = 93000000, .spd = 3, .bs = 2, .bp = 0, .cp = 0, .gc3 = 1, .div1p5 = 0}, | ||
572 | { .lomax = 98000000, .spd = 3, .bs = 3, .bp = 0, .cp = 0, .gc3 = 1, .div1p5 = 0}, | ||
573 | { .lomax = 109000000, .spd = 3, .bs = 3, .bp = 1, .cp = 0, .gc3 = 1, .div1p5 = 0}, | ||
574 | { .lomax = 123000000, .spd = 2, .bs = 2, .bp = 1, .cp = 0, .gc3 = 1, .div1p5 = 1}, | ||
575 | { .lomax = 133000000, .spd = 2, .bs = 3, .bp = 1, .cp = 0, .gc3 = 1, .div1p5 = 1}, | ||
576 | { .lomax = 151000000, .spd = 2, .bs = 1, .bp = 1, .cp = 0, .gc3 = 1, .div1p5 = 0}, | ||
577 | { .lomax = 154000000, .spd = 2, .bs = 2, .bp = 1, .cp = 0, .gc3 = 1, .div1p5 = 0}, | ||
578 | { .lomax = 181000000, .spd = 2, .bs = 2, .bp = 1, .cp = 0, .gc3 = 0, .div1p5 = 0}, | ||
579 | { .lomax = 185000000, .spd = 2, .bs = 2, .bp = 2, .cp = 0, .gc3 = 1, .div1p5 = 0}, | ||
580 | { .lomax = 217000000, .spd = 2, .bs = 3, .bp = 2, .cp = 0, .gc3 = 1, .div1p5 = 0}, | ||
581 | { .lomax = 244000000, .spd = 1, .bs = 2, .bp = 2, .cp = 0, .gc3 = 1, .div1p5 = 1}, | ||
582 | { .lomax = 265000000, .spd = 1, .bs = 3, .bp = 2, .cp = 0, .gc3 = 1, .div1p5 = 1}, | ||
583 | { .lomax = 302000000, .spd = 1, .bs = 1, .bp = 2, .cp = 0, .gc3 = 1, .div1p5 = 0}, | ||
584 | { .lomax = 324000000, .spd = 1, .bs = 2, .bp = 2, .cp = 0, .gc3 = 1, .div1p5 = 0}, | ||
585 | { .lomax = 370000000, .spd = 1, .bs = 2, .bp = 3, .cp = 0, .gc3 = 1, .div1p5 = 0}, | ||
586 | { .lomax = 454000000, .spd = 1, .bs = 3, .bp = 3, .cp = 0, .gc3 = 1, .div1p5 = 0}, | ||
587 | { .lomax = 493000000, .spd = 0, .bs = 2, .bp = 3, .cp = 0, .gc3 = 1, .div1p5 = 1}, | ||
588 | { .lomax = 530000000, .spd = 0, .bs = 3, .bp = 3, .cp = 0, .gc3 = 1, .div1p5 = 1}, | ||
589 | { .lomax = 554000000, .spd = 0, .bs = 1, .bp = 3, .cp = 0, .gc3 = 1, .div1p5 = 0}, | ||
590 | { .lomax = 604000000, .spd = 0, .bs = 1, .bp = 4, .cp = 0, .gc3 = 0, .div1p5 = 0}, | ||
591 | { .lomax = 696000000, .spd = 0, .bs = 2, .bp = 4, .cp = 0, .gc3 = 0, .div1p5 = 0}, | ||
592 | { .lomax = 740000000, .spd = 0, .bs = 2, .bp = 4, .cp = 1, .gc3 = 0, .div1p5 = 0}, | ||
593 | { .lomax = 820000000, .spd = 0, .bs = 3, .bp = 4, .cp = 0, .gc3 = 0, .div1p5 = 0}, | ||
594 | { .lomax = 865000000, .spd = 0, .bs = 3, .bp = 4, .cp = 1, .gc3 = 0, .div1p5 = 0}, | ||
595 | { .lomax = 0, .spd = 0, .bs = 0, .bp = 0, .cp = 0, .gc3 = 0, .div1p5 = 0} | ||
596 | }; | ||
597 | |||
598 | static int philips_tda827x_tuner_init(struct dvb_frontend *fe) | ||
599 | { | ||
600 | return 0; | ||
601 | } | ||
602 | 590 | ||
603 | static int philips_tda827x_tuner_set_params(struct dvb_frontend *fe, struct dvb_frontend_parameters *params) | 591 | static void philips_tda827x_lna_gain(struct dvb_frontend *fe, int high) |
604 | { | 592 | { |
605 | struct saa7134_dev *dev = fe->dvb->priv; | 593 | struct saa7134_dev *dev = fe->dvb->priv; |
606 | u8 tuner_buf[14]; | 594 | struct tda1004x_state *state = fe->demodulator_priv; |
607 | 595 | u8 addr = state->config->i2c_gate; | |
608 | struct i2c_msg tuner_msg = {.addr = 0x60,.flags = 0,.buf = tuner_buf, | 596 | u8 config = state->config->tuner_config; |
609 | .len = sizeof(tuner_buf) }; | 597 | u8 GP00_CF[] = {0x20, 0x01}; |
610 | int i, tuner_freq, if_freq; | 598 | u8 GP00_LEV[] = {0x22, 0x00}; |
611 | u32 N; | 599 | |
612 | switch (params->u.ofdm.bandwidth) { | 600 | struct i2c_msg msg = {.addr = addr,.flags = 0,.buf = GP00_CF, .len = 2}; |
613 | case BANDWIDTH_6_MHZ: | 601 | if (config) { |
614 | if_freq = 4000000; | 602 | if (high) { |
615 | break; | 603 | dprintk("setting LNA to high gain\n"); |
616 | case BANDWIDTH_7_MHZ: | 604 | } else { |
617 | if_freq = 4500000; | 605 | dprintk("setting LNA to low gain\n"); |
618 | break; | 606 | } |
619 | default: /* 8 MHz or Auto */ | ||
620 | if_freq = 5000000; | ||
621 | break; | ||
622 | } | ||
623 | tuner_freq = params->frequency + if_freq; | ||
624 | |||
625 | i = 0; | ||
626 | while (tda827x_dvbt[i].lomax < tuner_freq) { | ||
627 | if(tda827x_dvbt[i + 1].lomax == 0) | ||
628 | break; | ||
629 | i++; | ||
630 | } | 607 | } |
631 | 608 | switch (config) { | |
632 | N = ((tuner_freq + 125000) / 250000) << (tda827x_dvbt[i].spd + 2); | 609 | case 0: /* no LNA */ |
633 | tuner_buf[0] = 0; | ||
634 | tuner_buf[1] = (N>>8) | 0x40; | ||
635 | tuner_buf[2] = N & 0xff; | ||
636 | tuner_buf[3] = 0; | ||
637 | tuner_buf[4] = 0x52; | ||
638 | tuner_buf[5] = (tda827x_dvbt[i].spd << 6) + (tda827x_dvbt[i].div1p5 << 5) + | ||
639 | (tda827x_dvbt[i].bs << 3) + tda827x_dvbt[i].bp; | ||
640 | tuner_buf[6] = (tda827x_dvbt[i].gc3 << 4) + 0x8f; | ||
641 | tuner_buf[7] = 0xbf; | ||
642 | tuner_buf[8] = 0x2a; | ||
643 | tuner_buf[9] = 0x05; | ||
644 | tuner_buf[10] = 0xff; | ||
645 | tuner_buf[11] = 0x00; | ||
646 | tuner_buf[12] = 0x00; | ||
647 | tuner_buf[13] = 0x40; | ||
648 | |||
649 | tuner_msg.len = 14; | ||
650 | if (fe->ops.i2c_gate_ctrl) | ||
651 | fe->ops.i2c_gate_ctrl(fe, 1); | ||
652 | if (i2c_transfer(&dev->i2c_adap, &tuner_msg, 1) != 1) | ||
653 | return -EIO; | ||
654 | |||
655 | msleep(500); | ||
656 | /* correct CP value */ | ||
657 | tuner_buf[0] = 0x30; | ||
658 | tuner_buf[1] = 0x50 + tda827x_dvbt[i].cp; | ||
659 | tuner_msg.len = 2; | ||
660 | if (fe->ops.i2c_gate_ctrl) | ||
661 | fe->ops.i2c_gate_ctrl(fe, 1); | ||
662 | i2c_transfer(&dev->i2c_adap, &tuner_msg, 1); | ||
663 | |||
664 | return 0; | ||
665 | } | ||
666 | |||
667 | static int philips_tda827x_tuner_sleep(struct dvb_frontend *fe) | ||
668 | { | ||
669 | struct saa7134_dev *dev = fe->dvb->priv; | ||
670 | static u8 tda827x_sleep[] = { 0x30, 0xd0}; | ||
671 | struct i2c_msg tuner_msg = {.addr = 0x60,.flags = 0,.buf = tda827x_sleep, | ||
672 | .len = sizeof(tda827x_sleep) }; | ||
673 | if (fe->ops.i2c_gate_ctrl) | ||
674 | fe->ops.i2c_gate_ctrl(fe, 1); | ||
675 | i2c_transfer(&dev->i2c_adap, &tuner_msg, 1); | ||
676 | return 0; | ||
677 | } | ||
678 | |||
679 | static struct tda1004x_config tda827x_lifeview_config = { | ||
680 | .demod_address = 0x08, | ||
681 | .invert = 1, | ||
682 | .invert_oclk = 0, | ||
683 | .xtal_freq = TDA10046_XTAL_16M, | ||
684 | .agc_config = TDA10046_AGC_TDA827X_GP11, | ||
685 | .if_freq = TDA10046_FREQ_045, | ||
686 | .request_firmware = NULL, | ||
687 | }; | ||
688 | |||
689 | /* ------------------------------------------------------------------ */ | ||
690 | |||
691 | struct tda827xa_data { | ||
692 | u32 lomax; | ||
693 | u8 svco; | ||
694 | u8 spd; | ||
695 | u8 scr; | ||
696 | u8 sbs; | ||
697 | u8 gc3; | ||
698 | }; | ||
699 | |||
700 | static struct tda827xa_data tda827xa_dvbt[] = { | ||
701 | { .lomax = 56875000, .svco = 3, .spd = 4, .scr = 0, .sbs = 0, .gc3 = 1}, | ||
702 | { .lomax = 67250000, .svco = 0, .spd = 3, .scr = 0, .sbs = 0, .gc3 = 1}, | ||
703 | { .lomax = 81250000, .svco = 1, .spd = 3, .scr = 0, .sbs = 0, .gc3 = 1}, | ||
704 | { .lomax = 97500000, .svco = 2, .spd = 3, .scr = 0, .sbs = 0, .gc3 = 1}, | ||
705 | { .lomax = 113750000, .svco = 3, .spd = 3, .scr = 0, .sbs = 1, .gc3 = 1}, | ||
706 | { .lomax = 134500000, .svco = 0, .spd = 2, .scr = 0, .sbs = 1, .gc3 = 1}, | ||
707 | { .lomax = 154000000, .svco = 1, .spd = 2, .scr = 0, .sbs = 1, .gc3 = 1}, | ||
708 | { .lomax = 162500000, .svco = 1, .spd = 2, .scr = 0, .sbs = 1, .gc3 = 1}, | ||
709 | { .lomax = 183000000, .svco = 2, .spd = 2, .scr = 0, .sbs = 1, .gc3 = 1}, | ||
710 | { .lomax = 195000000, .svco = 2, .spd = 2, .scr = 0, .sbs = 2, .gc3 = 1}, | ||
711 | { .lomax = 227500000, .svco = 3, .spd = 2, .scr = 0, .sbs = 2, .gc3 = 1}, | ||
712 | { .lomax = 269000000, .svco = 0, .spd = 1, .scr = 0, .sbs = 2, .gc3 = 1}, | ||
713 | { .lomax = 290000000, .svco = 1, .spd = 1, .scr = 0, .sbs = 2, .gc3 = 1}, | ||
714 | { .lomax = 325000000, .svco = 1, .spd = 1, .scr = 0, .sbs = 3, .gc3 = 1}, | ||
715 | { .lomax = 390000000, .svco = 2, .spd = 1, .scr = 0, .sbs = 3, .gc3 = 1}, | ||
716 | { .lomax = 455000000, .svco = 3, .spd = 1, .scr = 0, .sbs = 3, .gc3 = 1}, | ||
717 | { .lomax = 520000000, .svco = 0, .spd = 0, .scr = 0, .sbs = 3, .gc3 = 1}, | ||
718 | { .lomax = 538000000, .svco = 0, .spd = 0, .scr = 1, .sbs = 3, .gc3 = 1}, | ||
719 | { .lomax = 550000000, .svco = 1, .spd = 0, .scr = 0, .sbs = 3, .gc3 = 1}, | ||
720 | { .lomax = 620000000, .svco = 1, .spd = 0, .scr = 0, .sbs = 4, .gc3 = 0}, | ||
721 | { .lomax = 650000000, .svco = 1, .spd = 0, .scr = 1, .sbs = 4, .gc3 = 0}, | ||
722 | { .lomax = 700000000, .svco = 2, .spd = 0, .scr = 0, .sbs = 4, .gc3 = 0}, | ||
723 | { .lomax = 780000000, .svco = 2, .spd = 0, .scr = 1, .sbs = 4, .gc3 = 0}, | ||
724 | { .lomax = 820000000, .svco = 3, .spd = 0, .scr = 0, .sbs = 4, .gc3 = 0}, | ||
725 | { .lomax = 870000000, .svco = 3, .spd = 0, .scr = 1, .sbs = 4, .gc3 = 0}, | ||
726 | { .lomax = 911000000, .svco = 3, .spd = 0, .scr = 2, .sbs = 4, .gc3 = 0}, | ||
727 | { .lomax = 0, .svco = 0, .spd = 0, .scr = 0, .sbs = 0, .gc3 = 0}}; | ||
728 | |||
729 | |||
730 | static int philips_tda827xa_pll_set(u8 addr, struct dvb_frontend *fe, struct dvb_frontend_parameters *params) | ||
731 | { | ||
732 | struct saa7134_dev *dev = fe->dvb->priv; | ||
733 | u8 tuner_buf[14]; | ||
734 | unsigned char reg2[2]; | ||
735 | |||
736 | struct i2c_msg msg = {.addr = addr,.flags = 0,.buf = tuner_buf}; | ||
737 | int i, tuner_freq, if_freq; | ||
738 | u32 N; | ||
739 | |||
740 | switch (params->u.ofdm.bandwidth) { | ||
741 | case BANDWIDTH_6_MHZ: | ||
742 | if_freq = 4000000; | ||
743 | break; | 610 | break; |
744 | case BANDWIDTH_7_MHZ: | 611 | case 1: /* switch is GPIO 0 of tda8290 */ |
745 | if_freq = 4500000; | 612 | case 2: |
613 | /* turn Vsync off */ | ||
614 | saa7134_set_gpio(dev, 22, 0); | ||
615 | GP00_LEV[1] = high ? 0 : 1; | ||
616 | if (i2c_transfer(&dev->i2c_adap, &msg, 1) != 1) { | ||
617 | wprintk("could not access tda8290 at addr: 0x%02x\n", | ||
618 | addr << 1); | ||
619 | return; | ||
620 | } | ||
621 | msg.buf = GP00_LEV; | ||
622 | if (config == 2) | ||
623 | GP00_LEV[1] = high ? 1 : 0; | ||
624 | i2c_transfer(&dev->i2c_adap, &msg, 1); | ||
746 | break; | 625 | break; |
747 | default: /* 8 MHz or Auto */ | 626 | case 3: /* switch with GPIO of saa713x */ |
748 | if_freq = 5000000; | 627 | saa7134_set_gpio(dev, 22, high); |
749 | break; | 628 | break; |
750 | } | 629 | } |
751 | tuner_freq = params->frequency + if_freq; | ||
752 | |||
753 | i = 0; | ||
754 | while (tda827xa_dvbt[i].lomax < tuner_freq) { | ||
755 | if(tda827xa_dvbt[i + 1].lomax == 0) | ||
756 | break; | ||
757 | i++; | ||
758 | } | ||
759 | |||
760 | N = ((tuner_freq + 31250) / 62500) << tda827xa_dvbt[i].spd; | ||
761 | tuner_buf[0] = 0; // subaddress | ||
762 | tuner_buf[1] = N >> 8; | ||
763 | tuner_buf[2] = N & 0xff; | ||
764 | tuner_buf[3] = 0; | ||
765 | tuner_buf[4] = 0x16; | ||
766 | tuner_buf[5] = (tda827xa_dvbt[i].spd << 5) + (tda827xa_dvbt[i].svco << 3) + | ||
767 | tda827xa_dvbt[i].sbs; | ||
768 | tuner_buf[6] = 0x4b + (tda827xa_dvbt[i].gc3 << 4); | ||
769 | tuner_buf[7] = 0x0c; | ||
770 | tuner_buf[8] = 0x06; | ||
771 | tuner_buf[9] = 0x24; | ||
772 | tuner_buf[10] = 0xff; | ||
773 | tuner_buf[11] = 0x60; | ||
774 | tuner_buf[12] = 0x00; | ||
775 | tuner_buf[13] = 0x39; // lpsel | ||
776 | msg.len = 14; | ||
777 | if (fe->ops.i2c_gate_ctrl) | ||
778 | fe->ops.i2c_gate_ctrl(fe, 1); | ||
779 | if (i2c_transfer(&dev->i2c_adap, &msg, 1) != 1) | ||
780 | return -EIO; | ||
781 | |||
782 | msg.buf= reg2; | ||
783 | msg.len = 2; | ||
784 | reg2[0] = 0x60; | ||
785 | reg2[1] = 0x3c; | ||
786 | if (fe->ops.i2c_gate_ctrl) | ||
787 | fe->ops.i2c_gate_ctrl(fe, 1); | ||
788 | i2c_transfer(&dev->i2c_adap, &msg, 1); | ||
789 | |||
790 | reg2[0] = 0xa0; | ||
791 | reg2[1] = 0x40; | ||
792 | if (fe->ops.i2c_gate_ctrl) | ||
793 | fe->ops.i2c_gate_ctrl(fe, 1); | ||
794 | i2c_transfer(&dev->i2c_adap, &msg, 1); | ||
795 | |||
796 | msleep(2); | ||
797 | /* correct CP value */ | ||
798 | reg2[0] = 0x30; | ||
799 | reg2[1] = 0x10 + tda827xa_dvbt[i].scr; | ||
800 | msg.len = 2; | ||
801 | if (fe->ops.i2c_gate_ctrl) | ||
802 | fe->ops.i2c_gate_ctrl(fe, 1); | ||
803 | i2c_transfer(&dev->i2c_adap, &msg, 1); | ||
804 | |||
805 | msleep(550); | ||
806 | reg2[0] = 0x50; | ||
807 | reg2[1] = 0x4f + (tda827xa_dvbt[i].gc3 << 4); | ||
808 | if (fe->ops.i2c_gate_ctrl) | ||
809 | fe->ops.i2c_gate_ctrl(fe, 1); | ||
810 | i2c_transfer(&dev->i2c_adap, &msg, 1); | ||
811 | |||
812 | return 0; | ||
813 | |||
814 | } | 630 | } |
815 | 631 | ||
816 | static int philips_tda827xa_tuner_sleep(u8 addr, struct dvb_frontend *fe) | 632 | static int tda8290_i2c_gate_ctrl( struct dvb_frontend* fe, int enable) |
817 | { | 633 | { |
818 | struct saa7134_dev *dev = fe->dvb->priv; | 634 | struct tda1004x_state *state = fe->demodulator_priv; |
819 | static u8 tda827xa_sleep[] = { 0x30, 0x90}; | ||
820 | struct i2c_msg tuner_msg = {.addr = addr,.flags = 0,.buf = tda827xa_sleep, | ||
821 | .len = sizeof(tda827xa_sleep) }; | ||
822 | if (fe->ops.i2c_gate_ctrl) | ||
823 | fe->ops.i2c_gate_ctrl(fe, 1); | ||
824 | i2c_transfer(&dev->i2c_adap, &tuner_msg, 1); | ||
825 | if (fe->ops.i2c_gate_ctrl) | ||
826 | fe->ops.i2c_gate_ctrl(fe, 0); | ||
827 | return 0; | ||
828 | } | ||
829 | 635 | ||
830 | /* ------------------------------------------------------------------ */ | 636 | u8 addr = state->config->i2c_gate; |
831 | |||
832 | static int tda8290_i2c_gate_ctrl(struct dvb_frontend* fe, int enable) | ||
833 | { | ||
834 | struct saa7134_dev *dev = fe->dvb->priv; | ||
835 | static u8 tda8290_close[] = { 0x21, 0xc0}; | 637 | static u8 tda8290_close[] = { 0x21, 0xc0}; |
836 | static u8 tda8290_open[] = { 0x21, 0x80}; | 638 | static u8 tda8290_open[] = { 0x21, 0x80}; |
837 | struct i2c_msg tda8290_msg = {.addr = 0x4b,.flags = 0, .len = 2}; | 639 | struct i2c_msg tda8290_msg = {.addr = addr,.flags = 0, .len = 2}; |
838 | if (enable) { | 640 | if (enable) { |
839 | tda8290_msg.buf = tda8290_close; | 641 | tda8290_msg.buf = tda8290_close; |
840 | } else { | 642 | } else { |
841 | tda8290_msg.buf = tda8290_open; | 643 | tda8290_msg.buf = tda8290_open; |
842 | } | 644 | } |
843 | if (i2c_transfer(&dev->i2c_adap, &tda8290_msg, 1) != 1) | 645 | if (i2c_transfer(state->i2c, &tda8290_msg, 1) != 1) { |
646 | struct saa7134_dev *dev = fe->dvb->priv; | ||
647 | wprintk("could not access tda8290 I2C gate\n"); | ||
844 | return -EIO; | 648 | return -EIO; |
649 | } | ||
845 | msleep(20); | 650 | msleep(20); |
846 | return 0; | 651 | return 0; |
847 | } | 652 | } |
848 | 653 | ||
849 | /* ------------------------------------------------------------------ */ | 654 | /* ------------------------------------------------------------------ */ |
850 | 655 | ||
851 | static int philips_tiger_tuner_set_params(struct dvb_frontend *fe, struct dvb_frontend_parameters *params) | 656 | static int philips_tda827x_tuner_init(struct dvb_frontend *fe) |
852 | { | 657 | { |
853 | int ret; | 658 | struct saa7134_dev *dev = fe->dvb->priv; |
659 | struct tda1004x_state *state = fe->demodulator_priv; | ||
854 | 660 | ||
855 | ret = philips_tda827xa_pll_set(0x61, fe, params); | 661 | switch (state->config->antenna_switch) { |
856 | if (ret != 0) | 662 | case 0: break; |
857 | return ret; | 663 | case 1: dprintk("setting GPIO21 to 0 (TV antenna?)\n"); |
664 | saa7134_set_gpio(dev, 21, 0); | ||
665 | break; | ||
666 | case 2: dprintk("setting GPIO21 to 1 (Radio antenna?)\n"); | ||
667 | saa7134_set_gpio(dev, 21, 1); | ||
668 | break; | ||
669 | } | ||
858 | return 0; | 670 | return 0; |
859 | } | 671 | } |
860 | 672 | ||
861 | static int philips_tiger_tuner_init(struct dvb_frontend *fe) | 673 | static int philips_tda827x_tuner_sleep(struct dvb_frontend *fe) |
862 | { | 674 | { |
863 | struct saa7134_dev *dev = fe->dvb->priv; | 675 | struct saa7134_dev *dev = fe->dvb->priv; |
864 | static u8 data[] = { 0x3c, 0x33, 0x6a}; | 676 | struct tda1004x_state *state = fe->demodulator_priv; |
865 | struct i2c_msg msg = {.addr=0x08, .flags=0, .buf=data, .len = sizeof(data)}; | ||
866 | 677 | ||
867 | if (i2c_transfer(&dev->i2c_adap, &msg, 1) != 1) | 678 | switch (state->config->antenna_switch) { |
868 | return -EIO; | 679 | case 0: break; |
680 | case 1: dprintk("setting GPIO21 to 1 (Radio antenna?)\n"); | ||
681 | saa7134_set_gpio(dev, 21, 1); | ||
682 | break; | ||
683 | case 2: dprintk("setting GPIO21 to 0 (TV antenna?)\n"); | ||
684 | saa7134_set_gpio(dev, 21, 0); | ||
685 | break; | ||
686 | } | ||
869 | return 0; | 687 | return 0; |
870 | } | 688 | } |
871 | 689 | ||
872 | static int philips_tiger_tuner_sleep(struct dvb_frontend *fe) | 690 | static struct tda827x_config tda827x_cfg = { |
873 | { | 691 | .lna_gain = philips_tda827x_lna_gain, |
874 | struct saa7134_dev *dev = fe->dvb->priv; | 692 | .init = philips_tda827x_tuner_init, |
875 | static u8 data[] = { 0x3c, 0x33, 0x68}; | 693 | .sleep = philips_tda827x_tuner_sleep |
876 | struct i2c_msg msg = {.addr=0x08, .flags=0, .buf=data, .len = sizeof(data)}; | 694 | }; |
877 | 695 | ||
878 | i2c_transfer(&dev->i2c_adap, &msg, 1); | 696 | static void configure_tda827x_fe(struct saa7134_dev *dev, struct tda1004x_config *tda_conf) |
879 | philips_tda827xa_tuner_sleep( 0x61, fe); | 697 | { |
880 | return 0; | 698 | dev->dvb.frontend = dvb_attach(tda10046_attach, tda_conf, &dev->i2c_adap); |
699 | if (dev->dvb.frontend) { | ||
700 | if (tda_conf->i2c_gate) | ||
701 | dev->dvb.frontend->ops.i2c_gate_ctrl = tda8290_i2c_gate_ctrl; | ||
702 | if (dvb_attach(tda827x_attach, dev->dvb.frontend, tda_conf->tuner_address, | ||
703 | &dev->i2c_adap,&tda827x_cfg) == NULL) { | ||
704 | wprintk("no tda827x tuner found at addr: %02x\n", | ||
705 | tda_conf->tuner_address); | ||
706 | } | ||
707 | } | ||
881 | } | 708 | } |
882 | 709 | ||
883 | static struct tda1004x_config philips_tiger_config = { | 710 | /* ------------------------------------------------------------------ */ |
711 | static struct tda1004x_config tda827x_lifeview_config = { | ||
884 | .demod_address = 0x08, | 712 | .demod_address = 0x08, |
885 | .invert = 1, | 713 | .invert = 1, |
886 | .invert_oclk = 0, | 714 | .invert_oclk = 0, |
887 | .xtal_freq = TDA10046_XTAL_16M, | 715 | .xtal_freq = TDA10046_XTAL_16M, |
888 | .agc_config = TDA10046_AGC_TDA827X_GP11, | 716 | .agc_config = TDA10046_AGC_TDA827X, |
717 | .gpio_config = TDA10046_GP11_I, | ||
889 | .if_freq = TDA10046_FREQ_045, | 718 | .if_freq = TDA10046_FREQ_045, |
890 | .request_firmware = NULL, | 719 | .tuner_address = 0x60, |
720 | .request_firmware = philips_tda1004x_request_firmware | ||
891 | }; | 721 | }; |
892 | /* ------------------------------------------------------------------ */ | ||
893 | |||
894 | static int cinergy_ht_tuner_init(struct dvb_frontend *fe) | ||
895 | { | ||
896 | struct saa7134_dev *dev = fe->dvb->priv; | ||
897 | static u8 data[] = { 0x3c, 0x33, 0x62}; | ||
898 | struct i2c_msg msg = {.addr=0x08, .flags=0, .buf=data, .len = sizeof(data)}; | ||
899 | 722 | ||
900 | if (i2c_transfer(&dev->i2c_adap, &msg, 1) != 1) | 723 | static struct tda1004x_config philips_tiger_config = { |
901 | return -EIO; | 724 | .demod_address = 0x08, |
902 | return 0; | 725 | .invert = 1, |
903 | } | 726 | .invert_oclk = 0, |
904 | 727 | .xtal_freq = TDA10046_XTAL_16M, | |
905 | static int cinergy_ht_tuner_sleep(struct dvb_frontend *fe) | 728 | .agc_config = TDA10046_AGC_TDA827X, |
906 | { | 729 | .gpio_config = TDA10046_GP11_I, |
907 | struct saa7134_dev *dev = fe->dvb->priv; | 730 | .if_freq = TDA10046_FREQ_045, |
908 | static u8 data[] = { 0x3c, 0x33, 0x60}; | 731 | .i2c_gate = 0x4b, |
909 | struct i2c_msg msg = {.addr=0x08, .flags=0, .buf=data, .len = sizeof(data)}; | 732 | .tuner_address = 0x61, |
910 | 733 | .tuner_config = 0, | |
911 | i2c_transfer(&dev->i2c_adap, &msg, 1); | 734 | .antenna_switch= 1, |
912 | philips_tda827xa_tuner_sleep( 0x61, fe); | 735 | .request_firmware = philips_tda1004x_request_firmware |
913 | return 0; | 736 | }; |
914 | } | ||
915 | 737 | ||
916 | static struct tda1004x_config cinergy_ht_config = { | 738 | static struct tda1004x_config cinergy_ht_config = { |
917 | .demod_address = 0x08, | 739 | .demod_address = 0x08, |
918 | .invert = 1, | 740 | .invert = 1, |
919 | .invert_oclk = 0, | 741 | .invert_oclk = 0, |
920 | .xtal_freq = TDA10046_XTAL_16M, | 742 | .xtal_freq = TDA10046_XTAL_16M, |
921 | .agc_config = TDA10046_AGC_TDA827X_GP01, | 743 | .agc_config = TDA10046_AGC_TDA827X, |
744 | .gpio_config = TDA10046_GP01_I, | ||
922 | .if_freq = TDA10046_FREQ_045, | 745 | .if_freq = TDA10046_FREQ_045, |
923 | .request_firmware = NULL, | 746 | .i2c_gate = 0x4b, |
747 | .tuner_address = 0x61, | ||
748 | .tuner_config = 0, | ||
749 | .request_firmware = philips_tda1004x_request_firmware | ||
924 | }; | 750 | }; |
925 | 751 | ||
926 | /* ------------------------------------------------------------------ */ | 752 | static struct tda1004x_config cinergy_ht_pci_config = { |
753 | .demod_address = 0x08, | ||
754 | .invert = 1, | ||
755 | .invert_oclk = 0, | ||
756 | .xtal_freq = TDA10046_XTAL_16M, | ||
757 | .agc_config = TDA10046_AGC_TDA827X, | ||
758 | .gpio_config = TDA10046_GP01_I, | ||
759 | .if_freq = TDA10046_FREQ_045, | ||
760 | .i2c_gate = 0x4b, | ||
761 | .tuner_address = 0x60, | ||
762 | .tuner_config = 0, | ||
763 | .request_firmware = philips_tda1004x_request_firmware | ||
764 | }; | ||
927 | 765 | ||
928 | static struct tda1004x_config pinnacle_pctv_310i_config = { | 766 | static struct tda1004x_config philips_tiger_s_config = { |
929 | .demod_address = 0x08, | 767 | .demod_address = 0x08, |
930 | .invert = 1, | 768 | .invert = 1, |
931 | .invert_oclk = 0, | 769 | .invert_oclk = 0, |
932 | .xtal_freq = TDA10046_XTAL_16M, | 770 | .xtal_freq = TDA10046_XTAL_16M, |
933 | .agc_config = TDA10046_AGC_TDA827X_GP11, | 771 | .agc_config = TDA10046_AGC_TDA827X, |
772 | .gpio_config = TDA10046_GP01_I, | ||
934 | .if_freq = TDA10046_FREQ_045, | 773 | .if_freq = TDA10046_FREQ_045, |
935 | .request_firmware = philips_tda1004x_request_firmware, | 774 | .i2c_gate = 0x4b, |
775 | .tuner_address = 0x61, | ||
776 | .tuner_config = 2, | ||
777 | .antenna_switch= 1, | ||
778 | .request_firmware = philips_tda1004x_request_firmware | ||
936 | }; | 779 | }; |
937 | 780 | ||
938 | /* ------------------------------------------------------------------ */ | 781 | static struct tda1004x_config pinnacle_pctv_310i_config = { |
782 | .demod_address = 0x08, | ||
783 | .invert = 1, | ||
784 | .invert_oclk = 0, | ||
785 | .xtal_freq = TDA10046_XTAL_16M, | ||
786 | .agc_config = TDA10046_AGC_TDA827X, | ||
787 | .gpio_config = TDA10046_GP11_I, | ||
788 | .if_freq = TDA10046_FREQ_045, | ||
789 | .i2c_gate = 0x4b, | ||
790 | .tuner_address = 0x61, | ||
791 | .tuner_config = 1, | ||
792 | .request_firmware = philips_tda1004x_request_firmware | ||
793 | }; | ||
939 | 794 | ||
940 | static struct tda1004x_config hauppauge_hvr_1110_config = { | 795 | static struct tda1004x_config hauppauge_hvr_1110_config = { |
941 | .demod_address = 0x08, | 796 | .demod_address = 0x08, |
942 | .invert = 1, | 797 | .invert = 1, |
943 | .invert_oclk = 0, | 798 | .invert_oclk = 0, |
944 | .xtal_freq = TDA10046_XTAL_16M, | 799 | .xtal_freq = TDA10046_XTAL_16M, |
945 | .agc_config = TDA10046_AGC_TDA827X_GP11, | 800 | .agc_config = TDA10046_AGC_TDA827X, |
801 | .gpio_config = TDA10046_GP11_I, | ||
946 | .if_freq = TDA10046_FREQ_045, | 802 | .if_freq = TDA10046_FREQ_045, |
947 | .request_firmware = philips_tda1004x_request_firmware, | 803 | .i2c_gate = 0x4b, |
804 | .tuner_address = 0x61, | ||
805 | .request_firmware = philips_tda1004x_request_firmware | ||
948 | }; | 806 | }; |
949 | 807 | ||
950 | /* ------------------------------------------------------------------ */ | ||
951 | |||
952 | static struct tda1004x_config asus_p7131_dual_config = { | 808 | static struct tda1004x_config asus_p7131_dual_config = { |
953 | .demod_address = 0x08, | 809 | .demod_address = 0x08, |
954 | .invert = 1, | 810 | .invert = 1, |
955 | .invert_oclk = 0, | 811 | .invert_oclk = 0, |
956 | .xtal_freq = TDA10046_XTAL_16M, | 812 | .xtal_freq = TDA10046_XTAL_16M, |
957 | .agc_config = TDA10046_AGC_TDA827X_GP11, | 813 | .agc_config = TDA10046_AGC_TDA827X, |
814 | .gpio_config = TDA10046_GP11_I, | ||
958 | .if_freq = TDA10046_FREQ_045, | 815 | .if_freq = TDA10046_FREQ_045, |
959 | .request_firmware = philips_tda1004x_request_firmware, | 816 | .i2c_gate = 0x4b, |
817 | .tuner_address = 0x61, | ||
818 | .tuner_config = 0, | ||
819 | .antenna_switch= 2, | ||
820 | .request_firmware = philips_tda1004x_request_firmware | ||
960 | }; | 821 | }; |
961 | 822 | ||
962 | static int asus_p7131_dual_tuner_init(struct dvb_frontend *fe) | ||
963 | { | ||
964 | struct saa7134_dev *dev = fe->dvb->priv; | ||
965 | static u8 data[] = { 0x3c, 0x33, 0x6a}; | ||
966 | struct i2c_msg msg = {.addr=0x08, .flags=0, .buf=data, .len = sizeof(data)}; | ||
967 | |||
968 | if (i2c_transfer(&dev->i2c_adap, &msg, 1) != 1) | ||
969 | return -EIO; | ||
970 | /* make sure the DVB-T antenna input is set */ | ||
971 | saa_setl(SAA7134_GPIO_GPSTATUS0 >> 2, 0x0200000); | ||
972 | return 0; | ||
973 | } | ||
974 | |||
975 | static int asus_p7131_dual_tuner_sleep(struct dvb_frontend *fe) | ||
976 | { | ||
977 | struct saa7134_dev *dev = fe->dvb->priv; | ||
978 | static u8 data[] = { 0x3c, 0x33, 0x68}; | ||
979 | struct i2c_msg msg = {.addr=0x08, .flags=0, .buf=data, .len = sizeof(data)}; | ||
980 | |||
981 | i2c_transfer(&dev->i2c_adap, &msg, 1); | ||
982 | philips_tda827xa_tuner_sleep( 0x61, fe); | ||
983 | /* reset antenna inputs for analog usage */ | ||
984 | saa_clearl(SAA7134_GPIO_GPSTATUS0 >> 2, 0x0200000); | ||
985 | return 0; | ||
986 | } | ||
987 | |||
988 | /* ------------------------------------------------------------------ */ | ||
989 | |||
990 | static int lifeview_trio_tuner_set_params(struct dvb_frontend *fe, struct dvb_frontend_parameters *params) | ||
991 | { | ||
992 | int ret; | ||
993 | |||
994 | ret = philips_tda827xa_pll_set(0x60, fe, params); | ||
995 | return ret; | ||
996 | } | ||
997 | |||
998 | static int lifeview_trio_tuner_sleep(struct dvb_frontend *fe) | ||
999 | { | ||
1000 | philips_tda827xa_tuner_sleep(0x60, fe); | ||
1001 | return 0; | ||
1002 | } | ||
1003 | |||
1004 | static struct tda1004x_config lifeview_trio_config = { | 823 | static struct tda1004x_config lifeview_trio_config = { |
1005 | .demod_address = 0x09, | 824 | .demod_address = 0x09, |
1006 | .invert = 1, | 825 | .invert = 1, |
1007 | .invert_oclk = 0, | 826 | .invert_oclk = 0, |
1008 | .xtal_freq = TDA10046_XTAL_16M, | 827 | .xtal_freq = TDA10046_XTAL_16M, |
1009 | .agc_config = TDA10046_AGC_TDA827X_GP00, | 828 | .agc_config = TDA10046_AGC_TDA827X, |
829 | .gpio_config = TDA10046_GP00_I, | ||
1010 | .if_freq = TDA10046_FREQ_045, | 830 | .if_freq = TDA10046_FREQ_045, |
1011 | .request_firmware = NULL, | 831 | .tuner_address = 0x60, |
832 | .request_firmware = philips_tda1004x_request_firmware | ||
1012 | }; | 833 | }; |
1013 | 834 | ||
1014 | /* ------------------------------------------------------------------ */ | 835 | static struct tda1004x_config tevion_dvbt220rf_config = { |
1015 | |||
1016 | static int ads_duo_tuner_set_params(struct dvb_frontend *fe, struct dvb_frontend_parameters *params) | ||
1017 | { | ||
1018 | int ret; | ||
1019 | |||
1020 | ret = philips_tda827xa_pll_set(0x61, fe, params); | ||
1021 | return ret; | ||
1022 | } | ||
1023 | |||
1024 | static int ads_duo_tuner_init(struct dvb_frontend *fe) | ||
1025 | { | ||
1026 | struct saa7134_dev *dev = fe->dvb->priv; | ||
1027 | /* route TDA8275a AGC input to the channel decoder */ | ||
1028 | saa_writeb(SAA7134_GPIO_GPSTATUS2, 0x60); | ||
1029 | return 0; | ||
1030 | } | ||
1031 | |||
1032 | static int ads_duo_tuner_sleep(struct dvb_frontend *fe) | ||
1033 | { | ||
1034 | struct saa7134_dev *dev = fe->dvb->priv; | ||
1035 | /* route TDA8275a AGC input to the analog IF chip*/ | ||
1036 | saa_writeb(SAA7134_GPIO_GPSTATUS2, 0x20); | ||
1037 | philips_tda827xa_tuner_sleep( 0x61, fe); | ||
1038 | return 0; | ||
1039 | } | ||
1040 | |||
1041 | static struct tda1004x_config ads_tech_duo_config = { | ||
1042 | .demod_address = 0x08, | 836 | .demod_address = 0x08, |
1043 | .invert = 1, | 837 | .invert = 1, |
1044 | .invert_oclk = 0, | 838 | .invert_oclk = 0, |
1045 | .xtal_freq = TDA10046_XTAL_16M, | 839 | .xtal_freq = TDA10046_XTAL_16M, |
1046 | .agc_config = TDA10046_AGC_TDA827X_GP00, | 840 | .agc_config = TDA10046_AGC_TDA827X, |
841 | .gpio_config = TDA10046_GP11_I, | ||
1047 | .if_freq = TDA10046_FREQ_045, | 842 | .if_freq = TDA10046_FREQ_045, |
1048 | .request_firmware = NULL, | 843 | .tuner_address = 0x60, |
844 | .request_firmware = philips_tda1004x_request_firmware | ||
1049 | }; | 845 | }; |
1050 | 846 | ||
1051 | /* ------------------------------------------------------------------ */ | 847 | static struct tda1004x_config md8800_dvbt_config = { |
1052 | 848 | .demod_address = 0x08, | |
1053 | static int tevion_dvb220rf_tuner_set_params(struct dvb_frontend *fe, struct dvb_frontend_parameters *params) | 849 | .invert = 1, |
1054 | { | 850 | .invert_oclk = 0, |
1055 | int ret; | 851 | .xtal_freq = TDA10046_XTAL_16M, |
1056 | ret = philips_tda827xa_pll_set(0x60, fe, params); | 852 | .agc_config = TDA10046_AGC_TDA827X, |
1057 | return ret; | 853 | .gpio_config = TDA10046_GP01_I, |
1058 | } | 854 | .if_freq = TDA10046_FREQ_045, |
1059 | 855 | .i2c_gate = 0x4b, | |
1060 | static int tevion_dvb220rf_tuner_sleep(struct dvb_frontend *fe) | 856 | .tuner_address = 0x60, |
1061 | { | 857 | .tuner_config = 0, |
1062 | philips_tda827xa_tuner_sleep( 0x61, fe); | 858 | .request_firmware = philips_tda1004x_request_firmware |
1063 | return 0; | 859 | }; |
1064 | } | ||
1065 | 860 | ||
1066 | static struct tda1004x_config tevion_dvbt220rf_config = { | 861 | static struct tda1004x_config asus_p7131_4871_config = { |
1067 | .demod_address = 0x08, | 862 | .demod_address = 0x08, |
1068 | .invert = 1, | 863 | .invert = 1, |
1069 | .invert_oclk = 0, | 864 | .invert_oclk = 0, |
1070 | .xtal_freq = TDA10046_XTAL_16M, | 865 | .xtal_freq = TDA10046_XTAL_16M, |
1071 | .agc_config = TDA10046_AGC_TDA827X_GP11, | 866 | .agc_config = TDA10046_AGC_TDA827X, |
867 | .gpio_config = TDA10046_GP01_I, | ||
1072 | .if_freq = TDA10046_FREQ_045, | 868 | .if_freq = TDA10046_FREQ_045, |
1073 | .request_firmware = NULL, | 869 | .i2c_gate = 0x4b, |
870 | .tuner_address = 0x61, | ||
871 | .tuner_config = 2, | ||
872 | .antenna_switch= 2, | ||
873 | .request_firmware = philips_tda1004x_request_firmware | ||
1074 | }; | 874 | }; |
1075 | 875 | ||
1076 | /* ------------------------------------------------------------------ */ | 876 | static struct tda1004x_config asus_p7131_hybrid_lna_config = { |
877 | .demod_address = 0x08, | ||
878 | .invert = 1, | ||
879 | .invert_oclk = 0, | ||
880 | .xtal_freq = TDA10046_XTAL_16M, | ||
881 | .agc_config = TDA10046_AGC_TDA827X, | ||
882 | .gpio_config = TDA10046_GP11_I, | ||
883 | .if_freq = TDA10046_FREQ_045, | ||
884 | .i2c_gate = 0x4b, | ||
885 | .tuner_address = 0x61, | ||
886 | .tuner_config = 2, | ||
887 | .antenna_switch= 2, | ||
888 | .request_firmware = philips_tda1004x_request_firmware | ||
889 | }; | ||
890 | /* ------------------------------------------------------------------ | ||
891 | * special case: this card uses saa713x GPIO22 for the mode switch | ||
892 | */ | ||
1077 | 893 | ||
1078 | static int md8800_dvbt_analog_mode(struct dvb_frontend *fe) | 894 | static int ads_duo_tuner_init(struct dvb_frontend *fe) |
1079 | { | 895 | { |
1080 | struct saa7134_dev *dev = fe->dvb->priv; | 896 | struct saa7134_dev *dev = fe->dvb->priv; |
1081 | static u8 data[] = { 0x3c, 0x33, 0x68}; | 897 | philips_tda827x_tuner_init(fe); |
1082 | struct i2c_msg msg = {.addr=0x08, .flags=0, .buf=data, .len = sizeof(data)}; | 898 | /* route TDA8275a AGC input to the channel decoder */ |
1083 | 899 | saa7134_set_gpio(dev, 22, 1); | |
1084 | i2c_transfer(&dev->i2c_adap, &msg, 1); | ||
1085 | philips_tda827xa_tuner_sleep( 0x61, fe); | ||
1086 | return 0; | 900 | return 0; |
1087 | } | 901 | } |
1088 | 902 | ||
1089 | static int md8800_dvbt_pll_set(struct dvb_frontend *fe, struct dvb_frontend_parameters *params) | 903 | static int ads_duo_tuner_sleep(struct dvb_frontend *fe) |
1090 | { | 904 | { |
1091 | int ret; | ||
1092 | struct saa7134_dev *dev = fe->dvb->priv; | 905 | struct saa7134_dev *dev = fe->dvb->priv; |
1093 | static u8 tda8290_close[] = { 0x21, 0xc0}; | 906 | /* route TDA8275a AGC input to the analog IF chip*/ |
1094 | static u8 tda8290_open[] = { 0x21, 0x80}; | 907 | saa7134_set_gpio(dev, 22, 0); |
1095 | struct i2c_msg tda8290_msg = {.addr = 0x4b,.flags = 0, .len = 2}; | 908 | philips_tda827x_tuner_sleep(fe); |
1096 | /* close tda8290 i2c bridge */ | 909 | return 0; |
1097 | tda8290_msg.buf = tda8290_close; | ||
1098 | ret = i2c_transfer(&dev->i2c_adap, &tda8290_msg, 1); | ||
1099 | if (ret != 1) | ||
1100 | return -EIO; | ||
1101 | msleep(20); | ||
1102 | ret = philips_tda827xa_pll_set(0x60, fe, params); | ||
1103 | if (ret != 0) | ||
1104 | return ret; | ||
1105 | /* open tda8290 i2c bridge */ | ||
1106 | tda8290_msg.buf = tda8290_open; | ||
1107 | i2c_transfer(&dev->i2c_adap, &tda8290_msg, 1); | ||
1108 | return ret; | ||
1109 | } | 910 | } |
1110 | 911 | ||
1111 | static struct tda1004x_config md8800_dvbt_config = { | 912 | static struct tda827x_config ads_duo_cfg = { |
913 | .lna_gain = philips_tda827x_lna_gain, | ||
914 | .init = ads_duo_tuner_init, | ||
915 | .sleep = ads_duo_tuner_sleep | ||
916 | }; | ||
917 | |||
918 | static struct tda1004x_config ads_tech_duo_config = { | ||
1112 | .demod_address = 0x08, | 919 | .demod_address = 0x08, |
1113 | .invert = 1, | 920 | .invert = 1, |
1114 | .invert_oclk = 0, | 921 | .invert_oclk = 0, |
1115 | .xtal_freq = TDA10046_XTAL_16M, | 922 | .xtal_freq = TDA10046_XTAL_16M, |
1116 | .agc_config = TDA10046_AGC_TDA827X_GP11, | 923 | .agc_config = TDA10046_AGC_TDA827X, |
924 | .gpio_config = TDA10046_GP00_I, | ||
1117 | .if_freq = TDA10046_FREQ_045, | 925 | .if_freq = TDA10046_FREQ_045, |
1118 | .request_firmware = NULL, | 926 | .tuner_address = 0x61, |
927 | .request_firmware = philips_tda1004x_request_firmware | ||
1119 | }; | 928 | }; |
1120 | 929 | ||
930 | /* ================================================================== | ||
931 | * tda10086 based DVB-S cards, helper functions | ||
932 | */ | ||
933 | |||
1121 | static struct tda10086_config flydvbs = { | 934 | static struct tda10086_config flydvbs = { |
1122 | .demod_address = 0x0e, | 935 | .demod_address = 0x0e, |
1123 | .invert = 0, | 936 | .invert = 0, |
1124 | }; | 937 | }; |
1125 | 938 | ||
1126 | /* ------------------------------------------------------------------ */ | 939 | /* ================================================================== |
940 | * nxt200x based ATSC cards, helper functions | ||
941 | */ | ||
1127 | 942 | ||
1128 | static struct nxt200x_config avertvhda180 = { | 943 | static struct nxt200x_config avertvhda180 = { |
1129 | .demod_address = 0x0a, | 944 | .demod_address = 0x0a, |
@@ -1143,10 +958,13 @@ static struct nxt200x_config kworldatsc110 = { | |||
1143 | .set_pll_input = nxt200x_set_pll_input, | 958 | .set_pll_input = nxt200x_set_pll_input, |
1144 | }; | 959 | }; |
1145 | 960 | ||
1146 | /* ------------------------------------------------------------------ */ | 961 | /* ================================================================== |
962 | * Core code | ||
963 | */ | ||
1147 | 964 | ||
1148 | static int dvb_init(struct saa7134_dev *dev) | 965 | static int dvb_init(struct saa7134_dev *dev) |
1149 | { | 966 | { |
967 | int ret; | ||
1150 | /* init struct videobuf_dvb */ | 968 | /* init struct videobuf_dvb */ |
1151 | dev->ts.nr_bufs = 32; | 969 | dev->ts.nr_bufs = 32; |
1152 | dev->ts.nr_packets = 32*4; | 970 | dev->ts.nr_packets = 32*4; |
@@ -1160,7 +978,7 @@ static int dvb_init(struct saa7134_dev *dev) | |||
1160 | 978 | ||
1161 | switch (dev->board) { | 979 | switch (dev->board) { |
1162 | case SAA7134_BOARD_PINNACLE_300I_DVBT_PAL: | 980 | case SAA7134_BOARD_PINNACLE_300I_DVBT_PAL: |
1163 | printk("%s: pinnacle 300i dvb setup\n",dev->name); | 981 | dprintk("pinnacle 300i dvb setup\n"); |
1164 | dev->dvb.frontend = dvb_attach(mt352_attach, &pinnacle_300i, | 982 | dev->dvb.frontend = dvb_attach(mt352_attach, &pinnacle_300i, |
1165 | &dev->i2c_adap); | 983 | &dev->i2c_adap); |
1166 | if (dev->dvb.frontend) { | 984 | if (dev->dvb.frontend) { |
@@ -1169,7 +987,7 @@ static int dvb_init(struct saa7134_dev *dev) | |||
1169 | break; | 987 | break; |
1170 | case SAA7134_BOARD_AVERMEDIA_777: | 988 | case SAA7134_BOARD_AVERMEDIA_777: |
1171 | case SAA7134_BOARD_AVERMEDIA_A16AR: | 989 | case SAA7134_BOARD_AVERMEDIA_A16AR: |
1172 | printk("%s: avertv 777 dvb setup\n",dev->name); | 990 | dprintk("avertv 777 dvb setup\n"); |
1173 | dev->dvb.frontend = dvb_attach(mt352_attach, &avermedia_777, | 991 | dev->dvb.frontend = dvb_attach(mt352_attach, &avermedia_777, |
1174 | &dev->i2c_adap); | 992 | &dev->i2c_adap); |
1175 | if (dev->dvb.frontend) { | 993 | if (dev->dvb.frontend) { |
@@ -1191,42 +1009,15 @@ static int dvb_init(struct saa7134_dev *dev) | |||
1191 | &philips_tu1216_60_config, | 1009 | &philips_tu1216_60_config, |
1192 | &dev->i2c_adap); | 1010 | &dev->i2c_adap); |
1193 | if (dev->dvb.frontend) { | 1011 | if (dev->dvb.frontend) { |
1194 | dev->dvb.frontend->ops.tuner_ops.init = philips_tu1216_tuner_60_init; | 1012 | dev->dvb.frontend->ops.tuner_ops.init = philips_tu1216_init; |
1195 | dev->dvb.frontend->ops.tuner_ops.set_params = philips_tu1216_tuner_60_set_params; | 1013 | dev->dvb.frontend->ops.tuner_ops.set_params = philips_tda6651_pll_set; |
1196 | } | 1014 | } |
1197 | break; | 1015 | break; |
1198 | case SAA7134_BOARD_FLYDVBTDUO: | 1016 | case SAA7134_BOARD_FLYDVBTDUO: |
1199 | dev->dvb.frontend = dvb_attach(tda10046_attach, | ||
1200 | &tda827x_lifeview_config, | ||
1201 | &dev->i2c_adap); | ||
1202 | if (dev->dvb.frontend) { | ||
1203 | dev->dvb.frontend->ops.tuner_ops.init = philips_tda827x_tuner_init; | ||
1204 | dev->dvb.frontend->ops.tuner_ops.sleep = philips_tda827x_tuner_sleep; | ||
1205 | dev->dvb.frontend->ops.tuner_ops.set_params = philips_tda827x_tuner_set_params; | ||
1206 | } | ||
1207 | break; | ||
1208 | case SAA7134_BOARD_FLYDVBT_DUO_CARDBUS: | 1017 | case SAA7134_BOARD_FLYDVBT_DUO_CARDBUS: |
1209 | dev->dvb.frontend = dvb_attach(tda10046_attach, | 1018 | configure_tda827x_fe(dev, &tda827x_lifeview_config); |
1210 | &tda827x_lifeview_config, | ||
1211 | &dev->i2c_adap); | ||
1212 | if (dev->dvb.frontend) { | ||
1213 | dev->dvb.frontend->ops.tuner_ops.init = philips_tda827x_tuner_init; | ||
1214 | dev->dvb.frontend->ops.tuner_ops.sleep = philips_tda827x_tuner_sleep; | ||
1215 | dev->dvb.frontend->ops.tuner_ops.set_params = philips_tda827x_tuner_set_params; | ||
1216 | } | ||
1217 | break; | 1019 | break; |
1218 | case SAA7134_BOARD_PHILIPS_EUROPA: | 1020 | case SAA7134_BOARD_PHILIPS_EUROPA: |
1219 | dev->dvb.frontend = dvb_attach(tda10046_attach, | ||
1220 | &philips_europa_config, | ||
1221 | &dev->i2c_adap); | ||
1222 | if (dev->dvb.frontend) { | ||
1223 | dev->original_demod_sleep = dev->dvb.frontend->ops.sleep; | ||
1224 | dev->dvb.frontend->ops.sleep = philips_europa_demod_sleep; | ||
1225 | dev->dvb.frontend->ops.tuner_ops.init = philips_europa_tuner_init; | ||
1226 | dev->dvb.frontend->ops.tuner_ops.sleep = philips_europa_tuner_sleep; | ||
1227 | dev->dvb.frontend->ops.tuner_ops.set_params = philips_td1316_tuner_set_params; | ||
1228 | } | ||
1229 | break; | ||
1230 | case SAA7134_BOARD_VIDEOMATE_DVBT_300: | 1021 | case SAA7134_BOARD_VIDEOMATE_DVBT_300: |
1231 | dev->dvb.frontend = dvb_attach(tda10046_attach, | 1022 | dev->dvb.frontend = dvb_attach(tda10046_attach, |
1232 | &philips_europa_config, | 1023 | &philips_europa_config, |
@@ -1244,125 +1035,61 @@ static int dvb_init(struct saa7134_dev *dev) | |||
1244 | &philips_tu1216_61_config, | 1035 | &philips_tu1216_61_config, |
1245 | &dev->i2c_adap); | 1036 | &dev->i2c_adap); |
1246 | if (dev->dvb.frontend) { | 1037 | if (dev->dvb.frontend) { |
1247 | dev->dvb.frontend->ops.tuner_ops.init = philips_tu1216_tuner_61_init; | 1038 | dev->dvb.frontend->ops.tuner_ops.init = philips_tu1216_init; |
1248 | dev->dvb.frontend->ops.tuner_ops.set_params = philips_tu1216_tuner_61_set_params; | 1039 | dev->dvb.frontend->ops.tuner_ops.set_params = philips_tda6651_pll_set; |
1249 | } | 1040 | } |
1250 | break; | 1041 | break; |
1251 | case SAA7134_BOARD_PHILIPS_TIGER: | 1042 | case SAA7134_BOARD_PHILIPS_TIGER: |
1252 | dev->dvb.frontend = dvb_attach(tda10046_attach, | 1043 | configure_tda827x_fe(dev, &philips_tiger_config); |
1253 | &philips_tiger_config, | ||
1254 | &dev->i2c_adap); | ||
1255 | if (dev->dvb.frontend) { | ||
1256 | dev->dvb.frontend->ops.i2c_gate_ctrl = tda8290_i2c_gate_ctrl; | ||
1257 | dev->dvb.frontend->ops.tuner_ops.init = philips_tiger_tuner_init; | ||
1258 | dev->dvb.frontend->ops.tuner_ops.sleep = philips_tiger_tuner_sleep; | ||
1259 | dev->dvb.frontend->ops.tuner_ops.set_params = philips_tiger_tuner_set_params; | ||
1260 | } | ||
1261 | break; | 1044 | break; |
1262 | case SAA7134_BOARD_PINNACLE_PCTV_310i: | 1045 | case SAA7134_BOARD_PINNACLE_PCTV_310i: |
1263 | dev->dvb.frontend = dvb_attach(tda10046_attach, | 1046 | configure_tda827x_fe(dev, &pinnacle_pctv_310i_config); |
1264 | &pinnacle_pctv_310i_config, | ||
1265 | &dev->i2c_adap); | ||
1266 | if (dev->dvb.frontend) { | ||
1267 | dev->dvb.frontend->ops.i2c_gate_ctrl = tda8290_i2c_gate_ctrl; | ||
1268 | dev->dvb.frontend->ops.tuner_ops.init = philips_tiger_tuner_init; | ||
1269 | dev->dvb.frontend->ops.tuner_ops.sleep = philips_tiger_tuner_sleep; | ||
1270 | dev->dvb.frontend->ops.tuner_ops.set_params = philips_tiger_tuner_set_params; | ||
1271 | } | ||
1272 | break; | 1047 | break; |
1273 | case SAA7134_BOARD_HAUPPAUGE_HVR1110: | 1048 | case SAA7134_BOARD_HAUPPAUGE_HVR1110: |
1274 | dev->dvb.frontend = dvb_attach(tda10046_attach, | 1049 | configure_tda827x_fe(dev, &hauppauge_hvr_1110_config); |
1275 | &hauppauge_hvr_1110_config, | ||
1276 | &dev->i2c_adap); | ||
1277 | if (dev->dvb.frontend) { | ||
1278 | dev->dvb.frontend->ops.i2c_gate_ctrl = tda8290_i2c_gate_ctrl; | ||
1279 | dev->dvb.frontend->ops.tuner_ops.init = philips_tiger_tuner_init; | ||
1280 | dev->dvb.frontend->ops.tuner_ops.sleep = philips_tiger_tuner_sleep; | ||
1281 | dev->dvb.frontend->ops.tuner_ops.set_params = philips_tiger_tuner_set_params; | ||
1282 | } | ||
1283 | break; | 1050 | break; |
1284 | case SAA7134_BOARD_ASUSTeK_P7131_DUAL: | 1051 | case SAA7134_BOARD_ASUSTeK_P7131_DUAL: |
1285 | dev->dvb.frontend = dvb_attach(tda10046_attach, | 1052 | configure_tda827x_fe(dev, &asus_p7131_dual_config); |
1286 | &asus_p7131_dual_config, | ||
1287 | &dev->i2c_adap); | ||
1288 | if (dev->dvb.frontend) { | ||
1289 | dev->dvb.frontend->ops.i2c_gate_ctrl = tda8290_i2c_gate_ctrl; | ||
1290 | dev->dvb.frontend->ops.tuner_ops.init = asus_p7131_dual_tuner_init; | ||
1291 | dev->dvb.frontend->ops.tuner_ops.sleep = asus_p7131_dual_tuner_sleep; | ||
1292 | dev->dvb.frontend->ops.tuner_ops.set_params = philips_tiger_tuner_set_params; | ||
1293 | } | ||
1294 | break; | 1053 | break; |
1295 | case SAA7134_BOARD_FLYDVBT_LR301: | 1054 | case SAA7134_BOARD_FLYDVBT_LR301: |
1296 | dev->dvb.frontend = dvb_attach(tda10046_attach, | 1055 | configure_tda827x_fe(dev, &tda827x_lifeview_config); |
1297 | &tda827x_lifeview_config, | ||
1298 | &dev->i2c_adap); | ||
1299 | if (dev->dvb.frontend) { | ||
1300 | dev->dvb.frontend->ops.tuner_ops.init = philips_tda827x_tuner_init; | ||
1301 | dev->dvb.frontend->ops.tuner_ops.sleep = philips_tda827x_tuner_sleep; | ||
1302 | dev->dvb.frontend->ops.tuner_ops.set_params = philips_tda827x_tuner_set_params; | ||
1303 | } | ||
1304 | break; | 1056 | break; |
1305 | case SAA7134_BOARD_FLYDVB_TRIO: | 1057 | case SAA7134_BOARD_FLYDVB_TRIO: |
1306 | if(! use_frontend) { //terrestrial | 1058 | if(! use_frontend) { //terrestrial |
1307 | dev->dvb.frontend = dvb_attach(tda10046_attach, | 1059 | configure_tda827x_fe(dev, &lifeview_trio_config); |
1308 | &lifeview_trio_config, | ||
1309 | &dev->i2c_adap); | ||
1310 | if (dev->dvb.frontend) { | ||
1311 | dev->dvb.frontend->ops.tuner_ops.sleep = lifeview_trio_tuner_sleep; | ||
1312 | dev->dvb.frontend->ops.tuner_ops.set_params = | ||
1313 | lifeview_trio_tuner_set_params; | ||
1314 | } | ||
1315 | } else { //satellite | 1060 | } else { //satellite |
1316 | dev->dvb.frontend = dvb_attach(tda10086_attach, &flydvbs, &dev->i2c_adap); | 1061 | dev->dvb.frontend = dvb_attach(tda10086_attach, &flydvbs, &dev->i2c_adap); |
1317 | if (dev->dvb.frontend) { | 1062 | if (dev->dvb.frontend) { |
1318 | if (dvb_attach(tda826x_attach, dev->dvb.frontend, 0x63, | 1063 | if (dvb_attach(tda826x_attach, dev->dvb.frontend, 0x63, |
1319 | &dev->i2c_adap, 0) == NULL) { | 1064 | &dev->i2c_adap, 0) == NULL) { |
1320 | printk("%s: Lifeview Trio, No tda826x found!\n", __FUNCTION__); | 1065 | wprintk("%s: Lifeview Trio, No tda826x found!\n", __FUNCTION__); |
1321 | } | 1066 | } |
1322 | if (dvb_attach(isl6421_attach, dev->dvb.frontend, &dev->i2c_adap, | 1067 | if (dvb_attach(isl6421_attach, dev->dvb.frontend, &dev->i2c_adap, |
1323 | 0x08, 0, 0) == NULL) { | 1068 | 0x08, 0, 0) == NULL) { |
1324 | printk("%s: Lifeview Trio, No ISL6421 found!\n", __FUNCTION__); | 1069 | wprintk("%s: Lifeview Trio, No ISL6421 found!\n", __FUNCTION__); |
1325 | } | 1070 | } |
1326 | } | 1071 | } |
1327 | } | 1072 | } |
1328 | break; | 1073 | break; |
1329 | case SAA7134_BOARD_ADS_DUO_CARDBUS_PTV331: | 1074 | case SAA7134_BOARD_ADS_DUO_CARDBUS_PTV331: |
1075 | case SAA7134_BOARD_FLYDVBT_HYBRID_CARDBUS: | ||
1330 | dev->dvb.frontend = dvb_attach(tda10046_attach, | 1076 | dev->dvb.frontend = dvb_attach(tda10046_attach, |
1331 | &ads_tech_duo_config, | 1077 | &ads_tech_duo_config, |
1332 | &dev->i2c_adap); | 1078 | &dev->i2c_adap); |
1333 | if (dev->dvb.frontend) { | 1079 | if (dev->dvb.frontend) { |
1334 | dev->dvb.frontend->ops.tuner_ops.init = ads_duo_tuner_init; | 1080 | if (dvb_attach(tda827x_attach,dev->dvb.frontend, |
1335 | dev->dvb.frontend->ops.tuner_ops.sleep = ads_duo_tuner_sleep; | 1081 | ads_tech_duo_config.tuner_address, |
1336 | dev->dvb.frontend->ops.tuner_ops.set_params = ads_duo_tuner_set_params; | 1082 | &dev->i2c_adap,&ads_duo_cfg) == NULL) { |
1083 | wprintk("no tda827x tuner found at addr: %02x\n", | ||
1084 | ads_tech_duo_config.tuner_address); | ||
1085 | } | ||
1337 | } | 1086 | } |
1338 | break; | 1087 | break; |
1339 | case SAA7134_BOARD_TEVION_DVBT_220RF: | 1088 | case SAA7134_BOARD_TEVION_DVBT_220RF: |
1340 | dev->dvb.frontend = dvb_attach(tda10046_attach, | 1089 | configure_tda827x_fe(dev, &tevion_dvbt220rf_config); |
1341 | &tevion_dvbt220rf_config, | ||
1342 | &dev->i2c_adap); | ||
1343 | if (dev->dvb.frontend) { | ||
1344 | dev->dvb.frontend->ops.tuner_ops.sleep = tevion_dvb220rf_tuner_sleep; | ||
1345 | dev->dvb.frontend->ops.tuner_ops.set_params = tevion_dvb220rf_tuner_set_params; | ||
1346 | } | ||
1347 | break; | ||
1348 | case SAA7134_BOARD_FLYDVBT_HYBRID_CARDBUS: | ||
1349 | dev->dvb.frontend = dvb_attach(tda10046_attach, | ||
1350 | &ads_tech_duo_config, | ||
1351 | &dev->i2c_adap); | ||
1352 | if (dev->dvb.frontend) { | ||
1353 | dev->dvb.frontend->ops.tuner_ops.init = ads_duo_tuner_init; | ||
1354 | dev->dvb.frontend->ops.tuner_ops.sleep = ads_duo_tuner_sleep; | ||
1355 | dev->dvb.frontend->ops.tuner_ops.set_params = ads_duo_tuner_set_params; | ||
1356 | } | ||
1357 | break; | 1090 | break; |
1358 | case SAA7134_BOARD_MEDION_MD8800_QUADRO: | 1091 | case SAA7134_BOARD_MEDION_MD8800_QUADRO: |
1359 | dev->dvb.frontend = tda10046_attach(&md8800_dvbt_config, | 1092 | configure_tda827x_fe(dev, &md8800_dvbt_config); |
1360 | &dev->i2c_adap); | ||
1361 | if (dev->dvb.frontend) { | ||
1362 | dev->dvb.frontend->ops.tuner_ops.init = philips_tiger_tuner_init; | ||
1363 | dev->dvb.frontend->ops.tuner_ops.sleep = md8800_dvbt_analog_mode; | ||
1364 | dev->dvb.frontend->ops.tuner_ops.set_params = md8800_dvbt_pll_set; | ||
1365 | } | ||
1366 | break; | 1093 | break; |
1367 | case SAA7134_BOARD_AVERMEDIA_AVERTVHD_A180: | 1094 | case SAA7134_BOARD_AVERMEDIA_AVERTVHD_A180: |
1368 | dev->dvb.frontend = dvb_attach(nxt200x_attach, &avertvhda180, | 1095 | dev->dvb.frontend = dvb_attach(nxt200x_attach, &avertvhda180, |
@@ -1386,11 +1113,11 @@ static int dvb_init(struct saa7134_dev *dev) | |||
1386 | if (dev->dvb.frontend) { | 1113 | if (dev->dvb.frontend) { |
1387 | if (dvb_attach(tda826x_attach, dev->dvb.frontend, 0x60, | 1114 | if (dvb_attach(tda826x_attach, dev->dvb.frontend, 0x60, |
1388 | &dev->i2c_adap, 0) == NULL) { | 1115 | &dev->i2c_adap, 0) == NULL) { |
1389 | printk("%s: No tda826x found!\n", __FUNCTION__); | 1116 | wprintk("%s: No tda826x found!\n", __FUNCTION__); |
1390 | } | 1117 | } |
1391 | if (dvb_attach(isl6421_attach, dev->dvb.frontend, | 1118 | if (dvb_attach(isl6421_attach, dev->dvb.frontend, |
1392 | &dev->i2c_adap, 0x08, 0, 0) == NULL) { | 1119 | &dev->i2c_adap, 0x08, 0, 0) == NULL) { |
1393 | printk("%s: No ISL6421 found!\n", __FUNCTION__); | 1120 | wprintk("%s: No ISL6421 found!\n", __FUNCTION__); |
1394 | } | 1121 | } |
1395 | } | 1122 | } |
1396 | break; | 1123 | break; |
@@ -1415,41 +1142,45 @@ static int dvb_init(struct saa7134_dev *dev) | |||
1415 | } | 1142 | } |
1416 | break; | 1143 | break; |
1417 | case SAA7134_BOARD_CINERGY_HT_PCMCIA: | 1144 | case SAA7134_BOARD_CINERGY_HT_PCMCIA: |
1418 | dev->dvb.frontend = dvb_attach(tda10046_attach, | 1145 | configure_tda827x_fe(dev, &cinergy_ht_config); |
1419 | &cinergy_ht_config, | ||
1420 | &dev->i2c_adap); | ||
1421 | if (dev->dvb.frontend) { | ||
1422 | dev->dvb.frontend->ops.i2c_gate_ctrl = tda8290_i2c_gate_ctrl; | ||
1423 | dev->dvb.frontend->ops.tuner_ops.init = cinergy_ht_tuner_init; | ||
1424 | dev->dvb.frontend->ops.tuner_ops.sleep = cinergy_ht_tuner_sleep; | ||
1425 | dev->dvb.frontend->ops.tuner_ops.set_params = philips_tiger_tuner_set_params; | ||
1426 | |||
1427 | } | ||
1428 | break; | 1146 | break; |
1429 | case SAA7134_BOARD_CINERGY_HT_PCI: | 1147 | case SAA7134_BOARD_CINERGY_HT_PCI: |
1430 | dev->dvb.frontend = dvb_attach(tda10046_attach, | 1148 | configure_tda827x_fe(dev, &cinergy_ht_pci_config); |
1431 | &cinergy_ht_config, | 1149 | break; |
1432 | &dev->i2c_adap); | 1150 | case SAA7134_BOARD_PHILIPS_TIGER_S: |
1433 | if (dev->dvb.frontend) { | 1151 | configure_tda827x_fe(dev, &philips_tiger_s_config); |
1434 | dev->dvb.frontend->ops.i2c_gate_ctrl = tda8290_i2c_gate_ctrl; | 1152 | break; |
1435 | dev->dvb.frontend->ops.tuner_ops.init = cinergy_ht_tuner_init; | 1153 | case SAA7134_BOARD_ASUS_P7131_4871: |
1436 | dev->dvb.frontend->ops.tuner_ops.sleep = cinergy_ht_tuner_sleep; | 1154 | configure_tda827x_fe(dev, &asus_p7131_4871_config); |
1437 | dev->dvb.frontend->ops.tuner_ops.set_params = md8800_dvbt_pll_set; | 1155 | break; |
1438 | 1156 | case SAA7134_BOARD_ASUSTeK_P7131_HYBRID_LNA: | |
1439 | } | 1157 | configure_tda827x_fe(dev, &asus_p7131_hybrid_lna_config); |
1440 | break; | 1158 | break; |
1441 | default: | 1159 | default: |
1442 | printk("%s: Huh? unknown DVB card?\n",dev->name); | 1160 | wprintk("Huh? unknown DVB card?\n"); |
1443 | break; | 1161 | break; |
1444 | } | 1162 | } |
1445 | 1163 | ||
1446 | if (NULL == dev->dvb.frontend) { | 1164 | if (NULL == dev->dvb.frontend) { |
1447 | printk("%s: frontend initialization failed\n",dev->name); | 1165 | printk(KERN_ERR "%s/dvb: frontend initialization failed\n", dev->name); |
1448 | return -1; | 1166 | return -1; |
1449 | } | 1167 | } |
1450 | 1168 | ||
1451 | /* register everything else */ | 1169 | /* register everything else */ |
1452 | return videobuf_dvb_register(&dev->dvb, THIS_MODULE, dev, &dev->pci->dev); | 1170 | ret = videobuf_dvb_register(&dev->dvb, THIS_MODULE, dev, &dev->pci->dev); |
1171 | |||
1172 | /* this sequence is necessary to make the tda1004x load its firmware | ||
1173 | * and to enter analog mode of hybrid boards | ||
1174 | */ | ||
1175 | if (!ret) { | ||
1176 | if (dev->dvb.frontend->ops.init) | ||
1177 | dev->dvb.frontend->ops.init(dev->dvb.frontend); | ||
1178 | if (dev->dvb.frontend->ops.sleep) | ||
1179 | dev->dvb.frontend->ops.sleep(dev->dvb.frontend); | ||
1180 | if (dev->dvb.frontend->ops.tuner_ops.sleep) | ||
1181 | dev->dvb.frontend->ops.tuner_ops.sleep(dev->dvb.frontend); | ||
1182 | } | ||
1183 | return ret; | ||
1453 | } | 1184 | } |
1454 | 1185 | ||
1455 | static int dvb_fini(struct saa7134_dev *dev) | 1186 | static int dvb_fini(struct saa7134_dev *dev) |
diff --git a/drivers/media/video/saa7134/saa7134-i2c.c b/drivers/media/video/saa7134/saa7134-i2c.c index cce8da6a4f94..1cb8c709ca90 100644 --- a/drivers/media/video/saa7134/saa7134-i2c.c +++ b/drivers/media/video/saa7134/saa7134-i2c.c | |||
@@ -370,6 +370,8 @@ static int attach_inform(struct i2c_client *client) | |||
370 | 370 | ||
371 | tun_setup.type = tuner; | 371 | tun_setup.type = tuner; |
372 | tun_setup.addr = saa7134_boards[dev->board].tuner_addr; | 372 | tun_setup.addr = saa7134_boards[dev->board].tuner_addr; |
373 | tun_setup.config = saa7134_boards[dev->board].tuner_config; | ||
374 | tun_setup.tuner_callback = saa7134_tuner_callback; | ||
373 | 375 | ||
374 | if ((tun_setup.addr == ADDR_UNSET)||(tun_setup.addr == client->addr)) { | 376 | if ((tun_setup.addr == ADDR_UNSET)||(tun_setup.addr == client->addr)) { |
375 | 377 | ||
@@ -445,7 +447,7 @@ static void do_i2c_scan(char *name, struct i2c_client *c) | |||
445 | unsigned char buf; | 447 | unsigned char buf; |
446 | int i,rc; | 448 | int i,rc; |
447 | 449 | ||
448 | for (i = 0; i < 128; i++) { | 450 | for (i = 0; i < ARRAY_SIZE(i2c_devs); i++) { |
449 | c->addr = i; | 451 | c->addr = i; |
450 | rc = i2c_master_recv(c,&buf,0); | 452 | rc = i2c_master_recv(c,&buf,0); |
451 | if (rc < 0) | 453 | if (rc < 0) |
diff --git a/drivers/media/video/saa7134/saa7134-input.c b/drivers/media/video/saa7134/saa7134-input.c index 46c583f1e788..c0de37e3f5c6 100644 --- a/drivers/media/video/saa7134/saa7134-input.c +++ b/drivers/media/video/saa7134/saa7134-input.c | |||
@@ -321,6 +321,7 @@ int saa7134_input_init1(struct saa7134_dev *dev) | |||
321 | mask_keydown = 0x0040000; | 321 | mask_keydown = 0x0040000; |
322 | break; | 322 | break; |
323 | case SAA7134_BOARD_ASUSTeK_P7131_DUAL: | 323 | case SAA7134_BOARD_ASUSTeK_P7131_DUAL: |
324 | case SAA7134_BOARD_ASUSTeK_P7131_HYBRID_LNA: | ||
324 | ir_codes = ir_codes_asus_pc39; | 325 | ir_codes = ir_codes_asus_pc39; |
325 | mask_keydown = 0x0040000; | 326 | mask_keydown = 0x0040000; |
326 | rc5_gpio = 1; | 327 | rc5_gpio = 1; |
diff --git a/drivers/media/video/saa7134/saa7134-video.c b/drivers/media/video/saa7134/saa7134-video.c index f2cb63053041..9985ded20950 100644 --- a/drivers/media/video/saa7134/saa7134-video.c +++ b/drivers/media/video/saa7134/saa7134-video.c | |||
@@ -26,6 +26,7 @@ | |||
26 | #include <linux/moduleparam.h> | 26 | #include <linux/moduleparam.h> |
27 | #include <linux/kernel.h> | 27 | #include <linux/kernel.h> |
28 | #include <linux/slab.h> | 28 | #include <linux/slab.h> |
29 | #include <linux/sort.h> | ||
29 | 30 | ||
30 | #include "saa7134-reg.h" | 31 | #include "saa7134-reg.h" |
31 | #include "saa7134.h" | 32 | #include "saa7134.h" |
@@ -516,14 +517,12 @@ static int res_get(struct saa7134_dev *dev, struct saa7134_fh *fh, unsigned int | |||
516 | return 1; | 517 | return 1; |
517 | } | 518 | } |
518 | 519 | ||
519 | static | 520 | static int res_check(struct saa7134_fh *fh, unsigned int bit) |
520 | int res_check(struct saa7134_fh *fh, unsigned int bit) | ||
521 | { | 521 | { |
522 | return (fh->resources & bit); | 522 | return (fh->resources & bit); |
523 | } | 523 | } |
524 | 524 | ||
525 | static | 525 | static int res_locked(struct saa7134_dev *dev, unsigned int bit) |
526 | int res_locked(struct saa7134_dev *dev, unsigned int bit) | ||
527 | { | 526 | { |
528 | return (dev->resources & bit); | 527 | return (dev->resources & bit); |
529 | } | 528 | } |
@@ -603,7 +602,14 @@ static void set_tvnorm(struct saa7134_dev *dev, struct saa7134_tvnorm *norm) | |||
603 | saa_writeb(SAA7134_RAW_DATA_GAIN, 0x40); | 602 | saa_writeb(SAA7134_RAW_DATA_GAIN, 0x40); |
604 | saa_writeb(SAA7134_RAW_DATA_OFFSET, 0x80); | 603 | saa_writeb(SAA7134_RAW_DATA_OFFSET, 0x80); |
605 | 604 | ||
606 | saa7134_i2c_call_clients(dev,VIDIOC_S_STD,&norm->id); | 605 | /* only tell the tuner if this is a tv input */ |
606 | if (card_in(dev,dev->ctl_input).tv) { | ||
607 | if ((card(dev).tuner_type == TUNER_PHILIPS_TDA8290) | ||
608 | && ((card(dev).tuner_config == 1) | ||
609 | || (card(dev).tuner_config == 2))) | ||
610 | saa7134_set_gpio(dev, 22, 5); | ||
611 | saa7134_i2c_call_clients(dev,VIDIOC_S_STD,&norm->id); | ||
612 | } | ||
607 | } | 613 | } |
608 | 614 | ||
609 | static void video_mux(struct saa7134_dev *dev, int input) | 615 | static void video_mux(struct saa7134_dev *dev, int input) |
@@ -732,25 +738,6 @@ struct cliplist { | |||
732 | __u8 disable; | 738 | __u8 disable; |
733 | }; | 739 | }; |
734 | 740 | ||
735 | static void sort_cliplist(struct cliplist *cl, int entries) | ||
736 | { | ||
737 | struct cliplist swap; | ||
738 | int i,j,n; | ||
739 | |||
740 | for (i = entries-2; i >= 0; i--) { | ||
741 | for (n = 0, j = 0; j <= i; j++) { | ||
742 | if (cl[j].position > cl[j+1].position) { | ||
743 | swap = cl[j]; | ||
744 | cl[j] = cl[j+1]; | ||
745 | cl[j+1] = swap; | ||
746 | n++; | ||
747 | } | ||
748 | } | ||
749 | if (0 == n) | ||
750 | break; | ||
751 | } | ||
752 | } | ||
753 | |||
754 | static void set_cliplist(struct saa7134_dev *dev, int reg, | 741 | static void set_cliplist(struct saa7134_dev *dev, int reg, |
755 | struct cliplist *cl, int entries, char *name) | 742 | struct cliplist *cl, int entries, char *name) |
756 | { | 743 | { |
@@ -784,15 +771,27 @@ static int clip_range(int val) | |||
784 | return val; | 771 | return val; |
785 | } | 772 | } |
786 | 773 | ||
774 | /* Sort into smallest position first order */ | ||
775 | static int cliplist_cmp(const void *a, const void *b) | ||
776 | { | ||
777 | const struct cliplist *cla = a; | ||
778 | const struct cliplist *clb = b; | ||
779 | if (cla->position < clb->position) | ||
780 | return -1; | ||
781 | if (cla->position > clb->position) | ||
782 | return 1; | ||
783 | return 0; | ||
784 | } | ||
785 | |||
787 | static int setup_clipping(struct saa7134_dev *dev, struct v4l2_clip *clips, | 786 | static int setup_clipping(struct saa7134_dev *dev, struct v4l2_clip *clips, |
788 | int nclips, int interlace) | 787 | int nclips, int interlace) |
789 | { | 788 | { |
790 | struct cliplist col[16], row[16]; | 789 | struct cliplist col[16], row[16]; |
791 | int cols, rows, i; | 790 | int cols = 0, rows = 0, i; |
792 | int div = interlace ? 2 : 1; | 791 | int div = interlace ? 2 : 1; |
793 | 792 | ||
794 | memset(col,0,sizeof(col)); cols = 0; | 793 | memset(col, 0, sizeof(col)); |
795 | memset(row,0,sizeof(row)); rows = 0; | 794 | memset(row, 0, sizeof(row)); |
796 | for (i = 0; i < nclips && i < 8; i++) { | 795 | for (i = 0; i < nclips && i < 8; i++) { |
797 | col[cols].position = clip_range(clips[i].c.left); | 796 | col[cols].position = clip_range(clips[i].c.left); |
798 | col[cols].enable = (1 << i); | 797 | col[cols].enable = (1 << i); |
@@ -808,8 +807,8 @@ static int setup_clipping(struct saa7134_dev *dev, struct v4l2_clip *clips, | |||
808 | row[rows].disable = (1 << i); | 807 | row[rows].disable = (1 << i); |
809 | rows++; | 808 | rows++; |
810 | } | 809 | } |
811 | sort_cliplist(col,cols); | 810 | sort(col, cols, sizeof col[0], cliplist_cmp, NULL); |
812 | sort_cliplist(row,rows); | 811 | sort(row, rows, sizeof row[0], cliplist_cmp, NULL); |
813 | set_cliplist(dev,0x380,col,cols,"cols"); | 812 | set_cliplist(dev,0x380,col,cols,"cols"); |
814 | set_cliplist(dev,0x384,row,rows,"rows"); | 813 | set_cliplist(dev,0x384,row,rows,"rows"); |
815 | return 0; | 814 | return 0; |
@@ -1261,19 +1260,14 @@ static struct videobuf_queue* saa7134_queue(struct saa7134_fh *fh) | |||
1261 | 1260 | ||
1262 | static int saa7134_resource(struct saa7134_fh *fh) | 1261 | static int saa7134_resource(struct saa7134_fh *fh) |
1263 | { | 1262 | { |
1264 | int res = 0; | 1263 | if (fh->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) |
1264 | return RESOURCE_VIDEO; | ||
1265 | 1265 | ||
1266 | switch (fh->type) { | 1266 | if (fh->type == V4L2_BUF_TYPE_VBI_CAPTURE) |
1267 | case V4L2_BUF_TYPE_VIDEO_CAPTURE: | 1267 | return RESOURCE_VBI; |
1268 | res = RESOURCE_VIDEO; | 1268 | |
1269 | break; | 1269 | BUG(); |
1270 | case V4L2_BUF_TYPE_VBI_CAPTURE: | 1270 | return 0; |
1271 | res = RESOURCE_VBI; | ||
1272 | break; | ||
1273 | default: | ||
1274 | BUG(); | ||
1275 | } | ||
1276 | return res; | ||
1277 | } | 1271 | } |
1278 | 1272 | ||
1279 | static int video_open(struct inode *inode, struct file *file) | 1273 | static int video_open(struct inode *inode, struct file *file) |
@@ -1461,8 +1455,7 @@ static int video_release(struct inode *inode, struct file *file) | |||
1461 | return 0; | 1455 | return 0; |
1462 | } | 1456 | } |
1463 | 1457 | ||
1464 | static int | 1458 | static int video_mmap(struct file *file, struct vm_area_struct * vma) |
1465 | video_mmap(struct file *file, struct vm_area_struct * vma) | ||
1466 | { | 1459 | { |
1467 | struct saa7134_fh *fh = file->private_data; | 1460 | struct saa7134_fh *fh = file->private_data; |
1468 | 1461 | ||
@@ -2461,12 +2454,6 @@ int saa7134_video_init2(struct saa7134_dev *dev) | |||
2461 | return 0; | 2454 | return 0; |
2462 | } | 2455 | } |
2463 | 2456 | ||
2464 | int saa7134_video_fini(struct saa7134_dev *dev) | ||
2465 | { | ||
2466 | /* nothing */ | ||
2467 | return 0; | ||
2468 | } | ||
2469 | |||
2470 | void saa7134_irq_video_intl(struct saa7134_dev *dev) | 2457 | void saa7134_irq_video_intl(struct saa7134_dev *dev) |
2471 | { | 2458 | { |
2472 | static const char *st[] = { | 2459 | static const char *st[] = { |
diff --git a/drivers/media/video/saa7134/saa7134.h b/drivers/media/video/saa7134/saa7134.h index b3e3957c89b5..62224cc958f1 100644 --- a/drivers/media/video/saa7134/saa7134.h +++ b/drivers/media/video/saa7134/saa7134.h | |||
@@ -231,6 +231,10 @@ struct saa7134_format { | |||
231 | #define SAA7134_BOARD_ENCORE_ENLTV 106 | 231 | #define SAA7134_BOARD_ENCORE_ENLTV 106 |
232 | #define SAA7134_BOARD_ENCORE_ENLTV_FM 107 | 232 | #define SAA7134_BOARD_ENCORE_ENLTV_FM 107 |
233 | #define SAA7134_BOARD_CINERGY_HT_PCI 108 | 233 | #define SAA7134_BOARD_CINERGY_HT_PCI 108 |
234 | #define SAA7134_BOARD_PHILIPS_TIGER_S 109 | ||
235 | #define SAA7134_BOARD_AVERMEDIA_M102 110 | ||
236 | #define SAA7134_BOARD_ASUS_P7131_4871 111 | ||
237 | #define SAA7134_BOARD_ASUSTeK_P7131_HYBRID_LNA 112 | ||
234 | 238 | ||
235 | #define SAA7134_MAXBOARDS 8 | 239 | #define SAA7134_MAXBOARDS 8 |
236 | #define SAA7134_INPUT_MAX 8 | 240 | #define SAA7134_INPUT_MAX 8 |
@@ -280,6 +284,7 @@ struct saa7134_board { | |||
280 | unsigned char radio_addr; | 284 | unsigned char radio_addr; |
281 | 285 | ||
282 | unsigned int tda9887_conf; | 286 | unsigned int tda9887_conf; |
287 | unsigned int tuner_config; | ||
283 | 288 | ||
284 | /* peripheral I/O */ | 289 | /* peripheral I/O */ |
285 | enum saa7134_video_out video_out; | 290 | enum saa7134_video_out video_out; |
@@ -435,6 +440,8 @@ struct saa7134_dev { | |||
435 | #ifdef VIDIOC_G_PRIORITY | 440 | #ifdef VIDIOC_G_PRIORITY |
436 | struct v4l2_prio_state prio; | 441 | struct v4l2_prio_state prio; |
437 | #endif | 442 | #endif |
443 | /* workstruct for loading modules */ | ||
444 | struct work_struct request_module_wk; | ||
438 | 445 | ||
439 | /* insmod option/autodetected */ | 446 | /* insmod option/autodetected */ |
440 | int autodetected; | 447 | int autodetected; |
@@ -562,6 +569,8 @@ extern struct list_head saa7134_devlist; | |||
562 | extern int saa7134_no_overlay; | 569 | extern int saa7134_no_overlay; |
563 | 570 | ||
564 | void saa7134_track_gpio(struct saa7134_dev *dev, char *msg); | 571 | void saa7134_track_gpio(struct saa7134_dev *dev, char *msg); |
572 | void saa7134_set_gpio(struct saa7134_dev *dev, int bit_no, int value); | ||
573 | int saa7134_tuner_callback(void *ptr, int command, int arg); | ||
565 | 574 | ||
566 | #define SAA7134_PGTABLE_SIZE 4096 | 575 | #define SAA7134_PGTABLE_SIZE 4096 |
567 | 576 | ||
@@ -620,7 +629,6 @@ int saa7134_common_ioctl(struct saa7134_dev *dev, | |||
620 | 629 | ||
621 | int saa7134_video_init1(struct saa7134_dev *dev); | 630 | int saa7134_video_init1(struct saa7134_dev *dev); |
622 | int saa7134_video_init2(struct saa7134_dev *dev); | 631 | int saa7134_video_init2(struct saa7134_dev *dev); |
623 | int saa7134_video_fini(struct saa7134_dev *dev); | ||
624 | void saa7134_irq_video_intl(struct saa7134_dev *dev); | 632 | void saa7134_irq_video_intl(struct saa7134_dev *dev); |
625 | void saa7134_irq_video_done(struct saa7134_dev *dev, unsigned long status); | 633 | void saa7134_irq_video_done(struct saa7134_dev *dev, unsigned long status); |
626 | 634 | ||
diff --git a/drivers/media/video/se401.c b/drivers/media/video/se401.c index 038448f5a978..93fb04ed99a0 100644 --- a/drivers/media/video/se401.c +++ b/drivers/media/video/se401.c | |||
@@ -450,6 +450,13 @@ static int se401_start_stream(struct usb_se401 *se401) | |||
450 | } | 450 | } |
451 | for (i=0; i<SE401_NUMSBUF; i++) { | 451 | for (i=0; i<SE401_NUMSBUF; i++) { |
452 | se401->sbuf[i].data=kmalloc(SE401_PACKETSIZE, GFP_KERNEL); | 452 | se401->sbuf[i].data=kmalloc(SE401_PACKETSIZE, GFP_KERNEL); |
453 | if (!se401->sbuf[i].data) { | ||
454 | for(i = i - 1; i >= 0; i--) { | ||
455 | kfree(se401->sbuf[i].data); | ||
456 | se401->sbuf[i].data = NULL; | ||
457 | } | ||
458 | return -ENOMEM; | ||
459 | } | ||
453 | } | 460 | } |
454 | 461 | ||
455 | se401->bayeroffset=0; | 462 | se401->bayeroffset=0; |
@@ -458,13 +465,26 @@ static int se401_start_stream(struct usb_se401 *se401) | |||
458 | se401->scratch_overflow=0; | 465 | se401->scratch_overflow=0; |
459 | for (i=0; i<SE401_NUMSCRATCH; i++) { | 466 | for (i=0; i<SE401_NUMSCRATCH; i++) { |
460 | se401->scratch[i].data=kmalloc(SE401_PACKETSIZE, GFP_KERNEL); | 467 | se401->scratch[i].data=kmalloc(SE401_PACKETSIZE, GFP_KERNEL); |
468 | if (!se401->scratch[i].data) { | ||
469 | for(i = i - 1; i >= 0; i--) { | ||
470 | kfree(se401->scratch[i].data); | ||
471 | se401->scratch[i].data = NULL; | ||
472 | } | ||
473 | goto nomem_sbuf; | ||
474 | } | ||
461 | se401->scratch[i].state=BUFFER_UNUSED; | 475 | se401->scratch[i].state=BUFFER_UNUSED; |
462 | } | 476 | } |
463 | 477 | ||
464 | for (i=0; i<SE401_NUMSBUF; i++) { | 478 | for (i=0; i<SE401_NUMSBUF; i++) { |
465 | urb=usb_alloc_urb(0, GFP_KERNEL); | 479 | urb=usb_alloc_urb(0, GFP_KERNEL); |
466 | if(!urb) | 480 | if(!urb) { |
467 | return -ENOMEM; | 481 | for(i = i - 1; i >= 0; i--) { |
482 | usb_kill_urb(se401->urb[i]); | ||
483 | usb_free_urb(se401->urb[i]); | ||
484 | se401->urb[i] = NULL; | ||
485 | } | ||
486 | goto nomem_scratch; | ||
487 | } | ||
468 | 488 | ||
469 | usb_fill_bulk_urb(urb, se401->dev, | 489 | usb_fill_bulk_urb(urb, se401->dev, |
470 | usb_rcvbulkpipe(se401->dev, SE401_VIDEO_ENDPOINT), | 490 | usb_rcvbulkpipe(se401->dev, SE401_VIDEO_ENDPOINT), |
@@ -482,6 +502,18 @@ static int se401_start_stream(struct usb_se401 *se401) | |||
482 | se401->framecount=0; | 502 | se401->framecount=0; |
483 | 503 | ||
484 | return 0; | 504 | return 0; |
505 | |||
506 | nomem_scratch: | ||
507 | for (i=0; i<SE401_NUMSCRATCH; i++) { | ||
508 | kfree(se401->scratch[i].data); | ||
509 | se401->scratch[i].data = NULL; | ||
510 | } | ||
511 | nomem_sbuf: | ||
512 | for (i=0; i<SE401_NUMSBUF; i++) { | ||
513 | kfree(se401->sbuf[i].data); | ||
514 | se401->sbuf[i].data = NULL; | ||
515 | } | ||
516 | return -ENOMEM; | ||
485 | } | 517 | } |
486 | 518 | ||
487 | static int se401_stop_stream(struct usb_se401 *se401) | 519 | static int se401_stop_stream(struct usb_se401 *se401) |
diff --git a/drivers/media/video/sn9c102/Kconfig b/drivers/media/video/sn9c102/Kconfig index 1a7ccb666ab0..19204f5686e1 100644 --- a/drivers/media/video/sn9c102/Kconfig +++ b/drivers/media/video/sn9c102/Kconfig | |||
@@ -1,6 +1,6 @@ | |||
1 | config USB_SN9C102 | 1 | config USB_SN9C102 |
2 | tristate "USB SN9C1xx PC Camera Controller support" | 2 | tristate "USB SN9C1xx PC Camera Controller support" |
3 | depends on USB && VIDEO_V4L1 | 3 | depends on USB && VIDEO_V4L2 |
4 | ---help--- | 4 | ---help--- |
5 | Say Y here if you want support for cameras based on SONiX SN9C101, | 5 | Say Y here if you want support for cameras based on SONiX SN9C101, |
6 | SN9C102, SN9C103, SN9C105 and SN9C120 PC Camera Controllers. | 6 | SN9C102, SN9C103, SN9C105 and SN9C120 PC Camera Controllers. |
diff --git a/drivers/media/video/sn9c102/Makefile b/drivers/media/video/sn9c102/Makefile index 30e3dfe537fe..a56d16f69c71 100644 --- a/drivers/media/video/sn9c102/Makefile +++ b/drivers/media/video/sn9c102/Makefile | |||
@@ -1,7 +1,14 @@ | |||
1 | sn9c102-objs := sn9c102_core.o sn9c102_hv7131d.o sn9c102_mi0343.o \ | 1 | sn9c102-objs := sn9c102_core.o \ |
2 | sn9c102_ov7630.o sn9c102_ov7660.o sn9c102_pas106b.o \ | 2 | sn9c102_hv7131d.o \ |
3 | sn9c102_pas202bcb.o sn9c102_tas5110c1b.o \ | 3 | sn9c102_hv7131r.o \ |
4 | sn9c102_tas5130d1b.o | 4 | sn9c102_mi0343.o \ |
5 | sn9c102_mi0360.o \ | ||
6 | sn9c102_ov7630.o \ | ||
7 | sn9c102_ov7660.o \ | ||
8 | sn9c102_pas106b.o \ | ||
9 | sn9c102_pas202bcb.o \ | ||
10 | sn9c102_tas5110c1b.o \ | ||
11 | sn9c102_tas5110d.o \ | ||
12 | sn9c102_tas5130d1b.o | ||
5 | 13 | ||
6 | obj-$(CONFIG_USB_SN9C102) += sn9c102.o | 14 | obj-$(CONFIG_USB_SN9C102) += sn9c102.o |
7 | |||
diff --git a/drivers/media/video/sn9c102/sn9c102.h b/drivers/media/video/sn9c102/sn9c102.h index 5428f34e7c5b..680e74634527 100644 --- a/drivers/media/video/sn9c102/sn9c102.h +++ b/drivers/media/video/sn9c102/sn9c102.h | |||
@@ -78,8 +78,13 @@ enum sn9c102_stream_state { | |||
78 | 78 | ||
79 | typedef char sn9c102_sof_header_t[62]; | 79 | typedef char sn9c102_sof_header_t[62]; |
80 | 80 | ||
81 | struct sn9c102_sof_t { | ||
82 | sn9c102_sof_header_t header; | ||
83 | u16 bytesread; | ||
84 | }; | ||
85 | |||
81 | struct sn9c102_sysfs_attr { | 86 | struct sn9c102_sysfs_attr { |
82 | u8 reg, i2c_reg; | 87 | u16 reg, i2c_reg; |
83 | sn9c102_sof_header_t frame_header; | 88 | sn9c102_sof_header_t frame_header; |
84 | }; | 89 | }; |
85 | 90 | ||
@@ -112,7 +117,7 @@ struct sn9c102_device { | |||
112 | struct v4l2_jpegcompression compression; | 117 | struct v4l2_jpegcompression compression; |
113 | 118 | ||
114 | struct sn9c102_sysfs_attr sysfs; | 119 | struct sn9c102_sysfs_attr sysfs; |
115 | sn9c102_sof_header_t sof_header; | 120 | struct sn9c102_sof_t sof; |
116 | u16 reg[384]; | 121 | u16 reg[384]; |
117 | 122 | ||
118 | struct sn9c102_module_param module_param; | 123 | struct sn9c102_module_param module_param; |
@@ -182,8 +187,8 @@ do { \ | |||
182 | if ((level) == 1 || (level) == 2) \ | 187 | if ((level) == 1 || (level) == 2) \ |
183 | pr_info("sn9c102: " fmt "\n", ## args); \ | 188 | pr_info("sn9c102: " fmt "\n", ## args); \ |
184 | else if ((level) == 3) \ | 189 | else if ((level) == 3) \ |
185 | pr_debug("sn9c102: [%s:%d] " fmt "\n", __FUNCTION__, \ | 190 | pr_debug("sn9c102: [%s:%d] " fmt "\n", \ |
186 | __LINE__ , ## args); \ | 191 | __FUNCTION__, __LINE__ , ## args); \ |
187 | } \ | 192 | } \ |
188 | } while (0) | 193 | } while (0) |
189 | #else | 194 | #else |
@@ -194,8 +199,8 @@ do { \ | |||
194 | 199 | ||
195 | #undef PDBG | 200 | #undef PDBG |
196 | #define PDBG(fmt, args...) \ | 201 | #define PDBG(fmt, args...) \ |
197 | dev_info(&cam->usbdev->dev, "[%s:%d] " fmt "\n", \ | 202 | dev_info(&cam->usbdev->dev, "[%s:%s:%d] " fmt "\n", __FILE__, __FUNCTION__, \ |
198 | __FUNCTION__, __LINE__ , ## args) | 203 | __LINE__ , ## args) |
199 | 204 | ||
200 | #undef PDBGG | 205 | #undef PDBGG |
201 | #define PDBGG(fmt, args...) do {;} while(0) /* placeholder */ | 206 | #define PDBGG(fmt, args...) do {;} while(0) /* placeholder */ |
diff --git a/drivers/media/video/sn9c102/sn9c102_core.c b/drivers/media/video/sn9c102/sn9c102_core.c index d0e2b40a7725..89f83354de3b 100644 --- a/drivers/media/video/sn9c102/sn9c102_core.c +++ b/drivers/media/video/sn9c102/sn9c102_core.c | |||
@@ -44,11 +44,12 @@ | |||
44 | /*****************************************************************************/ | 44 | /*****************************************************************************/ |
45 | 45 | ||
46 | #define SN9C102_MODULE_NAME "V4L2 driver for SN9C1xx PC Camera Controllers" | 46 | #define SN9C102_MODULE_NAME "V4L2 driver for SN9C1xx PC Camera Controllers" |
47 | #define SN9C102_MODULE_AUTHOR "(C) 2004-2006 Luca Risolia" | 47 | #define SN9C102_MODULE_ALIAS "sn9c1xx" |
48 | #define SN9C102_MODULE_AUTHOR "(C) 2004-2007 Luca Risolia" | ||
48 | #define SN9C102_AUTHOR_EMAIL "<luca.risolia@studio.unibo.it>" | 49 | #define SN9C102_AUTHOR_EMAIL "<luca.risolia@studio.unibo.it>" |
49 | #define SN9C102_MODULE_LICENSE "GPL" | 50 | #define SN9C102_MODULE_LICENSE "GPL" |
50 | #define SN9C102_MODULE_VERSION "1:1.34" | 51 | #define SN9C102_MODULE_VERSION "1:1.39" |
51 | #define SN9C102_MODULE_VERSION_CODE KERNEL_VERSION(1, 1, 34) | 52 | #define SN9C102_MODULE_VERSION_CODE KERNEL_VERSION(1, 1, 39) |
52 | 53 | ||
53 | /*****************************************************************************/ | 54 | /*****************************************************************************/ |
54 | 55 | ||
@@ -56,6 +57,7 @@ MODULE_DEVICE_TABLE(usb, sn9c102_id_table); | |||
56 | 57 | ||
57 | MODULE_AUTHOR(SN9C102_MODULE_AUTHOR " " SN9C102_AUTHOR_EMAIL); | 58 | MODULE_AUTHOR(SN9C102_MODULE_AUTHOR " " SN9C102_AUTHOR_EMAIL); |
58 | MODULE_DESCRIPTION(SN9C102_MODULE_NAME); | 59 | MODULE_DESCRIPTION(SN9C102_MODULE_NAME); |
60 | MODULE_ALIAS(SN9C102_MODULE_ALIAS); | ||
59 | MODULE_VERSION(SN9C102_MODULE_VERSION); | 61 | MODULE_VERSION(SN9C102_MODULE_VERSION); |
60 | MODULE_LICENSE(SN9C102_MODULE_LICENSE); | 62 | MODULE_LICENSE(SN9C102_MODULE_LICENSE); |
61 | 63 | ||
@@ -106,8 +108,7 @@ MODULE_PARM_DESC(debug, | |||
106 | "\n1 = critical errors" | 108 | "\n1 = critical errors" |
107 | "\n2 = significant informations" | 109 | "\n2 = significant informations" |
108 | "\n3 = more verbose messages" | 110 | "\n3 = more verbose messages" |
109 | "\nLevel 3 is useful for testing only, when only " | 111 | "\nLevel 3 is useful for testing only." |
110 | "one device is used." | ||
111 | "\nDefault value is "__MODULE_STRING(SN9C102_DEBUG_LEVEL)"." | 112 | "\nDefault value is "__MODULE_STRING(SN9C102_DEBUG_LEVEL)"." |
112 | "\n"); | 113 | "\n"); |
113 | #endif | 114 | #endif |
@@ -121,8 +122,8 @@ sn9c102_request_buffers(struct sn9c102_device* cam, u32 count, | |||
121 | struct v4l2_pix_format* p = &(cam->sensor.pix_format); | 122 | struct v4l2_pix_format* p = &(cam->sensor.pix_format); |
122 | struct v4l2_rect* r = &(cam->sensor.cropcap.bounds); | 123 | struct v4l2_rect* r = &(cam->sensor.cropcap.bounds); |
123 | size_t imagesize = cam->module_param.force_munmap || io == IO_READ ? | 124 | size_t imagesize = cam->module_param.force_munmap || io == IO_READ ? |
124 | (p->width * p->height * p->priv) / 8 : | 125 | (p->width * p->height * p->priv) / 8 : |
125 | (r->width * r->height * p->priv) / 8; | 126 | (r->width * r->height * p->priv) / 8; |
126 | void* buff = NULL; | 127 | void* buff = NULL; |
127 | u32 i; | 128 | u32 i; |
128 | 129 | ||
@@ -208,27 +209,40 @@ static void sn9c102_queue_unusedframes(struct sn9c102_device* cam) | |||
208 | } | 209 | } |
209 | 210 | ||
210 | /*****************************************************************************/ | 211 | /*****************************************************************************/ |
211 | 212 | /* | |
212 | int sn9c102_write_regs(struct sn9c102_device* cam, u8* buff, u16 index) | 213 | * Write a sequence of count value/register pairs. Returns -1 after the |
214 | * first failed write, or 0 for no errors. | ||
215 | */ | ||
216 | int sn9c102_write_regs(struct sn9c102_device* cam, const u8 valreg[][2], | ||
217 | int count) | ||
213 | { | 218 | { |
214 | struct usb_device* udev = cam->usbdev; | 219 | struct usb_device* udev = cam->usbdev; |
220 | u8* value = cam->control_buffer; /* Needed for DMA'able memory */ | ||
215 | int i, res; | 221 | int i, res; |
216 | 222 | ||
217 | if (index + sizeof(buff) >= ARRAY_SIZE(cam->reg)) | 223 | for (i = 0; i < count; i++) { |
218 | return -1; | 224 | u8 index = valreg[i][1]; |
225 | |||
226 | /* | ||
227 | * index is a u8, so it must be <256 and can't be out of range. | ||
228 | * If we put in a check anyway, gcc annoys us with a warning | ||
229 | * that our check is useless. People get all uppity when they | ||
230 | * see warnings in the kernel compile. | ||
231 | */ | ||
232 | |||
233 | *value = valreg[i][0]; | ||
234 | res = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), | ||
235 | 0x08, 0x41, index, 0, | ||
236 | value, 1, SN9C102_CTRL_TIMEOUT); | ||
237 | if (res < 0) { | ||
238 | DBG(3, "Failed to write a register (value 0x%02X, " | ||
239 | "index 0x%02X, error %d)", *value, index, res); | ||
240 | return -1; | ||
241 | } | ||
219 | 242 | ||
220 | res = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), 0x08, 0x41, | 243 | cam->reg[index] = *value; |
221 | index, 0, buff, sizeof(buff), | ||
222 | SN9C102_CTRL_TIMEOUT*sizeof(buff)); | ||
223 | if (res < 0) { | ||
224 | DBG(3, "Failed to write registers (index 0x%02X, error %d)", | ||
225 | index, res); | ||
226 | return -1; | ||
227 | } | 244 | } |
228 | 245 | ||
229 | for (i = 0; i < sizeof(buff); i++) | ||
230 | cam->reg[index+i] = buff[i]; | ||
231 | |||
232 | return 0; | 246 | return 0; |
233 | } | 247 | } |
234 | 248 | ||
@@ -485,18 +499,43 @@ static size_t sn9c102_sof_length(struct sn9c102_device* cam) | |||
485 | static void* | 499 | static void* |
486 | sn9c102_find_sof_header(struct sn9c102_device* cam, void* mem, size_t len) | 500 | sn9c102_find_sof_header(struct sn9c102_device* cam, void* mem, size_t len) |
487 | { | 501 | { |
488 | char sof_header[6] = {0xff, 0xff, 0x00, 0xc4, 0xc4, 0x96}; | 502 | static const char marker[6] = {0xff, 0xff, 0x00, 0xc4, 0xc4, 0x96}; |
489 | size_t soflen = 0, i; | 503 | const char *m = mem; |
504 | size_t soflen = 0, i, j; | ||
490 | 505 | ||
491 | soflen = sn9c102_sof_length(cam); | 506 | soflen = sn9c102_sof_length(cam); |
492 | 507 | ||
493 | for (i = 0; (len >= soflen) && (i <= len - soflen); i++) | 508 | for (i = 0; i < len; i++) { |
494 | if (!memcmp(mem + i, sof_header, sizeof(sof_header))) { | 509 | size_t b; |
495 | memcpy(cam->sof_header, mem + i, | 510 | |
496 | sizeof(sn9c102_sof_header_t)); | 511 | /* Read the variable part of the header */ |
497 | /* Skip the header */ | 512 | if (unlikely(cam->sof.bytesread >= sizeof(marker))) { |
498 | return mem + i + soflen; | 513 | cam->sof.header[cam->sof.bytesread] = *(m+i); |
514 | if (++cam->sof.bytesread == soflen) { | ||
515 | cam->sof.bytesread = 0; | ||
516 | return mem + i; | ||
517 | } | ||
518 | continue; | ||
519 | } | ||
520 | |||
521 | /* Search for the SOF marker (fixed part) in the header */ | ||
522 | for (j = 0, b=cam->sof.bytesread; j+b < sizeof(marker); j++) { | ||
523 | if (unlikely(i+j) == len) | ||
524 | return NULL; | ||
525 | if (*(m+i+j) == marker[cam->sof.bytesread]) { | ||
526 | cam->sof.header[cam->sof.bytesread] = *(m+i+j); | ||
527 | if (++cam->sof.bytesread == sizeof(marker)) { | ||
528 | PDBGG("Bytes to analyze: %zd. SOF " | ||
529 | "starts at byte #%zd", len, i); | ||
530 | i += j+1; | ||
531 | break; | ||
532 | } | ||
533 | } else { | ||
534 | cam->sof.bytesread = 0; | ||
535 | break; | ||
499 | } | 536 | } |
537 | } | ||
538 | } | ||
500 | 539 | ||
501 | return NULL; | 540 | return NULL; |
502 | } | 541 | } |
@@ -505,7 +544,7 @@ sn9c102_find_sof_header(struct sn9c102_device* cam, void* mem, size_t len) | |||
505 | static void* | 544 | static void* |
506 | sn9c102_find_eof_header(struct sn9c102_device* cam, void* mem, size_t len) | 545 | sn9c102_find_eof_header(struct sn9c102_device* cam, void* mem, size_t len) |
507 | { | 546 | { |
508 | char eof_header[4][4] = { | 547 | static const u8 eof_header[4][4] = { |
509 | {0x00, 0x00, 0x00, 0x00}, | 548 | {0x00, 0x00, 0x00, 0x00}, |
510 | {0x40, 0x00, 0x00, 0x00}, | 549 | {0x40, 0x00, 0x00, 0x00}, |
511 | {0x80, 0x00, 0x00, 0x00}, | 550 | {0x80, 0x00, 0x00, 0x00}, |
@@ -513,10 +552,16 @@ sn9c102_find_eof_header(struct sn9c102_device* cam, void* mem, size_t len) | |||
513 | }; | 552 | }; |
514 | size_t i, j; | 553 | size_t i, j; |
515 | 554 | ||
555 | /* The EOF header does not exist in compressed data */ | ||
516 | if (cam->sensor.pix_format.pixelformat == V4L2_PIX_FMT_SN9C10X || | 556 | if (cam->sensor.pix_format.pixelformat == V4L2_PIX_FMT_SN9C10X || |
517 | cam->sensor.pix_format.pixelformat == V4L2_PIX_FMT_JPEG) | 557 | cam->sensor.pix_format.pixelformat == V4L2_PIX_FMT_JPEG) |
518 | return NULL; /* EOF header does not exist in compressed data */ | 558 | return NULL; |
519 | 559 | ||
560 | /* | ||
561 | The EOF header might cross the packet boundary, but this is not a | ||
562 | problem, since the end of a frame is determined by checking its size | ||
563 | in the first place. | ||
564 | */ | ||
520 | for (i = 0; (len >= 4) && (i <= len - 4); i++) | 565 | for (i = 0; (len >= 4) && (i <= len - 4); i++) |
521 | for (j = 0; j < ARRAY_SIZE(eof_header); j++) | 566 | for (j = 0; j < ARRAY_SIZE(eof_header); j++) |
522 | if (!memcmp(mem + i, eof_header[j], 4)) | 567 | if (!memcmp(mem + i, eof_header[j], 4)) |
@@ -529,7 +574,7 @@ sn9c102_find_eof_header(struct sn9c102_device* cam, void* mem, size_t len) | |||
529 | static void | 574 | static void |
530 | sn9c102_write_jpegheader(struct sn9c102_device* cam, struct sn9c102_frame_t* f) | 575 | sn9c102_write_jpegheader(struct sn9c102_device* cam, struct sn9c102_frame_t* f) |
531 | { | 576 | { |
532 | static u8 jpeg_header[589] = { | 577 | static const u8 jpeg_header[589] = { |
533 | 0xff, 0xd8, 0xff, 0xdb, 0x00, 0x84, 0x00, 0x06, 0x04, 0x05, | 578 | 0xff, 0xd8, 0xff, 0xdb, 0x00, 0x84, 0x00, 0x06, 0x04, 0x05, |
534 | 0x06, 0x05, 0x04, 0x06, 0x06, 0x05, 0x06, 0x07, 0x07, 0x06, | 579 | 0x06, 0x05, 0x04, 0x06, 0x06, 0x05, 0x06, 0x07, 0x07, 0x06, |
535 | 0x08, 0x0a, 0x10, 0x0a, 0x0a, 0x09, 0x09, 0x0a, 0x14, 0x0e, | 580 | 0x08, 0x0a, 0x10, 0x0a, 0x0a, 0x09, 0x09, 0x0a, 0x14, 0x0e, |
@@ -639,6 +684,7 @@ static void sn9c102_urb_complete(struct urb *urb) | |||
639 | cam->stream = STREAM_OFF; | 684 | cam->stream = STREAM_OFF; |
640 | if ((*f)) | 685 | if ((*f)) |
641 | (*f)->state = F_QUEUED; | 686 | (*f)->state = F_QUEUED; |
687 | cam->sof.bytesread = 0; | ||
642 | DBG(3, "Stream interrupted by application"); | 688 | DBG(3, "Stream interrupted by application"); |
643 | wake_up(&cam->wait_stream); | 689 | wake_up(&cam->wait_stream); |
644 | } | 690 | } |
@@ -676,6 +722,7 @@ static void sn9c102_urb_complete(struct urb *urb) | |||
676 | if (status) { | 722 | if (status) { |
677 | DBG(3, "Error in isochronous frame"); | 723 | DBG(3, "Error in isochronous frame"); |
678 | (*f)->state = F_ERROR; | 724 | (*f)->state = F_ERROR; |
725 | cam->sof.bytesread = 0; | ||
679 | continue; | 726 | continue; |
680 | } | 727 | } |
681 | 728 | ||
@@ -692,13 +739,13 @@ end_of_frame: | |||
692 | if (eof) | 739 | if (eof) |
693 | img = (eof > pos) ? eof - pos - 1 : 0; | 740 | img = (eof > pos) ? eof - pos - 1 : 0; |
694 | 741 | ||
695 | if ((*f)->buf.bytesused+img > imagesize) { | 742 | if ((*f)->buf.bytesused + img > imagesize) { |
696 | u32 b; | 743 | u32 b; |
697 | b = (*f)->buf.bytesused + img - | 744 | b = (*f)->buf.bytesused + img - |
698 | imagesize; | 745 | imagesize; |
699 | img = imagesize - (*f)->buf.bytesused; | 746 | img = imagesize - (*f)->buf.bytesused; |
700 | DBG(3, "Expected EOF not found: " | 747 | PDBGG("Expected EOF not found: video " |
701 | "video frame cut"); | 748 | "frame cut"); |
702 | if (eof) | 749 | if (eof) |
703 | DBG(3, "Exceeded limit: +%u " | 750 | DBG(3, "Exceeded limit: +%u " |
704 | "bytes", (unsigned)(b)); | 751 | "bytes", (unsigned)(b)); |
@@ -719,11 +766,6 @@ end_of_frame: | |||
719 | V4L2_PIX_FMT_JPEG) && eof)) { | 766 | V4L2_PIX_FMT_JPEG) && eof)) { |
720 | u32 b; | 767 | u32 b; |
721 | 768 | ||
722 | if (cam->sensor.pix_format.pixelformat | ||
723 | == V4L2_PIX_FMT_JPEG) | ||
724 | sn9c102_write_eoimarker(cam, | ||
725 | (*f)); | ||
726 | |||
727 | b = (*f)->buf.bytesused; | 769 | b = (*f)->buf.bytesused; |
728 | (*f)->state = F_DONE; | 770 | (*f)->state = F_DONE; |
729 | (*f)->buf.sequence= ++cam->frame_count; | 771 | (*f)->buf.sequence= ++cam->frame_count; |
@@ -741,7 +783,7 @@ end_of_frame: | |||
741 | spin_unlock(&cam->queue_lock); | 783 | spin_unlock(&cam->queue_lock); |
742 | 784 | ||
743 | memcpy(cam->sysfs.frame_header, | 785 | memcpy(cam->sysfs.frame_header, |
744 | cam->sof_header, soflen); | 786 | cam->sof.header, soflen); |
745 | 787 | ||
746 | DBG(3, "Video frame captured: %lu " | 788 | DBG(3, "Video frame captured: %lu " |
747 | "bytes", (unsigned long)(b)); | 789 | "bytes", (unsigned long)(b)); |
@@ -791,7 +833,13 @@ start_of_frame: | |||
791 | V4L2_PIX_FMT_SN9C10X || | 833 | V4L2_PIX_FMT_SN9C10X || |
792 | cam->sensor.pix_format.pixelformat == | 834 | cam->sensor.pix_format.pixelformat == |
793 | V4L2_PIX_FMT_JPEG) { | 835 | V4L2_PIX_FMT_JPEG) { |
794 | eof = sof - soflen; | 836 | if (sof - pos >= soflen) { |
837 | eof = sof - soflen; | ||
838 | } else { /* remove header */ | ||
839 | eof = pos; | ||
840 | (*f)->buf.bytesused -= | ||
841 | (soflen - (sof - pos)); | ||
842 | } | ||
795 | goto end_of_frame; | 843 | goto end_of_frame; |
796 | } else { | 844 | } else { |
797 | DBG(3, "SOF before expected EOF after " | 845 | DBG(3, "SOF before expected EOF after " |
@@ -878,6 +926,7 @@ static int sn9c102_start_transfer(struct sn9c102_device* cam) | |||
878 | } | 926 | } |
879 | 927 | ||
880 | cam->frame_current = NULL; | 928 | cam->frame_current = NULL; |
929 | cam->sof.bytesread = 0; | ||
881 | 930 | ||
882 | for (i = 0; i < SN9C102_URBS; i++) { | 931 | for (i = 0; i < SN9C102_URBS; i++) { |
883 | err = usb_submit_urb(cam->urb[i], GFP_KERNEL); | 932 | err = usb_submit_urb(cam->urb[i], GFP_KERNEL); |
@@ -959,9 +1008,9 @@ static u16 sn9c102_strtou16(const char* buff, size_t len, ssize_t* count) | |||
959 | 1008 | ||
960 | if (len < 6) { | 1009 | if (len < 6) { |
961 | strncpy(str, buff, len); | 1010 | strncpy(str, buff, len); |
962 | str[len+1] = '\0'; | 1011 | str[len] = '\0'; |
963 | } else { | 1012 | } else { |
964 | strncpy(str, buff, 4); | 1013 | strncpy(str, buff, 6); |
965 | str[6] = '\0'; | 1014 | str[6] = '\0'; |
966 | } | 1015 | } |
967 | 1016 | ||
@@ -1062,7 +1111,7 @@ static ssize_t sn9c102_show_val(struct class_device* cd, char* buf) | |||
1062 | 1111 | ||
1063 | count = sprintf(buf, "%d\n", val); | 1112 | count = sprintf(buf, "%d\n", val); |
1064 | 1113 | ||
1065 | DBG(3, "Read bytes: %zd", count); | 1114 | DBG(3, "Read bytes: %zd, value: %d", count, val); |
1066 | 1115 | ||
1067 | mutex_unlock(&sn9c102_sysfs_lock); | 1116 | mutex_unlock(&sn9c102_sysfs_lock); |
1068 | 1117 | ||
@@ -1197,7 +1246,7 @@ static ssize_t sn9c102_show_i2c_val(struct class_device* cd, char* buf) | |||
1197 | 1246 | ||
1198 | count = sprintf(buf, "%d\n", val); | 1247 | count = sprintf(buf, "%d\n", val); |
1199 | 1248 | ||
1200 | DBG(3, "Read bytes: %zd", count); | 1249 | DBG(3, "Read bytes: %zd, value: %d", count, val); |
1201 | 1250 | ||
1202 | mutex_unlock(&sn9c102_sysfs_lock); | 1251 | mutex_unlock(&sn9c102_sysfs_lock); |
1203 | 1252 | ||
@@ -1371,35 +1420,35 @@ static CLASS_DEVICE_ATTR(frame_header, S_IRUGO, | |||
1371 | 1420 | ||
1372 | static int sn9c102_create_sysfs(struct sn9c102_device* cam) | 1421 | static int sn9c102_create_sysfs(struct sn9c102_device* cam) |
1373 | { | 1422 | { |
1374 | struct video_device *v4ldev = cam->v4ldev; | 1423 | struct class_device *classdev = &(cam->v4ldev->class_dev); |
1375 | int err = 0; | 1424 | int err = 0; |
1376 | 1425 | ||
1377 | if ((err = video_device_create_file(v4ldev, &class_device_attr_reg))) | 1426 | if ((err = class_device_create_file(classdev, &class_device_attr_reg))) |
1378 | goto err_out; | 1427 | goto err_out; |
1379 | if ((err = video_device_create_file(v4ldev, &class_device_attr_val))) | 1428 | if ((err = class_device_create_file(classdev, &class_device_attr_val))) |
1380 | goto err_reg; | 1429 | goto err_reg; |
1381 | if ((err = video_device_create_file(v4ldev, | 1430 | if ((err = class_device_create_file(classdev, |
1382 | &class_device_attr_frame_header))) | 1431 | &class_device_attr_frame_header))) |
1383 | goto err_val; | 1432 | goto err_val; |
1384 | 1433 | ||
1385 | if (cam->sensor.sysfs_ops) { | 1434 | if (cam->sensor.sysfs_ops) { |
1386 | if ((err = video_device_create_file(v4ldev, | 1435 | if ((err = class_device_create_file(classdev, |
1387 | &class_device_attr_i2c_reg))) | 1436 | &class_device_attr_i2c_reg))) |
1388 | goto err_frame_header; | 1437 | goto err_frame_header; |
1389 | if ((err = video_device_create_file(v4ldev, | 1438 | if ((err = class_device_create_file(classdev, |
1390 | &class_device_attr_i2c_val))) | 1439 | &class_device_attr_i2c_val))) |
1391 | goto err_i2c_reg; | 1440 | goto err_i2c_reg; |
1392 | } | 1441 | } |
1393 | 1442 | ||
1394 | if (cam->bridge == BRIDGE_SN9C101 || cam->bridge == BRIDGE_SN9C102) { | 1443 | if (cam->bridge == BRIDGE_SN9C101 || cam->bridge == BRIDGE_SN9C102) { |
1395 | if ((err = video_device_create_file(v4ldev, | 1444 | if ((err = class_device_create_file(classdev, |
1396 | &class_device_attr_green))) | 1445 | &class_device_attr_green))) |
1397 | goto err_i2c_val; | 1446 | goto err_i2c_val; |
1398 | } else { | 1447 | } else { |
1399 | if ((err = video_device_create_file(v4ldev, | 1448 | if ((err = class_device_create_file(classdev, |
1400 | &class_device_attr_blue))) | 1449 | &class_device_attr_blue))) |
1401 | goto err_i2c_val; | 1450 | goto err_i2c_val; |
1402 | if ((err = video_device_create_file(v4ldev, | 1451 | if ((err = class_device_create_file(classdev, |
1403 | &class_device_attr_red))) | 1452 | &class_device_attr_red))) |
1404 | goto err_blue; | 1453 | goto err_blue; |
1405 | } | 1454 | } |
@@ -1407,19 +1456,19 @@ static int sn9c102_create_sysfs(struct sn9c102_device* cam) | |||
1407 | return 0; | 1456 | return 0; |
1408 | 1457 | ||
1409 | err_blue: | 1458 | err_blue: |
1410 | video_device_remove_file(v4ldev, &class_device_attr_blue); | 1459 | class_device_remove_file(classdev, &class_device_attr_blue); |
1411 | err_i2c_val: | 1460 | err_i2c_val: |
1412 | if (cam->sensor.sysfs_ops) | 1461 | if (cam->sensor.sysfs_ops) |
1413 | video_device_remove_file(v4ldev, &class_device_attr_i2c_val); | 1462 | class_device_remove_file(classdev, &class_device_attr_i2c_val); |
1414 | err_i2c_reg: | 1463 | err_i2c_reg: |
1415 | if (cam->sensor.sysfs_ops) | 1464 | if (cam->sensor.sysfs_ops) |
1416 | video_device_remove_file(v4ldev, &class_device_attr_i2c_reg); | 1465 | class_device_remove_file(classdev, &class_device_attr_i2c_reg); |
1417 | err_frame_header: | 1466 | err_frame_header: |
1418 | video_device_remove_file(v4ldev, &class_device_attr_frame_header); | 1467 | class_device_remove_file(classdev, &class_device_attr_frame_header); |
1419 | err_val: | 1468 | err_val: |
1420 | video_device_remove_file(v4ldev, &class_device_attr_val); | 1469 | class_device_remove_file(classdev, &class_device_attr_val); |
1421 | err_reg: | 1470 | err_reg: |
1422 | video_device_remove_file(v4ldev, &class_device_attr_reg); | 1471 | class_device_remove_file(classdev, &class_device_attr_reg); |
1423 | err_out: | 1472 | err_out: |
1424 | return err; | 1473 | return err; |
1425 | } | 1474 | } |
@@ -1477,10 +1526,10 @@ sn9c102_set_compression(struct sn9c102_device* cam, | |||
1477 | case BRIDGE_SN9C101: | 1526 | case BRIDGE_SN9C101: |
1478 | case BRIDGE_SN9C102: | 1527 | case BRIDGE_SN9C102: |
1479 | case BRIDGE_SN9C103: | 1528 | case BRIDGE_SN9C103: |
1480 | if (compression->quality == 0) | 1529 | if (compression->quality == 0) |
1481 | err += sn9c102_write_reg(cam, cam->reg[0x17] | 0x01, | 1530 | err += sn9c102_write_reg(cam, cam->reg[0x17] | 0x01, |
1482 | 0x17); | 1531 | 0x17); |
1483 | else if (compression->quality == 1) | 1532 | else if (compression->quality == 1) |
1484 | err += sn9c102_write_reg(cam, cam->reg[0x17] & 0xfe, | 1533 | err += sn9c102_write_reg(cam, cam->reg[0x17] & 0xfe, |
1485 | 0x17); | 1534 | 0x17); |
1486 | break; | 1535 | break; |
@@ -1489,10 +1538,10 @@ sn9c102_set_compression(struct sn9c102_device* cam, | |||
1489 | if (compression->quality == 0) { | 1538 | if (compression->quality == 0) { |
1490 | for (i = 0; i <= 63; i++) { | 1539 | for (i = 0; i <= 63; i++) { |
1491 | err += sn9c102_write_reg(cam, | 1540 | err += sn9c102_write_reg(cam, |
1492 | SN9C102_Y_QTABLE0[i], | 1541 | SN9C102_Y_QTABLE1[i], |
1493 | 0x100 + i); | 1542 | 0x100 + i); |
1494 | err += sn9c102_write_reg(cam, | 1543 | err += sn9c102_write_reg(cam, |
1495 | SN9C102_UV_QTABLE0[i], | 1544 | SN9C102_UV_QTABLE1[i], |
1496 | 0x140 + i); | 1545 | 0x140 + i); |
1497 | } | 1546 | } |
1498 | err += sn9c102_write_reg(cam, cam->reg[0x18] & 0xbf, | 1547 | err += sn9c102_write_reg(cam, cam->reg[0x18] & 0xbf, |
@@ -1597,9 +1646,13 @@ static int sn9c102_init(struct sn9c102_device* cam) | |||
1597 | if (cam->bridge == BRIDGE_SN9C101 || | 1646 | if (cam->bridge == BRIDGE_SN9C101 || |
1598 | cam->bridge == BRIDGE_SN9C102 || | 1647 | cam->bridge == BRIDGE_SN9C102 || |
1599 | cam->bridge == BRIDGE_SN9C103) { | 1648 | cam->bridge == BRIDGE_SN9C103) { |
1649 | if (s->pix_format.pixelformat == V4L2_PIX_FMT_JPEG) | ||
1650 | s->pix_format.pixelformat= V4L2_PIX_FMT_SBGGR8; | ||
1600 | cam->compression.quality = cam->reg[0x17] & 0x01 ? | 1651 | cam->compression.quality = cam->reg[0x17] & 0x01 ? |
1601 | 0 : 1; | 1652 | 0 : 1; |
1602 | } else { | 1653 | } else { |
1654 | if (s->pix_format.pixelformat == V4L2_PIX_FMT_SN9C10X) | ||
1655 | s->pix_format.pixelformat = V4L2_PIX_FMT_JPEG; | ||
1603 | cam->compression.quality = cam->reg[0x18] & 0x40 ? | 1656 | cam->compression.quality = cam->reg[0x18] & 0x40 ? |
1604 | 0 : 1; | 1657 | 0 : 1; |
1605 | err += sn9c102_set_compression(cam, &cam->compression); | 1658 | err += sn9c102_set_compression(cam, &cam->compression); |
@@ -1805,7 +1858,7 @@ sn9c102_read(struct file* filp, char __user * buf, size_t count, loff_t* f_pos) | |||
1805 | DBG(3, "Close and open the device again to choose " | 1858 | DBG(3, "Close and open the device again to choose " |
1806 | "the read method"); | 1859 | "the read method"); |
1807 | mutex_unlock(&cam->fileop_mutex); | 1860 | mutex_unlock(&cam->fileop_mutex); |
1808 | return -EINVAL; | 1861 | return -EBUSY; |
1809 | } | 1862 | } |
1810 | 1863 | ||
1811 | if (cam->io == IO_NONE) { | 1864 | if (cam->io == IO_NONE) { |
@@ -1845,16 +1898,16 @@ sn9c102_read(struct file* filp, char __user * buf, size_t count, loff_t* f_pos) | |||
1845 | return err; | 1898 | return err; |
1846 | } | 1899 | } |
1847 | } else { | 1900 | } else { |
1848 | timeout = wait_event_interruptible_timeout | 1901 | timeout = wait_event_interruptible_timeout |
1849 | ( cam->wait_frame, | 1902 | ( cam->wait_frame, |
1850 | (!list_empty(&cam->outqueue)) || | 1903 | (!list_empty(&cam->outqueue)) || |
1851 | (cam->state & DEV_DISCONNECTED) || | 1904 | (cam->state & DEV_DISCONNECTED) || |
1852 | (cam->state & DEV_MISCONFIGURED), | 1905 | (cam->state & DEV_MISCONFIGURED), |
1853 | cam->module_param.frame_timeout * | 1906 | cam->module_param.frame_timeout * |
1854 | 1000 * msecs_to_jiffies(1) ); | 1907 | 1000 * msecs_to_jiffies(1) ); |
1855 | if (timeout < 0) { | 1908 | if (timeout < 0) { |
1856 | mutex_unlock(&cam->fileop_mutex); | 1909 | mutex_unlock(&cam->fileop_mutex); |
1857 | return timeout; | 1910 | return timeout; |
1858 | } else if (timeout == 0 && | 1911 | } else if (timeout == 0 && |
1859 | !(cam->state & DEV_DISCONNECTED)) { | 1912 | !(cam->state & DEV_DISCONNECTED)) { |
1860 | DBG(1, "Video frame timeout elapsed"); | 1913 | DBG(1, "Video frame timeout elapsed"); |
@@ -2001,7 +2054,12 @@ static int sn9c102_mmap(struct file* filp, struct vm_area_struct *vma) | |||
2001 | return -EIO; | 2054 | return -EIO; |
2002 | } | 2055 | } |
2003 | 2056 | ||
2004 | if (cam->io != IO_MMAP || !(vma->vm_flags & VM_WRITE) || | 2057 | if (!(vma->vm_flags & (VM_WRITE | VM_READ))) { |
2058 | mutex_unlock(&cam->fileop_mutex); | ||
2059 | return -EACCES; | ||
2060 | } | ||
2061 | |||
2062 | if (cam->io != IO_MMAP || | ||
2005 | size != PAGE_ALIGN(cam->frame[0].buf.length)) { | 2063 | size != PAGE_ALIGN(cam->frame[0].buf.length)) { |
2006 | mutex_unlock(&cam->fileop_mutex); | 2064 | mutex_unlock(&cam->fileop_mutex); |
2007 | return -EINVAL; | 2065 | return -EINVAL; |
@@ -2267,7 +2325,7 @@ sn9c102_vidioc_s_crop(struct sn9c102_device* cam, void __user * arg) | |||
2267 | if (cam->frame[i].vma_use_count) { | 2325 | if (cam->frame[i].vma_use_count) { |
2268 | DBG(3, "VIDIOC_S_CROP failed. " | 2326 | DBG(3, "VIDIOC_S_CROP failed. " |
2269 | "Unmap the buffers first."); | 2327 | "Unmap the buffers first."); |
2270 | return -EINVAL; | 2328 | return -EBUSY; |
2271 | } | 2329 | } |
2272 | 2330 | ||
2273 | /* Preserve R,G or B origin */ | 2331 | /* Preserve R,G or B origin */ |
@@ -2410,8 +2468,8 @@ sn9c102_vidioc_enum_fmt(struct sn9c102_device* cam, void __user * arg) | |||
2410 | case BRIDGE_SN9C101: | 2468 | case BRIDGE_SN9C101: |
2411 | case BRIDGE_SN9C102: | 2469 | case BRIDGE_SN9C102: |
2412 | case BRIDGE_SN9C103: | 2470 | case BRIDGE_SN9C103: |
2413 | strcpy(fmtd.description, "compressed"); | 2471 | strcpy(fmtd.description, "compressed"); |
2414 | fmtd.pixelformat = V4L2_PIX_FMT_SN9C10X; | 2472 | fmtd.pixelformat = V4L2_PIX_FMT_SN9C10X; |
2415 | break; | 2473 | break; |
2416 | case BRIDGE_SN9C105: | 2474 | case BRIDGE_SN9C105: |
2417 | case BRIDGE_SN9C120: | 2475 | case BRIDGE_SN9C120: |
@@ -2445,8 +2503,10 @@ sn9c102_vidioc_g_fmt(struct sn9c102_device* cam, void __user * arg) | |||
2445 | if (format.type != V4L2_BUF_TYPE_VIDEO_CAPTURE) | 2503 | if (format.type != V4L2_BUF_TYPE_VIDEO_CAPTURE) |
2446 | return -EINVAL; | 2504 | return -EINVAL; |
2447 | 2505 | ||
2448 | pfmt->bytesperline = (pfmt->pixelformat==V4L2_PIX_FMT_SN9C10X || | 2506 | pfmt->colorspace = (pfmt->pixelformat == V4L2_PIX_FMT_JPEG) ? |
2449 | pfmt->pixelformat==V4L2_PIX_FMT_JPEG) | 2507 | V4L2_COLORSPACE_JPEG : V4L2_COLORSPACE_SRGB; |
2508 | pfmt->bytesperline = (pfmt->pixelformat == V4L2_PIX_FMT_SN9C10X || | ||
2509 | pfmt->pixelformat == V4L2_PIX_FMT_JPEG) | ||
2450 | ? 0 : (pfmt->width * pfmt->priv) / 8; | 2510 | ? 0 : (pfmt->width * pfmt->priv) / 8; |
2451 | pfmt->sizeimage = pfmt->height * ((pfmt->width*pfmt->priv)/8); | 2511 | pfmt->sizeimage = pfmt->height * ((pfmt->width*pfmt->priv)/8); |
2452 | pfmt->field = V4L2_FIELD_NONE; | 2512 | pfmt->field = V4L2_FIELD_NONE; |
@@ -2521,9 +2581,9 @@ sn9c102_vidioc_try_s_fmt(struct sn9c102_device* cam, unsigned int cmd, | |||
2521 | case BRIDGE_SN9C101: | 2581 | case BRIDGE_SN9C101: |
2522 | case BRIDGE_SN9C102: | 2582 | case BRIDGE_SN9C102: |
2523 | case BRIDGE_SN9C103: | 2583 | case BRIDGE_SN9C103: |
2524 | if (pix->pixelformat != V4L2_PIX_FMT_SN9C10X && | 2584 | if (pix->pixelformat != V4L2_PIX_FMT_SN9C10X && |
2525 | pix->pixelformat != V4L2_PIX_FMT_SBGGR8) | 2585 | pix->pixelformat != V4L2_PIX_FMT_SBGGR8) |
2526 | pix->pixelformat = pfmt->pixelformat; | 2586 | pix->pixelformat = pfmt->pixelformat; |
2527 | break; | 2587 | break; |
2528 | case BRIDGE_SN9C105: | 2588 | case BRIDGE_SN9C105: |
2529 | case BRIDGE_SN9C120: | 2589 | case BRIDGE_SN9C120: |
@@ -2533,7 +2593,8 @@ sn9c102_vidioc_try_s_fmt(struct sn9c102_device* cam, unsigned int cmd, | |||
2533 | break; | 2593 | break; |
2534 | } | 2594 | } |
2535 | pix->priv = pfmt->priv; /* bpp */ | 2595 | pix->priv = pfmt->priv; /* bpp */ |
2536 | pix->colorspace = pfmt->colorspace; | 2596 | pix->colorspace = (pix->pixelformat == V4L2_PIX_FMT_JPEG) ? |
2597 | V4L2_COLORSPACE_JPEG : V4L2_COLORSPACE_SRGB; | ||
2537 | pix->bytesperline = (pix->pixelformat == V4L2_PIX_FMT_SN9C10X || | 2598 | pix->bytesperline = (pix->pixelformat == V4L2_PIX_FMT_SN9C10X || |
2538 | pix->pixelformat == V4L2_PIX_FMT_JPEG) | 2599 | pix->pixelformat == V4L2_PIX_FMT_JPEG) |
2539 | ? 0 : (pix->width * pix->priv) / 8; | 2600 | ? 0 : (pix->width * pix->priv) / 8; |
@@ -2551,7 +2612,7 @@ sn9c102_vidioc_try_s_fmt(struct sn9c102_device* cam, unsigned int cmd, | |||
2551 | if (cam->frame[i].vma_use_count) { | 2612 | if (cam->frame[i].vma_use_count) { |
2552 | DBG(3, "VIDIOC_S_FMT failed. Unmap the " | 2613 | DBG(3, "VIDIOC_S_FMT failed. Unmap the " |
2553 | "buffers first."); | 2614 | "buffers first."); |
2554 | return -EINVAL; | 2615 | return -EBUSY; |
2555 | } | 2616 | } |
2556 | 2617 | ||
2557 | if (cam->stream == STREAM_ON) | 2618 | if (cam->stream == STREAM_ON) |
@@ -2666,14 +2727,14 @@ sn9c102_vidioc_reqbufs(struct sn9c102_device* cam, void __user * arg) | |||
2666 | if (cam->io == IO_READ) { | 2727 | if (cam->io == IO_READ) { |
2667 | DBG(3, "Close and open the device again to choose the mmap " | 2728 | DBG(3, "Close and open the device again to choose the mmap " |
2668 | "I/O method"); | 2729 | "I/O method"); |
2669 | return -EINVAL; | 2730 | return -EBUSY; |
2670 | } | 2731 | } |
2671 | 2732 | ||
2672 | for (i = 0; i < cam->nbuffers; i++) | 2733 | for (i = 0; i < cam->nbuffers; i++) |
2673 | if (cam->frame[i].vma_use_count) { | 2734 | if (cam->frame[i].vma_use_count) { |
2674 | DBG(3, "VIDIOC_REQBUFS failed. Previous buffers are " | 2735 | DBG(3, "VIDIOC_REQBUFS failed. Previous buffers are " |
2675 | "still mapped."); | 2736 | "still mapped."); |
2676 | return -EINVAL; | 2737 | return -EBUSY; |
2677 | } | 2738 | } |
2678 | 2739 | ||
2679 | if (cam->stream == STREAM_ON) | 2740 | if (cam->stream == STREAM_ON) |
@@ -2785,15 +2846,15 @@ sn9c102_vidioc_dqbuf(struct sn9c102_device* cam, struct file* filp, | |||
2785 | if (err) | 2846 | if (err) |
2786 | return err; | 2847 | return err; |
2787 | } else { | 2848 | } else { |
2788 | timeout = wait_event_interruptible_timeout | 2849 | timeout = wait_event_interruptible_timeout |
2789 | ( cam->wait_frame, | 2850 | ( cam->wait_frame, |
2790 | (!list_empty(&cam->outqueue)) || | 2851 | (!list_empty(&cam->outqueue)) || |
2791 | (cam->state & DEV_DISCONNECTED) || | 2852 | (cam->state & DEV_DISCONNECTED) || |
2792 | (cam->state & DEV_MISCONFIGURED), | 2853 | (cam->state & DEV_MISCONFIGURED), |
2793 | cam->module_param.frame_timeout * | 2854 | cam->module_param.frame_timeout * |
2794 | 1000 * msecs_to_jiffies(1) ); | 2855 | 1000 * msecs_to_jiffies(1) ); |
2795 | if (timeout < 0) | 2856 | if (timeout < 0) |
2796 | return timeout; | 2857 | return timeout; |
2797 | else if (timeout == 0 && | 2858 | else if (timeout == 0 && |
2798 | !(cam->state & DEV_DISCONNECTED)) { | 2859 | !(cam->state & DEV_DISCONNECTED)) { |
2799 | DBG(1, "Video frame timeout elapsed"); | 2860 | DBG(1, "Video frame timeout elapsed"); |
@@ -2837,9 +2898,6 @@ sn9c102_vidioc_streamon(struct sn9c102_device* cam, void __user * arg) | |||
2837 | if (type != V4L2_BUF_TYPE_VIDEO_CAPTURE || cam->io != IO_MMAP) | 2898 | if (type != V4L2_BUF_TYPE_VIDEO_CAPTURE || cam->io != IO_MMAP) |
2838 | return -EINVAL; | 2899 | return -EINVAL; |
2839 | 2900 | ||
2840 | if (list_empty(&cam->inqueue)) | ||
2841 | return -EINVAL; | ||
2842 | |||
2843 | cam->stream = STREAM_ON; | 2901 | cam->stream = STREAM_ON; |
2844 | 2902 | ||
2845 | DBG(3, "Stream on"); | 2903 | DBG(3, "Stream on"); |
@@ -3166,8 +3224,8 @@ sn9c102_usb_probe(struct usb_interface* intf, const struct usb_device_id* id) | |||
3166 | 3224 | ||
3167 | r = sn9c102_read_reg(cam, 0x00); | 3225 | r = sn9c102_read_reg(cam, 0x00); |
3168 | if (r < 0 || (r != 0x10 && r != 0x11 && r != 0x12)) { | 3226 | if (r < 0 || (r != 0x10 && r != 0x11 && r != 0x12)) { |
3169 | DBG(1, "Sorry, this is not a SN9C1xx based camera " | 3227 | DBG(1, "Sorry, this is not a SN9C1xx-based camera " |
3170 | "(vid/pid 0x%04X:0x%04X)", id->idVendor, id->idProduct); | 3228 | "(vid:pid 0x%04X:0x%04X)", id->idVendor, id->idProduct); |
3171 | err = -ENODEV; | 3229 | err = -ENODEV; |
3172 | goto fail; | 3230 | goto fail; |
3173 | } | 3231 | } |
@@ -3177,19 +3235,19 @@ sn9c102_usb_probe(struct usb_interface* intf, const struct usb_device_id* id) | |||
3177 | case BRIDGE_SN9C101: | 3235 | case BRIDGE_SN9C101: |
3178 | case BRIDGE_SN9C102: | 3236 | case BRIDGE_SN9C102: |
3179 | DBG(2, "SN9C10[12] PC Camera Controller detected " | 3237 | DBG(2, "SN9C10[12] PC Camera Controller detected " |
3180 | "(vid/pid 0x%04X:0x%04X)", id->idVendor, id->idProduct); | 3238 | "(vid:pid 0x%04X:0x%04X)", id->idVendor, id->idProduct); |
3181 | break; | 3239 | break; |
3182 | case BRIDGE_SN9C103: | 3240 | case BRIDGE_SN9C103: |
3183 | DBG(2, "SN9C103 PC Camera Controller detected " | 3241 | DBG(2, "SN9C103 PC Camera Controller detected " |
3184 | "(vid/pid 0x%04X:0x%04X)", id->idVendor, id->idProduct); | 3242 | "(vid:pid 0x%04X:0x%04X)", id->idVendor, id->idProduct); |
3185 | break; | 3243 | break; |
3186 | case BRIDGE_SN9C105: | 3244 | case BRIDGE_SN9C105: |
3187 | DBG(2, "SN9C105 PC Camera Controller detected " | 3245 | DBG(2, "SN9C105 PC Camera Controller detected " |
3188 | "(vid/pid 0x%04X:0x%04X)", id->idVendor, id->idProduct); | 3246 | "(vid:pid 0x%04X:0x%04X)", id->idVendor, id->idProduct); |
3189 | break; | 3247 | break; |
3190 | case BRIDGE_SN9C120: | 3248 | case BRIDGE_SN9C120: |
3191 | DBG(2, "SN9C120 PC Camera Controller detected " | 3249 | DBG(2, "SN9C120 PC Camera Controller detected " |
3192 | "(vid/pid 0x%04X:0x%04X)", id->idVendor, id->idProduct); | 3250 | "(vid:pid 0x%04X:0x%04X)", id->idVendor, id->idProduct); |
3193 | break; | 3251 | break; |
3194 | } | 3252 | } |
3195 | 3253 | ||
@@ -3260,6 +3318,8 @@ sn9c102_usb_probe(struct usb_interface* intf, const struct usb_device_id* id) | |||
3260 | "device controlling. Error #%d", err); | 3318 | "device controlling. Error #%d", err); |
3261 | #else | 3319 | #else |
3262 | DBG(2, "Optional device control through 'sysfs' interface disabled"); | 3320 | DBG(2, "Optional device control through 'sysfs' interface disabled"); |
3321 | DBG(3, "Compile the kernel with the 'CONFIG_VIDEO_ADV_DEBUG' " | ||
3322 | "configuration option to enable it."); | ||
3263 | #endif | 3323 | #endif |
3264 | 3324 | ||
3265 | usb_set_intfdata(intf, cam); | 3325 | usb_set_intfdata(intf, cam); |
diff --git a/drivers/media/video/sn9c102/sn9c102_devtable.h b/drivers/media/video/sn9c102/sn9c102_devtable.h index 3a682eca6c65..f49bd8c5b86e 100644 --- a/drivers/media/video/sn9c102/sn9c102_devtable.h +++ b/drivers/media/video/sn9c102/sn9c102_devtable.h | |||
@@ -89,16 +89,22 @@ static const struct usb_device_id sn9c102_id_table[] = { | |||
89 | { SN9C102_USB_DEVICE(0x0471, 0x0327, BRIDGE_SN9C105), }, | 89 | { SN9C102_USB_DEVICE(0x0471, 0x0327, BRIDGE_SN9C105), }, |
90 | { SN9C102_USB_DEVICE(0x0471, 0x0328, BRIDGE_SN9C105), }, | 90 | { SN9C102_USB_DEVICE(0x0471, 0x0328, BRIDGE_SN9C105), }, |
91 | { SN9C102_USB_DEVICE(0x0c45, 0x60c0, BRIDGE_SN9C105), }, | 91 | { SN9C102_USB_DEVICE(0x0c45, 0x60c0, BRIDGE_SN9C105), }, |
92 | { SN9C102_USB_DEVICE(0x0c45, 0x60c2, BRIDGE_SN9C105), }, | ||
92 | { SN9C102_USB_DEVICE(0x0c45, 0x60c8, BRIDGE_SN9C105), }, | 93 | { SN9C102_USB_DEVICE(0x0c45, 0x60c8, BRIDGE_SN9C105), }, |
93 | { SN9C102_USB_DEVICE(0x0c45, 0x60cc, BRIDGE_SN9C105), }, | 94 | { SN9C102_USB_DEVICE(0x0c45, 0x60cc, BRIDGE_SN9C105), }, |
94 | { SN9C102_USB_DEVICE(0x0c45, 0x60ea, BRIDGE_SN9C105), }, | 95 | { SN9C102_USB_DEVICE(0x0c45, 0x60ea, BRIDGE_SN9C105), }, |
95 | { SN9C102_USB_DEVICE(0x0c45, 0x60ec, BRIDGE_SN9C105), }, | 96 | { SN9C102_USB_DEVICE(0x0c45, 0x60ec, BRIDGE_SN9C105), }, |
97 | { SN9C102_USB_DEVICE(0x0c45, 0x60ef, BRIDGE_SN9C105), }, | ||
96 | { SN9C102_USB_DEVICE(0x0c45, 0x60fa, BRIDGE_SN9C105), }, | 98 | { SN9C102_USB_DEVICE(0x0c45, 0x60fa, BRIDGE_SN9C105), }, |
97 | { SN9C102_USB_DEVICE(0x0c45, 0x60fb, BRIDGE_SN9C105), }, | 99 | { SN9C102_USB_DEVICE(0x0c45, 0x60fb, BRIDGE_SN9C105), }, |
98 | { SN9C102_USB_DEVICE(0x0c45, 0x60fc, BRIDGE_SN9C105), }, | 100 | { SN9C102_USB_DEVICE(0x0c45, 0x60fc, BRIDGE_SN9C105), }, |
99 | { SN9C102_USB_DEVICE(0x0c45, 0x60fe, BRIDGE_SN9C105), }, | 101 | { SN9C102_USB_DEVICE(0x0c45, 0x60fe, BRIDGE_SN9C105), }, |
100 | /* SN9C120 */ | 102 | /* SN9C120 */ |
103 | { SN9C102_USB_DEVICE(0x0c45, 0x6102, BRIDGE_SN9C120), }, | ||
104 | { SN9C102_USB_DEVICE(0x0c45, 0x6108, BRIDGE_SN9C120), }, | ||
105 | { SN9C102_USB_DEVICE(0x0c45, 0x610f, BRIDGE_SN9C120), }, | ||
101 | { SN9C102_USB_DEVICE(0x0c45, 0x6130, BRIDGE_SN9C120), }, | 106 | { SN9C102_USB_DEVICE(0x0c45, 0x6130, BRIDGE_SN9C120), }, |
107 | { SN9C102_USB_DEVICE(0x0c45, 0x6138, BRIDGE_SN9C120), }, | ||
102 | { SN9C102_USB_DEVICE(0x0c45, 0x613a, BRIDGE_SN9C120), }, | 108 | { SN9C102_USB_DEVICE(0x0c45, 0x613a, BRIDGE_SN9C120), }, |
103 | { SN9C102_USB_DEVICE(0x0c45, 0x613b, BRIDGE_SN9C120), }, | 109 | { SN9C102_USB_DEVICE(0x0c45, 0x613b, BRIDGE_SN9C120), }, |
104 | { SN9C102_USB_DEVICE(0x0c45, 0x613c, BRIDGE_SN9C120), }, | 110 | { SN9C102_USB_DEVICE(0x0c45, 0x613c, BRIDGE_SN9C120), }, |
@@ -114,12 +120,15 @@ static const struct usb_device_id sn9c102_id_table[] = { | |||
114 | Functions must return 0 on success, the appropriate error otherwise. | 120 | Functions must return 0 on success, the appropriate error otherwise. |
115 | */ | 121 | */ |
116 | extern int sn9c102_probe_hv7131d(struct sn9c102_device* cam); | 122 | extern int sn9c102_probe_hv7131d(struct sn9c102_device* cam); |
123 | extern int sn9c102_probe_hv7131r(struct sn9c102_device* cam); | ||
117 | extern int sn9c102_probe_mi0343(struct sn9c102_device* cam); | 124 | extern int sn9c102_probe_mi0343(struct sn9c102_device* cam); |
125 | extern int sn9c102_probe_mi0360(struct sn9c102_device* cam); | ||
118 | extern int sn9c102_probe_ov7630(struct sn9c102_device* cam); | 126 | extern int sn9c102_probe_ov7630(struct sn9c102_device* cam); |
119 | extern int sn9c102_probe_ov7660(struct sn9c102_device* cam); | 127 | extern int sn9c102_probe_ov7660(struct sn9c102_device* cam); |
120 | extern int sn9c102_probe_pas106b(struct sn9c102_device* cam); | 128 | extern int sn9c102_probe_pas106b(struct sn9c102_device* cam); |
121 | extern int sn9c102_probe_pas202bcb(struct sn9c102_device* cam); | 129 | extern int sn9c102_probe_pas202bcb(struct sn9c102_device* cam); |
122 | extern int sn9c102_probe_tas5110c1b(struct sn9c102_device* cam); | 130 | extern int sn9c102_probe_tas5110c1b(struct sn9c102_device* cam); |
131 | extern int sn9c102_probe_tas5110d(struct sn9c102_device* cam); | ||
123 | extern int sn9c102_probe_tas5130d1b(struct sn9c102_device* cam); | 132 | extern int sn9c102_probe_tas5130d1b(struct sn9c102_device* cam); |
124 | 133 | ||
125 | /* | 134 | /* |
@@ -128,13 +137,16 @@ extern int sn9c102_probe_tas5130d1b(struct sn9c102_device* cam); | |||
128 | the order of the list below, from top to bottom. | 137 | the order of the list below, from top to bottom. |
129 | */ | 138 | */ |
130 | static int (*sn9c102_sensor_table[])(struct sn9c102_device*) = { | 139 | static int (*sn9c102_sensor_table[])(struct sn9c102_device*) = { |
140 | &sn9c102_probe_hv7131d, /* strong detection based on SENSOR ids */ | ||
141 | &sn9c102_probe_hv7131r, /* strong detection based on SENSOR ids */ | ||
131 | &sn9c102_probe_mi0343, /* strong detection based on SENSOR ids */ | 142 | &sn9c102_probe_mi0343, /* strong detection based on SENSOR ids */ |
143 | &sn9c102_probe_mi0360, /* strong detection based on SENSOR ids */ | ||
132 | &sn9c102_probe_pas106b, /* strong detection based on SENSOR ids */ | 144 | &sn9c102_probe_pas106b, /* strong detection based on SENSOR ids */ |
133 | &sn9c102_probe_pas202bcb, /* strong detection based on SENSOR ids */ | 145 | &sn9c102_probe_pas202bcb, /* strong detection based on SENSOR ids */ |
134 | &sn9c102_probe_hv7131d, /* strong detection based on SENSOR ids */ | ||
135 | &sn9c102_probe_ov7630, /* strong detection based on SENSOR ids */ | 146 | &sn9c102_probe_ov7630, /* strong detection based on SENSOR ids */ |
136 | &sn9c102_probe_ov7660, /* strong detection based on SENSOR ids */ | 147 | &sn9c102_probe_ov7660, /* strong detection based on SENSOR ids */ |
137 | &sn9c102_probe_tas5110c1b, /* detection based on USB pid/vid */ | 148 | &sn9c102_probe_tas5110c1b, /* detection based on USB pid/vid */ |
149 | &sn9c102_probe_tas5110d, /* detection based on USB pid/vid */ | ||
138 | &sn9c102_probe_tas5130d1b, /* detection based on USB pid/vid */ | 150 | &sn9c102_probe_tas5130d1b, /* detection based on USB pid/vid */ |
139 | NULL, | 151 | NULL, |
140 | }; | 152 | }; |
diff --git a/drivers/media/video/sn9c102/sn9c102_hv7131d.c b/drivers/media/video/sn9c102/sn9c102_hv7131d.c index 7ae368f60d89..28a861aed044 100644 --- a/drivers/media/video/sn9c102/sn9c102_hv7131d.c +++ b/drivers/media/video/sn9c102/sn9c102_hv7131d.c | |||
@@ -22,19 +22,13 @@ | |||
22 | #include "sn9c102_sensor.h" | 22 | #include "sn9c102_sensor.h" |
23 | 23 | ||
24 | 24 | ||
25 | static struct sn9c102_sensor hv7131d; | ||
26 | |||
27 | |||
28 | static int hv7131d_init(struct sn9c102_device* cam) | 25 | static int hv7131d_init(struct sn9c102_device* cam) |
29 | { | 26 | { |
30 | int err = 0; | 27 | int err; |
31 | 28 | ||
32 | err += sn9c102_write_reg(cam, 0x00, 0x10); | 29 | err = sn9c102_write_const_regs(cam, {0x00, 0x10}, {0x00, 0x11}, |
33 | err += sn9c102_write_reg(cam, 0x00, 0x11); | 30 | {0x00, 0x14}, {0x60, 0x17}, |
34 | err += sn9c102_write_reg(cam, 0x00, 0x14); | 31 | {0x0e, 0x18}, {0xf2, 0x19}); |
35 | err += sn9c102_write_reg(cam, 0x60, 0x17); | ||
36 | err += sn9c102_write_reg(cam, 0x0e, 0x18); | ||
37 | err += sn9c102_write_reg(cam, 0xf2, 0x19); | ||
38 | 32 | ||
39 | err += sn9c102_i2c_write(cam, 0x01, 0x04); | 33 | err += sn9c102_i2c_write(cam, 0x01, 0x04); |
40 | err += sn9c102_i2c_write(cam, 0x02, 0x00); | 34 | err += sn9c102_i2c_write(cam, 0x02, 0x00); |
@@ -153,7 +147,7 @@ static int hv7131d_set_pix_format(struct sn9c102_device* cam, | |||
153 | static struct sn9c102_sensor hv7131d = { | 147 | static struct sn9c102_sensor hv7131d = { |
154 | .name = "HV7131D", | 148 | .name = "HV7131D", |
155 | .maintainer = "Luca Risolia <luca.risolia@studio.unibo.it>", | 149 | .maintainer = "Luca Risolia <luca.risolia@studio.unibo.it>", |
156 | .supported_bridge = BRIDGE_SN9C101 | BRIDGE_SN9C102 | BRIDGE_SN9C103, | 150 | .supported_bridge = BRIDGE_SN9C101 | BRIDGE_SN9C102, |
157 | .sysfs_ops = SN9C102_I2C_READ | SN9C102_I2C_WRITE, | 151 | .sysfs_ops = SN9C102_I2C_READ | SN9C102_I2C_WRITE, |
158 | .frequency = SN9C102_I2C_100KHZ, | 152 | .frequency = SN9C102_I2C_100KHZ, |
159 | .interface = SN9C102_I2C_2WIRES, | 153 | .interface = SN9C102_I2C_2WIRES, |
@@ -250,11 +244,10 @@ static struct sn9c102_sensor hv7131d = { | |||
250 | 244 | ||
251 | int sn9c102_probe_hv7131d(struct sn9c102_device* cam) | 245 | int sn9c102_probe_hv7131d(struct sn9c102_device* cam) |
252 | { | 246 | { |
253 | int r0 = 0, r1 = 0, err = 0; | 247 | int r0 = 0, r1 = 0, err; |
254 | 248 | ||
255 | err += sn9c102_write_reg(cam, 0x01, 0x01); | 249 | err = sn9c102_write_const_regs(cam, {0x01, 0x01}, {0x00, 0x01}, |
256 | err += sn9c102_write_reg(cam, 0x00, 0x01); | 250 | {0x28, 0x17}); |
257 | err += sn9c102_write_reg(cam, 0x28, 0x17); | ||
258 | if (err) | 251 | if (err) |
259 | return -EIO; | 252 | return -EIO; |
260 | 253 | ||
@@ -263,7 +256,7 @@ int sn9c102_probe_hv7131d(struct sn9c102_device* cam) | |||
263 | if (r0 < 0 || r1 < 0) | 256 | if (r0 < 0 || r1 < 0) |
264 | return -EIO; | 257 | return -EIO; |
265 | 258 | ||
266 | if (r0 != 0x00 && r1 != 0x04) | 259 | if (r0 != 0x00 || r1 != 0x04) |
267 | return -ENODEV; | 260 | return -ENODEV; |
268 | 261 | ||
269 | sn9c102_attach_sensor(cam, &hv7131d); | 262 | sn9c102_attach_sensor(cam, &hv7131d); |
diff --git a/drivers/media/video/sn9c102/sn9c102_hv7131r.c b/drivers/media/video/sn9c102/sn9c102_hv7131r.c new file mode 100644 index 000000000000..5a495baa5f95 --- /dev/null +++ b/drivers/media/video/sn9c102/sn9c102_hv7131r.c | |||
@@ -0,0 +1,366 @@ | |||
1 | /*************************************************************************** | ||
2 | * Plug-in for HV7131R image sensor connected to the SN9C1xx PC Camera * | ||
3 | * Controllers * | ||
4 | * * | ||
5 | * Copyright (C) 2007 by Luca Risolia <luca.risolia@studio.unibo.it> * | ||
6 | * * | ||
7 | * This program is free software; you can redistribute it and/or modify * | ||
8 | * it under the terms of the GNU General Public License as published by * | ||
9 | * the Free Software Foundation; either version 2 of the License, or * | ||
10 | * (at your option) any later version. * | ||
11 | * * | ||
12 | * This program is distributed in the hope that it will be useful, * | ||
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of * | ||
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * | ||
15 | * GNU General Public License for more details. * | ||
16 | * * | ||
17 | * You should have received a copy of the GNU General Public License * | ||
18 | * along with this program; if not, write to the Free Software * | ||
19 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * | ||
20 | ***************************************************************************/ | ||
21 | |||
22 | #include "sn9c102_sensor.h" | ||
23 | |||
24 | |||
25 | static int hv7131r_init(struct sn9c102_device* cam) | ||
26 | { | ||
27 | int err = 0; | ||
28 | |||
29 | switch (sn9c102_get_bridge(cam)) { | ||
30 | case BRIDGE_SN9C103: | ||
31 | err = sn9c102_write_const_regs(cam, {0x00, 0x03}, {0x1a, 0x04}, | ||
32 | {0x20, 0x05}, {0x20, 0x06}, | ||
33 | {0x03, 0x10}, {0x00, 0x14}, | ||
34 | {0x60, 0x17}, {0x0a, 0x18}, | ||
35 | {0xf0, 0x19}, {0x1d, 0x1a}, | ||
36 | {0x10, 0x1b}, {0x02, 0x1c}, | ||
37 | {0x03, 0x1d}, {0x0f, 0x1e}, | ||
38 | {0x0c, 0x1f}, {0x00, 0x20}, | ||
39 | {0x10, 0x21}, {0x20, 0x22}, | ||
40 | {0x30, 0x23}, {0x40, 0x24}, | ||
41 | {0x50, 0x25}, {0x60, 0x26}, | ||
42 | {0x70, 0x27}, {0x80, 0x28}, | ||
43 | {0x90, 0x29}, {0xa0, 0x2a}, | ||
44 | {0xb0, 0x2b}, {0xc0, 0x2c}, | ||
45 | {0xd0, 0x2d}, {0xe0, 0x2e}, | ||
46 | {0xf0, 0x2f}, {0xff, 0x30}); | ||
47 | |||
48 | break; | ||
49 | case BRIDGE_SN9C105: | ||
50 | case BRIDGE_SN9C120: | ||
51 | err = sn9c102_write_const_regs(cam, {0x44, 0x01}, {0x40, 0x02}, | ||
52 | {0x00, 0x03}, {0x1a, 0x04}, | ||
53 | {0x44, 0x05}, {0x3e, 0x06}, | ||
54 | {0x1a, 0x07}, {0x03, 0x10}, | ||
55 | {0x08, 0x14}, {0xa3, 0x17}, | ||
56 | {0x4b, 0x18}, {0x00, 0x19}, | ||
57 | {0x1d, 0x1a}, {0x10, 0x1b}, | ||
58 | {0x02, 0x1c}, {0x03, 0x1d}, | ||
59 | {0x0f, 0x1e}, {0x0c, 0x1f}, | ||
60 | {0x00, 0x20}, {0x29, 0x21}, | ||
61 | {0x40, 0x22}, {0x54, 0x23}, | ||
62 | {0x66, 0x24}, {0x76, 0x25}, | ||
63 | {0x85, 0x26}, {0x94, 0x27}, | ||
64 | {0xa1, 0x28}, {0xae, 0x29}, | ||
65 | {0xbb, 0x2a}, {0xc7, 0x2b}, | ||
66 | {0xd3, 0x2c}, {0xde, 0x2d}, | ||
67 | {0xea, 0x2e}, {0xf4, 0x2f}, | ||
68 | {0xff, 0x30}, {0x00, 0x3F}, | ||
69 | {0xC7, 0x40}, {0x01, 0x41}, | ||
70 | {0x44, 0x42}, {0x00, 0x43}, | ||
71 | {0x44, 0x44}, {0x00, 0x45}, | ||
72 | {0x44, 0x46}, {0x00, 0x47}, | ||
73 | {0xC7, 0x48}, {0x01, 0x49}, | ||
74 | {0xC7, 0x4A}, {0x01, 0x4B}, | ||
75 | {0xC7, 0x4C}, {0x01, 0x4D}, | ||
76 | {0x44, 0x4E}, {0x00, 0x4F}, | ||
77 | {0x44, 0x50}, {0x00, 0x51}, | ||
78 | {0x44, 0x52}, {0x00, 0x53}, | ||
79 | {0xC7, 0x54}, {0x01, 0x55}, | ||
80 | {0xC7, 0x56}, {0x01, 0x57}, | ||
81 | {0xC7, 0x58}, {0x01, 0x59}, | ||
82 | {0x44, 0x5A}, {0x00, 0x5B}, | ||
83 | {0x44, 0x5C}, {0x00, 0x5D}, | ||
84 | {0x44, 0x5E}, {0x00, 0x5F}, | ||
85 | {0xC7, 0x60}, {0x01, 0x61}, | ||
86 | {0xC7, 0x62}, {0x01, 0x63}, | ||
87 | {0xC7, 0x64}, {0x01, 0x65}, | ||
88 | {0x44, 0x66}, {0x00, 0x67}, | ||
89 | {0x44, 0x68}, {0x00, 0x69}, | ||
90 | {0x44, 0x6A}, {0x00, 0x6B}, | ||
91 | {0xC7, 0x6C}, {0x01, 0x6D}, | ||
92 | {0xC7, 0x6E}, {0x01, 0x6F}, | ||
93 | {0xC7, 0x70}, {0x01, 0x71}, | ||
94 | {0x44, 0x72}, {0x00, 0x73}, | ||
95 | {0x44, 0x74}, {0x00, 0x75}, | ||
96 | {0x44, 0x76}, {0x00, 0x77}, | ||
97 | {0xC7, 0x78}, {0x01, 0x79}, | ||
98 | {0xC7, 0x7A}, {0x01, 0x7B}, | ||
99 | {0xC7, 0x7C}, {0x01, 0x7D}, | ||
100 | {0x44, 0x7E}, {0x00, 0x7F}, | ||
101 | {0x14, 0x84}, {0x00, 0x85}, | ||
102 | {0x27, 0x86}, {0x00, 0x87}, | ||
103 | {0x07, 0x88}, {0x00, 0x89}, | ||
104 | {0xEC, 0x8A}, {0x0f, 0x8B}, | ||
105 | {0xD8, 0x8C}, {0x0f, 0x8D}, | ||
106 | {0x3D, 0x8E}, {0x00, 0x8F}, | ||
107 | {0x3D, 0x90}, {0x00, 0x91}, | ||
108 | {0xCD, 0x92}, {0x0f, 0x93}, | ||
109 | {0xf7, 0x94}, {0x0f, 0x95}, | ||
110 | {0x0C, 0x96}, {0x00, 0x97}, | ||
111 | {0x00, 0x98}, {0x66, 0x99}, | ||
112 | {0x05, 0x9A}, {0x00, 0x9B}, | ||
113 | {0x04, 0x9C}, {0x00, 0x9D}, | ||
114 | {0x08, 0x9E}, {0x00, 0x9F}, | ||
115 | {0x2D, 0xC0}, {0x2D, 0xC1}, | ||
116 | {0x3A, 0xC2}, {0x05, 0xC3}, | ||
117 | {0x04, 0xC4}, {0x3F, 0xC5}, | ||
118 | {0x00, 0xC6}, {0x00, 0xC7}, | ||
119 | {0x50, 0xC8}, {0x3C, 0xC9}, | ||
120 | {0x28, 0xCA}, {0xD8, 0xCB}, | ||
121 | {0x14, 0xCC}, {0xEC, 0xCD}, | ||
122 | {0x32, 0xCE}, {0xDD, 0xCF}, | ||
123 | {0x32, 0xD0}, {0xDD, 0xD1}, | ||
124 | {0x6A, 0xD2}, {0x50, 0xD3}, | ||
125 | {0x00, 0xD4}, {0x00, 0xD5}, | ||
126 | {0x00, 0xD6}); | ||
127 | break; | ||
128 | default: | ||
129 | break; | ||
130 | } | ||
131 | |||
132 | err += sn9c102_i2c_write(cam, 0x20, 0x00); | ||
133 | err += sn9c102_i2c_write(cam, 0x21, 0xd6); | ||
134 | err += sn9c102_i2c_write(cam, 0x25, 0x06); | ||
135 | |||
136 | return err; | ||
137 | } | ||
138 | |||
139 | |||
140 | static int hv7131r_get_ctrl(struct sn9c102_device* cam, | ||
141 | struct v4l2_control* ctrl) | ||
142 | { | ||
143 | switch (ctrl->id) { | ||
144 | case V4L2_CID_GAIN: | ||
145 | if ((ctrl->value = sn9c102_i2c_read(cam, 0x30)) < 0) | ||
146 | return -EIO; | ||
147 | return 0; | ||
148 | case V4L2_CID_RED_BALANCE: | ||
149 | if ((ctrl->value = sn9c102_i2c_read(cam, 0x31)) < 0) | ||
150 | return -EIO; | ||
151 | ctrl->value = ctrl->value & 0x3f; | ||
152 | return 0; | ||
153 | case V4L2_CID_BLUE_BALANCE: | ||
154 | if ((ctrl->value = sn9c102_i2c_read(cam, 0x33)) < 0) | ||
155 | return -EIO; | ||
156 | ctrl->value = ctrl->value & 0x3f; | ||
157 | return 0; | ||
158 | case SN9C102_V4L2_CID_GREEN_BALANCE: | ||
159 | if ((ctrl->value = sn9c102_i2c_read(cam, 0x32)) < 0) | ||
160 | return -EIO; | ||
161 | ctrl->value = ctrl->value & 0x3f; | ||
162 | return 0; | ||
163 | case V4L2_CID_BLACK_LEVEL: | ||
164 | if ((ctrl->value = sn9c102_i2c_read(cam, 0x01)) < 0) | ||
165 | return -EIO; | ||
166 | ctrl->value = (ctrl->value & 0x08) ? 1 : 0; | ||
167 | return 0; | ||
168 | default: | ||
169 | return -EINVAL; | ||
170 | } | ||
171 | } | ||
172 | |||
173 | |||
174 | static int hv7131r_set_ctrl(struct sn9c102_device* cam, | ||
175 | const struct v4l2_control* ctrl) | ||
176 | { | ||
177 | int err = 0; | ||
178 | |||
179 | switch (ctrl->id) { | ||
180 | case V4L2_CID_GAIN: | ||
181 | err += sn9c102_i2c_write(cam, 0x30, ctrl->value); | ||
182 | break; | ||
183 | case V4L2_CID_RED_BALANCE: | ||
184 | err += sn9c102_i2c_write(cam, 0x31, ctrl->value); | ||
185 | break; | ||
186 | case V4L2_CID_BLUE_BALANCE: | ||
187 | err += sn9c102_i2c_write(cam, 0x33, ctrl->value); | ||
188 | break; | ||
189 | case SN9C102_V4L2_CID_GREEN_BALANCE: | ||
190 | err += sn9c102_i2c_write(cam, 0x32, ctrl->value); | ||
191 | break; | ||
192 | case V4L2_CID_BLACK_LEVEL: | ||
193 | { | ||
194 | int r = sn9c102_i2c_read(cam, 0x01); | ||
195 | if (r < 0) | ||
196 | return -EIO; | ||
197 | err += sn9c102_i2c_write(cam, 0x01, | ||
198 | (ctrl->value<<3) | (r&0xf7)); | ||
199 | } | ||
200 | break; | ||
201 | default: | ||
202 | return -EINVAL; | ||
203 | } | ||
204 | |||
205 | return err ? -EIO : 0; | ||
206 | } | ||
207 | |||
208 | |||
209 | static int hv7131r_set_crop(struct sn9c102_device* cam, | ||
210 | const struct v4l2_rect* rect) | ||
211 | { | ||
212 | struct sn9c102_sensor* s = sn9c102_get_sensor(cam); | ||
213 | int err = 0; | ||
214 | u8 h_start = (u8)(rect->left - s->cropcap.bounds.left) + 1, | ||
215 | v_start = (u8)(rect->top - s->cropcap.bounds.top) + 1; | ||
216 | |||
217 | err += sn9c102_write_reg(cam, h_start, 0x12); | ||
218 | err += sn9c102_write_reg(cam, v_start, 0x13); | ||
219 | |||
220 | return err; | ||
221 | } | ||
222 | |||
223 | |||
224 | static int hv7131r_set_pix_format(struct sn9c102_device* cam, | ||
225 | const struct v4l2_pix_format* pix) | ||
226 | { | ||
227 | int err = 0; | ||
228 | |||
229 | switch (sn9c102_get_bridge(cam)) { | ||
230 | case BRIDGE_SN9C103: | ||
231 | if (pix->pixelformat == V4L2_PIX_FMT_SBGGR8) { | ||
232 | err += sn9c102_write_reg(cam, 0xa0, 0x19); | ||
233 | err += sn9c102_i2c_write(cam, 0x01, 0x04); | ||
234 | } else { | ||
235 | err += sn9c102_write_reg(cam, 0x30, 0x19); | ||
236 | err += sn9c102_i2c_write(cam, 0x01, 0x04); | ||
237 | } | ||
238 | break; | ||
239 | case BRIDGE_SN9C105: | ||
240 | case BRIDGE_SN9C120: | ||
241 | if (pix->pixelformat == V4L2_PIX_FMT_SBGGR8) { | ||
242 | err += sn9c102_write_reg(cam, 0xa5, 0x17); | ||
243 | err += sn9c102_i2c_write(cam, 0x01, 0x24); | ||
244 | } else { | ||
245 | err += sn9c102_write_reg(cam, 0xa3, 0x17); | ||
246 | err += sn9c102_i2c_write(cam, 0x01, 0x04); | ||
247 | } | ||
248 | break; | ||
249 | default: | ||
250 | break; | ||
251 | } | ||
252 | |||
253 | return err; | ||
254 | } | ||
255 | |||
256 | |||
257 | static struct sn9c102_sensor hv7131r = { | ||
258 | .name = "HV7131R", | ||
259 | .maintainer = "Luca Risolia <luca.risolia@studio.unibo.it>", | ||
260 | .supported_bridge = BRIDGE_SN9C103 | BRIDGE_SN9C105 | BRIDGE_SN9C120, | ||
261 | .sysfs_ops = SN9C102_I2C_READ | SN9C102_I2C_WRITE, | ||
262 | .frequency = SN9C102_I2C_100KHZ, | ||
263 | .interface = SN9C102_I2C_2WIRES, | ||
264 | .i2c_slave_id = 0x11, | ||
265 | .init = &hv7131r_init, | ||
266 | .qctrl = { | ||
267 | { | ||
268 | .id = V4L2_CID_GAIN, | ||
269 | .type = V4L2_CTRL_TYPE_INTEGER, | ||
270 | .name = "global gain", | ||
271 | .minimum = 0x00, | ||
272 | .maximum = 0xff, | ||
273 | .step = 0x01, | ||
274 | .default_value = 0x40, | ||
275 | .flags = 0, | ||
276 | }, | ||
277 | { | ||
278 | .id = V4L2_CID_RED_BALANCE, | ||
279 | .type = V4L2_CTRL_TYPE_INTEGER, | ||
280 | .name = "red balance", | ||
281 | .minimum = 0x00, | ||
282 | .maximum = 0x3f, | ||
283 | .step = 0x01, | ||
284 | .default_value = 0x08, | ||
285 | .flags = 0, | ||
286 | }, | ||
287 | { | ||
288 | .id = V4L2_CID_BLUE_BALANCE, | ||
289 | .type = V4L2_CTRL_TYPE_INTEGER, | ||
290 | .name = "blue balance", | ||
291 | .minimum = 0x00, | ||
292 | .maximum = 0x3f, | ||
293 | .step = 0x01, | ||
294 | .default_value = 0x1a, | ||
295 | .flags = 0, | ||
296 | }, | ||
297 | { | ||
298 | .id = SN9C102_V4L2_CID_GREEN_BALANCE, | ||
299 | .type = V4L2_CTRL_TYPE_INTEGER, | ||
300 | .name = "green balance", | ||
301 | .minimum = 0x00, | ||
302 | .maximum = 0x3f, | ||
303 | .step = 0x01, | ||
304 | .default_value = 0x2f, | ||
305 | .flags = 0, | ||
306 | }, | ||
307 | { | ||
308 | .id = V4L2_CID_BLACK_LEVEL, | ||
309 | .type = V4L2_CTRL_TYPE_BOOLEAN, | ||
310 | .name = "auto black level compensation", | ||
311 | .minimum = 0x00, | ||
312 | .maximum = 0x01, | ||
313 | .step = 0x01, | ||
314 | .default_value = 0x00, | ||
315 | .flags = 0, | ||
316 | }, | ||
317 | }, | ||
318 | .get_ctrl = &hv7131r_get_ctrl, | ||
319 | .set_ctrl = &hv7131r_set_ctrl, | ||
320 | .cropcap = { | ||
321 | .bounds = { | ||
322 | .left = 0, | ||
323 | .top = 0, | ||
324 | .width = 640, | ||
325 | .height = 480, | ||
326 | }, | ||
327 | .defrect = { | ||
328 | .left = 0, | ||
329 | .top = 0, | ||
330 | .width = 640, | ||
331 | .height = 480, | ||
332 | }, | ||
333 | }, | ||
334 | .set_crop = &hv7131r_set_crop, | ||
335 | .pix_format = { | ||
336 | .width = 640, | ||
337 | .height = 480, | ||
338 | .pixelformat = V4L2_PIX_FMT_SBGGR8, | ||
339 | .priv = 8, | ||
340 | }, | ||
341 | .set_pix_format = &hv7131r_set_pix_format | ||
342 | }; | ||
343 | |||
344 | |||
345 | int sn9c102_probe_hv7131r(struct sn9c102_device* cam) | ||
346 | { | ||
347 | int devid, err; | ||
348 | |||
349 | err = sn9c102_write_const_regs(cam, {0x09, 0x01}, {0x44, 0x02}, | ||
350 | {0x34, 0x01}, {0x20, 0x17}, | ||
351 | {0x34, 0x01}, {0x46, 0x01}); | ||
352 | |||
353 | if (err) | ||
354 | return -EIO; | ||
355 | |||
356 | devid = sn9c102_i2c_try_read(cam, &hv7131r, 0x00); | ||
357 | if (devid < 0) | ||
358 | return -EIO; | ||
359 | |||
360 | if (devid != 0x02) | ||
361 | return -ENODEV; | ||
362 | |||
363 | sn9c102_attach_sensor(cam, &hv7131r); | ||
364 | |||
365 | return 0; | ||
366 | } | ||
diff --git a/drivers/media/video/sn9c102/sn9c102_mi0343.c b/drivers/media/video/sn9c102/sn9c102_mi0343.c index a33d1bc10f90..9200845d011b 100644 --- a/drivers/media/video/sn9c102/sn9c102_mi0343.c +++ b/drivers/media/video/sn9c102/sn9c102_mi0343.c | |||
@@ -22,36 +22,30 @@ | |||
22 | #include "sn9c102_sensor.h" | 22 | #include "sn9c102_sensor.h" |
23 | 23 | ||
24 | 24 | ||
25 | static struct sn9c102_sensor mi0343; | ||
26 | static u8 mi0343_i2c_data[5+1]; | ||
27 | |||
28 | |||
29 | static int mi0343_init(struct sn9c102_device* cam) | 25 | static int mi0343_init(struct sn9c102_device* cam) |
30 | { | 26 | { |
27 | struct sn9c102_sensor* s = sn9c102_get_sensor(cam); | ||
31 | int err = 0; | 28 | int err = 0; |
32 | 29 | ||
33 | err += sn9c102_write_reg(cam, 0x00, 0x10); | 30 | err = sn9c102_write_const_regs(cam, {0x00, 0x10}, {0x00, 0x11}, |
34 | err += sn9c102_write_reg(cam, 0x00, 0x11); | 31 | {0x0a, 0x14}, {0x40, 0x01}, |
35 | err += sn9c102_write_reg(cam, 0x0a, 0x14); | 32 | {0x20, 0x17}, {0x07, 0x18}, |
36 | err += sn9c102_write_reg(cam, 0x40, 0x01); | 33 | {0xa0, 0x19}); |
37 | err += sn9c102_write_reg(cam, 0x20, 0x17); | 34 | |
38 | err += sn9c102_write_reg(cam, 0x07, 0x18); | 35 | err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, 0x0d, |
39 | err += sn9c102_write_reg(cam, 0xa0, 0x19); | 36 | 0x00, 0x01, 0, 0); |
40 | 37 | err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, 0x0d, | |
41 | err += sn9c102_i2c_try_raw_write(cam, &mi0343, 4, mi0343.i2c_slave_id, | 38 | 0x00, 0x00, 0, 0); |
42 | 0x0d, 0x00, 0x01, 0, 0); | 39 | err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, 0x03, |
43 | err += sn9c102_i2c_try_raw_write(cam, &mi0343, 4, mi0343.i2c_slave_id, | 40 | 0x01, 0xe1, 0, 0); |
44 | 0x0d, 0x00, 0x00, 0, 0); | 41 | err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, 0x04, |
45 | err += sn9c102_i2c_try_raw_write(cam, &mi0343, 4, mi0343.i2c_slave_id, | 42 | 0x02, 0x81, 0, 0); |
46 | 0x03, 0x01, 0xe1, 0, 0); | 43 | err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, 0x05, |
47 | err += sn9c102_i2c_try_raw_write(cam, &mi0343, 4, mi0343.i2c_slave_id, | 44 | 0x00, 0x17, 0, 0); |
48 | 0x04, 0x02, 0x81, 0, 0); | 45 | err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, 0x06, |
49 | err += sn9c102_i2c_try_raw_write(cam, &mi0343, 4, mi0343.i2c_slave_id, | 46 | 0x00, 0x11, 0, 0); |
50 | 0x05, 0x00, 0x17, 0, 0); | 47 | err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, 0x62, |
51 | err += sn9c102_i2c_try_raw_write(cam, &mi0343, 4, mi0343.i2c_slave_id, | 48 | 0x04, 0x9a, 0, 0); |
52 | 0x06, 0x00, 0x11, 0, 0); | ||
53 | err += sn9c102_i2c_try_raw_write(cam, &mi0343, 4, mi0343.i2c_slave_id, | ||
54 | 0x62, 0x04, 0x9a, 0, 0); | ||
55 | 49 | ||
56 | return err; | 50 | return err; |
57 | } | 51 | } |
@@ -60,43 +54,46 @@ static int mi0343_init(struct sn9c102_device* cam) | |||
60 | static int mi0343_get_ctrl(struct sn9c102_device* cam, | 54 | static int mi0343_get_ctrl(struct sn9c102_device* cam, |
61 | struct v4l2_control* ctrl) | 55 | struct v4l2_control* ctrl) |
62 | { | 56 | { |
57 | struct sn9c102_sensor* s = sn9c102_get_sensor(cam); | ||
58 | u8 data[5+1]; | ||
59 | |||
63 | switch (ctrl->id) { | 60 | switch (ctrl->id) { |
64 | case V4L2_CID_EXPOSURE: | 61 | case V4L2_CID_EXPOSURE: |
65 | if (sn9c102_i2c_try_raw_read(cam, &mi0343, mi0343.i2c_slave_id, | 62 | if (sn9c102_i2c_try_raw_read(cam, s, s->i2c_slave_id, 0x09, |
66 | 0x09, 2+1, mi0343_i2c_data) < 0) | 63 | 2+1, data) < 0) |
67 | return -EIO; | 64 | return -EIO; |
68 | ctrl->value = mi0343_i2c_data[2]; | 65 | ctrl->value = data[2]; |
69 | return 0; | 66 | return 0; |
70 | case V4L2_CID_GAIN: | 67 | case V4L2_CID_GAIN: |
71 | if (sn9c102_i2c_try_raw_read(cam, &mi0343, mi0343.i2c_slave_id, | 68 | if (sn9c102_i2c_try_raw_read(cam, s, s->i2c_slave_id, 0x35, |
72 | 0x35, 2+1, mi0343_i2c_data) < 0) | 69 | 2+1, data) < 0) |
73 | return -EIO; | 70 | return -EIO; |
74 | break; | 71 | break; |
75 | case V4L2_CID_HFLIP: | 72 | case V4L2_CID_HFLIP: |
76 | if (sn9c102_i2c_try_raw_read(cam, &mi0343, mi0343.i2c_slave_id, | 73 | if (sn9c102_i2c_try_raw_read(cam, s, s->i2c_slave_id, 0x20, |
77 | 0x20, 2+1, mi0343_i2c_data) < 0) | 74 | 2+1, data) < 0) |
78 | return -EIO; | 75 | return -EIO; |
79 | ctrl->value = mi0343_i2c_data[3] & 0x20 ? 1 : 0; | 76 | ctrl->value = data[3] & 0x20 ? 1 : 0; |
80 | return 0; | 77 | return 0; |
81 | case V4L2_CID_VFLIP: | 78 | case V4L2_CID_VFLIP: |
82 | if (sn9c102_i2c_try_raw_read(cam, &mi0343, mi0343.i2c_slave_id, | 79 | if (sn9c102_i2c_try_raw_read(cam, s, s->i2c_slave_id, 0x20, |
83 | 0x20, 2+1, mi0343_i2c_data) < 0) | 80 | 2+1, data) < 0) |
84 | return -EIO; | 81 | return -EIO; |
85 | ctrl->value = mi0343_i2c_data[3] & 0x80 ? 1 : 0; | 82 | ctrl->value = data[3] & 0x80 ? 1 : 0; |
86 | return 0; | 83 | return 0; |
87 | case V4L2_CID_RED_BALANCE: | 84 | case V4L2_CID_RED_BALANCE: |
88 | if (sn9c102_i2c_try_raw_read(cam, &mi0343, mi0343.i2c_slave_id, | 85 | if (sn9c102_i2c_try_raw_read(cam, s, s->i2c_slave_id, 0x2d, |
89 | 0x2d, 2+1, mi0343_i2c_data) < 0) | 86 | 2+1, data) < 0) |
90 | return -EIO; | 87 | return -EIO; |
91 | break; | 88 | break; |
92 | case V4L2_CID_BLUE_BALANCE: | 89 | case V4L2_CID_BLUE_BALANCE: |
93 | if (sn9c102_i2c_try_raw_read(cam, &mi0343, mi0343.i2c_slave_id, | 90 | if (sn9c102_i2c_try_raw_read(cam, s, s->i2c_slave_id, 0x2c, |
94 | 0x2c, 2+1, mi0343_i2c_data) < 0) | 91 | 2+1, data) < 0) |
95 | return -EIO; | 92 | return -EIO; |
96 | break; | 93 | break; |
97 | case SN9C102_V4L2_CID_GREEN_BALANCE: | 94 | case SN9C102_V4L2_CID_GREEN_BALANCE: |
98 | if (sn9c102_i2c_try_raw_read(cam, &mi0343, mi0343.i2c_slave_id, | 95 | if (sn9c102_i2c_try_raw_read(cam, s, s->i2c_slave_id, 0x2e, |
99 | 0x2e, 2+1, mi0343_i2c_data) < 0) | 96 | 2+1, data) < 0) |
100 | return -EIO; | 97 | return -EIO; |
101 | break; | 98 | break; |
102 | default: | 99 | default: |
@@ -108,7 +105,7 @@ static int mi0343_get_ctrl(struct sn9c102_device* cam, | |||
108 | case V4L2_CID_RED_BALANCE: | 105 | case V4L2_CID_RED_BALANCE: |
109 | case V4L2_CID_BLUE_BALANCE: | 106 | case V4L2_CID_BLUE_BALANCE: |
110 | case SN9C102_V4L2_CID_GREEN_BALANCE: | 107 | case SN9C102_V4L2_CID_GREEN_BALANCE: |
111 | ctrl->value = mi0343_i2c_data[3] | (mi0343_i2c_data[2] << 8); | 108 | ctrl->value = data[3] | (data[2] << 8); |
112 | if (ctrl->value >= 0x10 && ctrl->value <= 0x3f) | 109 | if (ctrl->value >= 0x10 && ctrl->value <= 0x3f) |
113 | ctrl->value -= 0x10; | 110 | ctrl->value -= 0x10; |
114 | else if (ctrl->value >= 0x60 && ctrl->value <= 0x7f) | 111 | else if (ctrl->value >= 0x60 && ctrl->value <= 0x7f) |
@@ -124,6 +121,7 @@ static int mi0343_get_ctrl(struct sn9c102_device* cam, | |||
124 | static int mi0343_set_ctrl(struct sn9c102_device* cam, | 121 | static int mi0343_set_ctrl(struct sn9c102_device* cam, |
125 | const struct v4l2_control* ctrl) | 122 | const struct v4l2_control* ctrl) |
126 | { | 123 | { |
124 | struct sn9c102_sensor* s = sn9c102_get_sensor(cam); | ||
127 | u16 reg = 0; | 125 | u16 reg = 0; |
128 | int err = 0; | 126 | int err = 0; |
129 | 127 | ||
@@ -143,50 +141,42 @@ static int mi0343_set_ctrl(struct sn9c102_device* cam, | |||
143 | 141 | ||
144 | switch (ctrl->id) { | 142 | switch (ctrl->id) { |
145 | case V4L2_CID_EXPOSURE: | 143 | case V4L2_CID_EXPOSURE: |
146 | err += sn9c102_i2c_try_raw_write(cam, &mi0343, 4, | 144 | err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, |
147 | mi0343.i2c_slave_id, | ||
148 | 0x09, ctrl->value, 0x00, | 145 | 0x09, ctrl->value, 0x00, |
149 | 0, 0); | 146 | 0, 0); |
150 | break; | 147 | break; |
151 | case V4L2_CID_GAIN: | 148 | case V4L2_CID_GAIN: |
152 | err += sn9c102_i2c_try_raw_write(cam, &mi0343, 4, | 149 | err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, |
153 | mi0343.i2c_slave_id, | ||
154 | 0x35, reg >> 8, reg & 0xff, | 150 | 0x35, reg >> 8, reg & 0xff, |
155 | 0, 0); | 151 | 0, 0); |
156 | break; | 152 | break; |
157 | case V4L2_CID_HFLIP: | 153 | case V4L2_CID_HFLIP: |
158 | err += sn9c102_i2c_try_raw_write(cam, &mi0343, 4, | 154 | err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, |
159 | mi0343.i2c_slave_id, | ||
160 | 0x20, ctrl->value ? 0x40:0x00, | 155 | 0x20, ctrl->value ? 0x40:0x00, |
161 | ctrl->value ? 0x20:0x00, | 156 | ctrl->value ? 0x20:0x00, |
162 | 0, 0); | 157 | 0, 0); |
163 | break; | 158 | break; |
164 | case V4L2_CID_VFLIP: | 159 | case V4L2_CID_VFLIP: |
165 | err += sn9c102_i2c_try_raw_write(cam, &mi0343, 4, | 160 | err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, |
166 | mi0343.i2c_slave_id, | ||
167 | 0x20, ctrl->value ? 0x80:0x00, | 161 | 0x20, ctrl->value ? 0x80:0x00, |
168 | ctrl->value ? 0x80:0x00, | 162 | ctrl->value ? 0x80:0x00, |
169 | 0, 0); | 163 | 0, 0); |
170 | break; | 164 | break; |
171 | case V4L2_CID_RED_BALANCE: | 165 | case V4L2_CID_RED_BALANCE: |
172 | err += sn9c102_i2c_try_raw_write(cam, &mi0343, 4, | 166 | err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, |
173 | mi0343.i2c_slave_id, | ||
174 | 0x2d, reg >> 8, reg & 0xff, | 167 | 0x2d, reg >> 8, reg & 0xff, |
175 | 0, 0); | 168 | 0, 0); |
176 | break; | 169 | break; |
177 | case V4L2_CID_BLUE_BALANCE: | 170 | case V4L2_CID_BLUE_BALANCE: |
178 | err += sn9c102_i2c_try_raw_write(cam, &mi0343, 4, | 171 | err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, |
179 | mi0343.i2c_slave_id, | ||
180 | 0x2c, reg >> 8, reg & 0xff, | 172 | 0x2c, reg >> 8, reg & 0xff, |
181 | 0, 0); | 173 | 0, 0); |
182 | break; | 174 | break; |
183 | case SN9C102_V4L2_CID_GREEN_BALANCE: | 175 | case SN9C102_V4L2_CID_GREEN_BALANCE: |
184 | err += sn9c102_i2c_try_raw_write(cam, &mi0343, 4, | 176 | err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, |
185 | mi0343.i2c_slave_id, | ||
186 | 0x2b, reg >> 8, reg & 0xff, | 177 | 0x2b, reg >> 8, reg & 0xff, |
187 | 0, 0); | 178 | 0, 0); |
188 | err += sn9c102_i2c_try_raw_write(cam, &mi0343, 4, | 179 | err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, |
189 | mi0343.i2c_slave_id, | ||
190 | 0x2e, reg >> 8, reg & 0xff, | 180 | 0x2e, reg >> 8, reg & 0xff, |
191 | 0, 0); | 181 | 0, 0); |
192 | break; | 182 | break; |
@@ -216,16 +206,15 @@ static int mi0343_set_crop(struct sn9c102_device* cam, | |||
216 | static int mi0343_set_pix_format(struct sn9c102_device* cam, | 206 | static int mi0343_set_pix_format(struct sn9c102_device* cam, |
217 | const struct v4l2_pix_format* pix) | 207 | const struct v4l2_pix_format* pix) |
218 | { | 208 | { |
209 | struct sn9c102_sensor* s = sn9c102_get_sensor(cam); | ||
219 | int err = 0; | 210 | int err = 0; |
220 | 211 | ||
221 | if (pix->pixelformat == V4L2_PIX_FMT_SN9C10X) { | 212 | if (pix->pixelformat == V4L2_PIX_FMT_SN9C10X) { |
222 | err += sn9c102_i2c_try_raw_write(cam, &mi0343, 4, | 213 | err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, |
223 | mi0343.i2c_slave_id, | ||
224 | 0x0a, 0x00, 0x03, 0, 0); | 214 | 0x0a, 0x00, 0x03, 0, 0); |
225 | err += sn9c102_write_reg(cam, 0x20, 0x19); | 215 | err += sn9c102_write_reg(cam, 0x20, 0x19); |
226 | } else { | 216 | } else { |
227 | err += sn9c102_i2c_try_raw_write(cam, &mi0343, 4, | 217 | err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, |
228 | mi0343.i2c_slave_id, | ||
229 | 0x0a, 0x00, 0x05, 0, 0); | 218 | 0x0a, 0x00, 0x05, 0, 0); |
230 | err += sn9c102_write_reg(cam, 0xa0, 0x19); | 219 | err += sn9c102_write_reg(cam, 0xa0, 0x19); |
231 | } | 220 | } |
@@ -237,7 +226,7 @@ static int mi0343_set_pix_format(struct sn9c102_device* cam, | |||
237 | static struct sn9c102_sensor mi0343 = { | 226 | static struct sn9c102_sensor mi0343 = { |
238 | .name = "MI-0343", | 227 | .name = "MI-0343", |
239 | .maintainer = "Luca Risolia <luca.risolia@studio.unibo.it>", | 228 | .maintainer = "Luca Risolia <luca.risolia@studio.unibo.it>", |
240 | .supported_bridge = BRIDGE_SN9C101 | BRIDGE_SN9C102 | BRIDGE_SN9C103, | 229 | .supported_bridge = BRIDGE_SN9C101 | BRIDGE_SN9C102, |
241 | .frequency = SN9C102_I2C_100KHZ, | 230 | .frequency = SN9C102_I2C_100KHZ, |
242 | .interface = SN9C102_I2C_2WIRES, | 231 | .interface = SN9C102_I2C_2WIRES, |
243 | .i2c_slave_id = 0x5d, | 232 | .i2c_slave_id = 0x5d, |
@@ -343,19 +332,20 @@ static struct sn9c102_sensor mi0343 = { | |||
343 | 332 | ||
344 | int sn9c102_probe_mi0343(struct sn9c102_device* cam) | 333 | int sn9c102_probe_mi0343(struct sn9c102_device* cam) |
345 | { | 334 | { |
335 | u8 data[5+1]; | ||
346 | int err = 0; | 336 | int err = 0; |
347 | 337 | ||
348 | err += sn9c102_write_reg(cam, 0x01, 0x01); | 338 | err = sn9c102_write_const_regs(cam, {0x01, 0x01}, {0x00, 0x01}, |
349 | err += sn9c102_write_reg(cam, 0x00, 0x01); | 339 | {0x28, 0x17}); |
350 | err += sn9c102_write_reg(cam, 0x28, 0x17); | 340 | |
351 | if (err) | 341 | if (err) |
352 | return -EIO; | 342 | return -EIO; |
353 | 343 | ||
354 | if (sn9c102_i2c_try_raw_read(cam, &mi0343, mi0343.i2c_slave_id, 0x00, | 344 | if (sn9c102_i2c_try_raw_read(cam, &mi0343, mi0343.i2c_slave_id, 0x00, |
355 | 2, mi0343_i2c_data) < 0) | 345 | 2, data) < 0) |
356 | return -EIO; | 346 | return -EIO; |
357 | 347 | ||
358 | if (mi0343_i2c_data[4] != 0x32 && mi0343_i2c_data[3] != 0xe3) | 348 | if (data[4] != 0x32 || data[3] != 0xe3) |
359 | return -ENODEV; | 349 | return -ENODEV; |
360 | 350 | ||
361 | sn9c102_attach_sensor(cam, &mi0343); | 351 | sn9c102_attach_sensor(cam, &mi0343); |
diff --git a/drivers/media/video/sn9c102/sn9c102_mi0360.c b/drivers/media/video/sn9c102/sn9c102_mi0360.c new file mode 100644 index 000000000000..64698acb0b15 --- /dev/null +++ b/drivers/media/video/sn9c102/sn9c102_mi0360.c | |||
@@ -0,0 +1,338 @@ | |||
1 | /*************************************************************************** | ||
2 | * Plug-in for MI-0360 image sensor connected to the SN9C1xx PC Camera * | ||
3 | * Controllers * | ||
4 | * * | ||
5 | * Copyright (C) 2007 by Luca Risolia <luca.risolia@studio.unibo.it> * | ||
6 | * * | ||
7 | * This program is free software; you can redistribute it and/or modify * | ||
8 | * it under the terms of the GNU General Public License as published by * | ||
9 | * the Free Software Foundation; either version 2 of the License, or * | ||
10 | * (at your option) any later version. * | ||
11 | * * | ||
12 | * This program is distributed in the hope that it will be useful, * | ||
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of * | ||
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * | ||
15 | * GNU General Public License for more details. * | ||
16 | * * | ||
17 | * You should have received a copy of the GNU General Public License * | ||
18 | * along with this program; if not, write to the Free Software * | ||
19 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * | ||
20 | ***************************************************************************/ | ||
21 | |||
22 | #include "sn9c102_sensor.h" | ||
23 | |||
24 | |||
25 | static int mi0360_init(struct sn9c102_device* cam) | ||
26 | { | ||
27 | struct sn9c102_sensor* s = sn9c102_get_sensor(cam); | ||
28 | int err = 0; | ||
29 | |||
30 | err = sn9c102_write_const_regs(cam, {0x00, 0x10}, {0x00, 0x11}, | ||
31 | {0x0a, 0x14}, {0x40, 0x01}, | ||
32 | {0x20, 0x17}, {0x07, 0x18}, | ||
33 | {0xa0, 0x19}, {0x02, 0x1c}, | ||
34 | {0x03, 0x1d}, {0x0f, 0x1e}, | ||
35 | {0x0c, 0x1f}, {0x00, 0x20}, | ||
36 | {0x10, 0x21}, {0x20, 0x22}, | ||
37 | {0x30, 0x23}, {0x40, 0x24}, | ||
38 | {0x50, 0x25}, {0x60, 0x26}, | ||
39 | {0x70, 0x27}, {0x80, 0x28}, | ||
40 | {0x90, 0x29}, {0xa0, 0x2a}, | ||
41 | {0xb0, 0x2b}, {0xc0, 0x2c}, | ||
42 | {0xd0, 0x2d}, {0xe0, 0x2e}, | ||
43 | {0xf0, 0x2f}, {0xff, 0x30}); | ||
44 | |||
45 | err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, 0x0d, | ||
46 | 0x00, 0x01, 0, 0); | ||
47 | err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, 0x0d, | ||
48 | 0x00, 0x00, 0, 0); | ||
49 | err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, 0x03, | ||
50 | 0x01, 0xe1, 0, 0); | ||
51 | err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, 0x04, | ||
52 | 0x02, 0x81, 0, 0); | ||
53 | err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, 0x05, | ||
54 | 0x00, 0x17, 0, 0); | ||
55 | err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, 0x06, | ||
56 | 0x00, 0x11, 0, 0); | ||
57 | err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, 0x62, | ||
58 | 0x04, 0x9a, 0, 0); | ||
59 | |||
60 | return err; | ||
61 | } | ||
62 | |||
63 | |||
64 | static int mi0360_get_ctrl(struct sn9c102_device* cam, | ||
65 | struct v4l2_control* ctrl) | ||
66 | { | ||
67 | struct sn9c102_sensor* s = sn9c102_get_sensor(cam); | ||
68 | u8 data[5+1]; | ||
69 | |||
70 | switch (ctrl->id) { | ||
71 | case V4L2_CID_EXPOSURE: | ||
72 | if (sn9c102_i2c_try_raw_read(cam, s, s->i2c_slave_id, 0x09, | ||
73 | 2+1, data) < 0) | ||
74 | return -EIO; | ||
75 | ctrl->value = data[2]; | ||
76 | return 0; | ||
77 | case V4L2_CID_GAIN: | ||
78 | if (sn9c102_i2c_try_raw_read(cam, s, s->i2c_slave_id, 0x35, | ||
79 | 2+1, data) < 0) | ||
80 | return -EIO; | ||
81 | ctrl->value = data[3]; | ||
82 | return 0; | ||
83 | case V4L2_CID_RED_BALANCE: | ||
84 | if (sn9c102_i2c_try_raw_read(cam, s, s->i2c_slave_id, 0x2c, | ||
85 | 2+1, data) < 0) | ||
86 | return -EIO; | ||
87 | ctrl->value = data[3]; | ||
88 | return 0; | ||
89 | case V4L2_CID_BLUE_BALANCE: | ||
90 | if (sn9c102_i2c_try_raw_read(cam, s, s->i2c_slave_id, 0x2d, | ||
91 | 2+1, data) < 0) | ||
92 | return -EIO; | ||
93 | ctrl->value = data[3]; | ||
94 | return 0; | ||
95 | case SN9C102_V4L2_CID_GREEN_BALANCE: | ||
96 | if (sn9c102_i2c_try_raw_read(cam, s, s->i2c_slave_id, 0x2e, | ||
97 | 2+1, data) < 0) | ||
98 | return -EIO; | ||
99 | ctrl->value = data[3]; | ||
100 | return 0; | ||
101 | case V4L2_CID_HFLIP: | ||
102 | if (sn9c102_i2c_try_raw_read(cam, s, s->i2c_slave_id, 0x20, | ||
103 | 2+1, data) < 0) | ||
104 | return -EIO; | ||
105 | ctrl->value = data[3] & 0x20 ? 1 : 0; | ||
106 | return 0; | ||
107 | case V4L2_CID_VFLIP: | ||
108 | if (sn9c102_i2c_try_raw_read(cam, s, s->i2c_slave_id, 0x20, | ||
109 | 2+1, data) < 0) | ||
110 | return -EIO; | ||
111 | ctrl->value = data[3] & 0x80 ? 1 : 0; | ||
112 | return 0; | ||
113 | default: | ||
114 | return -EINVAL; | ||
115 | } | ||
116 | |||
117 | return 0; | ||
118 | } | ||
119 | |||
120 | |||
121 | static int mi0360_set_ctrl(struct sn9c102_device* cam, | ||
122 | const struct v4l2_control* ctrl) | ||
123 | { | ||
124 | struct sn9c102_sensor* s = sn9c102_get_sensor(cam); | ||
125 | int err = 0; | ||
126 | |||
127 | switch (ctrl->id) { | ||
128 | case V4L2_CID_EXPOSURE: | ||
129 | err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, | ||
130 | 0x09, ctrl->value, 0x00, | ||
131 | 0, 0); | ||
132 | break; | ||
133 | case V4L2_CID_GAIN: | ||
134 | err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, | ||
135 | 0x35, 0x03, ctrl->value, | ||
136 | 0, 0); | ||
137 | break; | ||
138 | case V4L2_CID_RED_BALANCE: | ||
139 | err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, | ||
140 | 0x2c, 0x03, ctrl->value, | ||
141 | 0, 0); | ||
142 | break; | ||
143 | case V4L2_CID_BLUE_BALANCE: | ||
144 | err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, | ||
145 | 0x2d, 0x03, ctrl->value, | ||
146 | 0, 0); | ||
147 | break; | ||
148 | case SN9C102_V4L2_CID_GREEN_BALANCE: | ||
149 | err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, | ||
150 | 0x2b, 0x03, ctrl->value, | ||
151 | 0, 0); | ||
152 | err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, | ||
153 | 0x2e, 0x03, ctrl->value, | ||
154 | 0, 0); | ||
155 | break; | ||
156 | case V4L2_CID_HFLIP: | ||
157 | err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, | ||
158 | 0x20, ctrl->value ? 0x40:0x00, | ||
159 | ctrl->value ? 0x20:0x00, | ||
160 | 0, 0); | ||
161 | break; | ||
162 | case V4L2_CID_VFLIP: | ||
163 | err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, | ||
164 | 0x20, ctrl->value ? 0x80:0x00, | ||
165 | ctrl->value ? 0x80:0x00, | ||
166 | 0, 0); | ||
167 | break; | ||
168 | default: | ||
169 | return -EINVAL; | ||
170 | } | ||
171 | |||
172 | return err ? -EIO : 0; | ||
173 | } | ||
174 | |||
175 | |||
176 | static int mi0360_set_crop(struct sn9c102_device* cam, | ||
177 | const struct v4l2_rect* rect) | ||
178 | { | ||
179 | struct sn9c102_sensor* s = sn9c102_get_sensor(cam); | ||
180 | int err = 0; | ||
181 | u8 h_start = (u8)(rect->left - s->cropcap.bounds.left) + 0, | ||
182 | v_start = (u8)(rect->top - s->cropcap.bounds.top) + 1; | ||
183 | |||
184 | err += sn9c102_write_reg(cam, h_start, 0x12); | ||
185 | err += sn9c102_write_reg(cam, v_start, 0x13); | ||
186 | |||
187 | return err; | ||
188 | } | ||
189 | |||
190 | |||
191 | static int mi0360_set_pix_format(struct sn9c102_device* cam, | ||
192 | const struct v4l2_pix_format* pix) | ||
193 | { | ||
194 | struct sn9c102_sensor* s = sn9c102_get_sensor(cam); | ||
195 | int err = 0; | ||
196 | |||
197 | if (pix->pixelformat == V4L2_PIX_FMT_SN9C10X) { | ||
198 | err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, | ||
199 | 0x0a, 0x00, 0x02, 0, 0); | ||
200 | err += sn9c102_write_reg(cam, 0x20, 0x19); | ||
201 | } else { | ||
202 | err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, | ||
203 | 0x0a, 0x00, 0x05, 0, 0); | ||
204 | err += sn9c102_write_reg(cam, 0x60, 0x19); | ||
205 | } | ||
206 | |||
207 | return err; | ||
208 | } | ||
209 | |||
210 | |||
211 | static struct sn9c102_sensor mi0360 = { | ||
212 | .name = "MI-0360", | ||
213 | .maintainer = "Luca Risolia <luca.risolia@studio.unibo.it>", | ||
214 | .supported_bridge = BRIDGE_SN9C103, | ||
215 | .frequency = SN9C102_I2C_100KHZ, | ||
216 | .interface = SN9C102_I2C_2WIRES, | ||
217 | .i2c_slave_id = 0x5d, | ||
218 | .init = &mi0360_init, | ||
219 | .qctrl = { | ||
220 | { | ||
221 | .id = V4L2_CID_EXPOSURE, | ||
222 | .type = V4L2_CTRL_TYPE_INTEGER, | ||
223 | .name = "exposure", | ||
224 | .minimum = 0x00, | ||
225 | .maximum = 0x0f, | ||
226 | .step = 0x01, | ||
227 | .default_value = 0x05, | ||
228 | .flags = 0, | ||
229 | }, | ||
230 | { | ||
231 | .id = V4L2_CID_GAIN, | ||
232 | .type = V4L2_CTRL_TYPE_INTEGER, | ||
233 | .name = "global gain", | ||
234 | .minimum = 0x00, | ||
235 | .maximum = 0x7f, | ||
236 | .step = 0x01, | ||
237 | .default_value = 0x25, | ||
238 | .flags = 0, | ||
239 | }, | ||
240 | { | ||
241 | .id = V4L2_CID_HFLIP, | ||
242 | .type = V4L2_CTRL_TYPE_BOOLEAN, | ||
243 | .name = "horizontal mirror", | ||
244 | .minimum = 0, | ||
245 | .maximum = 1, | ||
246 | .step = 1, | ||
247 | .default_value = 0, | ||
248 | .flags = 0, | ||
249 | }, | ||
250 | { | ||
251 | .id = V4L2_CID_VFLIP, | ||
252 | .type = V4L2_CTRL_TYPE_BOOLEAN, | ||
253 | .name = "vertical mirror", | ||
254 | .minimum = 0, | ||
255 | .maximum = 1, | ||
256 | .step = 1, | ||
257 | .default_value = 0, | ||
258 | .flags = 0, | ||
259 | }, | ||
260 | { | ||
261 | .id = V4L2_CID_BLUE_BALANCE, | ||
262 | .type = V4L2_CTRL_TYPE_INTEGER, | ||
263 | .name = "blue balance", | ||
264 | .minimum = 0x00, | ||
265 | .maximum = 0x7f, | ||
266 | .step = 0x01, | ||
267 | .default_value = 0x0f, | ||
268 | .flags = 0, | ||
269 | }, | ||
270 | { | ||
271 | .id = V4L2_CID_RED_BALANCE, | ||
272 | .type = V4L2_CTRL_TYPE_INTEGER, | ||
273 | .name = "red balance", | ||
274 | .minimum = 0x00, | ||
275 | .maximum = 0x7f, | ||
276 | .step = 0x01, | ||
277 | .default_value = 0x32, | ||
278 | .flags = 0, | ||
279 | }, | ||
280 | { | ||
281 | .id = SN9C102_V4L2_CID_GREEN_BALANCE, | ||
282 | .type = V4L2_CTRL_TYPE_INTEGER, | ||
283 | .name = "green balance", | ||
284 | .minimum = 0x00, | ||
285 | .maximum = 0x7f, | ||
286 | .step = 0x01, | ||
287 | .default_value = 0x25, | ||
288 | .flags = 0, | ||
289 | }, | ||
290 | }, | ||
291 | .get_ctrl = &mi0360_get_ctrl, | ||
292 | .set_ctrl = &mi0360_set_ctrl, | ||
293 | .cropcap = { | ||
294 | .bounds = { | ||
295 | .left = 0, | ||
296 | .top = 0, | ||
297 | .width = 640, | ||
298 | .height = 480, | ||
299 | }, | ||
300 | .defrect = { | ||
301 | .left = 0, | ||
302 | .top = 0, | ||
303 | .width = 640, | ||
304 | .height = 480, | ||
305 | }, | ||
306 | }, | ||
307 | .set_crop = &mi0360_set_crop, | ||
308 | .pix_format = { | ||
309 | .width = 640, | ||
310 | .height = 480, | ||
311 | .pixelformat = V4L2_PIX_FMT_SBGGR8, | ||
312 | .priv = 8, | ||
313 | }, | ||
314 | .set_pix_format = &mi0360_set_pix_format | ||
315 | }; | ||
316 | |||
317 | |||
318 | int sn9c102_probe_mi0360(struct sn9c102_device* cam) | ||
319 | { | ||
320 | u8 data[5+1]; | ||
321 | int err; | ||
322 | |||
323 | err = sn9c102_write_const_regs(cam, {0x01, 0x01}, {0x00, 0x01}, | ||
324 | {0x28, 0x17}); | ||
325 | if (err) | ||
326 | return -EIO; | ||
327 | |||
328 | if (sn9c102_i2c_try_raw_read(cam, &mi0360, mi0360.i2c_slave_id, 0x00, | ||
329 | 2+1, data) < 0) | ||
330 | return -EIO; | ||
331 | |||
332 | if (data[2] != 0x82 || data[3] != 0x43) | ||
333 | return -ENODEV; | ||
334 | |||
335 | sn9c102_attach_sensor(cam, &mi0360); | ||
336 | |||
337 | return 0; | ||
338 | } | ||
diff --git a/drivers/media/video/sn9c102/sn9c102_ov7630.c b/drivers/media/video/sn9c102/sn9c102_ov7630.c index 7df09ff38e63..31b6080b0615 100644 --- a/drivers/media/video/sn9c102/sn9c102_ov7630.c +++ b/drivers/media/video/sn9c102/sn9c102_ov7630.c | |||
@@ -22,9 +22,6 @@ | |||
22 | #include "sn9c102_sensor.h" | 22 | #include "sn9c102_sensor.h" |
23 | 23 | ||
24 | 24 | ||
25 | static struct sn9c102_sensor ov7630; | ||
26 | |||
27 | |||
28 | static int ov7630_init(struct sn9c102_device* cam) | 25 | static int ov7630_init(struct sn9c102_device* cam) |
29 | { | 26 | { |
30 | int err = 0; | 27 | int err = 0; |
@@ -32,21 +29,20 @@ static int ov7630_init(struct sn9c102_device* cam) | |||
32 | switch (sn9c102_get_bridge(cam)) { | 29 | switch (sn9c102_get_bridge(cam)) { |
33 | case BRIDGE_SN9C101: | 30 | case BRIDGE_SN9C101: |
34 | case BRIDGE_SN9C102: | 31 | case BRIDGE_SN9C102: |
35 | err += sn9c102_write_reg(cam, 0x00, 0x14); | 32 | err = sn9c102_write_const_regs(cam, {0x00, 0x14}, |
36 | err += sn9c102_write_reg(cam, 0x60, 0x17); | 33 | {0x60, 0x17}, {0x0f, 0x18}, |
37 | err += sn9c102_write_reg(cam, 0x0f, 0x18); | 34 | {0x50, 0x19}); |
38 | err += sn9c102_write_reg(cam, 0x50, 0x19); | ||
39 | 35 | ||
40 | err += sn9c102_i2c_write(cam, 0x12, 0x8d); | 36 | err += sn9c102_i2c_write(cam, 0x12, 0x8d); |
41 | err += sn9c102_i2c_write(cam, 0x12, 0x0d); | 37 | err += sn9c102_i2c_write(cam, 0x12, 0x0d); |
42 | err += sn9c102_i2c_write(cam, 0x11, 0x00); | 38 | err += sn9c102_i2c_write(cam, 0x11, 0x00); |
43 | err += sn9c102_i2c_write(cam, 0x15, 0x34); | 39 | err += sn9c102_i2c_write(cam, 0x15, 0x35); |
44 | err += sn9c102_i2c_write(cam, 0x16, 0x03); | 40 | err += sn9c102_i2c_write(cam, 0x16, 0x03); |
45 | err += sn9c102_i2c_write(cam, 0x17, 0x1c); | 41 | err += sn9c102_i2c_write(cam, 0x17, 0x1c); |
46 | err += sn9c102_i2c_write(cam, 0x18, 0xbd); | 42 | err += sn9c102_i2c_write(cam, 0x18, 0xbd); |
47 | err += sn9c102_i2c_write(cam, 0x19, 0x06); | 43 | err += sn9c102_i2c_write(cam, 0x19, 0x06); |
48 | err += sn9c102_i2c_write(cam, 0x1a, 0xf6); | 44 | err += sn9c102_i2c_write(cam, 0x1a, 0xf6); |
49 | err += sn9c102_i2c_write(cam, 0x1b, 0x04); | 45 | err += sn9c102_i2c_write(cam, 0x1b, 0x04); |
50 | err += sn9c102_i2c_write(cam, 0x20, 0x44); | 46 | err += sn9c102_i2c_write(cam, 0x20, 0x44); |
51 | err += sn9c102_i2c_write(cam, 0x23, 0xee); | 47 | err += sn9c102_i2c_write(cam, 0x23, 0xee); |
52 | err += sn9c102_i2c_write(cam, 0x26, 0xa0); | 48 | err += sn9c102_i2c_write(cam, 0x26, 0xa0); |
@@ -65,42 +61,26 @@ static int ov7630_init(struct sn9c102_device* cam) | |||
65 | err += sn9c102_i2c_write(cam, 0x71, 0x00); | 61 | err += sn9c102_i2c_write(cam, 0x71, 0x00); |
66 | err += sn9c102_i2c_write(cam, 0x74, 0x21); | 62 | err += sn9c102_i2c_write(cam, 0x74, 0x21); |
67 | err += sn9c102_i2c_write(cam, 0x7d, 0xf7); | 63 | err += sn9c102_i2c_write(cam, 0x7d, 0xf7); |
64 | |||
68 | break; | 65 | break; |
69 | case BRIDGE_SN9C103: | 66 | case BRIDGE_SN9C103: |
70 | err += sn9c102_write_reg(cam, 0x00, 0x02); | 67 | err = sn9c102_write_const_regs(cam, {0x00, 0x02}, {0x00, 0x03}, |
71 | err += sn9c102_write_reg(cam, 0x00, 0x03); | 68 | {0x1a, 0x04}, {0x20, 0x05}, |
72 | err += sn9c102_write_reg(cam, 0x1a, 0x04); | 69 | {0x20, 0x06}, {0x20, 0x07}, |
73 | err += sn9c102_write_reg(cam, 0x20, 0x05); | 70 | {0x03, 0x10}, {0x0a, 0x14}, |
74 | err += sn9c102_write_reg(cam, 0x20, 0x06); | 71 | {0x60, 0x17}, {0x0f, 0x18}, |
75 | err += sn9c102_write_reg(cam, 0x20, 0x07); | 72 | {0x50, 0x19}, {0x1d, 0x1a}, |
76 | err += sn9c102_write_reg(cam, 0x03, 0x10); | 73 | {0x10, 0x1b}, {0x02, 0x1c}, |
77 | err += sn9c102_write_reg(cam, 0x0a, 0x14); | 74 | {0x03, 0x1d}, {0x0f, 0x1e}, |
78 | err += sn9c102_write_reg(cam, 0x60, 0x17); | 75 | {0x0c, 0x1f}, {0x00, 0x20}, |
79 | err += sn9c102_write_reg(cam, 0x0f, 0x18); | 76 | {0x10, 0x21}, {0x20, 0x22}, |
80 | err += sn9c102_write_reg(cam, 0x50, 0x19); | 77 | {0x30, 0x23}, {0x40, 0x24}, |
81 | err += sn9c102_write_reg(cam, 0x1d, 0x1a); | 78 | {0x50, 0x25}, {0x60, 0x26}, |
82 | err += sn9c102_write_reg(cam, 0x10, 0x1b); | 79 | {0x70, 0x27}, {0x80, 0x28}, |
83 | err += sn9c102_write_reg(cam, 0x02, 0x1c); | 80 | {0x90, 0x29}, {0xa0, 0x2a}, |
84 | err += sn9c102_write_reg(cam, 0x03, 0x1d); | 81 | {0xb0, 0x2b}, {0xc0, 0x2c}, |
85 | err += sn9c102_write_reg(cam, 0x0f, 0x1e); | 82 | {0xd0, 0x2d}, {0xe0, 0x2e}, |
86 | err += sn9c102_write_reg(cam, 0x0c, 0x1f); | 83 | {0xf0, 0x2f}, {0xff, 0x30}); |
87 | err += sn9c102_write_reg(cam, 0x00, 0x20); | ||
88 | err += sn9c102_write_reg(cam, 0x10, 0x21); | ||
89 | err += sn9c102_write_reg(cam, 0x20, 0x22); | ||
90 | err += sn9c102_write_reg(cam, 0x30, 0x23); | ||
91 | err += sn9c102_write_reg(cam, 0x40, 0x24); | ||
92 | err += sn9c102_write_reg(cam, 0x50, 0x25); | ||
93 | err += sn9c102_write_reg(cam, 0x60, 0x26); | ||
94 | err += sn9c102_write_reg(cam, 0x70, 0x27); | ||
95 | err += sn9c102_write_reg(cam, 0x80, 0x28); | ||
96 | err += sn9c102_write_reg(cam, 0x90, 0x29); | ||
97 | err += sn9c102_write_reg(cam, 0xa0, 0x2a); | ||
98 | err += sn9c102_write_reg(cam, 0xb0, 0x2b); | ||
99 | err += sn9c102_write_reg(cam, 0xc0, 0x2c); | ||
100 | err += sn9c102_write_reg(cam, 0xd0, 0x2d); | ||
101 | err += sn9c102_write_reg(cam, 0xe0, 0x2e); | ||
102 | err += sn9c102_write_reg(cam, 0xf0, 0x2f); | ||
103 | err += sn9c102_write_reg(cam, 0xff, 0x30); | ||
104 | 84 | ||
105 | err += sn9c102_i2c_write(cam, 0x12, 0x8d); | 85 | err += sn9c102_i2c_write(cam, 0x12, 0x8d); |
106 | err += sn9c102_i2c_write(cam, 0x12, 0x0d); | 86 | err += sn9c102_i2c_write(cam, 0x12, 0x0d); |
@@ -108,23 +88,23 @@ static int ov7630_init(struct sn9c102_device* cam) | |||
108 | err += sn9c102_i2c_write(cam, 0x11, 0x01); | 88 | err += sn9c102_i2c_write(cam, 0x11, 0x01); |
109 | err += sn9c102_i2c_write(cam, 0x1b, 0x04); | 89 | err += sn9c102_i2c_write(cam, 0x1b, 0x04); |
110 | err += sn9c102_i2c_write(cam, 0x20, 0x44); | 90 | err += sn9c102_i2c_write(cam, 0x20, 0x44); |
111 | err += sn9c102_i2c_write(cam, 0x23, 0xee); | 91 | err += sn9c102_i2c_write(cam, 0x23, 0xee); |
112 | err += sn9c102_i2c_write(cam, 0x26, 0xa0); | 92 | err += sn9c102_i2c_write(cam, 0x26, 0xa0); |
113 | err += sn9c102_i2c_write(cam, 0x27, 0x9a); | 93 | err += sn9c102_i2c_write(cam, 0x27, 0x9a); |
114 | err += sn9c102_i2c_write(cam, 0x28, 0x20); | 94 | err += sn9c102_i2c_write(cam, 0x28, 0x20); |
115 | err += sn9c102_i2c_write(cam, 0x29, 0x30); | 95 | err += sn9c102_i2c_write(cam, 0x29, 0x30); |
116 | err += sn9c102_i2c_write(cam, 0x2f, 0x3d); | 96 | err += sn9c102_i2c_write(cam, 0x2f, 0x3d); |
117 | err += sn9c102_i2c_write(cam, 0x30, 0x24); | 97 | err += sn9c102_i2c_write(cam, 0x30, 0x24); |
118 | err += sn9c102_i2c_write(cam, 0x32, 0x86); | 98 | err += sn9c102_i2c_write(cam, 0x32, 0x86); |
119 | err += sn9c102_i2c_write(cam, 0x60, 0xa9); | 99 | err += sn9c102_i2c_write(cam, 0x60, 0xa9); |
120 | err += sn9c102_i2c_write(cam, 0x61, 0x42); | 100 | err += sn9c102_i2c_write(cam, 0x61, 0x42); |
121 | err += sn9c102_i2c_write(cam, 0x65, 0x00); | 101 | err += sn9c102_i2c_write(cam, 0x65, 0x00); |
122 | err += sn9c102_i2c_write(cam, 0x69, 0x38); | 102 | err += sn9c102_i2c_write(cam, 0x69, 0x38); |
123 | err += sn9c102_i2c_write(cam, 0x6f, 0x88); | 103 | err += sn9c102_i2c_write(cam, 0x6f, 0x88); |
124 | err += sn9c102_i2c_write(cam, 0x70, 0x0b); | 104 | err += sn9c102_i2c_write(cam, 0x70, 0x0b); |
125 | err += sn9c102_i2c_write(cam, 0x71, 0x00); | 105 | err += sn9c102_i2c_write(cam, 0x71, 0x00); |
126 | err += sn9c102_i2c_write(cam, 0x74, 0x21); | 106 | err += sn9c102_i2c_write(cam, 0x74, 0x21); |
127 | err += sn9c102_i2c_write(cam, 0x7d, 0xf7); | 107 | err += sn9c102_i2c_write(cam, 0x7d, 0xf7); |
128 | break; | 108 | break; |
129 | default: | 109 | default: |
130 | break; | 110 | break; |
@@ -428,15 +408,14 @@ int sn9c102_probe_ov7630(struct sn9c102_device* cam) | |||
428 | switch (sn9c102_get_bridge(cam)) { | 408 | switch (sn9c102_get_bridge(cam)) { |
429 | case BRIDGE_SN9C101: | 409 | case BRIDGE_SN9C101: |
430 | case BRIDGE_SN9C102: | 410 | case BRIDGE_SN9C102: |
431 | err += sn9c102_write_reg(cam, 0x01, 0x01); | 411 | err = sn9c102_write_const_regs(cam, {0x01, 0x01}, |
432 | err += sn9c102_write_reg(cam, 0x00, 0x01); | 412 | {0x00, 0x01}, {0x28, 0x17}); |
433 | err += sn9c102_write_reg(cam, 0x28, 0x17); | 413 | |
434 | break; | 414 | break; |
435 | case BRIDGE_SN9C103: /* do _not_ change anything! */ | 415 | case BRIDGE_SN9C103: /* do _not_ change anything! */ |
436 | err += sn9c102_write_reg(cam, 0x09, 0x01); | 416 | err = sn9c102_write_const_regs(cam, {0x09, 0x01}, |
437 | err += sn9c102_write_reg(cam, 0x42, 0x01); | 417 | {0x42, 0x01}, {0x28, 0x17}, |
438 | err += sn9c102_write_reg(cam, 0x28, 0x17); | 418 | {0x44, 0x02}); |
439 | err += sn9c102_write_reg(cam, 0x44, 0x02); | ||
440 | pid = sn9c102_i2c_try_read(cam, &ov7630, 0x0a); | 419 | pid = sn9c102_i2c_try_read(cam, &ov7630, 0x0a); |
441 | if (err || pid < 0) { /* try a different initialization */ | 420 | if (err || pid < 0) { /* try a different initialization */ |
442 | err = sn9c102_write_reg(cam, 0x01, 0x01); | 421 | err = sn9c102_write_reg(cam, 0x01, 0x01); |
diff --git a/drivers/media/video/sn9c102/sn9c102_ov7660.c b/drivers/media/video/sn9c102/sn9c102_ov7660.c index d670c24d4435..c898e948fe8d 100644 --- a/drivers/media/video/sn9c102/sn9c102_ov7660.c +++ b/drivers/media/video/sn9c102/sn9c102_ov7660.c | |||
@@ -22,160 +22,84 @@ | |||
22 | #include "sn9c102_sensor.h" | 22 | #include "sn9c102_sensor.h" |
23 | 23 | ||
24 | 24 | ||
25 | static struct sn9c102_sensor ov7660; | ||
26 | |||
27 | |||
28 | static int ov7660_init(struct sn9c102_device* cam) | 25 | static int ov7660_init(struct sn9c102_device* cam) |
29 | { | 26 | { |
30 | int err = 0; | 27 | int err = 0; |
31 | 28 | ||
32 | err += sn9c102_write_reg(cam, 0x40, 0x02); | 29 | err = sn9c102_write_const_regs(cam, {0x40, 0x02}, {0x00, 0x03}, |
33 | err += sn9c102_write_reg(cam, 0x00, 0x03); | 30 | {0x1a, 0x04}, {0x03, 0x10}, |
34 | err += sn9c102_write_reg(cam, 0x1a, 0x04); | 31 | {0x08, 0x14}, {0x20, 0x17}, |
35 | err += sn9c102_write_reg(cam, 0x03, 0x10); | 32 | {0x8b, 0x18}, {0x00, 0x19}, |
36 | err += sn9c102_write_reg(cam, 0x08, 0x14); | 33 | {0x1d, 0x1a}, {0x10, 0x1b}, |
37 | err += sn9c102_write_reg(cam, 0x20, 0x17); | 34 | {0x02, 0x1c}, {0x03, 0x1d}, |
38 | err += sn9c102_write_reg(cam, 0x8b, 0x18); | 35 | {0x0f, 0x1e}, {0x0c, 0x1f}, |
39 | err += sn9c102_write_reg(cam, 0x00, 0x19); | 36 | {0x00, 0x20}, {0x29, 0x21}, |
40 | err += sn9c102_write_reg(cam, 0x1d, 0x1a); | 37 | {0x40, 0x22}, {0x54, 0x23}, |
41 | err += sn9c102_write_reg(cam, 0x10, 0x1b); | 38 | {0x66, 0x24}, {0x76, 0x25}, |
42 | err += sn9c102_write_reg(cam, 0x02, 0x1c); | 39 | {0x85, 0x26}, {0x94, 0x27}, |
43 | err += sn9c102_write_reg(cam, 0x03, 0x1d); | 40 | {0xa1, 0x28}, {0xae, 0x29}, |
44 | err += sn9c102_write_reg(cam, 0x0f, 0x1e); | 41 | {0xbb, 0x2a}, {0xc7, 0x2b}, |
45 | err += sn9c102_write_reg(cam, 0x0c, 0x1f); | 42 | {0xd3, 0x2c}, {0xde, 0x2d}, |
46 | err += sn9c102_write_reg(cam, 0x00, 0x20); | 43 | {0xea, 0x2e}, {0xf4, 0x2f}, |
47 | err += sn9c102_write_reg(cam, 0x29, 0x21); | 44 | {0xff, 0x30}, {0x00, 0x3F}, |
48 | err += sn9c102_write_reg(cam, 0x40, 0x22); | 45 | {0xC7, 0x40}, {0x01, 0x41}, |
49 | err += sn9c102_write_reg(cam, 0x54, 0x23); | 46 | {0x44, 0x42}, {0x00, 0x43}, |
50 | err += sn9c102_write_reg(cam, 0x66, 0x24); | 47 | {0x44, 0x44}, {0x00, 0x45}, |
51 | err += sn9c102_write_reg(cam, 0x76, 0x25); | 48 | {0x44, 0x46}, {0x00, 0x47}, |
52 | err += sn9c102_write_reg(cam, 0x85, 0x26); | 49 | {0xC7, 0x48}, {0x01, 0x49}, |
53 | err += sn9c102_write_reg(cam, 0x94, 0x27); | 50 | {0xC7, 0x4A}, {0x01, 0x4B}, |
54 | err += sn9c102_write_reg(cam, 0xa1, 0x28); | 51 | {0xC7, 0x4C}, {0x01, 0x4D}, |
55 | err += sn9c102_write_reg(cam, 0xae, 0x29); | 52 | {0x44, 0x4E}, {0x00, 0x4F}, |
56 | err += sn9c102_write_reg(cam, 0xbb, 0x2a); | 53 | {0x44, 0x50}, {0x00, 0x51}, |
57 | err += sn9c102_write_reg(cam, 0xc7, 0x2b); | 54 | {0x44, 0x52}, {0x00, 0x53}, |
58 | err += sn9c102_write_reg(cam, 0xd3, 0x2c); | 55 | {0xC7, 0x54}, {0x01, 0x55}, |
59 | err += sn9c102_write_reg(cam, 0xde, 0x2d); | 56 | {0xC7, 0x56}, {0x01, 0x57}, |
60 | err += sn9c102_write_reg(cam, 0xea, 0x2e); | 57 | {0xC7, 0x58}, {0x01, 0x59}, |
61 | err += sn9c102_write_reg(cam, 0xf4, 0x2f); | 58 | {0x44, 0x5A}, {0x00, 0x5B}, |
62 | err += sn9c102_write_reg(cam, 0xff, 0x30); | 59 | {0x44, 0x5C}, {0x00, 0x5D}, |
63 | err += sn9c102_write_reg(cam, 0x00, 0x3F); | 60 | {0x44, 0x5E}, {0x00, 0x5F}, |
64 | err += sn9c102_write_reg(cam, 0xC7, 0x40); | 61 | {0xC7, 0x60}, {0x01, 0x61}, |
65 | err += sn9c102_write_reg(cam, 0x01, 0x41); | 62 | {0xC7, 0x62}, {0x01, 0x63}, |
66 | err += sn9c102_write_reg(cam, 0x44, 0x42); | 63 | {0xC7, 0x64}, {0x01, 0x65}, |
67 | err += sn9c102_write_reg(cam, 0x00, 0x43); | 64 | {0x44, 0x66}, {0x00, 0x67}, |
68 | err += sn9c102_write_reg(cam, 0x44, 0x44); | 65 | {0x44, 0x68}, {0x00, 0x69}, |
69 | err += sn9c102_write_reg(cam, 0x00, 0x45); | 66 | {0x44, 0x6A}, {0x00, 0x6B}, |
70 | err += sn9c102_write_reg(cam, 0x44, 0x46); | 67 | {0xC7, 0x6C}, {0x01, 0x6D}, |
71 | err += sn9c102_write_reg(cam, 0x00, 0x47); | 68 | {0xC7, 0x6E}, {0x01, 0x6F}, |
72 | err += sn9c102_write_reg(cam, 0xC7, 0x48); | 69 | {0xC7, 0x70}, {0x01, 0x71}, |
73 | err += sn9c102_write_reg(cam, 0x01, 0x49); | 70 | {0x44, 0x72}, {0x00, 0x73}, |
74 | err += sn9c102_write_reg(cam, 0xC7, 0x4A); | 71 | {0x44, 0x74}, {0x00, 0x75}, |
75 | err += sn9c102_write_reg(cam, 0x01, 0x4B); | 72 | {0x44, 0x76}, {0x00, 0x77}, |
76 | err += sn9c102_write_reg(cam, 0xC7, 0x4C); | 73 | {0xC7, 0x78}, {0x01, 0x79}, |
77 | err += sn9c102_write_reg(cam, 0x01, 0x4D); | 74 | {0xC7, 0x7A}, {0x01, 0x7B}, |
78 | err += sn9c102_write_reg(cam, 0x44, 0x4E); | 75 | {0xC7, 0x7C}, {0x01, 0x7D}, |
79 | err += sn9c102_write_reg(cam, 0x00, 0x4F); | 76 | {0x44, 0x7E}, {0x00, 0x7F}, |
80 | err += sn9c102_write_reg(cam, 0x44, 0x50); | 77 | {0x14, 0x84}, {0x00, 0x85}, |
81 | err += sn9c102_write_reg(cam, 0x00, 0x51); | 78 | {0x27, 0x86}, {0x00, 0x87}, |
82 | err += sn9c102_write_reg(cam, 0x44, 0x52); | 79 | {0x07, 0x88}, {0x00, 0x89}, |
83 | err += sn9c102_write_reg(cam, 0x00, 0x53); | 80 | {0xEC, 0x8A}, {0x0f, 0x8B}, |
84 | err += sn9c102_write_reg(cam, 0xC7, 0x54); | 81 | {0xD8, 0x8C}, {0x0f, 0x8D}, |
85 | err += sn9c102_write_reg(cam, 0x01, 0x55); | 82 | {0x3D, 0x8E}, {0x00, 0x8F}, |
86 | err += sn9c102_write_reg(cam, 0xC7, 0x56); | 83 | {0x3D, 0x90}, {0x00, 0x91}, |
87 | err += sn9c102_write_reg(cam, 0x01, 0x57); | 84 | {0xCD, 0x92}, {0x0f, 0x93}, |
88 | err += sn9c102_write_reg(cam, 0xC7, 0x58); | 85 | {0xf7, 0x94}, {0x0f, 0x95}, |
89 | err += sn9c102_write_reg(cam, 0x01, 0x59); | 86 | {0x0C, 0x96}, {0x00, 0x97}, |
90 | err += sn9c102_write_reg(cam, 0x44, 0x5A); | 87 | {0x00, 0x98}, {0x66, 0x99}, |
91 | err += sn9c102_write_reg(cam, 0x00, 0x5B); | 88 | {0x05, 0x9A}, {0x00, 0x9B}, |
92 | err += sn9c102_write_reg(cam, 0x44, 0x5C); | 89 | {0x04, 0x9C}, {0x00, 0x9D}, |
93 | err += sn9c102_write_reg(cam, 0x00, 0x5D); | 90 | {0x08, 0x9E}, {0x00, 0x9F}, |
94 | err += sn9c102_write_reg(cam, 0x44, 0x5E); | 91 | {0x2D, 0xC0}, {0x2D, 0xC1}, |
95 | err += sn9c102_write_reg(cam, 0x00, 0x5F); | 92 | {0x3A, 0xC2}, {0x05, 0xC3}, |
96 | err += sn9c102_write_reg(cam, 0xC7, 0x60); | 93 | {0x04, 0xC4}, {0x3F, 0xC5}, |
97 | err += sn9c102_write_reg(cam, 0x01, 0x61); | 94 | {0x00, 0xC6}, {0x00, 0xC7}, |
98 | err += sn9c102_write_reg(cam, 0xC7, 0x62); | 95 | {0x50, 0xC8}, {0x3C, 0xC9}, |
99 | err += sn9c102_write_reg(cam, 0x01, 0x63); | 96 | {0x28, 0xCA}, {0xD8, 0xCB}, |
100 | err += sn9c102_write_reg(cam, 0xC7, 0x64); | 97 | {0x14, 0xCC}, {0xEC, 0xCD}, |
101 | err += sn9c102_write_reg(cam, 0x01, 0x65); | 98 | {0x32, 0xCE}, {0xDD, 0xCF}, |
102 | err += sn9c102_write_reg(cam, 0x44, 0x66); | 99 | {0x32, 0xD0}, {0xDD, 0xD1}, |
103 | err += sn9c102_write_reg(cam, 0x00, 0x67); | 100 | {0x6A, 0xD2}, {0x50, 0xD3}, |
104 | err += sn9c102_write_reg(cam, 0x44, 0x68); | 101 | {0x00, 0xD4}, {0x00, 0xD5}, |
105 | err += sn9c102_write_reg(cam, 0x00, 0x69); | 102 | {0x00, 0xD6}); |
106 | err += sn9c102_write_reg(cam, 0x44, 0x6A); | ||
107 | err += sn9c102_write_reg(cam, 0x00, 0x6B); | ||
108 | err += sn9c102_write_reg(cam, 0xC7, 0x6C); | ||
109 | err += sn9c102_write_reg(cam, 0x01, 0x6D); | ||
110 | err += sn9c102_write_reg(cam, 0xC7, 0x6E); | ||
111 | err += sn9c102_write_reg(cam, 0x01, 0x6F); | ||
112 | err += sn9c102_write_reg(cam, 0xC7, 0x70); | ||
113 | err += sn9c102_write_reg(cam, 0x01, 0x71); | ||
114 | err += sn9c102_write_reg(cam, 0x44, 0x72); | ||
115 | err += sn9c102_write_reg(cam, 0x00, 0x73); | ||
116 | err += sn9c102_write_reg(cam, 0x44, 0x74); | ||
117 | err += sn9c102_write_reg(cam, 0x00, 0x75); | ||
118 | err += sn9c102_write_reg(cam, 0x44, 0x76); | ||
119 | err += sn9c102_write_reg(cam, 0x00, 0x77); | ||
120 | err += sn9c102_write_reg(cam, 0xC7, 0x78); | ||
121 | err += sn9c102_write_reg(cam, 0x01, 0x79); | ||
122 | err += sn9c102_write_reg(cam, 0xC7, 0x7A); | ||
123 | err += sn9c102_write_reg(cam, 0x01, 0x7B); | ||
124 | err += sn9c102_write_reg(cam, 0xC7, 0x7C); | ||
125 | err += sn9c102_write_reg(cam, 0x01, 0x7D); | ||
126 | err += sn9c102_write_reg(cam, 0x44, 0x7E); | ||
127 | err += sn9c102_write_reg(cam, 0x00, 0x7F); | ||
128 | err += sn9c102_write_reg(cam, 0x14, 0x84); | ||
129 | err += sn9c102_write_reg(cam, 0x00, 0x85); | ||
130 | err += sn9c102_write_reg(cam, 0x27, 0x86); | ||
131 | err += sn9c102_write_reg(cam, 0x00, 0x87); | ||
132 | err += sn9c102_write_reg(cam, 0x07, 0x88); | ||
133 | err += sn9c102_write_reg(cam, 0x00, 0x89); | ||
134 | err += sn9c102_write_reg(cam, 0xEC, 0x8A); | ||
135 | err += sn9c102_write_reg(cam, 0x0f, 0x8B); | ||
136 | err += sn9c102_write_reg(cam, 0xD8, 0x8C); | ||
137 | err += sn9c102_write_reg(cam, 0x0f, 0x8D); | ||
138 | err += sn9c102_write_reg(cam, 0x3D, 0x8E); | ||
139 | err += sn9c102_write_reg(cam, 0x00, 0x8F); | ||
140 | err += sn9c102_write_reg(cam, 0x3D, 0x90); | ||
141 | err += sn9c102_write_reg(cam, 0x00, 0x91); | ||
142 | err += sn9c102_write_reg(cam, 0xCD, 0x92); | ||
143 | err += sn9c102_write_reg(cam, 0x0f, 0x93); | ||
144 | err += sn9c102_write_reg(cam, 0xf7, 0x94); | ||
145 | err += sn9c102_write_reg(cam, 0x0f, 0x95); | ||
146 | err += sn9c102_write_reg(cam, 0x0C, 0x96); | ||
147 | err += sn9c102_write_reg(cam, 0x00, 0x97); | ||
148 | err += sn9c102_write_reg(cam, 0x00, 0x98); | ||
149 | err += sn9c102_write_reg(cam, 0x66, 0x99); | ||
150 | err += sn9c102_write_reg(cam, 0x05, 0x9A); | ||
151 | err += sn9c102_write_reg(cam, 0x00, 0x9B); | ||
152 | err += sn9c102_write_reg(cam, 0x04, 0x9C); | ||
153 | err += sn9c102_write_reg(cam, 0x00, 0x9D); | ||
154 | err += sn9c102_write_reg(cam, 0x08, 0x9E); | ||
155 | err += sn9c102_write_reg(cam, 0x00, 0x9F); | ||
156 | err += sn9c102_write_reg(cam, 0x2D, 0xC0); | ||
157 | err += sn9c102_write_reg(cam, 0x2D, 0xC1); | ||
158 | err += sn9c102_write_reg(cam, 0x3A, 0xC2); | ||
159 | err += sn9c102_write_reg(cam, 0x05, 0xC3); | ||
160 | err += sn9c102_write_reg(cam, 0x04, 0xC4); | ||
161 | err += sn9c102_write_reg(cam, 0x3F, 0xC5); | ||
162 | err += sn9c102_write_reg(cam, 0x00, 0xC6); | ||
163 | err += sn9c102_write_reg(cam, 0x00, 0xC7); | ||
164 | err += sn9c102_write_reg(cam, 0x50, 0xC8); | ||
165 | err += sn9c102_write_reg(cam, 0x3C, 0xC9); | ||
166 | err += sn9c102_write_reg(cam, 0x28, 0xCA); | ||
167 | err += sn9c102_write_reg(cam, 0xD8, 0xCB); | ||
168 | err += sn9c102_write_reg(cam, 0x14, 0xCC); | ||
169 | err += sn9c102_write_reg(cam, 0xEC, 0xCD); | ||
170 | err += sn9c102_write_reg(cam, 0x32, 0xCE); | ||
171 | err += sn9c102_write_reg(cam, 0xDD, 0xCF); | ||
172 | err += sn9c102_write_reg(cam, 0x32, 0xD0); | ||
173 | err += sn9c102_write_reg(cam, 0xDD, 0xD1); | ||
174 | err += sn9c102_write_reg(cam, 0x6A, 0xD2); | ||
175 | err += sn9c102_write_reg(cam, 0x50, 0xD3); | ||
176 | err += sn9c102_write_reg(cam, 0x00, 0xD4); | ||
177 | err += sn9c102_write_reg(cam, 0x00, 0xD5); | ||
178 | err += sn9c102_write_reg(cam, 0x00, 0xD6); | ||
179 | 103 | ||
180 | err += sn9c102_i2c_write(cam, 0x12, 0x80); | 104 | err += sn9c102_i2c_write(cam, 0x12, 0x80); |
181 | err += sn9c102_i2c_write(cam, 0x11, 0x09); | 105 | err += sn9c102_i2c_write(cam, 0x11, 0x09); |
@@ -572,13 +496,11 @@ static struct sn9c102_sensor ov7660 = { | |||
572 | 496 | ||
573 | int sn9c102_probe_ov7660(struct sn9c102_device* cam) | 497 | int sn9c102_probe_ov7660(struct sn9c102_device* cam) |
574 | { | 498 | { |
575 | int pid, ver, err = 0; | 499 | int pid, ver, err; |
576 | 500 | ||
577 | err += sn9c102_write_reg(cam, 0x01, 0xf1); | 501 | err = sn9c102_write_const_regs(cam, {0x01, 0xf1}, {0x00, 0xf1}, |
578 | err += sn9c102_write_reg(cam, 0x00, 0xf1); | 502 | {0x01, 0x01}, {0x00, 0x01}, |
579 | err += sn9c102_write_reg(cam, 0x01, 0x01); | 503 | {0x28, 0x17}); |
580 | err += sn9c102_write_reg(cam, 0x00, 0x01); | ||
581 | err += sn9c102_write_reg(cam, 0x28, 0x17); | ||
582 | 504 | ||
583 | pid = sn9c102_i2c_try_read(cam, &ov7660, 0x0a); | 505 | pid = sn9c102_i2c_try_read(cam, &ov7660, 0x0a); |
584 | ver = sn9c102_i2c_try_read(cam, &ov7660, 0x0b); | 506 | ver = sn9c102_i2c_try_read(cam, &ov7660, 0x0b); |
diff --git a/drivers/media/video/sn9c102/sn9c102_pas106b.c b/drivers/media/video/sn9c102/sn9c102_pas106b.c index 8d79a5fae5de..67151964801f 100644 --- a/drivers/media/video/sn9c102/sn9c102_pas106b.c +++ b/drivers/media/video/sn9c102/sn9c102_pas106b.c | |||
@@ -23,19 +23,13 @@ | |||
23 | #include "sn9c102_sensor.h" | 23 | #include "sn9c102_sensor.h" |
24 | 24 | ||
25 | 25 | ||
26 | static struct sn9c102_sensor pas106b; | ||
27 | |||
28 | |||
29 | static int pas106b_init(struct sn9c102_device* cam) | 26 | static int pas106b_init(struct sn9c102_device* cam) |
30 | { | 27 | { |
31 | int err = 0; | 28 | int err = 0; |
32 | 29 | ||
33 | err += sn9c102_write_reg(cam, 0x00, 0x10); | 30 | err = sn9c102_write_const_regs(cam, {0x00, 0x10}, {0x00, 0x11}, |
34 | err += sn9c102_write_reg(cam, 0x00, 0x11); | 31 | {0x00, 0x14}, {0x20, 0x17}, |
35 | err += sn9c102_write_reg(cam, 0x00, 0x14); | 32 | {0x20, 0x19}, {0x09, 0x18}); |
36 | err += sn9c102_write_reg(cam, 0x20, 0x17); | ||
37 | err += sn9c102_write_reg(cam, 0x20, 0x19); | ||
38 | err += sn9c102_write_reg(cam, 0x09, 0x18); | ||
39 | 33 | ||
40 | err += sn9c102_i2c_write(cam, 0x02, 0x0c); | 34 | err += sn9c102_i2c_write(cam, 0x02, 0x0c); |
41 | err += sn9c102_i2c_write(cam, 0x05, 0x5a); | 35 | err += sn9c102_i2c_write(cam, 0x05, 0x5a); |
@@ -172,7 +166,7 @@ static int pas106b_set_pix_format(struct sn9c102_device* cam, | |||
172 | static struct sn9c102_sensor pas106b = { | 166 | static struct sn9c102_sensor pas106b = { |
173 | .name = "PAS106B", | 167 | .name = "PAS106B", |
174 | .maintainer = "Luca Risolia <luca.risolia@studio.unibo.it>", | 168 | .maintainer = "Luca Risolia <luca.risolia@studio.unibo.it>", |
175 | .supported_bridge = BRIDGE_SN9C101 | BRIDGE_SN9C102 | BRIDGE_SN9C103, | 169 | .supported_bridge = BRIDGE_SN9C101 | BRIDGE_SN9C102, |
176 | .sysfs_ops = SN9C102_I2C_READ | SN9C102_I2C_WRITE, | 170 | .sysfs_ops = SN9C102_I2C_READ | SN9C102_I2C_WRITE, |
177 | .frequency = SN9C102_I2C_400KHZ | SN9C102_I2C_100KHZ, | 171 | .frequency = SN9C102_I2C_400KHZ | SN9C102_I2C_100KHZ, |
178 | .interface = SN9C102_I2C_2WIRES, | 172 | .interface = SN9C102_I2C_2WIRES, |
@@ -279,16 +273,17 @@ static struct sn9c102_sensor pas106b = { | |||
279 | 273 | ||
280 | int sn9c102_probe_pas106b(struct sn9c102_device* cam) | 274 | int sn9c102_probe_pas106b(struct sn9c102_device* cam) |
281 | { | 275 | { |
282 | int r0 = 0, r1 = 0, err = 0; | 276 | int r0 = 0, r1 = 0, err; |
283 | unsigned int pid = 0; | 277 | unsigned int pid = 0; |
284 | 278 | ||
285 | /* | 279 | /* |
286 | Minimal initialization to enable the I2C communication | 280 | Minimal initialization to enable the I2C communication |
287 | NOTE: do NOT change the values! | 281 | NOTE: do NOT change the values! |
288 | */ | 282 | */ |
289 | err += sn9c102_write_reg(cam, 0x01, 0x01); /* sensor power down */ | 283 | err = sn9c102_write_const_regs(cam, |
290 | err += sn9c102_write_reg(cam, 0x00, 0x01); /* sensor power on */ | 284 | {0x01, 0x01}, /* sensor power down */ |
291 | err += sn9c102_write_reg(cam, 0x28, 0x17); /* sensor clock at 24 MHz */ | 285 | {0x00, 0x01}, /* sensor power on */ |
286 | {0x28, 0x17});/* sensor clock 24 MHz */ | ||
292 | if (err) | 287 | if (err) |
293 | return -EIO; | 288 | return -EIO; |
294 | 289 | ||
diff --git a/drivers/media/video/sn9c102/sn9c102_pas202bcb.c b/drivers/media/video/sn9c102/sn9c102_pas202bcb.c index 7894f01b56e8..c1b8d6b63b47 100644 --- a/drivers/media/video/sn9c102/sn9c102_pas202bcb.c +++ b/drivers/media/video/sn9c102/sn9c102_pas202bcb.c | |||
@@ -28,9 +28,6 @@ | |||
28 | #include "sn9c102_sensor.h" | 28 | #include "sn9c102_sensor.h" |
29 | 29 | ||
30 | 30 | ||
31 | static struct sn9c102_sensor pas202bcb; | ||
32 | |||
33 | |||
34 | static int pas202bcb_init(struct sn9c102_device* cam) | 31 | static int pas202bcb_init(struct sn9c102_device* cam) |
35 | { | 32 | { |
36 | int err = 0; | 33 | int err = 0; |
@@ -38,47 +35,29 @@ static int pas202bcb_init(struct sn9c102_device* cam) | |||
38 | switch (sn9c102_get_bridge(cam)) { | 35 | switch (sn9c102_get_bridge(cam)) { |
39 | case BRIDGE_SN9C101: | 36 | case BRIDGE_SN9C101: |
40 | case BRIDGE_SN9C102: | 37 | case BRIDGE_SN9C102: |
41 | err += sn9c102_write_reg(cam, 0x00, 0x10); | 38 | err = sn9c102_write_const_regs(cam, {0x00, 0x10}, |
42 | err += sn9c102_write_reg(cam, 0x00, 0x11); | 39 | {0x00, 0x11}, {0x00, 0x14}, |
43 | err += sn9c102_write_reg(cam, 0x00, 0x14); | 40 | {0x20, 0x17}, {0x30, 0x19}, |
44 | err += sn9c102_write_reg(cam, 0x20, 0x17); | 41 | {0x09, 0x18}); |
45 | err += sn9c102_write_reg(cam, 0x30, 0x19); | ||
46 | err += sn9c102_write_reg(cam, 0x09, 0x18); | ||
47 | break; | 42 | break; |
48 | case BRIDGE_SN9C103: | 43 | case BRIDGE_SN9C103: |
49 | err += sn9c102_write_reg(cam, 0x00, 0x02); | 44 | err = sn9c102_write_const_regs(cam, {0x00, 0x02}, |
50 | err += sn9c102_write_reg(cam, 0x00, 0x03); | 45 | {0x00, 0x03}, {0x1a, 0x04}, |
51 | err += sn9c102_write_reg(cam, 0x1a, 0x04); | 46 | {0x20, 0x05}, {0x20, 0x06}, |
52 | err += sn9c102_write_reg(cam, 0x20, 0x05); | 47 | {0x20, 0x07}, {0x00, 0x10}, |
53 | err += sn9c102_write_reg(cam, 0x20, 0x06); | 48 | {0x00, 0x11}, {0x00, 0x14}, |
54 | err += sn9c102_write_reg(cam, 0x20, 0x07); | 49 | {0x20, 0x17}, {0x30, 0x19}, |
55 | err += sn9c102_write_reg(cam, 0x00, 0x10); | 50 | {0x09, 0x18}, {0x02, 0x1c}, |
56 | err += sn9c102_write_reg(cam, 0x00, 0x11); | 51 | {0x03, 0x1d}, {0x0f, 0x1e}, |
57 | err += sn9c102_write_reg(cam, 0x00, 0x14); | 52 | {0x0c, 0x1f}, {0x00, 0x20}, |
58 | err += sn9c102_write_reg(cam, 0x20, 0x17); | 53 | {0x10, 0x21}, {0x20, 0x22}, |
59 | err += sn9c102_write_reg(cam, 0x30, 0x19); | 54 | {0x30, 0x23}, {0x40, 0x24}, |
60 | err += sn9c102_write_reg(cam, 0x09, 0x18); | 55 | {0x50, 0x25}, {0x60, 0x26}, |
61 | err += sn9c102_write_reg(cam, 0x02, 0x1c); | 56 | {0x70, 0x27}, {0x80, 0x28}, |
62 | err += sn9c102_write_reg(cam, 0x03, 0x1d); | 57 | {0x90, 0x29}, {0xa0, 0x2a}, |
63 | err += sn9c102_write_reg(cam, 0x0f, 0x1e); | 58 | {0xb0, 0x2b}, {0xc0, 0x2c}, |
64 | err += sn9c102_write_reg(cam, 0x0c, 0x1f); | 59 | {0xd0, 0x2d}, {0xe0, 0x2e}, |
65 | err += sn9c102_write_reg(cam, 0x00, 0x20); | 60 | {0xf0, 0x2f}, {0xff, 0x30}); |
66 | err += sn9c102_write_reg(cam, 0x10, 0x21); | ||
67 | err += sn9c102_write_reg(cam, 0x20, 0x22); | ||
68 | err += sn9c102_write_reg(cam, 0x30, 0x23); | ||
69 | err += sn9c102_write_reg(cam, 0x40, 0x24); | ||
70 | err += sn9c102_write_reg(cam, 0x50, 0x25); | ||
71 | err += sn9c102_write_reg(cam, 0x60, 0x26); | ||
72 | err += sn9c102_write_reg(cam, 0x70, 0x27); | ||
73 | err += sn9c102_write_reg(cam, 0x80, 0x28); | ||
74 | err += sn9c102_write_reg(cam, 0x90, 0x29); | ||
75 | err += sn9c102_write_reg(cam, 0xa0, 0x2a); | ||
76 | err += sn9c102_write_reg(cam, 0xb0, 0x2b); | ||
77 | err += sn9c102_write_reg(cam, 0xc0, 0x2c); | ||
78 | err += sn9c102_write_reg(cam, 0xd0, 0x2d); | ||
79 | err += sn9c102_write_reg(cam, 0xe0, 0x2e); | ||
80 | err += sn9c102_write_reg(cam, 0xf0, 0x2f); | ||
81 | err += sn9c102_write_reg(cam, 0xff, 0x30); | ||
82 | break; | 61 | break; |
83 | default: | 62 | default: |
84 | break; | 63 | break; |
@@ -328,15 +307,15 @@ int sn9c102_probe_pas202bcb(struct sn9c102_device* cam) | |||
328 | switch (sn9c102_get_bridge(cam)) { | 307 | switch (sn9c102_get_bridge(cam)) { |
329 | case BRIDGE_SN9C101: | 308 | case BRIDGE_SN9C101: |
330 | case BRIDGE_SN9C102: | 309 | case BRIDGE_SN9C102: |
331 | err += sn9c102_write_reg(cam, 0x01, 0x01); /* power down */ | 310 | err = sn9c102_write_const_regs(cam, |
332 | err += sn9c102_write_reg(cam, 0x40, 0x01); /* power on */ | 311 | {0x01, 0x01}, /* power down */ |
333 | err += sn9c102_write_reg(cam, 0x28, 0x17); /* clock 24 MHz */ | 312 | {0x40, 0x01}, /* power on */ |
313 | {0x28, 0x17});/* clock 24 MHz */ | ||
334 | break; | 314 | break; |
335 | case BRIDGE_SN9C103: /* do _not_ change anything! */ | 315 | case BRIDGE_SN9C103: /* do _not_ change anything! */ |
336 | err += sn9c102_write_reg(cam, 0x09, 0x01); | 316 | err = sn9c102_write_const_regs(cam, {0x09, 0x01}, |
337 | err += sn9c102_write_reg(cam, 0x44, 0x01); | 317 | {0x44, 0x01}, {0x44, 0x02}, |
338 | err += sn9c102_write_reg(cam, 0x44, 0x02); | 318 | {0x29, 0x17}); |
339 | err += sn9c102_write_reg(cam, 0x29, 0x17); | ||
340 | break; | 319 | break; |
341 | default: | 320 | default: |
342 | break; | 321 | break; |
diff --git a/drivers/media/video/sn9c102/sn9c102_sensor.h b/drivers/media/video/sn9c102/sn9c102_sensor.h index 05f2942639c3..1bbf64c897a2 100644 --- a/drivers/media/video/sn9c102/sn9c102_sensor.h +++ b/drivers/media/video/sn9c102/sn9c102_sensor.h | |||
@@ -114,9 +114,17 @@ extern int sn9c102_i2c_write(struct sn9c102_device*, u8 address, u8 value); | |||
114 | extern int sn9c102_i2c_read(struct sn9c102_device*, u8 address); | 114 | extern int sn9c102_i2c_read(struct sn9c102_device*, u8 address); |
115 | 115 | ||
116 | /* I/O on registers in the bridge. Could be used by the sensor methods too */ | 116 | /* I/O on registers in the bridge. Could be used by the sensor methods too */ |
117 | extern int sn9c102_write_regs(struct sn9c102_device*, u8* buff, u16 index); | ||
118 | extern int sn9c102_write_reg(struct sn9c102_device*, u8 value, u16 index); | ||
119 | extern int sn9c102_pread_reg(struct sn9c102_device*, u16 index); | 117 | extern int sn9c102_pread_reg(struct sn9c102_device*, u16 index); |
118 | extern int sn9c102_write_reg(struct sn9c102_device*, u8 value, u16 index); | ||
119 | extern int sn9c102_write_regs(struct sn9c102_device*, const u8 valreg[][2], | ||
120 | int count); | ||
121 | /* | ||
122 | * Write multiple registers with constant values. For example: | ||
123 | * sn9c102_write_const_regs(cam, {0x00, 0x14}, {0x60, 0x17}, {0x0f, 0x18}); | ||
124 | */ | ||
125 | #define sn9c102_write_const_regs(device, data...) \ | ||
126 | ({ const static u8 _data[][2] = {data}; \ | ||
127 | sn9c102_write_regs(device, _data, ARRAY_SIZE(_data)); }) | ||
120 | 128 | ||
121 | /*****************************************************************************/ | 129 | /*****************************************************************************/ |
122 | 130 | ||
diff --git a/drivers/media/video/sn9c102/sn9c102_tas5110c1b.c b/drivers/media/video/sn9c102/sn9c102_tas5110c1b.c index 90023ad63adc..0e7ec8662c70 100644 --- a/drivers/media/video/sn9c102/sn9c102_tas5110c1b.c +++ b/drivers/media/video/sn9c102/sn9c102_tas5110c1b.c | |||
@@ -22,21 +22,14 @@ | |||
22 | #include "sn9c102_sensor.h" | 22 | #include "sn9c102_sensor.h" |
23 | 23 | ||
24 | 24 | ||
25 | static struct sn9c102_sensor tas5110c1b; | ||
26 | |||
27 | |||
28 | static int tas5110c1b_init(struct sn9c102_device* cam) | 25 | static int tas5110c1b_init(struct sn9c102_device* cam) |
29 | { | 26 | { |
30 | int err = 0; | 27 | int err = 0; |
31 | 28 | ||
32 | err += sn9c102_write_reg(cam, 0x01, 0x01); | 29 | err = sn9c102_write_const_regs(cam, {0x01, 0x01}, {0x44, 0x01}, |
33 | err += sn9c102_write_reg(cam, 0x44, 0x01); | 30 | {0x00, 0x10}, {0x00, 0x11}, |
34 | err += sn9c102_write_reg(cam, 0x00, 0x10); | 31 | {0x0a, 0x14}, {0x60, 0x17}, |
35 | err += sn9c102_write_reg(cam, 0x00, 0x11); | 32 | {0x06, 0x18}, {0xfb, 0x19}); |
36 | err += sn9c102_write_reg(cam, 0x0a, 0x14); | ||
37 | err += sn9c102_write_reg(cam, 0x60, 0x17); | ||
38 | err += sn9c102_write_reg(cam, 0x06, 0x18); | ||
39 | err += sn9c102_write_reg(cam, 0xfb, 0x19); | ||
40 | 33 | ||
41 | err += sn9c102_i2c_write(cam, 0xc0, 0x80); | 34 | err += sn9c102_i2c_write(cam, 0xc0, 0x80); |
42 | 35 | ||
@@ -98,7 +91,7 @@ static int tas5110c1b_set_pix_format(struct sn9c102_device* cam, | |||
98 | static struct sn9c102_sensor tas5110c1b = { | 91 | static struct sn9c102_sensor tas5110c1b = { |
99 | .name = "TAS5110C1B", | 92 | .name = "TAS5110C1B", |
100 | .maintainer = "Luca Risolia <luca.risolia@studio.unibo.it>", | 93 | .maintainer = "Luca Risolia <luca.risolia@studio.unibo.it>", |
101 | .supported_bridge = BRIDGE_SN9C101 | BRIDGE_SN9C102 | BRIDGE_SN9C103, | 94 | .supported_bridge = BRIDGE_SN9C101 | BRIDGE_SN9C102, |
102 | .sysfs_ops = SN9C102_I2C_WRITE, | 95 | .sysfs_ops = SN9C102_I2C_WRITE, |
103 | .frequency = SN9C102_I2C_100KHZ, | 96 | .frequency = SN9C102_I2C_100KHZ, |
104 | .interface = SN9C102_I2C_3WIRES, | 97 | .interface = SN9C102_I2C_3WIRES, |
@@ -146,7 +139,6 @@ int sn9c102_probe_tas5110c1b(struct sn9c102_device* cam) | |||
146 | const struct usb_device_id tas5110c1b_id_table[] = { | 139 | const struct usb_device_id tas5110c1b_id_table[] = { |
147 | { USB_DEVICE(0x0c45, 0x6001), }, | 140 | { USB_DEVICE(0x0c45, 0x6001), }, |
148 | { USB_DEVICE(0x0c45, 0x6005), }, | 141 | { USB_DEVICE(0x0c45, 0x6005), }, |
149 | { USB_DEVICE(0x0c45, 0x6007), }, | ||
150 | { USB_DEVICE(0x0c45, 0x60ab), }, | 142 | { USB_DEVICE(0x0c45, 0x60ab), }, |
151 | { } | 143 | { } |
152 | }; | 144 | }; |
diff --git a/drivers/media/video/sn9c102/sn9c102_tas5110d.c b/drivers/media/video/sn9c102/sn9c102_tas5110d.c new file mode 100644 index 000000000000..83a39e8b5e71 --- /dev/null +++ b/drivers/media/video/sn9c102/sn9c102_tas5110d.c | |||
@@ -0,0 +1,118 @@ | |||
1 | /*************************************************************************** | ||
2 | * Plug-in for TAS5110D image sensor connected to the SN9C1xx PC Camera * | ||
3 | * Controllers * | ||
4 | * * | ||
5 | * Copyright (C) 2007 by Luca Risolia <luca.risolia@studio.unibo.it> * | ||
6 | * * | ||
7 | * This program is free software; you can redistribute it and/or modify * | ||
8 | * it under the terms of the GNU General Public License as published by * | ||
9 | * the Free Software Foundation; either version 2 of the License, or * | ||
10 | * (at your option) any later version. * | ||
11 | * * | ||
12 | * This program is distributed in the hope that it will be useful, * | ||
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of * | ||
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * | ||
15 | * GNU General Public License for more details. * | ||
16 | * * | ||
17 | * You should have received a copy of the GNU General Public License * | ||
18 | * along with this program; if not, write to the Free Software * | ||
19 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * | ||
20 | ***************************************************************************/ | ||
21 | |||
22 | #include "sn9c102_sensor.h" | ||
23 | |||
24 | |||
25 | static int tas5110d_init(struct sn9c102_device* cam) | ||
26 | { | ||
27 | int err; | ||
28 | |||
29 | err = sn9c102_write_const_regs(cam, {0x01, 0x01}, {0x04, 0x01}, | ||
30 | {0x0a, 0x14}, {0x60, 0x17}, | ||
31 | {0x06, 0x18}, {0xfb, 0x19}); | ||
32 | |||
33 | err += sn9c102_i2c_write(cam, 0x9a, 0xca); | ||
34 | |||
35 | return err; | ||
36 | } | ||
37 | |||
38 | |||
39 | static int tas5110d_set_crop(struct sn9c102_device* cam, | ||
40 | const struct v4l2_rect* rect) | ||
41 | { | ||
42 | struct sn9c102_sensor* s = sn9c102_get_sensor(cam); | ||
43 | int err = 0; | ||
44 | u8 h_start = (u8)(rect->left - s->cropcap.bounds.left) + 69, | ||
45 | v_start = (u8)(rect->top - s->cropcap.bounds.top) + 9; | ||
46 | |||
47 | err += sn9c102_write_reg(cam, h_start, 0x12); | ||
48 | err += sn9c102_write_reg(cam, v_start, 0x13); | ||
49 | |||
50 | err += sn9c102_write_reg(cam, 0x14, 0x1a); | ||
51 | err += sn9c102_write_reg(cam, 0x0a, 0x1b); | ||
52 | |||
53 | return err; | ||
54 | } | ||
55 | |||
56 | |||
57 | static int tas5110d_set_pix_format(struct sn9c102_device* cam, | ||
58 | const struct v4l2_pix_format* pix) | ||
59 | { | ||
60 | int err = 0; | ||
61 | |||
62 | if (pix->pixelformat == V4L2_PIX_FMT_SN9C10X) | ||
63 | err += sn9c102_write_reg(cam, 0x3b, 0x19); | ||
64 | else | ||
65 | err += sn9c102_write_reg(cam, 0xfb, 0x19); | ||
66 | |||
67 | return err; | ||
68 | } | ||
69 | |||
70 | |||
71 | static struct sn9c102_sensor tas5110d = { | ||
72 | .name = "TAS5110D", | ||
73 | .maintainer = "Luca Risolia <luca.risolia@studio.unibo.it>", | ||
74 | .supported_bridge = BRIDGE_SN9C101 | BRIDGE_SN9C102, | ||
75 | .sysfs_ops = SN9C102_I2C_WRITE, | ||
76 | .frequency = SN9C102_I2C_100KHZ, | ||
77 | .interface = SN9C102_I2C_2WIRES, | ||
78 | .i2c_slave_id = 0x61, | ||
79 | .init = &tas5110d_init, | ||
80 | .cropcap = { | ||
81 | .bounds = { | ||
82 | .left = 0, | ||
83 | .top = 0, | ||
84 | .width = 352, | ||
85 | .height = 288, | ||
86 | }, | ||
87 | .defrect = { | ||
88 | .left = 0, | ||
89 | .top = 0, | ||
90 | .width = 352, | ||
91 | .height = 288, | ||
92 | }, | ||
93 | }, | ||
94 | .set_crop = &tas5110d_set_crop, | ||
95 | .pix_format = { | ||
96 | .width = 352, | ||
97 | .height = 288, | ||
98 | .pixelformat = V4L2_PIX_FMT_SBGGR8, | ||
99 | .priv = 8, | ||
100 | }, | ||
101 | .set_pix_format = &tas5110d_set_pix_format | ||
102 | }; | ||
103 | |||
104 | |||
105 | int sn9c102_probe_tas5110d(struct sn9c102_device* cam) | ||
106 | { | ||
107 | const struct usb_device_id tas5110d_id_table[] = { | ||
108 | { USB_DEVICE(0x0c45, 0x6007), }, | ||
109 | { } | ||
110 | }; | ||
111 | |||
112 | if (!sn9c102_match_id(cam, tas5110d_id_table)) | ||
113 | return -ENODEV; | ||
114 | |||
115 | sn9c102_attach_sensor(cam, &tas5110d); | ||
116 | |||
117 | return 0; | ||
118 | } | ||
diff --git a/drivers/media/video/sn9c102/sn9c102_tas5130d1b.c b/drivers/media/video/sn9c102/sn9c102_tas5130d1b.c index cb1b318bc1ff..50406503fc40 100644 --- a/drivers/media/video/sn9c102/sn9c102_tas5130d1b.c +++ b/drivers/media/video/sn9c102/sn9c102_tas5130d1b.c | |||
@@ -22,21 +22,14 @@ | |||
22 | #include "sn9c102_sensor.h" | 22 | #include "sn9c102_sensor.h" |
23 | 23 | ||
24 | 24 | ||
25 | static struct sn9c102_sensor tas5130d1b; | ||
26 | |||
27 | |||
28 | static int tas5130d1b_init(struct sn9c102_device* cam) | 25 | static int tas5130d1b_init(struct sn9c102_device* cam) |
29 | { | 26 | { |
30 | int err = 0; | 27 | int err; |
31 | 28 | ||
32 | err += sn9c102_write_reg(cam, 0x01, 0x01); | 29 | err = sn9c102_write_const_regs(cam, {0x01, 0x01}, {0x20, 0x17}, |
33 | err += sn9c102_write_reg(cam, 0x20, 0x17); | 30 | {0x04, 0x01}, {0x01, 0x10}, |
34 | err += sn9c102_write_reg(cam, 0x04, 0x01); | 31 | {0x00, 0x11}, {0x00, 0x14}, |
35 | err += sn9c102_write_reg(cam, 0x01, 0x10); | 32 | {0x60, 0x17}, {0x07, 0x18}); |
36 | err += sn9c102_write_reg(cam, 0x00, 0x11); | ||
37 | err += sn9c102_write_reg(cam, 0x00, 0x14); | ||
38 | err += sn9c102_write_reg(cam, 0x60, 0x17); | ||
39 | err += sn9c102_write_reg(cam, 0x07, 0x18); | ||
40 | 33 | ||
41 | return err; | 34 | return err; |
42 | } | 35 | } |
@@ -99,7 +92,7 @@ static int tas5130d1b_set_pix_format(struct sn9c102_device* cam, | |||
99 | static struct sn9c102_sensor tas5130d1b = { | 92 | static struct sn9c102_sensor tas5130d1b = { |
100 | .name = "TAS5130D1B", | 93 | .name = "TAS5130D1B", |
101 | .maintainer = "Luca Risolia <luca.risolia@studio.unibo.it>", | 94 | .maintainer = "Luca Risolia <luca.risolia@studio.unibo.it>", |
102 | .supported_bridge = BRIDGE_SN9C101 | BRIDGE_SN9C102 | BRIDGE_SN9C103, | 95 | .supported_bridge = BRIDGE_SN9C101 | BRIDGE_SN9C102, |
103 | .sysfs_ops = SN9C102_I2C_WRITE, | 96 | .sysfs_ops = SN9C102_I2C_WRITE, |
104 | .frequency = SN9C102_I2C_100KHZ, | 97 | .frequency = SN9C102_I2C_100KHZ, |
105 | .interface = SN9C102_I2C_3WIRES, | 98 | .interface = SN9C102_I2C_3WIRES, |
diff --git a/drivers/media/video/tda7432.c b/drivers/media/video/tda7432.c index d1ccc064206f..43225802a551 100644 --- a/drivers/media/video/tda7432.c +++ b/drivers/media/video/tda7432.c | |||
@@ -45,7 +45,6 @@ | |||
45 | #include <linux/slab.h> | 45 | #include <linux/slab.h> |
46 | #include <linux/videodev.h> | 46 | #include <linux/videodev.h> |
47 | #include <linux/i2c.h> | 47 | #include <linux/i2c.h> |
48 | #include <linux/i2c-algo-bit.h> | ||
49 | 48 | ||
50 | #include <media/v4l2-common.h> | 49 | #include <media/v4l2-common.h> |
51 | #include <media/i2c-addr.h> | 50 | #include <media/i2c-addr.h> |
diff --git a/drivers/media/video/tda8290.c b/drivers/media/video/tda8290.c index 027c8a074dfe..1a1bef0e9c3d 100644 --- a/drivers/media/video/tda8290.c +++ b/drivers/media/video/tda8290.c | |||
@@ -192,14 +192,52 @@ static struct tda827xa_data tda827xa_analog[] = { | |||
192 | { .lomax = 0, .svco = 0, .spd = 0, .scr = 0, .sbs = 0, .gc3 = 0} /* End */ | 192 | { .lomax = 0, .svco = 0, .spd = 0, .scr = 0, .sbs = 0, .gc3 = 0} /* End */ |
193 | }; | 193 | }; |
194 | 194 | ||
195 | static void tda827xa_lna_gain(struct i2c_client *c, int high) | ||
196 | { | ||
197 | struct tuner *t = i2c_get_clientdata(c); | ||
198 | unsigned char buf[] = {0x22, 0x01}; | ||
199 | int arg; | ||
200 | struct i2c_msg msg = {.addr = c->addr, .flags = 0, .buf = buf, .len = sizeof(buf)}; | ||
201 | if (t->config) { | ||
202 | if (high) | ||
203 | tuner_dbg("setting LNA to high gain\n"); | ||
204 | else | ||
205 | tuner_dbg("setting LNA to low gain\n"); | ||
206 | } | ||
207 | switch (t->config) { | ||
208 | case 0: /* no LNA */ | ||
209 | break; | ||
210 | case 1: /* switch is GPIO 0 of tda8290 */ | ||
211 | case 2: | ||
212 | /* turn Vsync on */ | ||
213 | if (t->std & V4L2_STD_MN) | ||
214 | arg = 1; | ||
215 | else | ||
216 | arg = 0; | ||
217 | if (t->tuner_callback) | ||
218 | t->tuner_callback(c->adapter->algo_data, 1, arg); | ||
219 | buf[1] = high ? 0 : 1; | ||
220 | if (t->config == 2) | ||
221 | buf[1] = high ? 1 : 0; | ||
222 | i2c_transfer(c->adapter, &msg, 1); | ||
223 | break; | ||
224 | case 3: /* switch with GPIO of saa713x */ | ||
225 | if (t->tuner_callback) | ||
226 | t->tuner_callback(c->adapter->algo_data, 0, high); | ||
227 | break; | ||
228 | } | ||
229 | } | ||
230 | |||
195 | static void tda827xa_tune(struct i2c_client *c, u16 ifc, unsigned int freq) | 231 | static void tda827xa_tune(struct i2c_client *c, u16 ifc, unsigned int freq) |
196 | { | 232 | { |
197 | unsigned char tuner_reg[14]; | 233 | unsigned char tuner_reg[11]; |
198 | unsigned char reg2[2]; | ||
199 | u32 N; | 234 | u32 N; |
200 | int i; | 235 | int i; |
201 | struct tuner *t = i2c_get_clientdata(c); | 236 | struct tuner *t = i2c_get_clientdata(c); |
202 | struct i2c_msg msg = {.addr = t->tda827x_addr, .flags = 0}; | 237 | struct i2c_msg msg = {.addr = t->tda827x_addr, .flags = 0, .buf = tuner_reg}; |
238 | |||
239 | tda827xa_lna_gain( c, 1); | ||
240 | msleep(10); | ||
203 | 241 | ||
204 | if (t->mode == V4L2_TUNER_RADIO) | 242 | if (t->mode == V4L2_TUNER_RADIO) |
205 | freq = freq / 1000; | 243 | freq = freq / 1000; |
@@ -222,48 +260,58 @@ static void tda827xa_tune(struct i2c_client *c, u16 ifc, unsigned int freq) | |||
222 | tuner_reg[5] = (tda827xa_analog[i].spd << 5) + (tda827xa_analog[i].svco << 3) + | 260 | tuner_reg[5] = (tda827xa_analog[i].spd << 5) + (tda827xa_analog[i].svco << 3) + |
223 | tda827xa_analog[i].sbs; | 261 | tda827xa_analog[i].sbs; |
224 | tuner_reg[6] = 0x8b + (tda827xa_analog[i].gc3 << 4); | 262 | tuner_reg[6] = 0x8b + (tda827xa_analog[i].gc3 << 4); |
225 | tuner_reg[7] = 0x0c; | 263 | tuner_reg[7] = 0x1c; |
226 | tuner_reg[8] = 4; | 264 | tuner_reg[8] = 4; |
227 | tuner_reg[9] = 0x20; | 265 | tuner_reg[9] = 0x20; |
228 | tuner_reg[10] = 0xff; | 266 | tuner_reg[10] = 0x00; |
229 | tuner_reg[11] = 0xe0; | 267 | msg.len = 11; |
230 | tuner_reg[12] = 0; | 268 | i2c_transfer(c->adapter, &msg, 1); |
231 | tuner_reg[13] = 0x39 + (t->tda827x_lpsel << 1); | ||
232 | 269 | ||
233 | msg.buf = tuner_reg; | 270 | tuner_reg[0] = 0x90; |
234 | msg.len = 14; | 271 | tuner_reg[1] = 0xff; |
272 | tuner_reg[2] = 0xe0; | ||
273 | tuner_reg[3] = 0; | ||
274 | tuner_reg[4] = 0x99 + (t->tda827x_lpsel << 1); | ||
275 | msg.len = 5; | ||
235 | i2c_transfer(c->adapter, &msg, 1); | 276 | i2c_transfer(c->adapter, &msg, 1); |
236 | 277 | ||
237 | msg.buf= reg2; | 278 | tuner_reg[0] = 0xa0; |
279 | tuner_reg[1] = 0xc0; | ||
238 | msg.len = 2; | 280 | msg.len = 2; |
239 | reg2[0] = 0x60; | ||
240 | reg2[1] = 0x3c; | ||
241 | i2c_transfer(c->adapter, &msg, 1); | 281 | i2c_transfer(c->adapter, &msg, 1); |
242 | 282 | ||
243 | reg2[0] = 0xa0; | 283 | tuner_reg[0] = 0x30; |
244 | reg2[1] = 0xc0; | 284 | tuner_reg[1] = 0x10 + tda827xa_analog[i].scr; |
245 | i2c_transfer(c->adapter, &msg, 1); | 285 | i2c_transfer(c->adapter, &msg, 1); |
246 | 286 | ||
247 | msleep(2); | 287 | msg.flags = I2C_M_RD; |
248 | reg2[0] = 0x30; | 288 | i2c_transfer(c->adapter, &msg, 1); |
249 | reg2[1] = 0x10 + tda827xa_analog[i].scr; | 289 | msg.flags = 0; |
290 | tuner_reg[1] >>= 4; | ||
291 | tuner_dbg("AGC2 gain is: %d\n", tuner_reg[1]); | ||
292 | if (tuner_reg[1] < 1) | ||
293 | tda827xa_lna_gain( c, 0); | ||
294 | |||
295 | msleep(100); | ||
296 | tuner_reg[0] = 0x60; | ||
297 | tuner_reg[1] = 0x3c; | ||
250 | i2c_transfer(c->adapter, &msg, 1); | 298 | i2c_transfer(c->adapter, &msg, 1); |
251 | 299 | ||
252 | msleep(550); | 300 | msleep(163); |
253 | reg2[0] = 0x50; | 301 | tuner_reg[0] = 0x50; |
254 | reg2[1] = 0x8f + (tda827xa_analog[i].gc3 << 4); | 302 | tuner_reg[1] = 0x8f + (tda827xa_analog[i].gc3 << 4); |
255 | i2c_transfer(c->adapter, &msg, 1); | 303 | i2c_transfer(c->adapter, &msg, 1); |
256 | 304 | ||
257 | reg2[0] = 0x80; | 305 | tuner_reg[0] = 0x80; |
258 | reg2[1] = 0x28; | 306 | tuner_reg[1] = 0x28; |
259 | i2c_transfer(c->adapter, &msg, 1); | 307 | i2c_transfer(c->adapter, &msg, 1); |
260 | 308 | ||
261 | reg2[0] = 0xb0; | 309 | tuner_reg[0] = 0xb0; |
262 | reg2[1] = 0x01; | 310 | tuner_reg[1] = 0x01; |
263 | i2c_transfer(c->adapter, &msg, 1); | 311 | i2c_transfer(c->adapter, &msg, 1); |
264 | 312 | ||
265 | reg2[0] = 0xc0; | 313 | tuner_reg[0] = 0xc0; |
266 | reg2[1] = 0x19 + (t->tda827x_lpsel << 1); | 314 | tuner_reg[1] = 0x19 + (t->tda827x_lpsel << 1); |
267 | i2c_transfer(c->adapter, &msg, 1); | 315 | i2c_transfer(c->adapter, &msg, 1); |
268 | } | 316 | } |
269 | 317 | ||
@@ -319,7 +367,9 @@ static int tda8290_tune(struct i2c_client *c, u16 ifc, unsigned int freq) | |||
319 | unsigned char addr_pll_stat = 0x1b; | 367 | unsigned char addr_pll_stat = 0x1b; |
320 | unsigned char adc_sat, agc_stat, | 368 | unsigned char adc_sat, agc_stat, |
321 | pll_stat; | 369 | pll_stat; |
370 | int i; | ||
322 | 371 | ||
372 | tuner_dbg("tda827xa config is 0x%02x\n", t->config); | ||
323 | i2c_master_send(c, easy_mode, 2); | 373 | i2c_master_send(c, easy_mode, 2); |
324 | i2c_master_send(c, agc_out_on, 2); | 374 | i2c_master_send(c, agc_out_on, 2); |
325 | i2c_master_send(c, soft_reset, 2); | 375 | i2c_master_send(c, soft_reset, 2); |
@@ -340,17 +390,22 @@ static int tda8290_tune(struct i2c_client *c, u16 ifc, unsigned int freq) | |||
340 | tda827xa_tune(c, ifc, freq); | 390 | tda827xa_tune(c, ifc, freq); |
341 | else | 391 | else |
342 | tda827x_tune(c, ifc, freq); | 392 | tda827x_tune(c, ifc, freq); |
393 | for (i = 0; i < 3; i++) { | ||
394 | i2c_master_send(c, &addr_pll_stat, 1); | ||
395 | i2c_master_recv(c, &pll_stat, 1); | ||
396 | if (pll_stat & 0x80) { | ||
397 | i2c_master_send(c, &addr_adc_sat, 1); | ||
398 | i2c_master_recv(c, &adc_sat, 1); | ||
399 | i2c_master_send(c, &addr_agc_stat, 1); | ||
400 | i2c_master_recv(c, &agc_stat, 1); | ||
401 | tuner_dbg("tda8290 is locked, AGC: %d\n", agc_stat); | ||
402 | break; | ||
403 | } else { | ||
404 | tuner_dbg("tda8290 not locked, no signal?\n"); | ||
405 | msleep(100); | ||
406 | } | ||
407 | } | ||
343 | /* adjust headroom resp. gain */ | 408 | /* adjust headroom resp. gain */ |
344 | i2c_master_send(c, &addr_adc_sat, 1); | ||
345 | i2c_master_recv(c, &adc_sat, 1); | ||
346 | i2c_master_send(c, &addr_agc_stat, 1); | ||
347 | i2c_master_recv(c, &agc_stat, 1); | ||
348 | i2c_master_send(c, &addr_pll_stat, 1); | ||
349 | i2c_master_recv(c, &pll_stat, 1); | ||
350 | if (pll_stat & 0x80) | ||
351 | tuner_dbg("tda8290 is locked, AGC: %d\n", agc_stat); | ||
352 | else | ||
353 | tuner_dbg("tda8290 not locked, no signal?\n"); | ||
354 | if ((agc_stat > 115) || (!(pll_stat & 0x80) && (adc_sat < 20))) { | 409 | if ((agc_stat > 115) || (!(pll_stat & 0x80) && (adc_sat < 20))) { |
355 | tuner_dbg("adjust gain, step 1. Agc: %d, ADC stat: %d, lock: %d\n", | 410 | tuner_dbg("adjust gain, step 1. Agc: %d, ADC stat: %d, lock: %d\n", |
356 | agc_stat, adc_sat, pll_stat & 0x80); | 411 | agc_stat, adc_sat, pll_stat & 0x80); |
@@ -407,7 +462,6 @@ static void set_audio(struct tuner *t) | |||
407 | char* mode; | 462 | char* mode; |
408 | 463 | ||
409 | t->tda827x_lpsel = 0; | 464 | t->tda827x_lpsel = 0; |
410 | mode = "xx"; | ||
411 | if (t->std & V4L2_STD_MN) { | 465 | if (t->std & V4L2_STD_MN) { |
412 | t->sgIF = 92; | 466 | t->sgIF = 92; |
413 | t->tda8290_easy_mode = 0x01; | 467 | t->tda8290_easy_mode = 0x01; |
@@ -437,8 +491,12 @@ static void set_audio(struct tuner *t) | |||
437 | t->sgIF = 20; | 491 | t->sgIF = 20; |
438 | t->tda8290_easy_mode = 0x40; | 492 | t->tda8290_easy_mode = 0x40; |
439 | mode = "LC"; | 493 | mode = "LC"; |
494 | } else { | ||
495 | t->sgIF = 124; | ||
496 | t->tda8290_easy_mode = 0x10; | ||
497 | mode = "xx"; | ||
440 | } | 498 | } |
441 | tuner_dbg("setting tda8290 to system %s\n", mode); | 499 | tuner_dbg("setting tda8290 to system %s\n", mode); |
442 | } | 500 | } |
443 | 501 | ||
444 | static void set_tv_freq(struct i2c_client *c, unsigned int freq) | 502 | static void set_tv_freq(struct i2c_client *c, unsigned int freq) |
@@ -487,11 +545,16 @@ static void standby(struct i2c_client *c) | |||
487 | 545 | ||
488 | static void tda8290_init_if(struct i2c_client *c) | 546 | static void tda8290_init_if(struct i2c_client *c) |
489 | { | 547 | { |
548 | struct tuner *t = i2c_get_clientdata(c); | ||
490 | unsigned char set_VS[] = { 0x30, 0x6F }; | 549 | unsigned char set_VS[] = { 0x30, 0x6F }; |
550 | unsigned char set_GP00_CF[] = { 0x20, 0x01 }; | ||
491 | unsigned char set_GP01_CF[] = { 0x20, 0x0B }; | 551 | unsigned char set_GP01_CF[] = { 0x20, 0x0B }; |
492 | 552 | ||
553 | if ((t->config == 1) || (t->config == 2)) | ||
554 | i2c_master_send(c, set_GP00_CF, 2); | ||
555 | else | ||
556 | i2c_master_send(c, set_GP01_CF, 2); | ||
493 | i2c_master_send(c, set_VS, 2); | 557 | i2c_master_send(c, set_VS, 2); |
494 | i2c_master_send(c, set_GP01_CF, 2); | ||
495 | } | 558 | } |
496 | 559 | ||
497 | static void tda8290_init_tuner(struct i2c_client *c) | 560 | static void tda8290_init_tuner(struct i2c_client *c) |
@@ -576,6 +639,7 @@ int tda8290_init(struct i2c_client *c) | |||
576 | t->has_signal = has_signal; | 639 | t->has_signal = has_signal; |
577 | t->standby = standby; | 640 | t->standby = standby; |
578 | t->tda827x_lpsel = 0; | 641 | t->tda827x_lpsel = 0; |
642 | t->mode = V4L2_TUNER_ANALOG_TV; | ||
579 | 643 | ||
580 | tda8290_init_tuner(c); | 644 | tda8290_init_tuner(c); |
581 | tda8290_init_if(c); | 645 | tda8290_init_if(c); |
diff --git a/drivers/media/video/tda9875.c b/drivers/media/video/tda9875.c index 00f0e8b6e03b..d11044170872 100644 --- a/drivers/media/video/tda9875.c +++ b/drivers/media/video/tda9875.c | |||
@@ -27,7 +27,6 @@ | |||
27 | #include <linux/videodev.h> | 27 | #include <linux/videodev.h> |
28 | #include <media/v4l2-common.h> | 28 | #include <media/v4l2-common.h> |
29 | #include <linux/i2c.h> | 29 | #include <linux/i2c.h> |
30 | #include <linux/i2c-algo-bit.h> | ||
31 | #include <linux/init.h> | 30 | #include <linux/init.h> |
32 | 31 | ||
33 | 32 | ||
diff --git a/drivers/media/video/tuner-core.c b/drivers/media/video/tuner-core.c index 15dbc6bf42a7..505591a7abe9 100644 --- a/drivers/media/video/tuner-core.c +++ b/drivers/media/video/tuner-core.c | |||
@@ -144,7 +144,8 @@ static void set_freq(struct i2c_client *c, unsigned long freq) | |||
144 | } | 144 | } |
145 | 145 | ||
146 | static void set_type(struct i2c_client *c, unsigned int type, | 146 | static void set_type(struct i2c_client *c, unsigned int type, |
147 | unsigned int new_mode_mask) | 147 | unsigned int new_mode_mask, unsigned int new_config, |
148 | int (*tuner_callback) (void *dev, int command,int arg)) | ||
148 | { | 149 | { |
149 | struct tuner *t = i2c_get_clientdata(c); | 150 | struct tuner *t = i2c_get_clientdata(c); |
150 | unsigned char buffer[4]; | 151 | unsigned char buffer[4]; |
@@ -159,15 +160,20 @@ static void set_type(struct i2c_client *c, unsigned int type, | |||
159 | return; | 160 | return; |
160 | } | 161 | } |
161 | 162 | ||
163 | t->type = type; | ||
164 | t->config = new_config; | ||
165 | if (tuner_callback != NULL) { | ||
166 | tuner_dbg("defining GPIO callback\n"); | ||
167 | t->tuner_callback = tuner_callback; | ||
168 | } | ||
169 | |||
162 | /* This code detects calls by card attach_inform */ | 170 | /* This code detects calls by card attach_inform */ |
163 | if (NULL == t->i2c.dev.driver) { | 171 | if (NULL == t->i2c.dev.driver) { |
164 | tuner_dbg ("tuner 0x%02x: called during i2c_client register by adapter's attach_inform\n", c->addr); | 172 | tuner_dbg ("tuner 0x%02x: called during i2c_client register by adapter's attach_inform\n", c->addr); |
165 | 173 | ||
166 | t->type=type; | ||
167 | return; | 174 | return; |
168 | } | 175 | } |
169 | 176 | ||
170 | t->type = type; | ||
171 | switch (t->type) { | 177 | switch (t->type) { |
172 | case TUNER_MT2032: | 178 | case TUNER_MT2032: |
173 | microtune_init(c); | 179 | microtune_init(c); |
@@ -234,10 +240,11 @@ static void set_addr(struct i2c_client *c, struct tuner_setup *tun_setup) | |||
234 | 240 | ||
235 | tuner_dbg("set addr for type %i\n", t->type); | 241 | tuner_dbg("set addr for type %i\n", t->type); |
236 | 242 | ||
237 | if ( t->type == UNSET && ((tun_setup->addr == ADDR_UNSET && | 243 | if ( (t->type == UNSET && ((tun_setup->addr == ADDR_UNSET) && |
238 | (t->mode_mask & tun_setup->mode_mask)) || | 244 | (t->mode_mask & tun_setup->mode_mask))) || |
239 | tun_setup->addr == c->addr)) { | 245 | (tun_setup->addr == c->addr)) { |
240 | set_type(c, tun_setup->type, tun_setup->mode_mask); | 246 | set_type(c, tun_setup->type, tun_setup->mode_mask, |
247 | tun_setup->config, tun_setup->tuner_callback); | ||
241 | } | 248 | } |
242 | } | 249 | } |
243 | 250 | ||
@@ -496,7 +503,7 @@ static int tuner_attach(struct i2c_adapter *adap, int addr, int kind) | |||
496 | register_client: | 503 | register_client: |
497 | tuner_info("chip found @ 0x%x (%s)\n", addr << 1, adap->name); | 504 | tuner_info("chip found @ 0x%x (%s)\n", addr << 1, adap->name); |
498 | i2c_attach_client (&t->i2c); | 505 | i2c_attach_client (&t->i2c); |
499 | set_type (&t->i2c,t->type, t->mode_mask); | 506 | set_type (&t->i2c,t->type, t->mode_mask, t->config, t->tuner_callback); |
500 | return 0; | 507 | return 0; |
501 | } | 508 | } |
502 | 509 | ||
@@ -576,10 +583,11 @@ static int tuner_command(struct i2c_client *client, unsigned int cmd, void *arg) | |||
576 | switch (cmd) { | 583 | switch (cmd) { |
577 | /* --- configuration --- */ | 584 | /* --- configuration --- */ |
578 | case TUNER_SET_TYPE_ADDR: | 585 | case TUNER_SET_TYPE_ADDR: |
579 | tuner_dbg ("Calling set_type_addr for type=%d, addr=0x%02x, mode=0x%02x\n", | 586 | tuner_dbg ("Calling set_type_addr for type=%d, addr=0x%02x, mode=0x%02x, config=0x%02x\n", |
580 | ((struct tuner_setup *)arg)->type, | 587 | ((struct tuner_setup *)arg)->type, |
581 | ((struct tuner_setup *)arg)->addr, | 588 | ((struct tuner_setup *)arg)->addr, |
582 | ((struct tuner_setup *)arg)->mode_mask); | 589 | ((struct tuner_setup *)arg)->mode_mask, |
590 | ((struct tuner_setup *)arg)->config); | ||
583 | 591 | ||
584 | set_addr(client, (struct tuner_setup *)arg); | 592 | set_addr(client, (struct tuner_setup *)arg); |
585 | break; | 593 | break; |
diff --git a/drivers/media/video/tvaudio.c b/drivers/media/video/tvaudio.c index d506dfaa45a9..a2da5d2affff 100644 --- a/drivers/media/video/tvaudio.c +++ b/drivers/media/video/tvaudio.c | |||
@@ -25,7 +25,6 @@ | |||
25 | #include <linux/slab.h> | 25 | #include <linux/slab.h> |
26 | #include <linux/videodev.h> | 26 | #include <linux/videodev.h> |
27 | #include <linux/i2c.h> | 27 | #include <linux/i2c.h> |
28 | #include <linux/i2c-algo-bit.h> | ||
29 | #include <linux/init.h> | 28 | #include <linux/init.h> |
30 | #include <linux/smp_lock.h> | 29 | #include <linux/smp_lock.h> |
31 | #include <linux/kthread.h> | 30 | #include <linux/kthread.h> |
@@ -33,6 +32,7 @@ | |||
33 | 32 | ||
34 | #include <media/tvaudio.h> | 33 | #include <media/tvaudio.h> |
35 | #include <media/v4l2-common.h> | 34 | #include <media/v4l2-common.h> |
35 | #include <media/v4l2-chip-ident.h> | ||
36 | 36 | ||
37 | #include <media/i2c-addr.h> | 37 | #include <media/i2c-addr.h> |
38 | 38 | ||
@@ -1775,6 +1775,9 @@ static int chip_command(struct i2c_client *client, | |||
1775 | /* the thread will call checkmode() later */ | 1775 | /* the thread will call checkmode() later */ |
1776 | } | 1776 | } |
1777 | break; | 1777 | break; |
1778 | |||
1779 | case VIDIOC_G_CHIP_IDENT: | ||
1780 | return v4l2_chip_ident_i2c_client(client, arg, V4L2_IDENT_TVAUDIO, 0); | ||
1778 | } | 1781 | } |
1779 | return 0; | 1782 | return 0; |
1780 | } | 1783 | } |
diff --git a/drivers/media/video/tveeprom.c b/drivers/media/video/tveeprom.c index 4e7c1fa668d3..a1136da74ba8 100644 --- a/drivers/media/video/tveeprom.c +++ b/drivers/media/video/tveeprom.c | |||
@@ -163,7 +163,7 @@ hauppauge_tuner[] = | |||
163 | /* 60-69 */ | 163 | /* 60-69 */ |
164 | { TUNER_PHILIPS_FM1216ME_MK3, "LG S001D MK3"}, | 164 | { TUNER_PHILIPS_FM1216ME_MK3, "LG S001D MK3"}, |
165 | { TUNER_ABSENT, "LG M001D MK3"}, | 165 | { TUNER_ABSENT, "LG M001D MK3"}, |
166 | { TUNER_ABSENT, "LG S701D MK3"}, | 166 | { TUNER_PHILIPS_FM1216ME_MK3, "LG S701D MK3"}, |
167 | { TUNER_ABSENT, "LG M701D MK3"}, | 167 | { TUNER_ABSENT, "LG M701D MK3"}, |
168 | { TUNER_ABSENT, "Temic 4146FM5"}, | 168 | { TUNER_ABSENT, "Temic 4146FM5"}, |
169 | { TUNER_ABSENT, "Temic 4136FY5"}, | 169 | { TUNER_ABSENT, "Temic 4136FY5"}, |
@@ -229,6 +229,36 @@ hauppauge_tuner[] = | |||
229 | /* 120-129 */ | 229 | /* 120-129 */ |
230 | { TUNER_ABSENT, "Xceive XC3028"}, | 230 | { TUNER_ABSENT, "Xceive XC3028"}, |
231 | { TUNER_ABSENT, "Philips FQ1216LME MK5"}, | 231 | { TUNER_ABSENT, "Philips FQ1216LME MK5"}, |
232 | { TUNER_ABSENT, "Philips FQD1216LME"}, | ||
233 | { TUNER_ABSENT, "Conexant CX24118A"}, | ||
234 | { TUNER_ABSENT, "TCL DMF11WIP"}, | ||
235 | { TUNER_ABSENT, "TCL MFNM05_4H_E"}, | ||
236 | { TUNER_ABSENT, "TCL MNM05_4H_E"}, | ||
237 | { TUNER_ABSENT, "TCL MPE05_2H_E"}, | ||
238 | { TUNER_ABSENT, "TCL MQNM05_4_U"}, | ||
239 | { TUNER_ABSENT, "TCL M2523_5NH_E"}, | ||
240 | /* 130-139 */ | ||
241 | { TUNER_ABSENT, "TCL M2523_3DBH_E"}, | ||
242 | { TUNER_ABSENT, "TCL M2523_3DIH_E"}, | ||
243 | { TUNER_ABSENT, "TCL MFPE05_2_U"}, | ||
244 | { TUNER_ABSENT, "Philips FMD1216MEX"}, | ||
245 | { TUNER_ABSENT, "Philips FRH2036B"}, | ||
246 | { TUNER_ABSENT, "Panasonic ENGF75_01GF"}, | ||
247 | { TUNER_ABSENT, "MaxLinear MXL5005"}, | ||
248 | { TUNER_ABSENT, "MaxLinear MXL5003"}, | ||
249 | { TUNER_ABSENT, "Xceive XC2028"}, | ||
250 | { TUNER_ABSENT, "Microtune MT2131"}, | ||
251 | /* 140-149 */ | ||
252 | { TUNER_ABSENT, "Philips 8275A_8295"}, | ||
253 | { TUNER_ABSENT, "TCL MF02GIP_5N_E"}, | ||
254 | { TUNER_ABSENT, "TCL MF02GIP_3DB_E"}, | ||
255 | { TUNER_ABSENT, "TCL MF02GIP_3DI_E"}, | ||
256 | { TUNER_ABSENT, "Microtune MT2266"}, | ||
257 | { TUNER_ABSENT, "TCL MF10WPP_4N_E"}, | ||
258 | { TUNER_ABSENT, "LG TAPQ_H702F"}, | ||
259 | { TUNER_ABSENT, "TCL M09WPP_4N_E"}, | ||
260 | { TUNER_ABSENT, "MaxLinear MXL5005_v2"}, | ||
261 | { TUNER_ABSENT, "Philips 18271_8295"}, | ||
232 | }; | 262 | }; |
233 | 263 | ||
234 | static struct HAUPPAUGE_AUDIOIC | 264 | static struct HAUPPAUGE_AUDIOIC |
@@ -280,11 +310,16 @@ audioIC[] = | |||
280 | {AUDIO_CHIP_INTERNAL, "CX883"}, | 310 | {AUDIO_CHIP_INTERNAL, "CX883"}, |
281 | {AUDIO_CHIP_INTERNAL, "CX882"}, | 311 | {AUDIO_CHIP_INTERNAL, "CX882"}, |
282 | {AUDIO_CHIP_INTERNAL, "CX25840"}, | 312 | {AUDIO_CHIP_INTERNAL, "CX25840"}, |
283 | /* 35-38 */ | 313 | /* 35-39 */ |
284 | {AUDIO_CHIP_INTERNAL, "CX25841"}, | 314 | {AUDIO_CHIP_INTERNAL, "CX25841"}, |
285 | {AUDIO_CHIP_INTERNAL, "CX25842"}, | 315 | {AUDIO_CHIP_INTERNAL, "CX25842"}, |
286 | {AUDIO_CHIP_INTERNAL, "CX25843"}, | 316 | {AUDIO_CHIP_INTERNAL, "CX25843"}, |
287 | {AUDIO_CHIP_INTERNAL, "CX23418"}, | 317 | {AUDIO_CHIP_INTERNAL, "CX23418"}, |
318 | {AUDIO_CHIP_INTERNAL, "CX23885"}, | ||
319 | /* 40-42 */ | ||
320 | {AUDIO_CHIP_INTERNAL, "CX23888"}, | ||
321 | {AUDIO_CHIP_INTERNAL, "SAA7131"}, | ||
322 | {AUDIO_CHIP_INTERNAL, "CX23887"}, | ||
288 | }; | 323 | }; |
289 | 324 | ||
290 | /* This list is supplied by Hauppauge. Thanks! */ | 325 | /* This list is supplied by Hauppauge. Thanks! */ |
@@ -301,8 +336,10 @@ static const char *decoderIC[] = { | |||
301 | "CX880", "CX881", "CX883", "SAA7111", "SAA7113", | 336 | "CX880", "CX881", "CX883", "SAA7111", "SAA7113", |
302 | /* 25-29 */ | 337 | /* 25-29 */ |
303 | "CX882", "TVP5150A", "CX25840", "CX25841", "CX25842", | 338 | "CX882", "TVP5150A", "CX25840", "CX25841", "CX25842", |
304 | /* 30-31 */ | 339 | /* 30-34 */ |
305 | "CX25843", "CX23418", | 340 | "CX25843", "CX23418", "NEC61153", "CX23885", "CX23888", |
341 | /* 35-37 */ | ||
342 | "SAA7131", "CX25837", "CX23887" | ||
306 | }; | 343 | }; |
307 | 344 | ||
308 | static int hasRadioTuner(int tunerType) | 345 | static int hasRadioTuner(int tunerType) |
diff --git a/drivers/media/video/upd64031a.c b/drivers/media/video/upd64031a.c index 28d1133a3b7a..0b2a961efd22 100644 --- a/drivers/media/video/upd64031a.c +++ b/drivers/media/video/upd64031a.c | |||
@@ -27,6 +27,7 @@ | |||
27 | #include <linux/i2c.h> | 27 | #include <linux/i2c.h> |
28 | #include <linux/videodev2.h> | 28 | #include <linux/videodev2.h> |
29 | #include <media/v4l2-common.h> | 29 | #include <media/v4l2-common.h> |
30 | #include <media/v4l2-chip-ident.h> | ||
30 | #include <media/upd64031a.h> | 31 | #include <media/upd64031a.h> |
31 | 32 | ||
32 | // --------------------- read registers functions define ----------------------- | 33 | // --------------------- read registers functions define ----------------------- |
@@ -179,6 +180,9 @@ static int upd64031a_command(struct i2c_client *client, unsigned int cmd, void * | |||
179 | } | 180 | } |
180 | #endif | 181 | #endif |
181 | 182 | ||
183 | case VIDIOC_G_CHIP_IDENT: | ||
184 | return v4l2_chip_ident_i2c_client(client, arg, V4L2_IDENT_UPD64031A, 0); | ||
185 | |||
182 | default: | 186 | default: |
183 | break; | 187 | break; |
184 | } | 188 | } |
diff --git a/drivers/media/video/upd64083.c b/drivers/media/video/upd64083.c index fe38224150d8..401bd21f46eb 100644 --- a/drivers/media/video/upd64083.c +++ b/drivers/media/video/upd64083.c | |||
@@ -26,6 +26,7 @@ | |||
26 | #include <linux/i2c.h> | 26 | #include <linux/i2c.h> |
27 | #include <linux/videodev2.h> | 27 | #include <linux/videodev2.h> |
28 | #include <media/v4l2-common.h> | 28 | #include <media/v4l2-common.h> |
29 | #include <media/v4l2-chip-ident.h> | ||
29 | #include <media/upd64083.h> | 30 | #include <media/upd64083.h> |
30 | 31 | ||
31 | MODULE_DESCRIPTION("uPD64083 driver"); | 32 | MODULE_DESCRIPTION("uPD64083 driver"); |
@@ -155,6 +156,10 @@ static int upd64083_command(struct i2c_client *client, unsigned int cmd, void *a | |||
155 | break; | 156 | break; |
156 | } | 157 | } |
157 | #endif | 158 | #endif |
159 | |||
160 | case VIDIOC_G_CHIP_IDENT: | ||
161 | return v4l2_chip_ident_i2c_client(client, arg, V4L2_IDENT_UPD64083, 0); | ||
162 | |||
158 | default: | 163 | default: |
159 | break; | 164 | break; |
160 | } | 165 | } |
diff --git a/drivers/media/video/usbvideo/usbvideo.c b/drivers/media/video/usbvideo/usbvideo.c index d34d8c8b7376..687f026753b2 100644 --- a/drivers/media/video/usbvideo/usbvideo.c +++ b/drivers/media/video/usbvideo/usbvideo.c | |||
@@ -628,24 +628,21 @@ EXPORT_SYMBOL(usbvideo_HexDump); | |||
628 | /* ******************************************************************** */ | 628 | /* ******************************************************************** */ |
629 | 629 | ||
630 | /* XXX: this piece of crap really wants some error handling.. */ | 630 | /* XXX: this piece of crap really wants some error handling.. */ |
631 | static void usbvideo_ClientIncModCount(struct uvd *uvd) | 631 | static int usbvideo_ClientIncModCount(struct uvd *uvd) |
632 | { | 632 | { |
633 | if (uvd == NULL) { | 633 | if (uvd == NULL) { |
634 | err("%s: uvd == NULL", __FUNCTION__); | 634 | err("%s: uvd == NULL", __FUNCTION__); |
635 | return; | 635 | return -EINVAL; |
636 | } | 636 | } |
637 | if (uvd->handle == NULL) { | 637 | if (uvd->handle == NULL) { |
638 | err("%s: uvd->handle == NULL", __FUNCTION__); | 638 | err("%s: uvd->handle == NULL", __FUNCTION__); |
639 | return; | 639 | return -EINVAL; |
640 | } | ||
641 | if (uvd->handle->md_module == NULL) { | ||
642 | err("%s: uvd->handle->md_module == NULL", __FUNCTION__); | ||
643 | return; | ||
644 | } | 640 | } |
645 | if (!try_module_get(uvd->handle->md_module)) { | 641 | if (!try_module_get(uvd->handle->md_module)) { |
646 | err("%s: try_module_get() == 0", __FUNCTION__); | 642 | err("%s: try_module_get() == 0", __FUNCTION__); |
647 | return; | 643 | return -ENODEV; |
648 | } | 644 | } |
645 | return 0; | ||
649 | } | 646 | } |
650 | 647 | ||
651 | static void usbvideo_ClientDecModCount(struct uvd *uvd) | 648 | static void usbvideo_ClientDecModCount(struct uvd *uvd) |
@@ -712,8 +709,6 @@ int usbvideo_register( | |||
712 | cams->num_cameras = num_cams; | 709 | cams->num_cameras = num_cams; |
713 | cams->cam = (struct uvd *) &cams[1]; | 710 | cams->cam = (struct uvd *) &cams[1]; |
714 | cams->md_module = md; | 711 | cams->md_module = md; |
715 | if (cams->md_module == NULL) | ||
716 | warn("%s: module == NULL!", __FUNCTION__); | ||
717 | mutex_init(&cams->lock); /* to 1 == available */ | 712 | mutex_init(&cams->lock); /* to 1 == available */ |
718 | 713 | ||
719 | for (i = 0; i < num_cams; i++) { | 714 | for (i = 0; i < num_cams; i++) { |
@@ -1119,7 +1114,8 @@ static int usbvideo_v4l_open(struct inode *inode, struct file *file) | |||
1119 | if (uvd->debug > 1) | 1114 | if (uvd->debug > 1) |
1120 | info("%s($%p)", __FUNCTION__, dev); | 1115 | info("%s($%p)", __FUNCTION__, dev); |
1121 | 1116 | ||
1122 | usbvideo_ClientIncModCount(uvd); | 1117 | if (0 < usbvideo_ClientIncModCount(uvd)) |
1118 | return -ENODEV; | ||
1123 | mutex_lock(&uvd->lock); | 1119 | mutex_lock(&uvd->lock); |
1124 | 1120 | ||
1125 | if (uvd->user) { | 1121 | if (uvd->user) { |
diff --git a/drivers/media/video/usbvision/usbvision-cards.c b/drivers/media/video/usbvision/usbvision-cards.c index a40e5838515b..13f69fe6360d 100644 --- a/drivers/media/video/usbvision/usbvision-cards.c +++ b/drivers/media/video/usbvision/usbvision-cards.c | |||
@@ -1,6 +1,6 @@ | |||
1 | /* | 1 | /* |
2 | * USBVISION.H | 2 | * usbvision-cards.c |
3 | * usbvision header file | 3 | * usbvision cards definition file |
4 | * | 4 | * |
5 | * Copyright (c) 1999-2005 Joerg Heckenbach <joerg@heckenbach-aw.de> | 5 | * Copyright (c) 1999-2005 Joerg Heckenbach <joerg@heckenbach-aw.de> |
6 | * | 6 | * |
@@ -28,129 +28,1060 @@ | |||
28 | #include <media/v4l2-dev.h> | 28 | #include <media/v4l2-dev.h> |
29 | #include <media/tuner.h> | 29 | #include <media/tuner.h> |
30 | #include "usbvision.h" | 30 | #include "usbvision.h" |
31 | #include "usbvision-cards.h" | ||
31 | 32 | ||
32 | /* Supported Devices: A table for usbvision.c*/ | 33 | /* Supported Devices: A table for usbvision.c*/ |
33 | struct usbvision_device_data_st usbvision_device_data[] = { | 34 | struct usbvision_device_data_st usbvision_device_data[] = { |
34 | {0xFFF0, 0xFFF0, -1, CODEC_SAA7111, 3, V4L2_STD_NTSC, 1, 1, 1, 1, TUNER_PHILIPS_NTSC_M, -1, -1, -1, -1, -1, "Custom Dummy USBVision Device"}, | 35 | [XANBOO] = { |
35 | {0x0A6F, 0x0400, -1, CODEC_SAA7113, 4, V4L2_STD_NTSC, 1, 0, 1, 0, 0, -1, -1, -1, -1, -1, "Xanboo"}, | 36 | .Interface = -1, |
36 | {0x050D, 0x0208, -1, CODEC_SAA7113, 2, V4L2_STD_PAL, 1, 0, 1, 0, 0, -1, -1, 0, 3, 7, "Belkin USBView II"}, | 37 | .Codec = CODEC_SAA7113, |
37 | {0x0571, 0x0002, 0, CODEC_SAA7111, 2, V4L2_STD_PAL, 0, 0, 1, 0, 0, -1, -1, -1, -1, 7, "echoFX InterView Lite"}, | 38 | .VideoChannels = 4, |
38 | {0x0573, 0x0003, -1, CODEC_SAA7111, 2, V4L2_STD_NTSC, 1, 0, 1, 0, 0, -1, -1, -1, -1, -1, "USBGear USBG-V1 resp. HAMA USB"}, | 39 | .VideoNorm = V4L2_STD_NTSC, |
39 | {0x0573, 0x0400, -1, CODEC_SAA7113, 4, V4L2_STD_NTSC, 0, 0, 1, 0, 0, -1, -1, 0, 3, 7, "D-Link V100"}, | 40 | .AudioChannels = 1, |
40 | {0x0573, 0x2000, -1, CODEC_SAA7111, 2, V4L2_STD_NTSC, 1, 0, 1, 0, 0, -1, -1, -1, -1, -1, "X10 USB Camera"}, | 41 | .Radio = 0, |
41 | {0x0573, 0x2d00, -1, CODEC_SAA7111, 2, V4L2_STD_PAL, 1, 0, 1, 0, 0, -1, -1, -1, 3, 7, "Osprey 50"}, | 42 | .vbi = 1, |
42 | {0x0573, 0x2d01, -1, CODEC_SAA7113, 2, V4L2_STD_NTSC, 0, 0, 1, 0, 0, -1, -1, 0, 3, 7, "Hauppauge USB-Live Model 600"}, | 43 | .Tuner = 0, |
43 | {0x0573, 0x2101, -1, CODEC_SAA7113, 2, V4L2_STD_PAL, 2, 0, 1, 0, 0, -1, -1, 0, 3, 7, "Zoran Co. PMD (Nogatech) AV-grabber Manhattan"}, | 44 | .TunerType = 0, |
44 | {0x0573, 0x4100, -1, CODEC_SAA7111, 3, V4L2_STD_NTSC, 1, 1, 1, 1, TUNER_PHILIPS_NTSC_M, -1, -1, -1, 20, -1, "Nogatech USB-TV (NTSC) FM"}, | 45 | .X_Offset = -1, |
45 | {0x0573, 0x4110, -1, CODEC_SAA7111, 3, V4L2_STD_NTSC, 1, 1, 1, 1, TUNER_PHILIPS_NTSC_M, -1, -1, -1, 20, -1, "PNY USB-TV (NTSC) FM"}, | 46 | .Y_Offset = -1, |
46 | {0x0573, 0x4450, 0, CODEC_SAA7113, 3, V4L2_STD_PAL, 1, 1, 1, 1, TUNER_PHILIPS_PAL, -1, -1, 0, 3, 7, "PixelView PlayTv-USB PRO (PAL) FM"}, | 47 | .ModelString = "Xanboo", |
47 | {0x0573, 0x4550, 0, CODEC_SAA7113, 3, V4L2_STD_PAL, 1, 1, 1, 1, TUNER_PHILIPS_PAL, -1, -1, 0, 3, 7, "ZTV ZT-721 2.4GHz USB A/V Receiver"}, | 48 | }, |
48 | {0x0573, 0x4d00, -1, CODEC_SAA7111, 3, V4L2_STD_NTSC, 1, 0, 1, 1, TUNER_PHILIPS_NTSC_M, -1, -1, -1, 20, -1, "Hauppauge WinTv-USB USA"}, | 49 | [BELKIN_VIDEOBUS_II] = { |
49 | {0x0573, 0x4d01, -1, CODEC_SAA7111, 3, V4L2_STD_NTSC, 1, 0, 1, 1, TUNER_PHILIPS_NTSC_M, -1, -1, -1, -1, -1, "Hauppauge WinTv-USB"}, | 50 | .Interface = -1, |
50 | {0x0573, 0x4d02, -1, CODEC_SAA7111, 3, V4L2_STD_NTSC, 1, 0, 1, 1, TUNER_PHILIPS_NTSC_M, -1, -1, -1, -1, -1, "Hauppauge WinTv-USB (NTSC)"}, | 51 | .Codec = CODEC_SAA7113, |
51 | {0x0573, 0x4d03, -1, CODEC_SAA7111, 3, V4L2_STD_SECAM, 1, 0, 1, 1, TUNER_PHILIPS_SECAM, -1, -1, -1, -1, -1, "Hauppauge WinTv-USB (SECAM) "}, | 52 | .VideoChannels = 2, |
52 | {0x0573, 0x4d10, -1, CODEC_SAA7111, 3, V4L2_STD_NTSC, 1, 1, 1, 1, TUNER_PHILIPS_NTSC_M, -1, -1, -1, -1, -1, "Hauppauge WinTv-USB (NTSC) FM"}, | 53 | .VideoNorm = V4L2_STD_PAL, |
53 | {0x0573, 0x4d11, -1, CODEC_SAA7111, 3, V4L2_STD_PAL, 1, 1, 1, 1, TUNER_PHILIPS_PAL, -1, -1, -1, -1, -1, "Hauppauge WinTv-USB (PAL) FM"}, | 54 | .AudioChannels = 1, |
54 | {0x0573, 0x4d12, -1, CODEC_SAA7111, 3, V4L2_STD_PAL, 1, 1, 1, 1, TUNER_PHILIPS_PAL, -1, -1, -1, -1, -1, "Hauppauge WinTv-USB (PAL) FM"}, | 55 | .Radio = 0, |
55 | {0x0573, 0x4d2a, 0, CODEC_SAA7113, 3, V4L2_STD_NTSC, 1, 1, 1, 1, TUNER_MICROTUNE_4049FM5, -1, -1, 0, 3, 7, "Hauppauge WinTv USB (NTSC) FM Model 602 40201 Rev B285"}, | 56 | .vbi = 1, |
56 | {0x0573, 0x4d2b, 0, CODEC_SAA7113, 3, V4L2_STD_NTSC, 1, 1, 1, 1, TUNER_MICROTUNE_4049FM5, -1, -1, 0, 3, 7, "Hauppauge WinTv USB (NTSC) FM Model 602 40201 Rev B282"}, | 57 | .Tuner = 0, |
57 | {0x0573, 0x4d2c, 0, CODEC_SAA7113, 3, V4L2_STD_PAL, 1, 0, 1, 1, TUNER_PHILIPS_FM1216ME_MK3, -1, -1, 0, 3, 7, "Hauppauge WinTv USB (PAL/SECAM) 40209 Rev E1A5"}, | 58 | .TunerType = 0, |
58 | {0x0573, 0x4d20, 0, CODEC_SAA7113, 3, V4L2_STD_PAL, 1, 1, 1, 1, TUNER_PHILIPS_PAL, -1, -1, 0, 3, 7, "Hauppauge WinTv-USB II (PAL) FM Model 40201 Rev B226"}, | 59 | .X_Offset = 0, |
59 | {0x0573, 0x4d21, 0, CODEC_SAA7113, 3, V4L2_STD_PAL, 1, 0, 1, 1, TUNER_PHILIPS_PAL, -1, -1, 0, 3, 7, "Hauppauge WinTv-USB II (PAL)"}, | 60 | .Y_Offset = 3, |
60 | {0x0573, 0x4d22, 0, CODEC_SAA7113, 3, V4L2_STD_PAL, 1, 0, 1, 1, TUNER_PHILIPS_PAL, -1, -1, 0, 3, 7, "Hauppauge WinTv-USB II (PAL) MODEL 566"}, | 61 | .Dvi_yuv_override = 1, |
61 | {0x0573, 0x4d23, -1, CODEC_SAA7113, 3, V4L2_STD_SECAM, 1, 0, 1, 1, TUNER_PHILIPS_SECAM, -1, -1, 0, 3, 7, "Hauppauge WinTv-USB (SECAM) 4D23"}, | 62 | .Dvi_yuv = 7, |
62 | {0x0573, 0x4d25, -1, CODEC_SAA7113, 3, V4L2_STD_SECAM, 1, 0, 1, 1, TUNER_PHILIPS_SECAM, -1, -1, 0, 3, 7, "Hauppauge WinTv-USB (SECAM) Model 40209 Rev B234"}, | 63 | .ModelString = "Belkin USB VideoBus II Adapter", |
63 | {0x0573, 0x4d26, -1, CODEC_SAA7113, 3, V4L2_STD_SECAM, 1, 0, 1, 1, TUNER_PHILIPS_SECAM, -1, -1, 0, 3, 7, "Hauppauge WinTv-USB (SECAM) Model 40209 Rev B243"}, | 64 | }, |
64 | {0x0573, 0x4d27, -1, CODEC_SAA7113, 3, V4L2_STD_PAL, 1, 0, 1, 1, TUNER_ALPS_TSBE1_PAL, -1, -1, 0, 3, 7, "Hauppauge WinTv-USB Model 40204 Rev B281"}, | 65 | [BELKIN_VIDEOBUS] = { |
65 | {0x0573, 0x4d28, -1, CODEC_SAA7113, 3, V4L2_STD_PAL, 1, 0, 1, 1, TUNER_ALPS_TSBE1_PAL, -1, -1, 0, 3, 7, "Hauppauge WinTv-USB Model 40204 Rev B283"}, | 66 | .Interface = -1, |
66 | {0x0573, 0x4d29, -1, CODEC_SAA7113, 3, V4L2_STD_PAL, 1, 0, 1, 1, TUNER_PHILIPS_PAL, -1, -1, 0, 3, 7, "Hauppauge WinTv-USB Model 40205 Rev B298"}, | 67 | .Codec = CODEC_SAA7111, |
67 | {0x0573, 0x4d30, -1, CODEC_SAA7113, 3, V4L2_STD_NTSC, 1, 1, 1, 1, TUNER_PHILIPS_NTSC_M, -1, -1, 0, 3, 7, "Hauppauge WinTv-USB FM Model 40211 Rev B123"}, | 68 | .VideoChannels = 2, |
68 | {0x0573, 0x4d31, 0, CODEC_SAA7113, 3, V4L2_STD_PAL, 1, 1, 1, 1, TUNER_PHILIPS_PAL, -1, -1, 0, 3, 7, "Hauppauge WinTv-USB III (PAL) FM Model 568"}, | 69 | .VideoNorm = V4L2_STD_NTSC, |
69 | {0x0573, 0x4d32, 0, CODEC_SAA7113, 3, V4L2_STD_PAL, 1, 1, 1, 1, TUNER_PHILIPS_PAL, -1, -1, 0, 3, 7, "Hauppauge WinTv-USB III (PAL) FM Model 573"}, | 70 | .AudioChannels = 1, |
70 | {0x0573, 0x4d35, 0, CODEC_SAA7113, 3, V4L2_STD_PAL, 1, 1, 1, 1, TUNER_MICROTUNE_4049FM5, -1, -1, 0, 3, 7, "Hauppauge WinTv-USB III (PAL) FM Model 40219 Rev B252"}, | 71 | .Radio = 0, |
71 | {0x0573, 0x4d37, 0, CODEC_SAA7113, 3, V4L2_STD_PAL, 1, 1, 1, 1, TUNER_PHILIPS_FM1216ME_MK3, -1, -1, 0, 3, 7, "Hauppauge WinTV USB device Model 40219 Rev E189"}, | 72 | .vbi = 1, |
72 | {0x0768, 0x0006, -1, CODEC_SAA7113, 3, V4L2_STD_NTSC, 1, 1, 1, 1, TUNER_PHILIPS_NTSC_M, -1, -1, 5, 5, -1, "Camtel Technology USB TV Genie Pro FM Model TVB330"}, | 73 | .Tuner = 0, |
73 | {0x07d0, 0x0001, -1, CODEC_SAA7113, 2, V4L2_STD_PAL, 0, 0, 1, 0, 0, -1, -1, 0, 3, 7, "Digital Video Creator I"}, | 74 | .TunerType = 0, |
74 | {0x07d0, 0x0002, -1, CODEC_SAA7111, 2, V4L2_STD_NTSC, 0, 0, 1, 0, 0, -1, -1, 82, 20, 7, "Global Village GV-007 (NTSC)"}, | 75 | .X_Offset = -1, |
75 | {0x07d0, 0x0003, 0, CODEC_SAA7113, 2, V4L2_STD_NTSC, 0, 0, 1, 0, 0, -1, -1, 0, 3, 7, "Dazzle Fusion Model DVC-50 Rev 1 (NTSC)"}, | 76 | .Y_Offset = -1, |
76 | {0x07d0, 0x0004, 0, CODEC_SAA7113, 2, V4L2_STD_PAL, 0, 0, 1, 0, 0, -1, -1, 0, 3, 7, "Dazzle Fusion Model DVC-80 Rev 1 (PAL)"}, | 77 | .ModelString = "Belkin Components USB VideoBus", |
77 | {0x07d0, 0x0005, 0, CODEC_SAA7113, 2, V4L2_STD_SECAM, 0, 0, 1, 0, 0, -1, -1, 0, 3, 7, "Dazzle Fusion Model DVC-90 Rev 1 (SECAM)"}, | 78 | }, |
78 | {0x2304, 0x010d, -1, CODEC_SAA7111, 3, V4L2_STD_PAL, 1, 0, 0, 1, TUNER_TEMIC_4066FY5_PAL_I, -1, -1, -1, -1, -1, "Pinnacle Studio PCTV USB (PAL)"}, | 79 | [BELKIN_USB_VIDEOBUS_II] = { |
79 | {0x2304, 0x0109, -1, CODEC_SAA7111, 3, V4L2_STD_SECAM, 1, 0, 1, 1, TUNER_PHILIPS_SECAM, -1, -1, -1, -1, -1, "Pinnacle Studio PCTV USB (SECAM)"}, | 80 | .Interface = -1, |
80 | {0x2304, 0x0110, -1, CODEC_SAA7111, 3, V4L2_STD_PAL, 1, 1, 1, 1, TUNER_PHILIPS_PAL, -1, -1,128, 23, -1, "Pinnacle Studio PCTV USB (PAL) FM"}, | 81 | .Codec = CODEC_SAA7113, |
81 | {0x2304, 0x0111, -1, CODEC_SAA7111, 3, V4L2_STD_PAL, 1, 0, 1, 1, TUNER_PHILIPS_PAL, -1, -1, -1, -1, -1, "Miro PCTV USB"}, | 82 | .VideoChannels = 2, |
82 | {0x2304, 0x0112, -1, CODEC_SAA7111, 3, V4L2_STD_NTSC, 1, 1, 1, 1, TUNER_PHILIPS_NTSC_M, -1, -1, -1, -1, -1, "Pinnacle Studio PCTV USB (NTSC) FM"}, | 83 | .VideoNorm = V4L2_STD_PAL, |
83 | {0x2304, 0x0210, -1, CODEC_SAA7113, 3, V4L2_STD_PAL, 1, 1, 1, 1, TUNER_TEMIC_4009FR5_PAL, -1, -1, 0, 3, 7, "Pinnacle Studio PCTV USB (PAL) FM"}, | 84 | .AudioChannels = 1, |
84 | {0x2304, 0x0212, -1, CODEC_SAA7111, 3, V4L2_STD_NTSC, 1, 1, 1, 1, TUNER_TEMIC_4039FR5_NTSC, -1, -1, 0, 3, 7, "Pinnacle Studio PCTV USB (NTSC) FM"}, | 85 | .Radio = 0, |
85 | {0x2304, 0x0214, -1, CODEC_SAA7113, 3, V4L2_STD_PAL, 1, 1, 1, 1, TUNER_TEMIC_4009FR5_PAL, -1, -1, 0, 3, 7, "Pinnacle Studio PCTV USB (PAL) FM"}, | 86 | .vbi = 1, |
86 | {0x2304, 0x0300, -1, CODEC_SAA7113, 2, V4L2_STD_NTSC, 1, 0, 1, 0, 0, -1, -1, 0, 3, 7, "Pinnacle Studio Linx Video input cable (NTSC)"}, | 87 | .Tuner = 0, |
87 | {0x2304, 0x0301, -1, CODEC_SAA7113, 2, V4L2_STD_PAL, 1, 0, 1, 0, 0, -1, -1, 0, 3, 7, "Pinnacle Studio Linx Video input cable (PAL)"}, | 88 | .TunerType = 0, |
88 | {0x2304, 0x0419, -1, CODEC_SAA7113, 3, V4L2_STD_PAL, 1, 1, 1, 1, TUNER_TEMIC_4009FR5_PAL, -1, -1, 0, 3, 7, "Pinnacle PCTV Bungee USB (PAL) FM"}, | 89 | .X_Offset = 0, |
89 | {0x2400, 0x4200, -1, CODEC_SAA7111, 3, V4L2_STD_NTSC, 1, 0, 1, 1, TUNER_PHILIPS_NTSC_M, -1, -1, -1, -1, -1, "Hauppauge WinTv-USB"}, | 90 | .Y_Offset = 3, |
90 | {} /* Terminating entry */ | 91 | .Dvi_yuv_override = 1, |
92 | .Dvi_yuv = 7, | ||
93 | .ModelString = "Belkin USB VideoBus II", | ||
94 | }, | ||
95 | [ECHOFX_INTERVIEW_LITE] = { | ||
96 | .Interface = 0, | ||
97 | .Codec = CODEC_SAA7111, | ||
98 | .VideoChannels = 2, | ||
99 | .VideoNorm = V4L2_STD_PAL, | ||
100 | .AudioChannels = 0, | ||
101 | .Radio = 0, | ||
102 | .vbi = 1, | ||
103 | .Tuner = 0, | ||
104 | .TunerType = 0, | ||
105 | .X_Offset = -1, | ||
106 | .Y_Offset = -1, | ||
107 | .Dvi_yuv_override = 1, | ||
108 | .Dvi_yuv = 7, | ||
109 | .ModelString = "echoFX InterView Lite", | ||
110 | }, | ||
111 | [USBGEAR_USBG_V1] = { | ||
112 | .Interface = -1, | ||
113 | .Codec = CODEC_SAA7111, | ||
114 | .VideoChannels = 2, | ||
115 | .VideoNorm = V4L2_STD_NTSC, | ||
116 | .AudioChannels = 1, | ||
117 | .Radio = 0, | ||
118 | .vbi = 1, | ||
119 | .Tuner = 0, | ||
120 | .TunerType = 0, | ||
121 | .X_Offset = -1, | ||
122 | .Y_Offset = -1, | ||
123 | .ModelString = "USBGear USBG-V1 resp. HAMA USB", | ||
124 | }, | ||
125 | [D_LINK_V100] = { | ||
126 | .Interface = -1, | ||
127 | .Codec = CODEC_SAA7113, | ||
128 | .VideoChannels = 4, | ||
129 | .VideoNorm = V4L2_STD_NTSC, | ||
130 | .AudioChannels = 0, | ||
131 | .Radio = 0, | ||
132 | .vbi = 1, | ||
133 | .Tuner = 0, | ||
134 | .TunerType = 0, | ||
135 | .X_Offset = 0, | ||
136 | .Y_Offset = 3, | ||
137 | .Dvi_yuv_override = 1, | ||
138 | .Dvi_yuv = 7, | ||
139 | .ModelString = "D-Link V100", | ||
140 | }, | ||
141 | [X10_USB_CAMERA] = { | ||
142 | .Interface = -1, | ||
143 | .Codec = CODEC_SAA7111, | ||
144 | .VideoChannels = 2, | ||
145 | .VideoNorm = V4L2_STD_NTSC, | ||
146 | .AudioChannels = 1, | ||
147 | .Radio = 0, | ||
148 | .vbi = 1, | ||
149 | .Tuner = 0, | ||
150 | .TunerType = 0, | ||
151 | .X_Offset = -1, | ||
152 | .Y_Offset = -1, | ||
153 | .ModelString = "X10 USB Camera", | ||
154 | }, | ||
155 | [HPG_WINTV_LIVE_PAL_BG] = { | ||
156 | .Interface = -1, | ||
157 | .Codec = CODEC_SAA7111, | ||
158 | .VideoChannels = 2, | ||
159 | .VideoNorm = V4L2_STD_PAL, | ||
160 | .AudioChannels = 1, | ||
161 | .Radio = 0, | ||
162 | .vbi = 1, | ||
163 | .Tuner = 0, | ||
164 | .TunerType = 0, | ||
165 | .X_Offset = -1, | ||
166 | .Y_Offset = 3, | ||
167 | .Dvi_yuv_override = 1, | ||
168 | .Dvi_yuv = 7, | ||
169 | .ModelString = "Hauppauge WinTV USB Live (PAL B/G)", | ||
170 | }, | ||
171 | [HPG_WINTV_LIVE_PRO_NTSC_MN] = { | ||
172 | .Interface = -1, | ||
173 | .Codec = CODEC_SAA7113, | ||
174 | .VideoChannels = 2, | ||
175 | .VideoNorm = V4L2_STD_NTSC, | ||
176 | .AudioChannels = 0, | ||
177 | .Radio = 0, | ||
178 | .vbi = 1, | ||
179 | .Tuner = 0, | ||
180 | .TunerType = 0, | ||
181 | .X_Offset = 0, | ||
182 | .Y_Offset = 3, | ||
183 | .Dvi_yuv_override = 1, | ||
184 | .Dvi_yuv = 7, | ||
185 | .ModelString = "Hauppauge WinTV USB Live Pro (NTSC M/N)", | ||
186 | }, | ||
187 | [ZORAN_PMD_NOGATECH] = { | ||
188 | .Interface = -1, | ||
189 | .Codec = CODEC_SAA7113, | ||
190 | .VideoChannels = 2, | ||
191 | .VideoNorm = V4L2_STD_PAL, | ||
192 | .AudioChannels = 2, | ||
193 | .Radio = 0, | ||
194 | .vbi = 1, | ||
195 | .Tuner = 0, | ||
196 | .TunerType = 0, | ||
197 | .X_Offset = 0, | ||
198 | .Y_Offset = 3, | ||
199 | .Dvi_yuv_override = 1, | ||
200 | .Dvi_yuv = 7, | ||
201 | .ModelString = "Zoran Co. PMD (Nogatech) AV-grabber Manhattan", | ||
202 | }, | ||
203 | [NOGATECH_USB_TV_NTSC_FM] = { | ||
204 | .Interface = -1, | ||
205 | .Codec = CODEC_SAA7111, | ||
206 | .VideoChannels = 3, | ||
207 | .VideoNorm = V4L2_STD_NTSC, | ||
208 | .AudioChannels = 1, | ||
209 | .Radio = 1, | ||
210 | .vbi = 1, | ||
211 | .Tuner = 1, | ||
212 | .TunerType = TUNER_PHILIPS_NTSC_M, | ||
213 | .X_Offset = -1, | ||
214 | .Y_Offset = 20, | ||
215 | .ModelString = "Nogatech USB-TV (NTSC) FM", | ||
216 | }, | ||
217 | [PNY_USB_TV_NTSC_FM] = { | ||
218 | .Interface = -1, | ||
219 | .Codec = CODEC_SAA7111, | ||
220 | .VideoChannels = 3, | ||
221 | .VideoNorm = V4L2_STD_NTSC, | ||
222 | .AudioChannels = 1, | ||
223 | .Radio = 1, | ||
224 | .vbi = 1, | ||
225 | .Tuner = 1, | ||
226 | .TunerType = TUNER_PHILIPS_NTSC_M, | ||
227 | .X_Offset = -1, | ||
228 | .Y_Offset = 20, | ||
229 | .ModelString = "PNY USB-TV (NTSC) FM", | ||
230 | }, | ||
231 | [PV_PLAYTV_USB_PRO_PAL_FM] = { | ||
232 | .Interface = 0, | ||
233 | .Codec = CODEC_SAA7113, | ||
234 | .VideoChannels = 3, | ||
235 | .VideoNorm = V4L2_STD_PAL, | ||
236 | .AudioChannels = 1, | ||
237 | .Radio = 1, | ||
238 | .vbi = 1, | ||
239 | .Tuner = 1, | ||
240 | .TunerType = TUNER_PHILIPS_PAL, | ||
241 | .X_Offset = 0, | ||
242 | .Y_Offset = 3, | ||
243 | .Dvi_yuv_override = 1, | ||
244 | .Dvi_yuv = 7, | ||
245 | .ModelString = "PixelView PlayTv-USB PRO (PAL) FM", | ||
246 | }, | ||
247 | [ZT_721] = { | ||
248 | .Interface = 0, | ||
249 | .Codec = CODEC_SAA7113, | ||
250 | .VideoChannels = 3, | ||
251 | .VideoNorm = V4L2_STD_PAL, | ||
252 | .AudioChannels = 1, | ||
253 | .Radio = 1, | ||
254 | .vbi = 1, | ||
255 | .Tuner = 1, | ||
256 | .TunerType = TUNER_PHILIPS_PAL, | ||
257 | .X_Offset = 0, | ||
258 | .Y_Offset = 3, | ||
259 | .Dvi_yuv_override = 1, | ||
260 | .Dvi_yuv = 7, | ||
261 | .ModelString = "ZTV ZT-721 2.4GHz USB A/V Receiver", | ||
262 | }, | ||
263 | [HPG_WINTV_NTSC_MN] = { | ||
264 | .Interface = -1, | ||
265 | .Codec = CODEC_SAA7111, | ||
266 | .VideoChannels = 3, | ||
267 | .VideoNorm = V4L2_STD_NTSC, | ||
268 | .AudioChannels = 1, | ||
269 | .Radio = 0, | ||
270 | .vbi = 1, | ||
271 | .Tuner = 1, | ||
272 | .TunerType = TUNER_PHILIPS_NTSC_M, | ||
273 | .X_Offset = -1, | ||
274 | .Y_Offset = 20, | ||
275 | .ModelString = "Hauppauge WinTV USB (NTSC M/N)", | ||
276 | }, | ||
277 | [HPG_WINTV_PAL_BG] = { | ||
278 | .Interface = -1, | ||
279 | .Codec = CODEC_SAA7111, | ||
280 | .VideoChannels = 3, | ||
281 | .VideoNorm = V4L2_STD_PAL, | ||
282 | .AudioChannels = 1, | ||
283 | .Radio = 0, | ||
284 | .vbi = 1, | ||
285 | .Tuner = 1, | ||
286 | .TunerType = TUNER_PHILIPS_PAL, | ||
287 | .X_Offset = -1, | ||
288 | .Y_Offset = -1, | ||
289 | .ModelString = "Hauppauge WinTV USB (PAL B/G)", | ||
290 | }, | ||
291 | [HPG_WINTV_PAL_I] = { | ||
292 | .Interface = -1, | ||
293 | .Codec = CODEC_SAA7111, | ||
294 | .VideoChannels = 3, | ||
295 | .VideoNorm = V4L2_STD_PAL, | ||
296 | .AudioChannels = 1, | ||
297 | .Radio = 0, | ||
298 | .vbi = 1, | ||
299 | .Tuner = 1, | ||
300 | .TunerType = TUNER_PHILIPS_PAL, | ||
301 | .X_Offset = -1, | ||
302 | .Y_Offset = -1, | ||
303 | .ModelString = "Hauppauge WinTV USB (PAL I)", | ||
304 | }, | ||
305 | [HPG_WINTV_PAL_SECAM_L] = { | ||
306 | .Interface = -1, | ||
307 | .Codec = CODEC_SAA7111, | ||
308 | .VideoChannels = 3, | ||
309 | .VideoNorm = V4L2_STD_SECAM, | ||
310 | .AudioChannels = 1, | ||
311 | .Radio = 0, | ||
312 | .vbi = 1, | ||
313 | .Tuner = 1, | ||
314 | .TunerType = TUNER_PHILIPS_SECAM, | ||
315 | .X_Offset = -1, | ||
316 | .Y_Offset = -1, | ||
317 | .ModelString = "Hauppauge WinTV USB (PAL/SECAM L)", | ||
318 | }, | ||
319 | [HPG_WINTV_PAL_D_K] = { | ||
320 | .Interface = -1, | ||
321 | .Codec = CODEC_SAA7111, | ||
322 | .VideoChannels = 3, | ||
323 | .VideoNorm = V4L2_STD_PAL, | ||
324 | .AudioChannels = 1, | ||
325 | .Radio = 0, | ||
326 | .vbi = 1, | ||
327 | .Tuner = 1, | ||
328 | .TunerType = TUNER_PHILIPS_PAL, | ||
329 | .X_Offset = -1, | ||
330 | .Y_Offset = -1, | ||
331 | .ModelString = "Hauppauge WinTV USB (PAL D/K)", | ||
332 | }, | ||
333 | [HPG_WINTV_NTSC_FM] = { | ||
334 | .Interface = -1, | ||
335 | .Codec = CODEC_SAA7111, | ||
336 | .VideoChannels = 3, | ||
337 | .VideoNorm = V4L2_STD_NTSC, | ||
338 | .AudioChannels = 1, | ||
339 | .Radio = 1, | ||
340 | .vbi = 1, | ||
341 | .Tuner = 1, | ||
342 | .TunerType = TUNER_PHILIPS_NTSC_M, | ||
343 | .X_Offset = -1, | ||
344 | .Y_Offset = -1, | ||
345 | .ModelString = "Hauppauge WinTV USB (NTSC FM)", | ||
346 | }, | ||
347 | [HPG_WINTV_PAL_BG_FM] = { | ||
348 | .Interface = -1, | ||
349 | .Codec = CODEC_SAA7111, | ||
350 | .VideoChannels = 3, | ||
351 | .VideoNorm = V4L2_STD_PAL, | ||
352 | .AudioChannels = 1, | ||
353 | .Radio = 1, | ||
354 | .vbi = 1, | ||
355 | .Tuner = 1, | ||
356 | .TunerType = TUNER_PHILIPS_PAL, | ||
357 | .X_Offset = -1, | ||
358 | .Y_Offset = -1, | ||
359 | .ModelString = "Hauppauge WinTV USB (PAL B/G FM)", | ||
360 | }, | ||
361 | [HPG_WINTV_PAL_I_FM] = { | ||
362 | .Interface = -1, | ||
363 | .Codec = CODEC_SAA7111, | ||
364 | .VideoChannels = 3, | ||
365 | .VideoNorm = V4L2_STD_PAL, | ||
366 | .AudioChannels = 1, | ||
367 | .Radio = 1, | ||
368 | .vbi = 1, | ||
369 | .Tuner = 1, | ||
370 | .TunerType = TUNER_PHILIPS_PAL, | ||
371 | .X_Offset = -1, | ||
372 | .Y_Offset = -1, | ||
373 | .ModelString = "Hauppauge WinTV USB (PAL I FM)", | ||
374 | }, | ||
375 | [HPG_WINTV_PAL_D_K_FM] = { | ||
376 | .Interface = -1, | ||
377 | .Codec = CODEC_SAA7111, | ||
378 | .VideoChannels = 3, | ||
379 | .VideoNorm = V4L2_STD_PAL, | ||
380 | .AudioChannels = 1, | ||
381 | .Radio = 1, | ||
382 | .vbi = 1, | ||
383 | .Tuner = 1, | ||
384 | .TunerType = TUNER_PHILIPS_PAL, | ||
385 | .X_Offset = -1, | ||
386 | .Y_Offset = -1, | ||
387 | .ModelString = "Hauppauge WinTV USB (PAL D/K FM)", | ||
388 | }, | ||
389 | [HPG_WINTV_PRO_NTSC_MN] = { | ||
390 | .Interface = 0, | ||
391 | .Codec = CODEC_SAA7113, | ||
392 | .VideoChannels = 3, | ||
393 | .VideoNorm = V4L2_STD_NTSC, | ||
394 | .AudioChannels = 1, | ||
395 | .Radio = 1, | ||
396 | .vbi = 1, | ||
397 | .Tuner = 1, | ||
398 | .TunerType = TUNER_MICROTUNE_4049FM5, | ||
399 | .X_Offset = 0, | ||
400 | .Y_Offset = 3, | ||
401 | .Dvi_yuv_override = 1, | ||
402 | .Dvi_yuv = 7, | ||
403 | .ModelString = "Hauppauge WinTV USB Pro (NTSC M/N)", | ||
404 | }, | ||
405 | [HPG_WINTV_PRO_NTSC_MN_V2] = { | ||
406 | .Interface = 0, | ||
407 | .Codec = CODEC_SAA7113, | ||
408 | .VideoChannels = 3, | ||
409 | .VideoNorm = V4L2_STD_NTSC, | ||
410 | .AudioChannels = 1, | ||
411 | .Radio = 1, | ||
412 | .vbi = 1, | ||
413 | .Tuner = 1, | ||
414 | .TunerType = TUNER_MICROTUNE_4049FM5, | ||
415 | .X_Offset = 0, | ||
416 | .Y_Offset = 3, | ||
417 | .Dvi_yuv_override = 1, | ||
418 | .Dvi_yuv = 7, | ||
419 | .ModelString = "Hauppauge WinTV USB Pro (NTSC M/N) V2", | ||
420 | }, | ||
421 | [HPG_WINTV_PRO_PAL] = { | ||
422 | .Interface = 0, | ||
423 | .Codec = CODEC_SAA7113, | ||
424 | .VideoChannels = 3, | ||
425 | .VideoNorm = V4L2_STD_PAL, | ||
426 | .AudioChannels = 1, | ||
427 | .Radio = 0, | ||
428 | .vbi = 1, | ||
429 | .Tuner = 1, | ||
430 | .TunerType = TUNER_PHILIPS_FM1216ME_MK3, | ||
431 | .X_Offset = 0, | ||
432 | .Y_Offset = 3, | ||
433 | .Dvi_yuv_override = 1, | ||
434 | .Dvi_yuv = 7, | ||
435 | .ModelString = "Hauppauge WinTV USB Pro (PAL/SECAM B/G/I/D/K/L)", | ||
436 | }, | ||
437 | [HPG_WINTV_PRO_NTSC_MN_V3] = { | ||
438 | .Interface = 0, | ||
439 | .Codec = CODEC_SAA7113, | ||
440 | .VideoChannels = 3, | ||
441 | .VideoNorm = V4L2_STD_NTSC, | ||
442 | .AudioChannels = 1, | ||
443 | .Radio = 1, | ||
444 | .vbi = 1, | ||
445 | .Tuner = 1, | ||
446 | .TunerType = TUNER_PHILIPS_NTSC_M, | ||
447 | .X_Offset = 0, | ||
448 | .Y_Offset = 3, | ||
449 | .Dvi_yuv_override = 1, | ||
450 | .Dvi_yuv = 7, | ||
451 | .ModelString = "Hauppauge WinTV USB Pro (NTSC M/N) V3", | ||
452 | }, | ||
453 | [HPG_WINTV_PRO_PAL_BG] = { | ||
454 | .Interface = 0, | ||
455 | .Codec = CODEC_SAA7113, | ||
456 | .VideoChannels = 3, | ||
457 | .VideoNorm = V4L2_STD_PAL, | ||
458 | .AudioChannels = 1, | ||
459 | .Radio = 0, | ||
460 | .vbi = 1, | ||
461 | .Tuner = 1, | ||
462 | .TunerType = TUNER_PHILIPS_PAL, | ||
463 | .X_Offset = 0, | ||
464 | .Y_Offset = 3, | ||
465 | .Dvi_yuv_override = 1, | ||
466 | .Dvi_yuv = 7, | ||
467 | .ModelString = "Hauppauge WinTV USB Pro (PAL B/G)", | ||
468 | }, | ||
469 | [HPG_WINTV_PRO_PAL_I] = { | ||
470 | .Interface = 0, | ||
471 | .Codec = CODEC_SAA7113, | ||
472 | .VideoChannels = 3, | ||
473 | .VideoNorm = V4L2_STD_PAL, | ||
474 | .AudioChannels = 1, | ||
475 | .Radio = 0, | ||
476 | .vbi = 1, | ||
477 | .Tuner = 1, | ||
478 | .TunerType = TUNER_PHILIPS_PAL, | ||
479 | .X_Offset = 0, | ||
480 | .Y_Offset = 3, | ||
481 | .Dvi_yuv_override = 1, | ||
482 | .Dvi_yuv = 7, | ||
483 | .ModelString = "Hauppauge WinTV USB Pro (PAL I)", | ||
484 | }, | ||
485 | [HPG_WINTV_PRO_PAL_SECAM_L] = { | ||
486 | .Interface = -1, | ||
487 | .Codec = CODEC_SAA7113, | ||
488 | .VideoChannels = 3, | ||
489 | .VideoNorm = V4L2_STD_SECAM, | ||
490 | .AudioChannels = 1, | ||
491 | .Radio = 0, | ||
492 | .vbi = 1, | ||
493 | .Tuner = 1, | ||
494 | .TunerType = TUNER_PHILIPS_SECAM, | ||
495 | .X_Offset = 0, | ||
496 | .Y_Offset = 3, | ||
497 | .Dvi_yuv_override = 1, | ||
498 | .Dvi_yuv = 7, | ||
499 | .ModelString = "Hauppauge WinTV USB Pro (PAL/SECAM L)", | ||
500 | }, | ||
501 | [HPG_WINTV_PRO_PAL_D_K] = { | ||
502 | .Interface = -1, | ||
503 | .Codec = CODEC_SAA7113, | ||
504 | .VideoChannels = 3, | ||
505 | .VideoNorm = V4L2_STD_PAL, | ||
506 | .AudioChannels = 1, | ||
507 | .Radio = 0, | ||
508 | .vbi = 1, | ||
509 | .Tuner = 1, | ||
510 | .TunerType = TUNER_PHILIPS_PAL, | ||
511 | .X_Offset = 0, | ||
512 | .Y_Offset = 3, | ||
513 | .Dvi_yuv_override = 1, | ||
514 | .Dvi_yuv = 7, | ||
515 | .ModelString = "Hauppauge WinTV USB Pro (PAL D/K)", | ||
516 | }, | ||
517 | [HPG_WINTV_PRO_PAL_SECAM] = { | ||
518 | .Interface = -1, | ||
519 | .Codec = CODEC_SAA7113, | ||
520 | .VideoChannels = 3, | ||
521 | .VideoNorm = V4L2_STD_SECAM, | ||
522 | .AudioChannels = 1, | ||
523 | .Radio = 0, | ||
524 | .vbi = 1, | ||
525 | .Tuner = 1, | ||
526 | .TunerType = TUNER_PHILIPS_SECAM, | ||
527 | .X_Offset = 0, | ||
528 | .Y_Offset = 3, | ||
529 | .Dvi_yuv_override = 1, | ||
530 | .Dvi_yuv = 7, | ||
531 | .ModelString = "Hauppauge WinTV USB Pro (PAL/SECAM BGDK/I/L)", | ||
532 | }, | ||
533 | [HPG_WINTV_PRO_PAL_SECAM_V2] = { | ||
534 | .Interface = -1, | ||
535 | .Codec = CODEC_SAA7113, | ||
536 | .VideoChannels = 3, | ||
537 | .VideoNorm = V4L2_STD_SECAM, | ||
538 | .AudioChannels = 1, | ||
539 | .Radio = 0, | ||
540 | .vbi = 1, | ||
541 | .Tuner = 1, | ||
542 | .TunerType = TUNER_PHILIPS_SECAM, | ||
543 | .X_Offset = 0, | ||
544 | .Y_Offset = 3, | ||
545 | .Dvi_yuv_override = 1, | ||
546 | .Dvi_yuv = 7, | ||
547 | .ModelString = "Hauppauge WinTV USB Pro (PAL/SECAM BGDK/I/L) V2", | ||
548 | }, | ||
549 | [HPG_WINTV_PRO_PAL_BG_V2] = { | ||
550 | .Interface = -1, | ||
551 | .Codec = CODEC_SAA7113, | ||
552 | .VideoChannels = 3, | ||
553 | .VideoNorm = V4L2_STD_PAL, | ||
554 | .AudioChannels = 1, | ||
555 | .Radio = 0, | ||
556 | .vbi = 1, | ||
557 | .Tuner = 1, | ||
558 | .TunerType = TUNER_ALPS_TSBE1_PAL, | ||
559 | .X_Offset = 0, | ||
560 | .Y_Offset = 3, | ||
561 | .Dvi_yuv_override = 1, | ||
562 | .Dvi_yuv = 7, | ||
563 | .ModelString = "Hauppauge WinTV USB Pro (PAL B/G) V2", | ||
564 | }, | ||
565 | [HPG_WINTV_PRO_PAL_BG_D_K] = { | ||
566 | .Interface = -1, | ||
567 | .Codec = CODEC_SAA7113, | ||
568 | .VideoChannels = 3, | ||
569 | .VideoNorm = V4L2_STD_PAL, | ||
570 | .AudioChannels = 1, | ||
571 | .Radio = 0, | ||
572 | .vbi = 1, | ||
573 | .Tuner = 1, | ||
574 | .TunerType = TUNER_ALPS_TSBE1_PAL, | ||
575 | .X_Offset = 0, | ||
576 | .Y_Offset = 3, | ||
577 | .Dvi_yuv_override = 1, | ||
578 | .Dvi_yuv = 7, | ||
579 | .ModelString = "Hauppauge WinTV USB Pro (PAL B/G,D/K)", | ||
580 | }, | ||
581 | [HPG_WINTV_PRO_PAL_I_D_K] = { | ||
582 | .Interface = -1, | ||
583 | .Codec = CODEC_SAA7113, | ||
584 | .VideoChannels = 3, | ||
585 | .VideoNorm = V4L2_STD_PAL, | ||
586 | .AudioChannels = 1, | ||
587 | .Radio = 0, | ||
588 | .vbi = 1, | ||
589 | .Tuner = 1, | ||
590 | .TunerType = TUNER_PHILIPS_PAL, | ||
591 | .X_Offset = 0, | ||
592 | .Y_Offset = 3, | ||
593 | .Dvi_yuv_override = 1, | ||
594 | .Dvi_yuv = 7, | ||
595 | .ModelString = "Hauppauge WinTV USB Pro (PAL I,D/K)", | ||
596 | }, | ||
597 | [HPG_WINTV_PRO_NTSC_MN_FM] = { | ||
598 | .Interface = -1, | ||
599 | .Codec = CODEC_SAA7113, | ||
600 | .VideoChannels = 3, | ||
601 | .VideoNorm = V4L2_STD_NTSC, | ||
602 | .AudioChannels = 1, | ||
603 | .Radio = 1, | ||
604 | .vbi = 1, | ||
605 | .Tuner = 1, | ||
606 | .TunerType = TUNER_PHILIPS_NTSC_M, | ||
607 | .X_Offset = 0, | ||
608 | .Y_Offset = 3, | ||
609 | .Dvi_yuv_override = 1, | ||
610 | .Dvi_yuv = 7, | ||
611 | .ModelString = "Hauppauge WinTV USB Pro (NTSC M/N FM)", | ||
612 | }, | ||
613 | [HPG_WINTV_PRO_PAL_BG_FM] = { | ||
614 | .Interface = 0, | ||
615 | .Codec = CODEC_SAA7113, | ||
616 | .VideoChannels = 3, | ||
617 | .VideoNorm = V4L2_STD_PAL, | ||
618 | .AudioChannels = 1, | ||
619 | .Radio = 1, | ||
620 | .vbi = 1, | ||
621 | .Tuner = 1, | ||
622 | .TunerType = TUNER_PHILIPS_PAL, | ||
623 | .X_Offset = 0, | ||
624 | .Y_Offset = 3, | ||
625 | .Dvi_yuv_override = 1, | ||
626 | .Dvi_yuv = 7, | ||
627 | .ModelString = "Hauppauge WinTV USB Pro (PAL B/G FM)", | ||
628 | }, | ||
629 | [HPG_WINTV_PRO_PAL_I_FM] = { | ||
630 | .Interface = 0, | ||
631 | .Codec = CODEC_SAA7113, | ||
632 | .VideoChannels = 3, | ||
633 | .VideoNorm = V4L2_STD_PAL, | ||
634 | .AudioChannels = 1, | ||
635 | .Radio = 1, | ||
636 | .vbi = 1, | ||
637 | .Tuner = 1, | ||
638 | .TunerType = TUNER_PHILIPS_PAL, | ||
639 | .X_Offset = 0, | ||
640 | .Y_Offset = 3, | ||
641 | .Dvi_yuv_override = 1, | ||
642 | .Dvi_yuv = 7, | ||
643 | .ModelString = "Hauppauge WinTV USB Pro (PAL I FM)", | ||
644 | }, | ||
645 | [HPG_WINTV_PRO_PAL_D_K_FM] = { | ||
646 | .Interface = 0, | ||
647 | .Codec = CODEC_SAA7113, | ||
648 | .VideoChannels = 3, | ||
649 | .VideoNorm = V4L2_STD_PAL, | ||
650 | .AudioChannels = 1, | ||
651 | .Radio = 1, | ||
652 | .vbi = 1, | ||
653 | .Tuner = 1, | ||
654 | .TunerType = TUNER_PHILIPS_PAL, | ||
655 | .X_Offset = 0, | ||
656 | .Y_Offset = 3, | ||
657 | .Dvi_yuv_override = 1, | ||
658 | .Dvi_yuv = 7, | ||
659 | .ModelString = "Hauppauge WinTV USB Pro (PAL D/K FM)", | ||
660 | }, | ||
661 | [HPG_WINTV_PRO_TEMIC_PAL_FM] = { | ||
662 | .Interface = 0, | ||
663 | .Codec = CODEC_SAA7113, | ||
664 | .VideoChannels = 3, | ||
665 | .VideoNorm = V4L2_STD_PAL, | ||
666 | .AudioChannels = 1, | ||
667 | .Radio = 1, | ||
668 | .vbi = 1, | ||
669 | .Tuner = 1, | ||
670 | .TunerType = TUNER_MICROTUNE_4049FM5, | ||
671 | .X_Offset = 0, | ||
672 | .Y_Offset = 3, | ||
673 | .Dvi_yuv_override = 1, | ||
674 | .Dvi_yuv = 7, | ||
675 | .ModelString = "Hauppauge WinTV USB Pro (Temic PAL/SECAM B/G/I/D/K/L FM)", | ||
676 | }, | ||
677 | [HPG_WINTV_PRO_TEMIC_PAL_BG_FM] = { | ||
678 | .Interface = 0, | ||
679 | .Codec = CODEC_SAA7113, | ||
680 | .VideoChannels = 3, | ||
681 | .VideoNorm = V4L2_STD_PAL, | ||
682 | .AudioChannels = 1, | ||
683 | .Radio = 1, | ||
684 | .vbi = 1, | ||
685 | .Tuner = 1, | ||
686 | .TunerType = TUNER_MICROTUNE_4049FM5, | ||
687 | .X_Offset = 0, | ||
688 | .Y_Offset = 3, | ||
689 | .Dvi_yuv_override = 1, | ||
690 | .Dvi_yuv = 7, | ||
691 | .ModelString = "Hauppauge WinTV USB Pro (Temic PAL B/G FM)", | ||
692 | }, | ||
693 | [HPG_WINTV_PRO_PAL_FM] = { | ||
694 | .Interface = 0, | ||
695 | .Codec = CODEC_SAA7113, | ||
696 | .VideoChannels = 3, | ||
697 | .VideoNorm = V4L2_STD_PAL, | ||
698 | .AudioChannels = 1, | ||
699 | .Radio = 1, | ||
700 | .vbi = 1, | ||
701 | .Tuner = 1, | ||
702 | .TunerType = TUNER_PHILIPS_FM1216ME_MK3, | ||
703 | .X_Offset = 0, | ||
704 | .Y_Offset = 3, | ||
705 | .Dvi_yuv_override = 1, | ||
706 | .Dvi_yuv = 7, | ||
707 | .ModelString = "Hauppauge WinTV USB Pro (PAL/SECAM B/G/I/D/K/L FM)", | ||
708 | }, | ||
709 | [HPG_WINTV_PRO_NTSC_MN_FM_V2] = { | ||
710 | .Interface = 0, | ||
711 | .Codec = CODEC_SAA7113, | ||
712 | .VideoChannels = 3, | ||
713 | .VideoNorm = V4L2_STD_NTSC, | ||
714 | .AudioChannels = 1, | ||
715 | .Radio = 1, | ||
716 | .vbi = 1, | ||
717 | .Tuner = 1, | ||
718 | .TunerType = TUNER_PHILIPS_NTSC_M, | ||
719 | .X_Offset = 0, | ||
720 | .Y_Offset = 3, | ||
721 | .Dvi_yuv_override = 1, | ||
722 | .Dvi_yuv = 7, | ||
723 | .ModelString = "Hauppauge WinTV USB Pro (NTSC M/N FM) V2", | ||
724 | }, | ||
725 | [CAMTEL_TVB330] = { | ||
726 | .Interface = -1, | ||
727 | .Codec = CODEC_SAA7113, | ||
728 | .VideoChannels = 3, | ||
729 | .VideoNorm = V4L2_STD_NTSC, | ||
730 | .AudioChannels = 1, | ||
731 | .Radio = 1, | ||
732 | .vbi = 1, | ||
733 | .Tuner = 1, | ||
734 | .TunerType = TUNER_PHILIPS_NTSC_M, | ||
735 | .X_Offset = 5, | ||
736 | .Y_Offset = 5, | ||
737 | .ModelString = "Camtel Technology USB TV Genie Pro FM Model TVB330", | ||
738 | }, | ||
739 | [DIGITAL_VIDEO_CREATOR_I] = { | ||
740 | .Interface = -1, | ||
741 | .Codec = CODEC_SAA7113, | ||
742 | .VideoChannels = 2, | ||
743 | .VideoNorm = V4L2_STD_PAL, | ||
744 | .AudioChannels = 0, | ||
745 | .Radio = 0, | ||
746 | .vbi = 1, | ||
747 | .Tuner = 0, | ||
748 | .TunerType = 0, | ||
749 | .X_Offset = 0, | ||
750 | .Y_Offset = 3, | ||
751 | .Dvi_yuv_override = 1, | ||
752 | .Dvi_yuv = 7, | ||
753 | .ModelString = "Digital Video Creator I", | ||
754 | }, | ||
755 | [GLOBAL_VILLAGE_GV_007_NTSC] = { | ||
756 | .Interface = -1, | ||
757 | .Codec = CODEC_SAA7111, | ||
758 | .VideoChannels = 2, | ||
759 | .VideoNorm = V4L2_STD_NTSC, | ||
760 | .AudioChannels = 0, | ||
761 | .Radio = 0, | ||
762 | .vbi = 1, | ||
763 | .Tuner = 0, | ||
764 | .TunerType = 0, | ||
765 | .X_Offset = 82, | ||
766 | .Y_Offset = 20, | ||
767 | .Dvi_yuv_override = 1, | ||
768 | .Dvi_yuv = 7, | ||
769 | .ModelString = "Global Village GV-007 (NTSC)", | ||
770 | }, | ||
771 | [DAZZLE_DVC_50_REV_1_NTSC] = { | ||
772 | .Interface = 0, | ||
773 | .Codec = CODEC_SAA7113, | ||
774 | .VideoChannels = 2, | ||
775 | .VideoNorm = V4L2_STD_NTSC, | ||
776 | .AudioChannels = 0, | ||
777 | .Radio = 0, | ||
778 | .vbi = 1, | ||
779 | .Tuner = 0, | ||
780 | .TunerType = 0, | ||
781 | .X_Offset = 0, | ||
782 | .Y_Offset = 3, | ||
783 | .Dvi_yuv_override = 1, | ||
784 | .Dvi_yuv = 7, | ||
785 | .ModelString = "Dazzle Fusion Model DVC-50 Rev 1 (NTSC)", | ||
786 | }, | ||
787 | [DAZZLE_DVC_80_REV_1_PAL] = { | ||
788 | .Interface = 0, | ||
789 | .Codec = CODEC_SAA7113, | ||
790 | .VideoChannels = 2, | ||
791 | .VideoNorm = V4L2_STD_PAL, | ||
792 | .AudioChannels = 0, | ||
793 | .Radio = 0, | ||
794 | .vbi = 1, | ||
795 | .Tuner = 0, | ||
796 | .TunerType = 0, | ||
797 | .X_Offset = 0, | ||
798 | .Y_Offset = 3, | ||
799 | .Dvi_yuv_override = 1, | ||
800 | .Dvi_yuv = 7, | ||
801 | .ModelString = "Dazzle Fusion Model DVC-80 Rev 1 (PAL)", | ||
802 | }, | ||
803 | [DAZZLE_DVC_90_REV_1_SECAM] = { | ||
804 | .Interface = 0, | ||
805 | .Codec = CODEC_SAA7113, | ||
806 | .VideoChannels = 2, | ||
807 | .VideoNorm = V4L2_STD_SECAM, | ||
808 | .AudioChannels = 0, | ||
809 | .Radio = 0, | ||
810 | .vbi = 1, | ||
811 | .Tuner = 0, | ||
812 | .TunerType = 0, | ||
813 | .X_Offset = 0, | ||
814 | .Y_Offset = 3, | ||
815 | .Dvi_yuv_override = 1, | ||
816 | .Dvi_yuv = 7, | ||
817 | .ModelString = "Dazzle Fusion Model DVC-90 Rev 1 (SECAM)", | ||
818 | }, | ||
819 | [ESKAPE_LABS_MYTV2GO] = { | ||
820 | .Interface = 0, | ||
821 | .Codec = CODEC_SAA7113, | ||
822 | .VideoChannels = 2, | ||
823 | .VideoNorm = V4L2_STD_PAL, | ||
824 | .AudioChannels = 1, | ||
825 | .Radio = 1, | ||
826 | .vbi = 1, | ||
827 | .Tuner = 1, | ||
828 | .TunerType = TUNER_PHILIPS_FM1216ME_MK3, | ||
829 | .X_Offset = 0, | ||
830 | .Y_Offset = 3, | ||
831 | .Dvi_yuv_override = 1, | ||
832 | .Dvi_yuv = 7, | ||
833 | .ModelString = "Eskape Labs MyTV2Go", | ||
834 | }, | ||
835 | [PINNA_PCTV_USB_PAL] = { | ||
836 | .Interface = -1, | ||
837 | .Codec = CODEC_SAA7111, | ||
838 | .VideoChannels = 3, | ||
839 | .VideoNorm = V4L2_STD_PAL, | ||
840 | .AudioChannels = 1, | ||
841 | .Radio = 0, | ||
842 | .vbi = 0, | ||
843 | .Tuner = 1, | ||
844 | .TunerType = TUNER_TEMIC_4066FY5_PAL_I, | ||
845 | .X_Offset = -1, | ||
846 | .Y_Offset = -1, | ||
847 | .ModelString = "Pinnacle Studio PCTV USB (PAL)", | ||
848 | }, | ||
849 | [PINNA_PCTV_USB_SECAM] = { | ||
850 | .Interface = -1, | ||
851 | .Codec = CODEC_SAA7111, | ||
852 | .VideoChannels = 3, | ||
853 | .VideoNorm = V4L2_STD_SECAM, | ||
854 | .AudioChannels = 1, | ||
855 | .Radio = 0, | ||
856 | .vbi = 1, | ||
857 | .Tuner = 1, | ||
858 | .TunerType = TUNER_PHILIPS_SECAM, | ||
859 | .X_Offset = -1, | ||
860 | .Y_Offset = -1, | ||
861 | .ModelString = "Pinnacle Studio PCTV USB (SECAM)", | ||
862 | }, | ||
863 | [PINNA_PCTV_USB_PAL_FM] = { | ||
864 | .Interface = -1, | ||
865 | .Codec = CODEC_SAA7111, | ||
866 | .VideoChannels = 3, | ||
867 | .VideoNorm = V4L2_STD_PAL, | ||
868 | .AudioChannels = 1, | ||
869 | .Radio = 1, | ||
870 | .vbi = 1, | ||
871 | .Tuner = 1, | ||
872 | .TunerType = TUNER_PHILIPS_PAL, | ||
873 | .X_Offset = 128, | ||
874 | .Y_Offset = 23, | ||
875 | .ModelString = "Pinnacle Studio PCTV USB (PAL) FM", | ||
876 | }, | ||
877 | [MIRO_PCTV_USB] = { | ||
878 | .Interface = -1, | ||
879 | .Codec = CODEC_SAA7111, | ||
880 | .VideoChannels = 3, | ||
881 | .VideoNorm = V4L2_STD_PAL, | ||
882 | .AudioChannels = 1, | ||
883 | .Radio = 0, | ||
884 | .vbi = 1, | ||
885 | .Tuner = 1, | ||
886 | .TunerType = TUNER_PHILIPS_PAL, | ||
887 | .X_Offset = -1, | ||
888 | .Y_Offset = -1, | ||
889 | .ModelString = "Miro PCTV USB", | ||
890 | }, | ||
891 | [PINNA_PCTV_USB_NTSC_FM] = { | ||
892 | .Interface = -1, | ||
893 | .Codec = CODEC_SAA7111, | ||
894 | .VideoChannels = 3, | ||
895 | .VideoNorm = V4L2_STD_NTSC, | ||
896 | .AudioChannels = 1, | ||
897 | .Radio = 1, | ||
898 | .vbi = 1, | ||
899 | .Tuner = 1, | ||
900 | .TunerType = TUNER_PHILIPS_NTSC_M, | ||
901 | .X_Offset = -1, | ||
902 | .Y_Offset = -1, | ||
903 | .ModelString = "Pinnacle Studio PCTV USB (NTSC) FM", | ||
904 | }, | ||
905 | [PINNA_PCTV_USB_PAL_FM_V2] = { | ||
906 | .Interface = -1, | ||
907 | .Codec = CODEC_SAA7113, | ||
908 | .VideoChannels = 3, | ||
909 | .VideoNorm = V4L2_STD_PAL, | ||
910 | .AudioChannels = 1, | ||
911 | .Radio = 1, | ||
912 | .vbi = 1, | ||
913 | .Tuner = 1, | ||
914 | .TunerType = TUNER_TEMIC_4009FR5_PAL, | ||
915 | .X_Offset = 0, | ||
916 | .Y_Offset = 3, | ||
917 | .Dvi_yuv_override = 1, | ||
918 | .Dvi_yuv = 7, | ||
919 | .ModelString = "Pinnacle Studio PCTV USB (PAL) FM V2", | ||
920 | }, | ||
921 | [PINNA_PCTV_USB_NTSC_FM_V2] = { | ||
922 | .Interface = -1, | ||
923 | .Codec = CODEC_SAA7111, | ||
924 | .VideoChannels = 3, | ||
925 | .VideoNorm = V4L2_STD_NTSC, | ||
926 | .AudioChannels = 1, | ||
927 | .Radio = 1, | ||
928 | .vbi = 1, | ||
929 | .Tuner = 1, | ||
930 | .TunerType = TUNER_TEMIC_4039FR5_NTSC, | ||
931 | .X_Offset = 0, | ||
932 | .Y_Offset = 3, | ||
933 | .Dvi_yuv_override = 1, | ||
934 | .Dvi_yuv = 7, | ||
935 | .ModelString = "Pinnacle Studio PCTV USB (NTSC) FM V2", | ||
936 | }, | ||
937 | [PINNA_PCTV_USB_PAL_FM_V3] = { | ||
938 | .Interface = -1, | ||
939 | .Codec = CODEC_SAA7113, | ||
940 | .VideoChannels = 3, | ||
941 | .VideoNorm = V4L2_STD_PAL, | ||
942 | .AudioChannels = 1, | ||
943 | .Radio = 1, | ||
944 | .vbi = 1, | ||
945 | .Tuner = 1, | ||
946 | .TunerType = TUNER_TEMIC_4009FR5_PAL, | ||
947 | .X_Offset = 0, | ||
948 | .Y_Offset = 3, | ||
949 | .Dvi_yuv_override = 1, | ||
950 | .Dvi_yuv = 7, | ||
951 | .ModelString = "Pinnacle Studio PCTV USB (PAL) FM V3", | ||
952 | }, | ||
953 | [PINNA_LINX_VD_IN_CAB_NTSC] = { | ||
954 | .Interface = -1, | ||
955 | .Codec = CODEC_SAA7113, | ||
956 | .VideoChannels = 2, | ||
957 | .VideoNorm = V4L2_STD_NTSC, | ||
958 | .AudioChannels = 1, | ||
959 | .Radio = 0, | ||
960 | .vbi = 1, | ||
961 | .Tuner = 0, | ||
962 | .TunerType = 0, | ||
963 | .X_Offset = 0, | ||
964 | .Y_Offset = 3, | ||
965 | .Dvi_yuv_override = 1, | ||
966 | .Dvi_yuv = 7, | ||
967 | .ModelString = "Pinnacle Studio Linx Video input cable (NTSC)", | ||
968 | }, | ||
969 | [PINNA_LINX_VD_IN_CAB_PAL] = { | ||
970 | .Interface = -1, | ||
971 | .Codec = CODEC_SAA7113, | ||
972 | .VideoChannels = 2, | ||
973 | .VideoNorm = V4L2_STD_PAL, | ||
974 | .AudioChannels = 1, | ||
975 | .Radio = 0, | ||
976 | .vbi = 1, | ||
977 | .Tuner = 0, | ||
978 | .TunerType = 0, | ||
979 | .X_Offset = 0, | ||
980 | .Y_Offset = 3, | ||
981 | .Dvi_yuv_override = 1, | ||
982 | .Dvi_yuv = 7, | ||
983 | .ModelString = "Pinnacle Studio Linx Video input cable (PAL)", | ||
984 | }, | ||
985 | [PINNA_PCTV_BUNGEE_PAL_FM] = { | ||
986 | .Interface = -1, | ||
987 | .Codec = CODEC_SAA7113, | ||
988 | .VideoChannels = 3, | ||
989 | .VideoNorm = V4L2_STD_PAL, | ||
990 | .AudioChannels = 1, | ||
991 | .Radio = 1, | ||
992 | .vbi = 1, | ||
993 | .Tuner = 1, | ||
994 | .TunerType = TUNER_TEMIC_4009FR5_PAL, | ||
995 | .X_Offset = 0, | ||
996 | .Y_Offset = 3, | ||
997 | .Dvi_yuv_override = 1, | ||
998 | .Dvi_yuv = 7, | ||
999 | .ModelString = "Pinnacle PCTV Bungee USB (PAL) FM", | ||
1000 | }, | ||
1001 | [HPG_WINTV] = { | ||
1002 | .Interface = -1, | ||
1003 | .Codec = CODEC_SAA7111, | ||
1004 | .VideoChannels = 3, | ||
1005 | .VideoNorm = V4L2_STD_NTSC, | ||
1006 | .AudioChannels = 1, | ||
1007 | .Radio = 0, | ||
1008 | .vbi = 1, | ||
1009 | .Tuner = 1, | ||
1010 | .TunerType = TUNER_PHILIPS_NTSC_M, | ||
1011 | .X_Offset = -1, | ||
1012 | .Y_Offset = -1, | ||
1013 | .ModelString = "Hauppauge WinTv-USB", | ||
1014 | }, | ||
91 | }; | 1015 | }; |
1016 | const int usbvision_device_data_size=ARRAY_SIZE(usbvision_device_data); | ||
92 | 1017 | ||
93 | /* Supported Devices */ | 1018 | /* Supported Devices */ |
94 | 1019 | ||
95 | struct usb_device_id usbvision_table [] = { | 1020 | struct usb_device_id usbvision_table [] = { |
96 | { USB_DEVICE(0xFFF0, 0xFFF0) }, /* Custom Dummy USBVision Device */ | 1021 | { USB_DEVICE(0x0a6f, 0x0400), .driver_info=XANBOO }, |
97 | { USB_DEVICE(0x0A6F, 0x0400) }, /* Xanboo */ | 1022 | { USB_DEVICE(0x050d, 0x0106), .driver_info=BELKIN_VIDEOBUS_II }, |
98 | { USB_DEVICE(0x050d, 0x0208) }, /* Belkin USBView II */ | 1023 | { USB_DEVICE(0x050d, 0x0207), .driver_info=BELKIN_VIDEOBUS }, |
99 | { USB_DEVICE(0x0571, 0x0002) }, /* echoFX InterView Lite */ | 1024 | { USB_DEVICE(0x050d, 0x0208), .driver_info=BELKIN_USB_VIDEOBUS_II }, |
100 | { USB_DEVICE(0x0573, 0x0003) }, /* USBGear USBG-V1 */ | 1025 | { USB_DEVICE(0x0571, 0x0002), .driver_info=ECHOFX_INTERVIEW_LITE }, |
101 | { USB_DEVICE(0x0573, 0x0400) }, /* D-Link V100 */ | 1026 | { USB_DEVICE(0x0573, 0x0003), .driver_info=USBGEAR_USBG_V1 }, |
102 | { USB_DEVICE(0x0573, 0x2000) }, /* X10 USB Camera */ | 1027 | { USB_DEVICE(0x0573, 0x0400), .driver_info=D_LINK_V100 }, |
103 | { USB_DEVICE(0x0573, 0x2d00) }, /* Osprey 50 */ | 1028 | { USB_DEVICE(0x0573, 0x2000), .driver_info=X10_USB_CAMERA }, |
104 | { USB_DEVICE(0x0573, 0x2d01) }, /* Hauppauge USB-Live Model 600 */ | 1029 | { USB_DEVICE(0x0573, 0x2d00), .driver_info=HPG_WINTV_LIVE_PAL_BG }, |
105 | { USB_DEVICE(0x0573, 0x2101) }, /* Zoran Co. PMD (Nogatech) AV-grabber Manhattan */ | 1030 | { USB_DEVICE(0x0573, 0x2d01), .driver_info=HPG_WINTV_LIVE_PRO_NTSC_MN }, |
106 | { USB_DEVICE(0x0573, 0x4100) }, /* Nogatech USB-TV FM (NTSC) */ | 1031 | { USB_DEVICE(0x0573, 0x2101), .driver_info=ZORAN_PMD_NOGATECH }, |
107 | { USB_DEVICE(0x0573, 0x4110) }, /* PNY USB-TV (NTSC) FM */ | 1032 | { USB_DEVICE(0x0573, 0x4100), .driver_info=NOGATECH_USB_TV_NTSC_FM }, |
108 | { USB_DEVICE(0x0573, 0x4450) }, /* PixelView PlayTv-USB PRO (PAL) FM */ | 1033 | { USB_DEVICE(0x0573, 0x4110), .driver_info=PNY_USB_TV_NTSC_FM }, |
109 | { USB_DEVICE(0x0573, 0x4550) }, /* ZTV ZT-721 2.4GHz USB A/V Receiver */ | 1034 | { USB_DEVICE(0x0573, 0x4450), .driver_info=PV_PLAYTV_USB_PRO_PAL_FM }, |
110 | { USB_DEVICE(0x0573, 0x4d00) }, /* Hauppauge WinTv-USB USA */ | 1035 | { USB_DEVICE(0x0573, 0x4550), .driver_info=ZT_721 }, |
111 | { USB_DEVICE(0x0573, 0x4d01) }, /* Hauppauge WinTv-USB */ | 1036 | { USB_DEVICE(0x0573, 0x4d00), .driver_info=HPG_WINTV_NTSC_MN }, |
112 | { USB_DEVICE(0x0573, 0x4d02) }, /* Hauppauge WinTv-USB UK */ | 1037 | { USB_DEVICE(0x0573, 0x4d01), .driver_info=HPG_WINTV_PAL_BG }, |
113 | { USB_DEVICE(0x0573, 0x4d03) }, /* Hauppauge WinTv-USB France */ | 1038 | { USB_DEVICE(0x0573, 0x4d02), .driver_info=HPG_WINTV_PAL_I }, |
114 | { USB_DEVICE(0x0573, 0x4d10) }, /* Hauppauge WinTv-USB with FM USA radio */ | 1039 | { USB_DEVICE(0x0573, 0x4d03), .driver_info=HPG_WINTV_PAL_SECAM_L }, |
115 | { USB_DEVICE(0x0573, 0x4d11) }, /* Hauppauge WinTv-USB (PAL) with FM radio */ | 1040 | { USB_DEVICE(0x0573, 0x4d04), .driver_info=HPG_WINTV_PAL_D_K }, |
116 | { USB_DEVICE(0x0573, 0x4d12) }, /* Hauppauge WinTv-USB UK with FM Radio */ | 1041 | { USB_DEVICE(0x0573, 0x4d10), .driver_info=HPG_WINTV_NTSC_FM }, |
117 | { USB_DEVICE(0x0573, 0x4d2a) }, /* Hauppague WinTv USB Model 602 40201 Rev B285 */ | 1042 | { USB_DEVICE(0x0573, 0x4d11), .driver_info=HPG_WINTV_PAL_BG_FM }, |
118 | { USB_DEVICE(0x0573, 0x4d2b) }, /* Hauppague WinTv USB Model 602 40201 Rev B282 */ | 1043 | { USB_DEVICE(0x0573, 0x4d12), .driver_info=HPG_WINTV_PAL_I_FM }, |
119 | { USB_DEVICE(0x0573, 0x4d2c) }, /* Hauppague WinTv USB Model 40209 Rev. E1A5 PAL*/ | 1044 | { USB_DEVICE(0x0573, 0x4d14), .driver_info=HPG_WINTV_PAL_D_K_FM }, |
120 | { USB_DEVICE(0x0573, 0x4d20) }, /* Hauppauge WinTv-USB II (PAL) FM Model 40201 Rev B226 */ | 1045 | { USB_DEVICE(0x0573, 0x4d2a), .driver_info=HPG_WINTV_PRO_NTSC_MN }, |
121 | { USB_DEVICE(0x0573, 0x4d21) }, /* Hauppauge WinTv-USB II (PAL) with FM radio*/ | 1046 | { USB_DEVICE(0x0573, 0x4d2b), .driver_info=HPG_WINTV_PRO_NTSC_MN_V2 }, |
122 | { USB_DEVICE(0x0573, 0x4d22) }, /* Hauppauge WinTv-USB II (PAL) Model 566 */ | 1047 | { USB_DEVICE(0x0573, 0x4d2c), .driver_info=HPG_WINTV_PRO_PAL }, |
123 | { USB_DEVICE(0x0573, 0x4d23) }, /* Hauppauge WinTv-USB France 4D23*/ | 1048 | { USB_DEVICE(0x0573, 0x4d20), .driver_info=HPG_WINTV_PRO_NTSC_MN_V3 }, |
124 | { USB_DEVICE(0x0573, 0x4d25) }, /* Hauppauge WinTv-USB Model 40209 rev B234 */ | 1049 | { USB_DEVICE(0x0573, 0x4d21), .driver_info=HPG_WINTV_PRO_PAL_BG }, |
125 | { USB_DEVICE(0x0573, 0x4d26) }, /* Hauppauge WinTv-USB Model 40209 Rev B243 */ | 1050 | { USB_DEVICE(0x0573, 0x4d22), .driver_info=HPG_WINTV_PRO_PAL_I }, |
126 | { USB_DEVICE(0x0573, 0x4d27) }, /* Hauppauge WinTv-USB Model 40204 Rev B281 */ | 1051 | { USB_DEVICE(0x0573, 0x4d23), .driver_info=HPG_WINTV_PRO_PAL_SECAM_L }, |
127 | { USB_DEVICE(0x0573, 0x4d28) }, /* Hauppauge WinTv-USB Model 40204 Rev B283 */ | 1052 | { USB_DEVICE(0x0573, 0x4d24), .driver_info=HPG_WINTV_PRO_PAL_D_K }, |
128 | { USB_DEVICE(0x0573, 0x4d29) }, /* Hauppauge WinTv-USB Model 40205 Rev B298 */ | 1053 | { USB_DEVICE(0x0573, 0x4d25), .driver_info=HPG_WINTV_PRO_PAL_SECAM }, |
129 | { USB_DEVICE(0x0573, 0x4d30) }, /* Hauppauge WinTv-USB FM Model 40211 Rev B123 */ | 1054 | { USB_DEVICE(0x0573, 0x4d26), .driver_info=HPG_WINTV_PRO_PAL_SECAM_V2 }, |
130 | { USB_DEVICE(0x0573, 0x4d31) }, /* Hauppauge WinTv-USB III (PAL) with FM radio Model 568 */ | 1055 | { USB_DEVICE(0x0573, 0x4d27), .driver_info=HPG_WINTV_PRO_PAL_BG_V2 }, |
131 | { USB_DEVICE(0x0573, 0x4d32) }, /* Hauppauge WinTv-USB III (PAL) FM Model 573 */ | 1056 | { USB_DEVICE(0x0573, 0x4d28), .driver_info=HPG_WINTV_PRO_PAL_BG_D_K }, |
132 | { USB_DEVICE(0x0573, 0x4d35) }, /* Hauppauge WinTv-USB III (SECAM) FM Model 40219 Rev B252 */ | 1057 | { USB_DEVICE(0x0573, 0x4d29), .driver_info=HPG_WINTV_PRO_PAL_I_D_K }, |
133 | { USB_DEVICE(0x0573, 0x4d37) }, /* Hauppauge WinTv-USB Model 40219 Rev E189 */ | 1058 | { USB_DEVICE(0x0573, 0x4d30), .driver_info=HPG_WINTV_PRO_NTSC_MN_FM }, |
134 | { USB_DEVICE(0x0768, 0x0006) }, /* Camtel Technology USB TV Genie Pro FM Model TVB330 */ | 1059 | { USB_DEVICE(0x0573, 0x4d31), .driver_info=HPG_WINTV_PRO_PAL_BG_FM }, |
135 | { USB_DEVICE(0x07d0, 0x0001) }, /* Digital Video Creator I */ | 1060 | { USB_DEVICE(0x0573, 0x4d32), .driver_info=HPG_WINTV_PRO_PAL_I_FM }, |
136 | { USB_DEVICE(0x07d0, 0x0002) }, /* Global Village GV-007 (NTSC) */ | 1061 | { USB_DEVICE(0x0573, 0x4d34), .driver_info=HPG_WINTV_PRO_PAL_D_K_FM }, |
137 | { USB_DEVICE(0x07d0, 0x0003) }, /* Dazzle Fusion Model DVC-50 Rev 1 (NTSC) */ | 1062 | { USB_DEVICE(0x0573, 0x4d35), .driver_info=HPG_WINTV_PRO_TEMIC_PAL_FM }, |
138 | { USB_DEVICE(0x07d0, 0x0004) }, /* Dazzle Fusion Model DVC-80 Rev 1 (PAL) */ | 1063 | { USB_DEVICE(0x0573, 0x4d36), .driver_info=HPG_WINTV_PRO_TEMIC_PAL_BG_FM }, |
139 | { USB_DEVICE(0x07d0, 0x0005) }, /* Dazzle Fusion Model DVC-90 Rev 1 (SECAM) */ | 1064 | { USB_DEVICE(0x0573, 0x4d37), .driver_info=HPG_WINTV_PRO_PAL_FM }, |
140 | { USB_DEVICE(0x2304, 0x010d) }, /* Pinnacle Studio PCTV USB (PAL) */ | 1065 | { USB_DEVICE(0x0573, 0x4d38), .driver_info=HPG_WINTV_PRO_NTSC_MN_FM_V2 }, |
141 | { USB_DEVICE(0x2304, 0x0109) }, /* Pinnacle Studio PCTV USB (SECAM) */ | 1066 | { USB_DEVICE(0x0768, 0x0006), .driver_info=CAMTEL_TVB330 }, |
142 | { USB_DEVICE(0x2304, 0x0110) }, /* Pinnacle Studio PCTV USB (PAL) */ | 1067 | { USB_DEVICE(0x07d0, 0x0001), .driver_info=DIGITAL_VIDEO_CREATOR_I }, |
143 | { USB_DEVICE(0x2304, 0x0111) }, /* Miro PCTV USB */ | 1068 | { USB_DEVICE(0x07d0, 0x0002), .driver_info=GLOBAL_VILLAGE_GV_007_NTSC }, |
144 | { USB_DEVICE(0x2304, 0x0112) }, /* Pinnacle Studio PCTV USB (NTSC) with FM radio */ | 1069 | { USB_DEVICE(0x07d0, 0x0003), .driver_info=DAZZLE_DVC_50_REV_1_NTSC }, |
145 | { USB_DEVICE(0x2304, 0x0210) }, /* Pinnacle Studio PCTV USB (PAL) with FM radio */ | 1070 | { USB_DEVICE(0x07d0, 0x0004), .driver_info=DAZZLE_DVC_80_REV_1_PAL }, |
146 | { USB_DEVICE(0x2304, 0x0212) }, /* Pinnacle Studio PCTV USB (NTSC) with FM radio */ | 1071 | { USB_DEVICE(0x07d0, 0x0005), .driver_info=DAZZLE_DVC_90_REV_1_SECAM }, |
147 | { USB_DEVICE(0x2304, 0x0214) }, /* Pinnacle Studio PCTV USB (PAL) with FM radio */ | 1072 | { USB_DEVICE(0x07f8, 0x9104), .driver_info=ESKAPE_LABS_MYTV2GO }, |
148 | { USB_DEVICE(0x2304, 0x0300) }, /* Pinnacle Studio Linx Video input cable (NTSC) */ | 1073 | { USB_DEVICE(0x2304, 0x010d), .driver_info=PINNA_PCTV_USB_PAL }, |
149 | { USB_DEVICE(0x2304, 0x0301) }, /* Pinnacle Studio Linx Video input cable (PAL) */ | 1074 | { USB_DEVICE(0x2304, 0x0109), .driver_info=PINNA_PCTV_USB_SECAM }, |
150 | { USB_DEVICE(0x2304, 0x0419) }, /* Pinnacle PCTV Bungee USB (PAL) FM */ | 1075 | { USB_DEVICE(0x2304, 0x0110), .driver_info=PINNA_PCTV_USB_PAL_FM }, |
151 | { USB_DEVICE(0x2400, 0x4200) }, /* Hauppauge WinTv-USB2 Model 42012 */ | 1076 | { USB_DEVICE(0x2304, 0x0111), .driver_info=MIRO_PCTV_USB }, |
152 | 1077 | { USB_DEVICE(0x2304, 0x0112), .driver_info=PINNA_PCTV_USB_NTSC_FM }, | |
153 | { } /* Terminating entry */ | 1078 | { USB_DEVICE(0x2304, 0x0210), .driver_info=PINNA_PCTV_USB_PAL_FM_V2 }, |
1079 | { USB_DEVICE(0x2304, 0x0212), .driver_info=PINNA_PCTV_USB_NTSC_FM_V2 }, | ||
1080 | { USB_DEVICE(0x2304, 0x0214), .driver_info=PINNA_PCTV_USB_PAL_FM_V3 }, | ||
1081 | { USB_DEVICE(0x2304, 0x0300), .driver_info=PINNA_LINX_VD_IN_CAB_NTSC }, | ||
1082 | { USB_DEVICE(0x2304, 0x0301), .driver_info=PINNA_LINX_VD_IN_CAB_PAL }, | ||
1083 | { USB_DEVICE(0x2304, 0x0419), .driver_info=PINNA_PCTV_BUNGEE_PAL_FM }, | ||
1084 | { USB_DEVICE(0x2400, 0x4200), .driver_info=HPG_WINTV }, | ||
154 | }; | 1085 | }; |
155 | 1086 | ||
156 | MODULE_DEVICE_TABLE (usb, usbvision_table); | 1087 | MODULE_DEVICE_TABLE (usb, usbvision_table); |
diff --git a/drivers/media/video/usbvision/usbvision-cards.h b/drivers/media/video/usbvision/usbvision-cards.h new file mode 100644 index 000000000000..512c5cee4145 --- /dev/null +++ b/drivers/media/video/usbvision/usbvision-cards.h | |||
@@ -0,0 +1,66 @@ | |||
1 | #define XANBOO 0 | ||
2 | #define BELKIN_VIDEOBUS_II 1 | ||
3 | #define BELKIN_VIDEOBUS 2 | ||
4 | #define BELKIN_USB_VIDEOBUS_II 3 | ||
5 | #define ECHOFX_INTERVIEW_LITE 4 | ||
6 | #define USBGEAR_USBG_V1 5 | ||
7 | #define D_LINK_V100 6 | ||
8 | #define X10_USB_CAMERA 7 | ||
9 | #define HPG_WINTV_LIVE_PAL_BG 8 | ||
10 | #define HPG_WINTV_LIVE_PRO_NTSC_MN 9 | ||
11 | #define ZORAN_PMD_NOGATECH 10 | ||
12 | #define NOGATECH_USB_TV_NTSC_FM 11 | ||
13 | #define PNY_USB_TV_NTSC_FM 12 | ||
14 | #define PV_PLAYTV_USB_PRO_PAL_FM 13 | ||
15 | #define ZT_721 14 | ||
16 | #define HPG_WINTV_NTSC_MN 15 | ||
17 | #define HPG_WINTV_PAL_BG 16 | ||
18 | #define HPG_WINTV_PAL_I 17 | ||
19 | #define HPG_WINTV_PAL_SECAM_L 18 | ||
20 | #define HPG_WINTV_PAL_D_K 19 | ||
21 | #define HPG_WINTV_NTSC_FM 20 | ||
22 | #define HPG_WINTV_PAL_BG_FM 21 | ||
23 | #define HPG_WINTV_PAL_I_FM 22 | ||
24 | #define HPG_WINTV_PAL_D_K_FM 23 | ||
25 | #define HPG_WINTV_PRO_NTSC_MN 24 | ||
26 | #define HPG_WINTV_PRO_NTSC_MN_V2 25 | ||
27 | #define HPG_WINTV_PRO_PAL 26 | ||
28 | #define HPG_WINTV_PRO_NTSC_MN_V3 27 | ||
29 | #define HPG_WINTV_PRO_PAL_BG 28 | ||
30 | #define HPG_WINTV_PRO_PAL_I 29 | ||
31 | #define HPG_WINTV_PRO_PAL_SECAM_L 30 | ||
32 | #define HPG_WINTV_PRO_PAL_D_K 31 | ||
33 | #define HPG_WINTV_PRO_PAL_SECAM 32 | ||
34 | #define HPG_WINTV_PRO_PAL_SECAM_V2 33 | ||
35 | #define HPG_WINTV_PRO_PAL_BG_V2 34 | ||
36 | #define HPG_WINTV_PRO_PAL_BG_D_K 35 | ||
37 | #define HPG_WINTV_PRO_PAL_I_D_K 36 | ||
38 | #define HPG_WINTV_PRO_NTSC_MN_FM 37 | ||
39 | #define HPG_WINTV_PRO_PAL_BG_FM 38 | ||
40 | #define HPG_WINTV_PRO_PAL_I_FM 39 | ||
41 | #define HPG_WINTV_PRO_PAL_D_K_FM 40 | ||
42 | #define HPG_WINTV_PRO_TEMIC_PAL_FM 41 | ||
43 | #define HPG_WINTV_PRO_TEMIC_PAL_BG_FM 42 | ||
44 | #define HPG_WINTV_PRO_PAL_FM 43 | ||
45 | #define HPG_WINTV_PRO_NTSC_MN_FM_V2 44 | ||
46 | #define CAMTEL_TVB330 45 | ||
47 | #define DIGITAL_VIDEO_CREATOR_I 46 | ||
48 | #define GLOBAL_VILLAGE_GV_007_NTSC 47 | ||
49 | #define DAZZLE_DVC_50_REV_1_NTSC 48 | ||
50 | #define DAZZLE_DVC_80_REV_1_PAL 49 | ||
51 | #define DAZZLE_DVC_90_REV_1_SECAM 50 | ||
52 | #define ESKAPE_LABS_MYTV2GO 51 | ||
53 | #define PINNA_PCTV_USB_PAL 52 | ||
54 | #define PINNA_PCTV_USB_SECAM 53 | ||
55 | #define PINNA_PCTV_USB_PAL_FM 54 | ||
56 | #define MIRO_PCTV_USB 55 | ||
57 | #define PINNA_PCTV_USB_NTSC_FM 56 | ||
58 | #define PINNA_PCTV_USB_PAL_FM_V2 57 | ||
59 | #define PINNA_PCTV_USB_NTSC_FM_V2 58 | ||
60 | #define PINNA_PCTV_USB_PAL_FM_V3 59 | ||
61 | #define PINNA_LINX_VD_IN_CAB_NTSC 60 | ||
62 | #define PINNA_LINX_VD_IN_CAB_PAL 61 | ||
63 | #define PINNA_PCTV_BUNGEE_PAL_FM 62 | ||
64 | #define HPG_WINTV 63 | ||
65 | |||
66 | extern const int usbvision_device_data_size; | ||
diff --git a/drivers/media/video/usbvision/usbvision-core.c b/drivers/media/video/usbvision/usbvision-core.c index f2154dc072e2..bcb551adb7e6 100644 --- a/drivers/media/video/usbvision/usbvision-core.c +++ b/drivers/media/video/usbvision/usbvision-core.c | |||
@@ -2040,8 +2040,8 @@ int usbvision_set_input(struct usb_usbvision *usbvision) | |||
2040 | return 0; | 2040 | return 0; |
2041 | 2041 | ||
2042 | /* Set input format expected from decoder*/ | 2042 | /* Set input format expected from decoder*/ |
2043 | if (usbvision_device_data[usbvision->DevModel].Vin_Reg1 >= 0) { | 2043 | if (usbvision_device_data[usbvision->DevModel].Vin_Reg1_override) { |
2044 | value[0] = usbvision_device_data[usbvision->DevModel].Vin_Reg1 & 0xff; | 2044 | value[0] = usbvision_device_data[usbvision->DevModel].Vin_Reg1; |
2045 | } else if(usbvision_device_data[usbvision->DevModel].Codec == CODEC_SAA7113) { | 2045 | } else if(usbvision_device_data[usbvision->DevModel].Codec == CODEC_SAA7113) { |
2046 | /* SAA7113 uses 8 bit output */ | 2046 | /* SAA7113 uses 8 bit output */ |
2047 | value[0] = USBVISION_8_422_SYNC; | 2047 | value[0] = USBVISION_8_422_SYNC; |
@@ -2112,8 +2112,8 @@ int usbvision_set_input(struct usb_usbvision *usbvision) | |||
2112 | 2112 | ||
2113 | dvi_yuv_value = 0x00; /* U comes after V, Ya comes after U/V, Yb comes after Yb */ | 2113 | dvi_yuv_value = 0x00; /* U comes after V, Ya comes after U/V, Yb comes after Yb */ |
2114 | 2114 | ||
2115 | if(usbvision_device_data[usbvision->DevModel].Dvi_yuv >= 0){ | 2115 | if(usbvision_device_data[usbvision->DevModel].Dvi_yuv_override){ |
2116 | dvi_yuv_value = usbvision_device_data[usbvision->DevModel].Dvi_yuv & 0xff; | 2116 | dvi_yuv_value = usbvision_device_data[usbvision->DevModel].Dvi_yuv; |
2117 | } | 2117 | } |
2118 | else if(usbvision_device_data[usbvision->DevModel].Codec == CODEC_SAA7113) { | 2118 | else if(usbvision_device_data[usbvision->DevModel].Codec == CODEC_SAA7113) { |
2119 | /* This changes as the fine sync control changes. Further investigation necessary */ | 2119 | /* This changes as the fine sync control changes. Further investigation necessary */ |
@@ -2238,7 +2238,7 @@ static void call_usbvision_power_off(struct work_struct *work) | |||
2238 | PDEBUG(DBG_FUNC, ""); | 2238 | PDEBUG(DBG_FUNC, ""); |
2239 | down_interruptible(&usbvision->lock); | 2239 | down_interruptible(&usbvision->lock); |
2240 | if(usbvision->user == 0) { | 2240 | if(usbvision->user == 0) { |
2241 | usbvision_i2c_usb_del_bus(&usbvision->i2c_adap); | 2241 | usbvision_i2c_unregister(usbvision); |
2242 | 2242 | ||
2243 | usbvision_power_off(usbvision); | 2243 | usbvision_power_off(usbvision); |
2244 | usbvision->initialized = 0; | 2244 | usbvision->initialized = 0; |
diff --git a/drivers/media/video/usbvision/usbvision-i2c.c b/drivers/media/video/usbvision/usbvision-i2c.c index 609e1fd9c784..025be555194f 100644 --- a/drivers/media/video/usbvision/usbvision-i2c.c +++ b/drivers/media/video/usbvision/usbvision-i2c.c | |||
@@ -1,8 +1,8 @@ | |||
1 | /* | 1 | /* |
2 | * I2C_ALGO_USB.C | 2 | * usbvision_i2c.c |
3 | * i2c algorithm for USB-I2C Bridges | 3 | * i2c algorithm for USB-I2C Bridges |
4 | * | 4 | * |
5 | * Copyright (c) 1999-2005 Joerg Heckenbach <joerg@heckenbach-aw.de> | 5 | * Copyright (c) 1999-2007 Joerg Heckenbach <joerg@heckenbach-aw.de> |
6 | * Dwaine Garden <dwainegarden@rogers.com> | 6 | * Dwaine Garden <dwainegarden@rogers.com> |
7 | * | 7 | * |
8 | * This module is part of usbvision driver project. | 8 | * This module is part of usbvision driver project. |
@@ -39,7 +39,6 @@ | |||
39 | #include "usbvision.h" | 39 | #include "usbvision.h" |
40 | 40 | ||
41 | #define DBG_I2C 1<<0 | 41 | #define DBG_I2C 1<<0 |
42 | #define DBG_ALGO 1<<1 | ||
43 | 42 | ||
44 | static int i2c_debug = 0; | 43 | static int i2c_debug = 0; |
45 | 44 | ||
@@ -49,22 +48,22 @@ MODULE_PARM_DESC(i2c_debug, "enable debug messages [i2c]"); | |||
49 | #define PDEBUG(level, fmt, args...) \ | 48 | #define PDEBUG(level, fmt, args...) \ |
50 | if (i2c_debug & (level)) info("[%s:%d] " fmt, __PRETTY_FUNCTION__, __LINE__ , ## args) | 49 | if (i2c_debug & (level)) info("[%s:%d] " fmt, __PRETTY_FUNCTION__, __LINE__ , ## args) |
51 | 50 | ||
52 | static int usbvision_i2c_write(void *data, unsigned char addr, char *buf, | 51 | static int usbvision_i2c_write(struct usb_usbvision *usbvision, unsigned char addr, char *buf, |
53 | short len); | 52 | short len); |
54 | static int usbvision_i2c_read(void *data, unsigned char addr, char *buf, | 53 | static int usbvision_i2c_read(struct usb_usbvision *usbvision, unsigned char addr, char *buf, |
55 | short len); | 54 | short len); |
56 | 55 | ||
57 | static inline int try_write_address(struct i2c_adapter *i2c_adap, | 56 | static inline int try_write_address(struct i2c_adapter *i2c_adap, |
58 | unsigned char addr, int retries) | 57 | unsigned char addr, int retries) |
59 | { | 58 | { |
60 | void *data; | 59 | struct usb_usbvision *usbvision; |
61 | int i, ret = -1; | 60 | int i, ret = -1; |
62 | char buf[4]; | 61 | char buf[4]; |
63 | 62 | ||
64 | data = i2c_get_adapdata(i2c_adap); | 63 | usbvision = (struct usb_usbvision *)i2c_get_adapdata(i2c_adap); |
65 | buf[0] = 0x00; | 64 | buf[0] = 0x00; |
66 | for (i = 0; i <= retries; i++) { | 65 | for (i = 0; i <= retries; i++) { |
67 | ret = (usbvision_i2c_write(data, addr, buf, 1)); | 66 | ret = (usbvision_i2c_write(usbvision, addr, buf, 1)); |
68 | if (ret == 1) | 67 | if (ret == 1) |
69 | break; /* success! */ | 68 | break; /* success! */ |
70 | udelay(5); | 69 | udelay(5); |
@@ -73,8 +72,8 @@ static inline int try_write_address(struct i2c_adapter *i2c_adap, | |||
73 | udelay(10); | 72 | udelay(10); |
74 | } | 73 | } |
75 | if (i) { | 74 | if (i) { |
76 | PDEBUG(DBG_ALGO,"Needed %d retries for address %#2x", i, addr); | 75 | PDEBUG(DBG_I2C,"Needed %d retries for address %#2x", i, addr); |
77 | PDEBUG(DBG_ALGO,"Maybe there's no device at this address"); | 76 | PDEBUG(DBG_I2C,"Maybe there's no device at this address"); |
78 | } | 77 | } |
79 | return ret; | 78 | return ret; |
80 | } | 79 | } |
@@ -82,13 +81,13 @@ static inline int try_write_address(struct i2c_adapter *i2c_adap, | |||
82 | static inline int try_read_address(struct i2c_adapter *i2c_adap, | 81 | static inline int try_read_address(struct i2c_adapter *i2c_adap, |
83 | unsigned char addr, int retries) | 82 | unsigned char addr, int retries) |
84 | { | 83 | { |
85 | void *data; | 84 | struct usb_usbvision *usbvision; |
86 | int i, ret = -1; | 85 | int i, ret = -1; |
87 | char buf[4]; | 86 | char buf[4]; |
88 | 87 | ||
89 | data = i2c_get_adapdata(i2c_adap); | 88 | usbvision = (struct usb_usbvision *)i2c_get_adapdata(i2c_adap); |
90 | for (i = 0; i <= retries; i++) { | 89 | for (i = 0; i <= retries; i++) { |
91 | ret = (usbvision_i2c_read(data, addr, buf, 1)); | 90 | ret = (usbvision_i2c_read(usbvision, addr, buf, 1)); |
92 | if (ret == 1) | 91 | if (ret == 1) |
93 | break; /* success! */ | 92 | break; /* success! */ |
94 | udelay(5); | 93 | udelay(5); |
@@ -97,8 +96,8 @@ static inline int try_read_address(struct i2c_adapter *i2c_adap, | |||
97 | udelay(10); | 96 | udelay(10); |
98 | } | 97 | } |
99 | if (i) { | 98 | if (i) { |
100 | PDEBUG(DBG_ALGO,"Needed %d retries for address %#2x", i, addr); | 99 | PDEBUG(DBG_I2C,"Needed %d retries for address %#2x", i, addr); |
101 | PDEBUG(DBG_ALGO,"Maybe there's no device at this address"); | 100 | PDEBUG(DBG_I2C,"Maybe there's no device at this address"); |
102 | } | 101 | } |
103 | return ret; | 102 | return ret; |
104 | } | 103 | } |
@@ -152,32 +151,32 @@ static inline int usb_find_address(struct i2c_adapter *i2c_adap, | |||
152 | } | 151 | } |
153 | 152 | ||
154 | static int | 153 | static int |
155 | usb_xfer(struct i2c_adapter *i2c_adap, struct i2c_msg msgs[], int num) | 154 | usbvision_i2c_xfer(struct i2c_adapter *i2c_adap, struct i2c_msg msgs[], int num) |
156 | { | 155 | { |
157 | struct i2c_msg *pmsg; | 156 | struct i2c_msg *pmsg; |
158 | void *data; | 157 | struct usb_usbvision *usbvision; |
159 | int i, ret; | 158 | int i, ret; |
160 | unsigned char addr; | 159 | unsigned char addr; |
161 | 160 | ||
162 | data = i2c_get_adapdata(i2c_adap); | 161 | usbvision = (struct usb_usbvision *)i2c_get_adapdata(i2c_adap); |
163 | 162 | ||
164 | for (i = 0; i < num; i++) { | 163 | for (i = 0; i < num; i++) { |
165 | pmsg = &msgs[i]; | 164 | pmsg = &msgs[i]; |
166 | ret = usb_find_address(i2c_adap, pmsg, i2c_adap->retries, &addr); | 165 | ret = usb_find_address(i2c_adap, pmsg, i2c_adap->retries, &addr); |
167 | if (ret != 0) { | 166 | if (ret != 0) { |
168 | PDEBUG(DBG_ALGO,"got NAK from device, message #%d", i); | 167 | PDEBUG(DBG_I2C,"got NAK from device, message #%d", i); |
169 | return (ret < 0) ? ret : -EREMOTEIO; | 168 | return (ret < 0) ? ret : -EREMOTEIO; |
170 | } | 169 | } |
171 | 170 | ||
172 | if (pmsg->flags & I2C_M_RD) { | 171 | if (pmsg->flags & I2C_M_RD) { |
173 | /* read bytes into buffer */ | 172 | /* read bytes into buffer */ |
174 | ret = (usbvision_i2c_read(data, addr, pmsg->buf, pmsg->len)); | 173 | ret = (usbvision_i2c_read(usbvision, addr, pmsg->buf, pmsg->len)); |
175 | if (ret < pmsg->len) { | 174 | if (ret < pmsg->len) { |
176 | return (ret < 0) ? ret : -EREMOTEIO; | 175 | return (ret < 0) ? ret : -EREMOTEIO; |
177 | } | 176 | } |
178 | } else { | 177 | } else { |
179 | /* write bytes from buffer */ | 178 | /* write bytes from buffer */ |
180 | ret = (usbvision_i2c_write(data, addr, pmsg->buf, pmsg->len)); | 179 | ret = (usbvision_i2c_write(usbvision, addr, pmsg->buf, pmsg->len)); |
181 | if (ret < pmsg->len) { | 180 | if (ret < pmsg->len) { |
182 | return (ret < 0) ? ret : -EREMOTEIO; | 181 | return (ret < 0) ? ret : -EREMOTEIO; |
183 | } | 182 | } |
@@ -191,7 +190,7 @@ static int algo_control(struct i2c_adapter *adapter, unsigned int cmd, unsigned | |||
191 | return 0; | 190 | return 0; |
192 | } | 191 | } |
193 | 192 | ||
194 | static u32 usb_func(struct i2c_adapter *adap) | 193 | static u32 functionality(struct i2c_adapter *adap) |
195 | { | 194 | { |
196 | return I2C_FUNC_SMBUS_EMUL | I2C_FUNC_10BIT_ADDR | I2C_FUNC_PROTOCOL_MANGLING; | 195 | return I2C_FUNC_SMBUS_EMUL | I2C_FUNC_10BIT_ADDR | I2C_FUNC_PROTOCOL_MANGLING; |
197 | } | 196 | } |
@@ -199,11 +198,11 @@ static u32 usb_func(struct i2c_adapter *adap) | |||
199 | 198 | ||
200 | /* -----exported algorithm data: ------------------------------------- */ | 199 | /* -----exported algorithm data: ------------------------------------- */ |
201 | 200 | ||
202 | static struct i2c_algorithm i2c_usb_algo = { | 201 | static struct i2c_algorithm usbvision_algo = { |
203 | .master_xfer = usb_xfer, | 202 | .master_xfer = usbvision_i2c_xfer, |
204 | .smbus_xfer = NULL, | 203 | .smbus_xfer = NULL, |
205 | .algo_control = algo_control, | 204 | .algo_control = algo_control, |
206 | .functionality = usb_func, | 205 | .functionality = functionality, |
207 | }; | 206 | }; |
208 | 207 | ||
209 | 208 | ||
@@ -213,41 +212,29 @@ static struct i2c_algorithm i2c_usb_algo = { | |||
213 | static int usbvision_i2c_usb_add_bus(struct i2c_adapter *adap) | 212 | static int usbvision_i2c_usb_add_bus(struct i2c_adapter *adap) |
214 | { | 213 | { |
215 | PDEBUG(DBG_I2C, "I2C debugging is enabled [i2c]"); | 214 | PDEBUG(DBG_I2C, "I2C debugging is enabled [i2c]"); |
216 | PDEBUG(DBG_ALGO, "ALGO debugging is enabled [i2c]"); | 215 | PDEBUG(DBG_I2C, "ALGO debugging is enabled [i2c]"); |
217 | 216 | ||
218 | /* register new adapter to i2c module... */ | 217 | /* register new adapter to i2c module... */ |
219 | 218 | ||
220 | adap->algo = &i2c_usb_algo; | 219 | adap->algo = &usbvision_algo; |
221 | 220 | ||
222 | adap->timeout = 100; /* default values, should */ | 221 | adap->timeout = 100; /* default values, should */ |
223 | adap->retries = 3; /* be replaced by defines */ | 222 | adap->retries = 3; /* be replaced by defines */ |
224 | 223 | ||
225 | i2c_add_adapter(adap); | 224 | i2c_add_adapter(adap); |
226 | 225 | ||
227 | PDEBUG(DBG_ALGO,"i2c bus for %s registered", adap->name); | 226 | PDEBUG(DBG_I2C,"i2c bus for %s registered", adap->name); |
228 | |||
229 | return 0; | ||
230 | } | ||
231 | |||
232 | |||
233 | int usbvision_i2c_usb_del_bus(struct i2c_adapter *adap) | ||
234 | { | ||
235 | |||
236 | i2c_del_adapter(adap); | ||
237 | |||
238 | PDEBUG(DBG_ALGO,"i2c bus for %s unregistered", adap->name); | ||
239 | 227 | ||
240 | return 0; | 228 | return 0; |
241 | } | 229 | } |
242 | 230 | ||
243 | |||
244 | /* ----------------------------------------------------------------------- */ | 231 | /* ----------------------------------------------------------------------- */ |
245 | /* usbvision specific I2C functions */ | 232 | /* usbvision specific I2C functions */ |
246 | /* ----------------------------------------------------------------------- */ | 233 | /* ----------------------------------------------------------------------- */ |
247 | static struct i2c_adapter i2c_adap_template; | 234 | static struct i2c_adapter i2c_adap_template; |
248 | static struct i2c_client i2c_client_template; | 235 | static struct i2c_client i2c_client_template; |
249 | 236 | ||
250 | int usbvision_init_i2c(struct usb_usbvision *usbvision) | 237 | int usbvision_i2c_register(struct usb_usbvision *usbvision) |
251 | { | 238 | { |
252 | memcpy(&usbvision->i2c_adap, &i2c_adap_template, | 239 | memcpy(&usbvision->i2c_adap, &i2c_adap_template, |
253 | sizeof(struct i2c_adapter)); | 240 | sizeof(struct i2c_adapter)); |
@@ -265,7 +252,7 @@ int usbvision_init_i2c(struct usb_usbvision *usbvision) | |||
265 | usbvision->i2c_client.adapter = &usbvision->i2c_adap; | 252 | usbvision->i2c_client.adapter = &usbvision->i2c_adap; |
266 | 253 | ||
267 | if (usbvision_write_reg(usbvision, USBVISION_SER_MODE, USBVISION_IIC_LRNACK) < 0) { | 254 | if (usbvision_write_reg(usbvision, USBVISION_SER_MODE, USBVISION_IIC_LRNACK) < 0) { |
268 | printk(KERN_ERR "usbvision_init_i2c: can't write reg\n"); | 255 | printk(KERN_ERR "usbvision_register: can't write reg\n"); |
269 | return -EBUSY; | 256 | return -EBUSY; |
270 | } | 257 | } |
271 | 258 | ||
@@ -287,6 +274,16 @@ int usbvision_init_i2c(struct usb_usbvision *usbvision) | |||
287 | return usbvision_i2c_usb_add_bus(&usbvision->i2c_adap); | 274 | return usbvision_i2c_usb_add_bus(&usbvision->i2c_adap); |
288 | } | 275 | } |
289 | 276 | ||
277 | int usbvision_i2c_unregister(struct usb_usbvision *usbvision) | ||
278 | { | ||
279 | |||
280 | i2c_del_adapter(&(usbvision->i2c_adap)); | ||
281 | |||
282 | PDEBUG(DBG_I2C,"i2c bus for %s unregistered", usbvision->i2c_adap.name); | ||
283 | |||
284 | return 0; | ||
285 | } | ||
286 | |||
290 | void call_i2c_clients(struct usb_usbvision *usbvision, unsigned int cmd, | 287 | void call_i2c_clients(struct usb_usbvision *usbvision, unsigned int cmd, |
291 | void *arg) | 288 | void *arg) |
292 | { | 289 | { |
@@ -300,19 +297,12 @@ static int attach_inform(struct i2c_client *client) | |||
300 | usbvision = (struct usb_usbvision *)i2c_get_adapdata(client->adapter); | 297 | usbvision = (struct usb_usbvision *)i2c_get_adapdata(client->adapter); |
301 | 298 | ||
302 | switch (client->addr << 1) { | 299 | switch (client->addr << 1) { |
303 | case 0x43: | 300 | case 0x42 << 1: |
304 | case 0x4b: | 301 | case 0x43 << 1: |
305 | { | 302 | case 0x4a << 1: |
306 | struct tuner_setup tun_setup; | 303 | case 0x4b << 1: |
307 | 304 | PDEBUG(DBG_I2C,"attach_inform: tda9887 detected."); | |
308 | tun_setup.mode_mask = T_ANALOG_TV | T_RADIO; | ||
309 | tun_setup.type = TUNER_TDA9887; | ||
310 | tun_setup.addr = client->addr; | ||
311 | |||
312 | call_i2c_clients(usbvision, TUNER_SET_TYPE_ADDR, &tun_setup); | ||
313 | |||
314 | break; | 305 | break; |
315 | } | ||
316 | case 0x42: | 306 | case 0x42: |
317 | PDEBUG(DBG_I2C,"attach_inform: saa7114 detected."); | 307 | PDEBUG(DBG_I2C,"attach_inform: saa7114 detected."); |
318 | break; | 308 | break; |
@@ -480,7 +470,7 @@ static int usbvision_i2c_write_max4(struct usb_usbvision *usbvision, | |||
480 | return len; | 470 | return len; |
481 | } | 471 | } |
482 | 472 | ||
483 | static int usbvision_i2c_write(void *data, unsigned char addr, char *buf, | 473 | static int usbvision_i2c_write(struct usb_usbvision *usbvision, unsigned char addr, char *buf, |
484 | short len) | 474 | short len) |
485 | { | 475 | { |
486 | char *bufPtr = buf; | 476 | char *bufPtr = buf; |
@@ -488,7 +478,6 @@ static int usbvision_i2c_write(void *data, unsigned char addr, char *buf, | |||
488 | int wrcount = 0; | 478 | int wrcount = 0; |
489 | int count; | 479 | int count; |
490 | int maxLen = 4; | 480 | int maxLen = 4; |
491 | struct usb_usbvision *usbvision = (struct usb_usbvision *) data; | ||
492 | 481 | ||
493 | while (len > 0) { | 482 | while (len > 0) { |
494 | count = (len > maxLen) ? maxLen : len; | 483 | count = (len > maxLen) ? maxLen : len; |
@@ -503,14 +492,13 @@ static int usbvision_i2c_write(void *data, unsigned char addr, char *buf, | |||
503 | return wrcount; | 492 | return wrcount; |
504 | } | 493 | } |
505 | 494 | ||
506 | static int usbvision_i2c_read(void *data, unsigned char addr, char *buf, | 495 | static int usbvision_i2c_read(struct usb_usbvision *usbvision, unsigned char addr, char *buf, |
507 | short len) | 496 | short len) |
508 | { | 497 | { |
509 | char temp[4]; | 498 | char temp[4]; |
510 | int retval, i; | 499 | int retval, i; |
511 | int rdcount = 0; | 500 | int rdcount = 0; |
512 | int count; | 501 | int count; |
513 | struct usb_usbvision *usbvision = (struct usb_usbvision *) data; | ||
514 | 502 | ||
515 | while (len > 0) { | 503 | while (len > 0) { |
516 | count = (len > 3) ? 4 : len; | 504 | count = (len > 3) ? 4 : len; |
diff --git a/drivers/media/video/usbvision/usbvision-video.c b/drivers/media/video/usbvision/usbvision-video.c index 6fc14557d623..216704170a4c 100644 --- a/drivers/media/video/usbvision/usbvision-video.c +++ b/drivers/media/video/usbvision/usbvision-video.c | |||
@@ -76,6 +76,7 @@ | |||
76 | #endif | 76 | #endif |
77 | 77 | ||
78 | #include "usbvision.h" | 78 | #include "usbvision.h" |
79 | #include "usbvision-cards.h" | ||
79 | 80 | ||
80 | #define DRIVER_AUTHOR "Joerg Heckenbach <joerg@heckenbach-aw.de>, Dwaine Garden <DwaineGarden@rogers.com>" | 81 | #define DRIVER_AUTHOR "Joerg Heckenbach <joerg@heckenbach-aw.de>, Dwaine Garden <DwaineGarden@rogers.com>" |
81 | #define DRIVER_NAME "usbvision" | 82 | #define DRIVER_NAME "usbvision" |
@@ -150,7 +151,6 @@ static int PowerOnAtOpen = 1; // Set the default device to power on at startu | |||
150 | static int video_nr = -1; // Sequential Number of Video Device | 151 | static int video_nr = -1; // Sequential Number of Video Device |
151 | static int radio_nr = -1; // Sequential Number of Radio Device | 152 | static int radio_nr = -1; // Sequential Number of Radio Device |
152 | static int vbi_nr = -1; // Sequential Number of VBI Device | 153 | static int vbi_nr = -1; // Sequential Number of VBI Device |
153 | static char *CustomDevice=NULL; // Set as nothing.... | ||
154 | 154 | ||
155 | // Grab parameters for the device driver | 155 | // Grab parameters for the device driver |
156 | 156 | ||
@@ -161,7 +161,6 @@ module_param(PowerOnAtOpen, int, 0444); | |||
161 | module_param(video_nr, int, 0444); | 161 | module_param(video_nr, int, 0444); |
162 | module_param(radio_nr, int, 0444); | 162 | module_param(radio_nr, int, 0444); |
163 | module_param(vbi_nr, int, 0444); | 163 | module_param(vbi_nr, int, 0444); |
164 | module_param(CustomDevice, charp, 0444); | ||
165 | #else // Old Style | 164 | #else // Old Style |
166 | MODULE_PARAM(isocMode, "i"); | 165 | MODULE_PARAM(isocMode, "i"); |
167 | MODULE_PARM(video_debug, "i"); // Grab the Debug Mode of the device driver | 166 | MODULE_PARM(video_debug, "i"); // Grab the Debug Mode of the device driver |
@@ -171,7 +170,6 @@ MODULE_PARM(SwitchSVideoInput, "i"); // To help people with Black and White ou | |||
171 | MODULE_PARM(video_nr, "i"); // video_nr option allows to specify a certain /dev/videoX device (like /dev/video0 or /dev/video1 ...) | 170 | MODULE_PARM(video_nr, "i"); // video_nr option allows to specify a certain /dev/videoX device (like /dev/video0 or /dev/video1 ...) |
172 | MODULE_PARM(radio_nr, "i"); // radio_nr option allows to specify a certain /dev/radioX device (like /dev/radio0 or /dev/radio1 ...) | 171 | MODULE_PARM(radio_nr, "i"); // radio_nr option allows to specify a certain /dev/radioX device (like /dev/radio0 or /dev/radio1 ...) |
173 | MODULE_PARM(vbi_nr, "i"); // vbi_nr option allows to specify a certain /dev/vbiX device (like /dev/vbi0 or /dev/vbi1 ...) | 172 | MODULE_PARM(vbi_nr, "i"); // vbi_nr option allows to specify a certain /dev/vbiX device (like /dev/vbi0 or /dev/vbi1 ...) |
174 | MODULE_PARM(CustomDevice, "s"); // .... CustomDevice | ||
175 | #endif | 173 | #endif |
176 | 174 | ||
177 | MODULE_PARM_DESC(isocMode, " Set the default format for ISOC endpoint. Default: 0x60 (Compression On)"); | 175 | MODULE_PARM_DESC(isocMode, " Set the default format for ISOC endpoint. Default: 0x60 (Compression On)"); |
@@ -180,7 +178,6 @@ MODULE_PARM_DESC(PowerOnAtOpen, " Set the default device to power on when device | |||
180 | MODULE_PARM_DESC(video_nr, "Set video device number (/dev/videoX). Default: -1 (autodetect)"); | 178 | MODULE_PARM_DESC(video_nr, "Set video device number (/dev/videoX). Default: -1 (autodetect)"); |
181 | MODULE_PARM_DESC(radio_nr, "Set radio device number (/dev/radioX). Default: -1 (autodetect)"); | 179 | MODULE_PARM_DESC(radio_nr, "Set radio device number (/dev/radioX). Default: -1 (autodetect)"); |
182 | MODULE_PARM_DESC(vbi_nr, "Set vbi device number (/dev/vbiX). Default: -1 (autodetect)"); | 180 | MODULE_PARM_DESC(vbi_nr, "Set vbi device number (/dev/vbiX). Default: -1 (autodetect)"); |
183 | MODULE_PARM_DESC(CustomDevice, " Define the fine tuning parameters for the device. Default: null"); | ||
184 | 181 | ||
185 | 182 | ||
186 | // Misc stuff | 183 | // Misc stuff |
@@ -409,7 +406,7 @@ static int usbvision_v4l2_open(struct inode *inode, struct file *file) | |||
409 | down(&usbvision->lock); | 406 | down(&usbvision->lock); |
410 | if (usbvision->power == 0) { | 407 | if (usbvision->power == 0) { |
411 | usbvision_power_on(usbvision); | 408 | usbvision_power_on(usbvision); |
412 | usbvision_init_i2c(usbvision); | 409 | usbvision_i2c_register(usbvision); |
413 | } | 410 | } |
414 | 411 | ||
415 | /* Send init sequence only once, it's large! */ | 412 | /* Send init sequence only once, it's large! */ |
@@ -431,7 +428,7 @@ static int usbvision_v4l2_open(struct inode *inode, struct file *file) | |||
431 | } | 428 | } |
432 | else { | 429 | else { |
433 | if (PowerOnAtOpen) { | 430 | if (PowerOnAtOpen) { |
434 | usbvision_i2c_usb_del_bus(&usbvision->i2c_adap); | 431 | usbvision_i2c_unregister(usbvision); |
435 | usbvision_power_off(usbvision); | 432 | usbvision_power_off(usbvision); |
436 | usbvision->initialized = 0; | 433 | usbvision->initialized = 0; |
437 | } | 434 | } |
@@ -1239,7 +1236,7 @@ static int usbvision_radio_open(struct inode *inode, struct file *file) | |||
1239 | usbvision_reset_powerOffTimer(usbvision); | 1236 | usbvision_reset_powerOffTimer(usbvision); |
1240 | if (usbvision->power == 0) { | 1237 | if (usbvision->power == 0) { |
1241 | usbvision_power_on(usbvision); | 1238 | usbvision_power_on(usbvision); |
1242 | usbvision_init_i2c(usbvision); | 1239 | usbvision_i2c_register(usbvision); |
1243 | } | 1240 | } |
1244 | } | 1241 | } |
1245 | 1242 | ||
@@ -1261,7 +1258,7 @@ static int usbvision_radio_open(struct inode *inode, struct file *file) | |||
1261 | 1258 | ||
1262 | if (errCode) { | 1259 | if (errCode) { |
1263 | if (PowerOnAtOpen) { | 1260 | if (PowerOnAtOpen) { |
1264 | usbvision_i2c_usb_del_bus(&usbvision->i2c_adap); | 1261 | usbvision_i2c_unregister(usbvision); |
1265 | usbvision_power_off(usbvision); | 1262 | usbvision_power_off(usbvision); |
1266 | usbvision->initialized = 0; | 1263 | usbvision->initialized = 0; |
1267 | } | 1264 | } |
@@ -1744,8 +1741,8 @@ static void usbvision_configure_video(struct usb_usbvision *usbvision) | |||
1744 | model = usbvision->DevModel; | 1741 | model = usbvision->DevModel; |
1745 | usbvision->palette = usbvision_v4l2_format[2]; // V4L2_PIX_FMT_RGB24; | 1742 | usbvision->palette = usbvision_v4l2_format[2]; // V4L2_PIX_FMT_RGB24; |
1746 | 1743 | ||
1747 | if (usbvision_device_data[usbvision->DevModel].Vin_Reg2 >= 0) { | 1744 | if (usbvision_device_data[usbvision->DevModel].Vin_Reg2_override) { |
1748 | usbvision->Vin_Reg2_Preset = usbvision_device_data[usbvision->DevModel].Vin_Reg2 & 0xff; | 1745 | usbvision->Vin_Reg2_Preset = usbvision_device_data[usbvision->DevModel].Vin_Reg2; |
1749 | } else { | 1746 | } else { |
1750 | usbvision->Vin_Reg2_Preset = 0; | 1747 | usbvision->Vin_Reg2_Preset = 0; |
1751 | } | 1748 | } |
@@ -1764,7 +1761,7 @@ static void usbvision_configure_video(struct usb_usbvision *usbvision) | |||
1764 | usbvision_audio_off(usbvision); //first switch off audio | 1761 | usbvision_audio_off(usbvision); //first switch off audio |
1765 | if (!PowerOnAtOpen) { | 1762 | if (!PowerOnAtOpen) { |
1766 | usbvision_power_on(usbvision); //and then power up the noisy tuner | 1763 | usbvision_power_on(usbvision); //and then power up the noisy tuner |
1767 | usbvision_init_i2c(usbvision); | 1764 | usbvision_i2c_register(usbvision); |
1768 | } | 1765 | } |
1769 | } | 1766 | } |
1770 | 1767 | ||
@@ -1775,7 +1772,8 @@ static void usbvision_configure_video(struct usb_usbvision *usbvision) | |||
1775 | * if it looks like USBVISION video device | 1772 | * if it looks like USBVISION video device |
1776 | * | 1773 | * |
1777 | */ | 1774 | */ |
1778 | static int __devinit usbvision_probe(struct usb_interface *intf, const struct usb_device_id *devid) | 1775 | static int __devinit usbvision_probe(struct usb_interface *intf, |
1776 | const struct usb_device_id *devid) | ||
1779 | { | 1777 | { |
1780 | struct usb_device *dev = usb_get_dev(interface_to_usbdev(intf)); | 1778 | struct usb_device *dev = usb_get_dev(interface_to_usbdev(intf)); |
1781 | struct usb_interface *uif; | 1779 | struct usb_interface *uif; |
@@ -1786,25 +1784,17 @@ static int __devinit usbvision_probe(struct usb_interface *intf, const struct us | |||
1786 | int model,i; | 1784 | int model,i; |
1787 | 1785 | ||
1788 | PDEBUG(DBG_PROBE, "VID=%#04x, PID=%#04x, ifnum=%u", | 1786 | PDEBUG(DBG_PROBE, "VID=%#04x, PID=%#04x, ifnum=%u", |
1789 | dev->descriptor.idVendor, dev->descriptor.idProduct, ifnum); | 1787 | dev->descriptor.idVendor, |
1788 | dev->descriptor.idProduct, ifnum); | ||
1790 | 1789 | ||
1791 | /* Is it an USBVISION video dev? */ | 1790 | model = devid->driver_info; |
1792 | model = 0; | 1791 | if ( (model<0) || (model>=usbvision_device_data_size) ) { |
1793 | for(model = 0; usbvision_device_data[model].idVendor; model++) { | 1792 | PDEBUG(DBG_PROBE, "model out of bounds %d",model); |
1794 | if (le16_to_cpu(dev->descriptor.idVendor) != usbvision_device_data[model].idVendor) { | 1793 | return -ENODEV; |
1795 | continue; | ||
1796 | } | ||
1797 | if (le16_to_cpu(dev->descriptor.idProduct) != usbvision_device_data[model].idProduct) { | ||
1798 | continue; | ||
1799 | } | ||
1800 | |||
1801 | printk(KERN_INFO "%s: %s found\n", __FUNCTION__, usbvision_device_data[model].ModelString); | ||
1802 | break; | ||
1803 | } | 1794 | } |
1795 | printk(KERN_INFO "%s: %s found\n", __FUNCTION__, | ||
1796 | usbvision_device_data[model].ModelString); | ||
1804 | 1797 | ||
1805 | if (usbvision_device_data[model].idVendor == 0) { | ||
1806 | return -ENODEV; //no matching device | ||
1807 | } | ||
1808 | if (usbvision_device_data[model].Interface >= 0) { | 1798 | if (usbvision_device_data[model].Interface >= 0) { |
1809 | interface = &dev->actconfig->interface[usbvision_device_data[model].Interface]->altsetting[0]; | 1799 | interface = &dev->actconfig->interface[usbvision_device_data[model].Interface]->altsetting[0]; |
1810 | } | 1800 | } |
@@ -1822,16 +1812,15 @@ static int __devinit usbvision_probe(struct usb_interface *intf, const struct us | |||
1822 | return -ENODEV; | 1812 | return -ENODEV; |
1823 | } | 1813 | } |
1824 | 1814 | ||
1825 | usb_get_dev(dev); | ||
1826 | |||
1827 | if ((usbvision = usbvision_alloc(dev)) == NULL) { | 1815 | if ((usbvision = usbvision_alloc(dev)) == NULL) { |
1828 | err("%s: couldn't allocate USBVision struct", __FUNCTION__); | 1816 | err("%s: couldn't allocate USBVision struct", __FUNCTION__); |
1829 | return -ENOMEM; | 1817 | return -ENOMEM; |
1830 | } | 1818 | } |
1819 | |||
1831 | if (dev->descriptor.bNumConfigurations > 1) { | 1820 | if (dev->descriptor.bNumConfigurations > 1) { |
1832 | usbvision->bridgeType = BRIDGE_NT1004; | 1821 | usbvision->bridgeType = BRIDGE_NT1004; |
1833 | } | 1822 | } |
1834 | else if (usbvision_device_data[model].ModelString == "Dazzle Fusion Model DVC-90 Rev 1 (SECAM)") { | 1823 | else if (model == DAZZLE_DVC_90_REV_1_SECAM) { |
1835 | usbvision->bridgeType = BRIDGE_NT1005; | 1824 | usbvision->bridgeType = BRIDGE_NT1005; |
1836 | } | 1825 | } |
1837 | else { | 1826 | else { |
@@ -1920,7 +1909,7 @@ static void __devexit usbvision_disconnect(struct usb_interface *intf) | |||
1920 | usbvision_stop_isoc(usbvision); | 1909 | usbvision_stop_isoc(usbvision); |
1921 | 1910 | ||
1922 | if (usbvision->power) { | 1911 | if (usbvision->power) { |
1923 | usbvision_i2c_usb_del_bus(&usbvision->i2c_adap); | 1912 | usbvision_i2c_unregister(usbvision); |
1924 | usbvision_power_off(usbvision); | 1913 | usbvision_power_off(usbvision); |
1925 | } | 1914 | } |
1926 | usbvision->remove_pending = 1; // Now all ISO data will be ignored | 1915 | usbvision->remove_pending = 1; // Now all ISO data will be ignored |
@@ -1951,124 +1940,6 @@ static struct usb_driver usbvision_driver = { | |||
1951 | }; | 1940 | }; |
1952 | 1941 | ||
1953 | /* | 1942 | /* |
1954 | * customdevice_process() | ||
1955 | * | ||
1956 | * This procedure preprocesses CustomDevice parameter if any | ||
1957 | * | ||
1958 | */ | ||
1959 | static void customdevice_process(void) | ||
1960 | { | ||
1961 | usbvision_device_data[0]=usbvision_device_data[1]; | ||
1962 | usbvision_table[0]=usbvision_table[1]; | ||
1963 | |||
1964 | if(CustomDevice) | ||
1965 | { | ||
1966 | char *parse=CustomDevice; | ||
1967 | |||
1968 | PDEBUG(DBG_PROBE, "CustomDevide=%s", CustomDevice); | ||
1969 | |||
1970 | /*format is CustomDevice="0x0573 0x4D31 0 7113 3 PAL 1 1 1 5 -1 -1 -1 -1 -1" | ||
1971 | usbvision_device_data[0].idVendor; | ||
1972 | usbvision_device_data[0].idProduct; | ||
1973 | usbvision_device_data[0].Interface; | ||
1974 | usbvision_device_data[0].Codec; | ||
1975 | usbvision_device_data[0].VideoChannels; | ||
1976 | usbvision_device_data[0].VideoNorm; | ||
1977 | usbvision_device_data[0].AudioChannels; | ||
1978 | usbvision_device_data[0].Radio; | ||
1979 | usbvision_device_data[0].Tuner; | ||
1980 | usbvision_device_data[0].TunerType; | ||
1981 | usbvision_device_data[0].Vin_Reg1; | ||
1982 | usbvision_device_data[0].Vin_Reg2; | ||
1983 | usbvision_device_data[0].X_Offset; | ||
1984 | usbvision_device_data[0].Y_Offset; | ||
1985 | usbvision_device_data[0].Dvi_yuv; | ||
1986 | usbvision_device_data[0].ModelString; | ||
1987 | */ | ||
1988 | |||
1989 | rmspace(parse); | ||
1990 | usbvision_device_data[0].ModelString="USBVISION Custom Device"; | ||
1991 | |||
1992 | parse+=2; | ||
1993 | sscanf(parse,"%x",&usbvision_device_data[0].idVendor); | ||
1994 | goto2next(parse); | ||
1995 | PDEBUG(DBG_PROBE, "idVendor=0x%.4X", usbvision_device_data[0].idVendor); | ||
1996 | parse+=2; | ||
1997 | sscanf(parse,"%x",&usbvision_device_data[0].idProduct); | ||
1998 | goto2next(parse); | ||
1999 | PDEBUG(DBG_PROBE, "idProduct=0x%.4X", usbvision_device_data[0].idProduct); | ||
2000 | sscanf(parse,"%d",&usbvision_device_data[0].Interface); | ||
2001 | goto2next(parse); | ||
2002 | PDEBUG(DBG_PROBE, "Interface=%d", usbvision_device_data[0].Interface); | ||
2003 | sscanf(parse,"%d",&usbvision_device_data[0].Codec); | ||
2004 | goto2next(parse); | ||
2005 | PDEBUG(DBG_PROBE, "Codec=%d", usbvision_device_data[0].Codec); | ||
2006 | sscanf(parse,"%d",&usbvision_device_data[0].VideoChannels); | ||
2007 | goto2next(parse); | ||
2008 | PDEBUG(DBG_PROBE, "VideoChannels=%d", usbvision_device_data[0].VideoChannels); | ||
2009 | |||
2010 | switch(*parse) | ||
2011 | { | ||
2012 | case 'P': | ||
2013 | PDEBUG(DBG_PROBE, "VideoNorm=PAL"); | ||
2014 | usbvision_device_data[0].VideoNorm=V4L2_STD_PAL; | ||
2015 | break; | ||
2016 | |||
2017 | case 'S': | ||
2018 | PDEBUG(DBG_PROBE, "VideoNorm=SECAM"); | ||
2019 | usbvision_device_data[0].VideoNorm=V4L2_STD_SECAM; | ||
2020 | break; | ||
2021 | |||
2022 | case 'N': | ||
2023 | PDEBUG(DBG_PROBE, "VideoNorm=NTSC"); | ||
2024 | usbvision_device_data[0].VideoNorm=V4L2_STD_NTSC; | ||
2025 | break; | ||
2026 | |||
2027 | default: | ||
2028 | PDEBUG(DBG_PROBE, "VideoNorm=PAL (by default)"); | ||
2029 | usbvision_device_data[0].VideoNorm=V4L2_STD_PAL; | ||
2030 | break; | ||
2031 | } | ||
2032 | goto2next(parse); | ||
2033 | |||
2034 | sscanf(parse,"%d",&usbvision_device_data[0].AudioChannels); | ||
2035 | goto2next(parse); | ||
2036 | PDEBUG(DBG_PROBE, "AudioChannels=%d", usbvision_device_data[0].AudioChannels); | ||
2037 | sscanf(parse,"%d",&usbvision_device_data[0].Radio); | ||
2038 | goto2next(parse); | ||
2039 | PDEBUG(DBG_PROBE, "Radio=%d", usbvision_device_data[0].Radio); | ||
2040 | sscanf(parse,"%d",&usbvision_device_data[0].Tuner); | ||
2041 | goto2next(parse); | ||
2042 | PDEBUG(DBG_PROBE, "Tuner=%d", usbvision_device_data[0].Tuner); | ||
2043 | sscanf(parse,"%d",&usbvision_device_data[0].TunerType); | ||
2044 | goto2next(parse); | ||
2045 | PDEBUG(DBG_PROBE, "TunerType=%d", usbvision_device_data[0].TunerType); | ||
2046 | sscanf(parse,"%d",&usbvision_device_data[0].Vin_Reg1); | ||
2047 | goto2next(parse); | ||
2048 | PDEBUG(DBG_PROBE, "Vin_Reg1=%d", usbvision_device_data[0].Vin_Reg1); | ||
2049 | sscanf(parse,"%d",&usbvision_device_data[0].Vin_Reg2); | ||
2050 | goto2next(parse); | ||
2051 | PDEBUG(DBG_PROBE, "Vin_Reg2=%d", usbvision_device_data[0].Vin_Reg2); | ||
2052 | sscanf(parse,"%d",&usbvision_device_data[0].X_Offset); | ||
2053 | goto2next(parse); | ||
2054 | PDEBUG(DBG_PROBE, "X_Offset=%d", usbvision_device_data[0].X_Offset); | ||
2055 | sscanf(parse,"%d",&usbvision_device_data[0].Y_Offset); | ||
2056 | goto2next(parse); | ||
2057 | PDEBUG(DBG_PROBE, "Y_Offset=%d", usbvision_device_data[0].Y_Offset); | ||
2058 | sscanf(parse,"%d",&usbvision_device_data[0].Dvi_yuv); | ||
2059 | PDEBUG(DBG_PROBE, "Dvi_yuv=%d", usbvision_device_data[0].Dvi_yuv); | ||
2060 | |||
2061 | //add to usbvision_table also | ||
2062 | usbvision_table[0].match_flags=USB_DEVICE_ID_MATCH_DEVICE; | ||
2063 | usbvision_table[0].idVendor=usbvision_device_data[0].idVendor; | ||
2064 | usbvision_table[0].idProduct=usbvision_device_data[0].idProduct; | ||
2065 | |||
2066 | } | ||
2067 | } | ||
2068 | |||
2069 | |||
2070 | |||
2071 | /* | ||
2072 | * usbvision_init() | 1943 | * usbvision_init() |
2073 | * | 1944 | * |
2074 | * This code is run to initialize the driver. | 1945 | * This code is run to initialize the driver. |
@@ -2092,8 +1963,6 @@ static int __init usbvision_init(void) | |||
2092 | usbvision_v4l2_format[7].supported = 0; // V4L2_PIX_FMT_YUV422P | 1963 | usbvision_v4l2_format[7].supported = 0; // V4L2_PIX_FMT_YUV422P |
2093 | } | 1964 | } |
2094 | 1965 | ||
2095 | customdevice_process(); | ||
2096 | |||
2097 | errCode = usb_register(&usbvision_driver); | 1966 | errCode = usb_register(&usbvision_driver); |
2098 | 1967 | ||
2099 | if (errCode == 0) { | 1968 | if (errCode == 0) { |
diff --git a/drivers/media/video/usbvision/usbvision.h b/drivers/media/video/usbvision/usbvision.h index ad6afd3e42a4..bd6f6422ed54 100644 --- a/drivers/media/video/usbvision/usbvision.h +++ b/drivers/media/video/usbvision/usbvision.h | |||
@@ -342,23 +342,24 @@ struct usbvision_frame { | |||
342 | #define BRIDGE_NT1005 1005 | 342 | #define BRIDGE_NT1005 1005 |
343 | 343 | ||
344 | struct usbvision_device_data_st { | 344 | struct usbvision_device_data_st { |
345 | int idVendor; | ||
346 | int idProduct; | ||
347 | int Interface; /* to handle special interface number like BELKIN and Hauppauge WinTV-USB II */ | ||
348 | int Codec; | ||
349 | int VideoChannels; | ||
350 | __u64 VideoNorm; | 345 | __u64 VideoNorm; |
351 | int AudioChannels; | 346 | const char *ModelString; |
352 | int Radio; | 347 | int Interface; /* to handle special interface number like BELKIN and Hauppauge WinTV-USB II */ |
353 | int vbi; | 348 | __u16 Codec; |
354 | int Tuner; | 349 | unsigned VideoChannels:3; |
355 | int TunerType; | 350 | unsigned AudioChannels:2; |
356 | int Vin_Reg1; | 351 | unsigned Radio:1; |
357 | int Vin_Reg2; | 352 | unsigned vbi:1; |
358 | int X_Offset; | 353 | unsigned Tuner:1; |
359 | int Y_Offset; | 354 | unsigned Vin_Reg1_override:1; /* Override default value with */ |
360 | int Dvi_yuv; | 355 | unsigned Vin_Reg2_override:1; /* Vin_Reg1, Vin_Reg2, etc. */ |
361 | char *ModelString; | 356 | unsigned Dvi_yuv_override:1; |
357 | __u8 Vin_Reg1; | ||
358 | __u8 Vin_Reg2; | ||
359 | __u8 Dvi_yuv; | ||
360 | __u8 TunerType; | ||
361 | __s16 X_Offset; | ||
362 | __s16 Y_Offset; | ||
362 | }; | 363 | }; |
363 | 364 | ||
364 | /* Declared on usbvision-cards.c */ | 365 | /* Declared on usbvision-cards.c */ |
@@ -481,13 +482,11 @@ struct usb_usbvision { | |||
481 | /* i2c-algo-usb declaration */ | 482 | /* i2c-algo-usb declaration */ |
482 | /* --------------------------------------------------------------- */ | 483 | /* --------------------------------------------------------------- */ |
483 | 484 | ||
484 | int usbvision_i2c_usb_del_bus(struct i2c_adapter *); | ||
485 | |||
486 | |||
487 | /* ----------------------------------------------------------------------- */ | 485 | /* ----------------------------------------------------------------------- */ |
488 | /* usbvision specific I2C functions */ | 486 | /* usbvision specific I2C functions */ |
489 | /* ----------------------------------------------------------------------- */ | 487 | /* ----------------------------------------------------------------------- */ |
490 | int usbvision_init_i2c(struct usb_usbvision *usbvision); | 488 | int usbvision_i2c_register(struct usb_usbvision *usbvision); |
489 | int usbvision_i2c_unregister(struct usb_usbvision *usbvision); | ||
491 | void call_i2c_clients(struct usb_usbvision *usbvision, unsigned int cmd,void *arg); | 490 | void call_i2c_clients(struct usb_usbvision *usbvision, unsigned int cmd,void *arg); |
492 | 491 | ||
493 | /* defined in usbvision-core.c */ | 492 | /* defined in usbvision-core.c */ |
diff --git a/drivers/media/video/v4l2-common.c b/drivers/media/video/v4l2-common.c index 54747606eae1..49f1df74aa21 100644 --- a/drivers/media/video/v4l2-common.c +++ b/drivers/media/video/v4l2-common.c | |||
@@ -60,6 +60,7 @@ | |||
60 | #include <linux/video_decoder.h> | 60 | #include <linux/video_decoder.h> |
61 | #define __OLD_VIDIOC_ /* To allow fixing old calls*/ | 61 | #define __OLD_VIDIOC_ /* To allow fixing old calls*/ |
62 | #include <media/v4l2-common.h> | 62 | #include <media/v4l2-common.h> |
63 | #include <media/v4l2-chip-ident.h> | ||
63 | 64 | ||
64 | #ifdef CONFIG_KMOD | 65 | #ifdef CONFIG_KMOD |
65 | #include <linux/kmod.h> | 66 | #include <linux/kmod.h> |
@@ -260,6 +261,8 @@ char *v4l2_field_names[] = { | |||
260 | [V4L2_FIELD_SEQ_TB] = "seq-tb", | 261 | [V4L2_FIELD_SEQ_TB] = "seq-tb", |
261 | [V4L2_FIELD_SEQ_BT] = "seq-bt", | 262 | [V4L2_FIELD_SEQ_BT] = "seq-bt", |
262 | [V4L2_FIELD_ALTERNATE] = "alternate", | 263 | [V4L2_FIELD_ALTERNATE] = "alternate", |
264 | [V4L2_FIELD_INTERLACED_TB] = "interlaced-tb", | ||
265 | [V4L2_FIELD_INTERLACED_BT] = "interlaced-bt", | ||
263 | }; | 266 | }; |
264 | 267 | ||
265 | char *v4l2_type_names[] = { | 268 | char *v4l2_type_names[] = { |
@@ -269,7 +272,8 @@ char *v4l2_type_names[] = { | |||
269 | [V4L2_BUF_TYPE_VBI_CAPTURE] = "vbi-cap", | 272 | [V4L2_BUF_TYPE_VBI_CAPTURE] = "vbi-cap", |
270 | [V4L2_BUF_TYPE_VBI_OUTPUT] = "vbi-out", | 273 | [V4L2_BUF_TYPE_VBI_OUTPUT] = "vbi-out", |
271 | [V4L2_BUF_TYPE_SLICED_VBI_CAPTURE] = "sliced-vbi-cap", | 274 | [V4L2_BUF_TYPE_SLICED_VBI_CAPTURE] = "sliced-vbi-cap", |
272 | [V4L2_BUF_TYPE_SLICED_VBI_OUTPUT] = "slicec-vbi-out", | 275 | [V4L2_BUF_TYPE_SLICED_VBI_OUTPUT] = "sliced-vbi-out", |
276 | [V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY] = "video-out-over", | ||
273 | }; | 277 | }; |
274 | 278 | ||
275 | 279 | ||
@@ -380,6 +384,8 @@ static const char *v4l2_ioctls[] = { | |||
380 | 384 | ||
381 | [_IOC_NR(VIDIOC_DBG_S_REGISTER)] = "VIDIOC_DBG_S_REGISTER", | 385 | [_IOC_NR(VIDIOC_DBG_S_REGISTER)] = "VIDIOC_DBG_S_REGISTER", |
382 | [_IOC_NR(VIDIOC_DBG_G_REGISTER)] = "VIDIOC_DBG_G_REGISTER", | 386 | [_IOC_NR(VIDIOC_DBG_G_REGISTER)] = "VIDIOC_DBG_G_REGISTER", |
387 | |||
388 | [_IOC_NR(VIDIOC_G_CHIP_IDENT)] = "VIDIOC_G_CHIP_IDENT", | ||
383 | #endif | 389 | #endif |
384 | }; | 390 | }; |
385 | #define V4L2_IOCTLS ARRAY_SIZE(v4l2_ioctls) | 391 | #define V4L2_IOCTLS ARRAY_SIZE(v4l2_ioctls) |
@@ -410,14 +416,16 @@ static const char *v4l2_int_ioctls[] = { | |||
410 | [_IOC_NR(VIDIOC_INT_DECODE_VBI_LINE)] = "VIDIOC_INT_DECODE_VBI_LINE", | 416 | [_IOC_NR(VIDIOC_INT_DECODE_VBI_LINE)] = "VIDIOC_INT_DECODE_VBI_LINE", |
411 | [_IOC_NR(VIDIOC_INT_S_VBI_DATA)] = "VIDIOC_INT_S_VBI_DATA", | 417 | [_IOC_NR(VIDIOC_INT_S_VBI_DATA)] = "VIDIOC_INT_S_VBI_DATA", |
412 | [_IOC_NR(VIDIOC_INT_G_VBI_DATA)] = "VIDIOC_INT_G_VBI_DATA", | 418 | [_IOC_NR(VIDIOC_INT_G_VBI_DATA)] = "VIDIOC_INT_G_VBI_DATA", |
413 | [_IOC_NR(VIDIOC_INT_G_CHIP_IDENT)] = "VIDIOC_INT_G_CHIP_IDENT", | ||
414 | [_IOC_NR(VIDIOC_INT_I2S_CLOCK_FREQ)] = "VIDIOC_INT_I2S_CLOCK_FREQ", | 419 | [_IOC_NR(VIDIOC_INT_I2S_CLOCK_FREQ)] = "VIDIOC_INT_I2S_CLOCK_FREQ", |
415 | [_IOC_NR(VIDIOC_INT_S_STANDBY)] = "VIDIOC_INT_S_STANDBY", | 420 | [_IOC_NR(VIDIOC_INT_S_STANDBY)] = "VIDIOC_INT_S_STANDBY", |
416 | [_IOC_NR(VIDIOC_INT_S_AUDIO_ROUTING)] = "VIDIOC_INT_S_AUDIO_ROUTING", | 421 | [_IOC_NR(VIDIOC_INT_S_AUDIO_ROUTING)] = "VIDIOC_INT_S_AUDIO_ROUTING", |
417 | [_IOC_NR(VIDIOC_INT_G_AUDIO_ROUTING)] = "VIDIOC_INT_G_AUDIO_ROUTING", | 422 | [_IOC_NR(VIDIOC_INT_G_AUDIO_ROUTING)] = "VIDIOC_INT_G_AUDIO_ROUTING", |
418 | [_IOC_NR(VIDIOC_INT_S_VIDEO_ROUTING)] = "VIDIOC_INT_S_VIDEO_ROUTING", | 423 | [_IOC_NR(VIDIOC_INT_S_VIDEO_ROUTING)] = "VIDIOC_INT_S_VIDEO_ROUTING", |
419 | [_IOC_NR(VIDIOC_INT_G_VIDEO_ROUTING)] = "VIDIOC_INT_G_VIDEO_ROUTING", | 424 | [_IOC_NR(VIDIOC_INT_G_VIDEO_ROUTING)] = "VIDIOC_INT_G_VIDEO_ROUTING", |
420 | [_IOC_NR(VIDIOC_INT_S_CRYSTAL_FREQ)] = "VIDIOC_INT_S_CRYSTAL_FREQ" | 425 | [_IOC_NR(VIDIOC_INT_S_CRYSTAL_FREQ)] = "VIDIOC_INT_S_CRYSTAL_FREQ", |
426 | [_IOC_NR(VIDIOC_INT_INIT)] = "VIDIOC_INT_INIT", | ||
427 | [_IOC_NR(VIDIOC_INT_G_STD_OUTPUT)] = "VIDIOC_INT_G_STD_OUTPUT", | ||
428 | [_IOC_NR(VIDIOC_INT_S_STD_OUTPUT)] = "VIDIOC_INT_S_STD_OUTPUT", | ||
421 | }; | 429 | }; |
422 | #define V4L2_INT_IOCTLS ARRAY_SIZE(v4l2_int_ioctls) | 430 | #define V4L2_INT_IOCTLS ARRAY_SIZE(v4l2_int_ioctls) |
423 | 431 | ||
@@ -680,6 +688,7 @@ int v4l2_ctrl_query_fill(struct v4l2_queryctrl *qctrl, s32 min, s32 max, s32 ste | |||
680 | case V4L2_CID_MPEG_AUDIO_MODE_EXTENSION: name = "Audio Stereo Mode Extension"; break; | 688 | case V4L2_CID_MPEG_AUDIO_MODE_EXTENSION: name = "Audio Stereo Mode Extension"; break; |
681 | case V4L2_CID_MPEG_AUDIO_EMPHASIS: name = "Audio Emphasis"; break; | 689 | case V4L2_CID_MPEG_AUDIO_EMPHASIS: name = "Audio Emphasis"; break; |
682 | case V4L2_CID_MPEG_AUDIO_CRC: name = "Audio CRC"; break; | 690 | case V4L2_CID_MPEG_AUDIO_CRC: name = "Audio CRC"; break; |
691 | case V4L2_CID_MPEG_AUDIO_MUTE: name = "Audio Mute"; break; | ||
683 | case V4L2_CID_MPEG_VIDEO_ENCODING: name = "Video Encoding"; break; | 692 | case V4L2_CID_MPEG_VIDEO_ENCODING: name = "Video Encoding"; break; |
684 | case V4L2_CID_MPEG_VIDEO_ASPECT: name = "Video Aspect"; break; | 693 | case V4L2_CID_MPEG_VIDEO_ASPECT: name = "Video Aspect"; break; |
685 | case V4L2_CID_MPEG_VIDEO_B_FRAMES: name = "Video B Frames"; break; | 694 | case V4L2_CID_MPEG_VIDEO_B_FRAMES: name = "Video B Frames"; break; |
@@ -690,6 +699,8 @@ int v4l2_ctrl_query_fill(struct v4l2_queryctrl *qctrl, s32 min, s32 max, s32 ste | |||
690 | case V4L2_CID_MPEG_VIDEO_BITRATE: name = "Video Bitrate"; break; | 699 | case V4L2_CID_MPEG_VIDEO_BITRATE: name = "Video Bitrate"; break; |
691 | case V4L2_CID_MPEG_VIDEO_BITRATE_PEAK: name = "Video Peak Bitrate"; break; | 700 | case V4L2_CID_MPEG_VIDEO_BITRATE_PEAK: name = "Video Peak Bitrate"; break; |
692 | case V4L2_CID_MPEG_VIDEO_TEMPORAL_DECIMATION: name = "Video Temporal Decimation"; break; | 701 | case V4L2_CID_MPEG_VIDEO_TEMPORAL_DECIMATION: name = "Video Temporal Decimation"; break; |
702 | case V4L2_CID_MPEG_VIDEO_MUTE: name = "Video Mute"; break; | ||
703 | case V4L2_CID_MPEG_VIDEO_MUTE_YUV: name = "Video Mute YUV"; break; | ||
693 | case V4L2_CID_MPEG_STREAM_TYPE: name = "Stream Type"; break; | 704 | case V4L2_CID_MPEG_STREAM_TYPE: name = "Stream Type"; break; |
694 | case V4L2_CID_MPEG_STREAM_PID_PMT: name = "Stream PMT Program ID"; break; | 705 | case V4L2_CID_MPEG_STREAM_PID_PMT: name = "Stream PMT Program ID"; break; |
695 | case V4L2_CID_MPEG_STREAM_PID_AUDIO: name = "Stream Audio Program ID"; break; | 706 | case V4L2_CID_MPEG_STREAM_PID_AUDIO: name = "Stream Audio Program ID"; break; |
@@ -705,6 +716,7 @@ int v4l2_ctrl_query_fill(struct v4l2_queryctrl *qctrl, s32 min, s32 max, s32 ste | |||
705 | switch (qctrl->id) { | 716 | switch (qctrl->id) { |
706 | case V4L2_CID_AUDIO_MUTE: | 717 | case V4L2_CID_AUDIO_MUTE: |
707 | case V4L2_CID_AUDIO_LOUDNESS: | 718 | case V4L2_CID_AUDIO_LOUDNESS: |
719 | case V4L2_CID_MPEG_AUDIO_MUTE: | ||
708 | case V4L2_CID_MPEG_VIDEO_GOP_CLOSURE: | 720 | case V4L2_CID_MPEG_VIDEO_GOP_CLOSURE: |
709 | case V4L2_CID_MPEG_VIDEO_PULLDOWN: | 721 | case V4L2_CID_MPEG_VIDEO_PULLDOWN: |
710 | qctrl->type = V4L2_CTRL_TYPE_BOOLEAN; | 722 | qctrl->type = V4L2_CTRL_TYPE_BOOLEAN; |
@@ -838,6 +850,8 @@ int v4l2_ctrl_query_fill_std(struct v4l2_queryctrl *qctrl) | |||
838 | V4L2_MPEG_AUDIO_CRC_NONE, | 850 | V4L2_MPEG_AUDIO_CRC_NONE, |
839 | V4L2_MPEG_AUDIO_CRC_CRC16, 1, | 851 | V4L2_MPEG_AUDIO_CRC_CRC16, 1, |
840 | V4L2_MPEG_AUDIO_CRC_NONE); | 852 | V4L2_MPEG_AUDIO_CRC_NONE); |
853 | case V4L2_CID_MPEG_AUDIO_MUTE: | ||
854 | return v4l2_ctrl_query_fill(qctrl, 0, 1, 1, 0); | ||
841 | case V4L2_CID_MPEG_VIDEO_ENCODING: | 855 | case V4L2_CID_MPEG_VIDEO_ENCODING: |
842 | return v4l2_ctrl_query_fill(qctrl, | 856 | return v4l2_ctrl_query_fill(qctrl, |
843 | V4L2_MPEG_VIDEO_ENCODING_MPEG_1, | 857 | V4L2_MPEG_VIDEO_ENCODING_MPEG_1, |
@@ -867,6 +881,10 @@ int v4l2_ctrl_query_fill_std(struct v4l2_queryctrl *qctrl) | |||
867 | return v4l2_ctrl_query_fill(qctrl, 0, 27000000, 1, 8000000); | 881 | return v4l2_ctrl_query_fill(qctrl, 0, 27000000, 1, 8000000); |
868 | case V4L2_CID_MPEG_VIDEO_TEMPORAL_DECIMATION: | 882 | case V4L2_CID_MPEG_VIDEO_TEMPORAL_DECIMATION: |
869 | return v4l2_ctrl_query_fill(qctrl, 0, 255, 1, 0); | 883 | return v4l2_ctrl_query_fill(qctrl, 0, 255, 1, 0); |
884 | case V4L2_CID_MPEG_VIDEO_MUTE: | ||
885 | return v4l2_ctrl_query_fill(qctrl, 0, 1, 1, 0); | ||
886 | case V4L2_CID_MPEG_VIDEO_MUTE_YUV: /* Init YUV (really YCbCr) to black */ | ||
887 | return v4l2_ctrl_query_fill(qctrl, 0, 0xffffff, 1, 0x008080); | ||
870 | case V4L2_CID_MPEG_STREAM_TYPE: | 888 | case V4L2_CID_MPEG_STREAM_TYPE: |
871 | return v4l2_ctrl_query_fill(qctrl, | 889 | return v4l2_ctrl_query_fill(qctrl, |
872 | V4L2_MPEG_STREAM_TYPE_MPEG2_PS, | 890 | V4L2_MPEG_STREAM_TYPE_MPEG2_PS, |
@@ -965,6 +983,22 @@ int v4l2_chip_match_i2c_client(struct i2c_client *c, u32 match_type, u32 match_c | |||
965 | } | 983 | } |
966 | } | 984 | } |
967 | 985 | ||
986 | int v4l2_chip_ident_i2c_client(struct i2c_client *c, struct v4l2_chip_ident *chip, | ||
987 | u32 ident, u32 revision) | ||
988 | { | ||
989 | if (!v4l2_chip_match_i2c_client(c, chip->match_type, chip->match_chip)) | ||
990 | return 0; | ||
991 | if (chip->ident == V4L2_IDENT_NONE) { | ||
992 | chip->ident = ident; | ||
993 | chip->revision = revision; | ||
994 | } | ||
995 | else { | ||
996 | chip->ident = V4L2_IDENT_AMBIGUOUS; | ||
997 | chip->revision = 0; | ||
998 | } | ||
999 | return 0; | ||
1000 | } | ||
1001 | |||
968 | int v4l2_chip_match_host(u32 match_type, u32 match_chip) | 1002 | int v4l2_chip_match_host(u32 match_type, u32 match_chip) |
969 | { | 1003 | { |
970 | switch (match_type) { | 1004 | switch (match_type) { |
@@ -999,6 +1033,7 @@ EXPORT_SYMBOL(v4l2_ctrl_query_fill); | |||
999 | EXPORT_SYMBOL(v4l2_ctrl_query_fill_std); | 1033 | EXPORT_SYMBOL(v4l2_ctrl_query_fill_std); |
1000 | 1034 | ||
1001 | EXPORT_SYMBOL(v4l2_chip_match_i2c_client); | 1035 | EXPORT_SYMBOL(v4l2_chip_match_i2c_client); |
1036 | EXPORT_SYMBOL(v4l2_chip_ident_i2c_client); | ||
1002 | EXPORT_SYMBOL(v4l2_chip_match_host); | 1037 | EXPORT_SYMBOL(v4l2_chip_match_host); |
1003 | 1038 | ||
1004 | /* | 1039 | /* |
diff --git a/drivers/media/video/videocodec.c b/drivers/media/video/videocodec.c index 290e64135650..f2bbd7a4d562 100644 --- a/drivers/media/video/videocodec.c +++ b/drivers/media/video/videocodec.c | |||
@@ -348,6 +348,9 @@ videocodec_build_table (void) | |||
348 | kfree(videocodec_buf); | 348 | kfree(videocodec_buf); |
349 | videocodec_buf = kmalloc(size, GFP_KERNEL); | 349 | videocodec_buf = kmalloc(size, GFP_KERNEL); |
350 | 350 | ||
351 | if (!videocodec_buf) | ||
352 | return 0; | ||
353 | |||
351 | i = 0; | 354 | i = 0; |
352 | i += scnprintf(videocodec_buf + i, size - 1, | 355 | i += scnprintf(videocodec_buf + i, size - 1, |
353 | "<S>lave or attached <M>aster name type flags magic "); | 356 | "<S>lave or attached <M>aster name type flags magic "); |
diff --git a/drivers/media/video/videodev.c b/drivers/media/video/videodev.c index 011938fb7e0e..80ac5f86d9e5 100644 --- a/drivers/media/video/videodev.c +++ b/drivers/media/video/videodev.c | |||
@@ -318,6 +318,7 @@ static char *v4l2_type_names_FIXME[] = { | |||
318 | [V4L2_BUF_TYPE_VBI_OUTPUT] = "vbi-out", | 318 | [V4L2_BUF_TYPE_VBI_OUTPUT] = "vbi-out", |
319 | [V4L2_BUF_TYPE_SLICED_VBI_OUTPUT] = "sliced-vbi-out", | 319 | [V4L2_BUF_TYPE_SLICED_VBI_OUTPUT] = "sliced-vbi-out", |
320 | [V4L2_BUF_TYPE_SLICED_VBI_CAPTURE] = "sliced-vbi-capture", | 320 | [V4L2_BUF_TYPE_SLICED_VBI_CAPTURE] = "sliced-vbi-capture", |
321 | [V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY] = "video-out-over", | ||
321 | [V4L2_BUF_TYPE_PRIVATE] = "private", | 322 | [V4L2_BUF_TYPE_PRIVATE] = "private", |
322 | }; | 323 | }; |
323 | 324 | ||
@@ -330,6 +331,8 @@ static char *v4l2_field_names_FIXME[] = { | |||
330 | [V4L2_FIELD_SEQ_TB] = "seq-tb", | 331 | [V4L2_FIELD_SEQ_TB] = "seq-tb", |
331 | [V4L2_FIELD_SEQ_BT] = "seq-bt", | 332 | [V4L2_FIELD_SEQ_BT] = "seq-bt", |
332 | [V4L2_FIELD_ALTERNATE] = "alternate", | 333 | [V4L2_FIELD_ALTERNATE] = "alternate", |
334 | [V4L2_FIELD_INTERLACED_TB] = "interlaced-tb", | ||
335 | [V4L2_FIELD_INTERLACED_BT] = "interlaced-bt", | ||
333 | }; | 336 | }; |
334 | 337 | ||
335 | #define prt_names(a,arr) (((a)>=0)&&((a)<ARRAY_SIZE(arr)))?arr[a]:"unknown" | 338 | #define prt_names(a,arr) (((a)>=0)&&((a)<ARRAY_SIZE(arr)))?arr[a]:"unknown" |
@@ -411,6 +414,10 @@ static int check_fmt (struct video_device *vfd, enum v4l2_buf_type type) | |||
411 | if (vfd->vidioc_try_fmt_vbi_output) | 414 | if (vfd->vidioc_try_fmt_vbi_output) |
412 | return (0); | 415 | return (0); |
413 | break; | 416 | break; |
417 | case V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY: | ||
418 | if (vfd->vidioc_try_fmt_output_overlay) | ||
419 | return (0); | ||
420 | break; | ||
414 | case V4L2_BUF_TYPE_PRIVATE: | 421 | case V4L2_BUF_TYPE_PRIVATE: |
415 | if (vfd->vidioc_try_fmt_type_private) | 422 | if (vfd->vidioc_try_fmt_type_private) |
416 | return (0); | 423 | return (0); |
@@ -525,6 +532,10 @@ static int __video_do_ioctl(struct inode *inode, struct file *file, | |||
525 | ret=vfd->vidioc_enum_fmt_vbi_output(file, | 532 | ret=vfd->vidioc_enum_fmt_vbi_output(file, |
526 | fh, f); | 533 | fh, f); |
527 | break; | 534 | break; |
535 | case V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY: | ||
536 | if (vfd->vidioc_enum_fmt_output_overlay) | ||
537 | ret=vfd->vidioc_enum_fmt_output_overlay(file, fh, f); | ||
538 | break; | ||
528 | case V4L2_BUF_TYPE_PRIVATE: | 539 | case V4L2_BUF_TYPE_PRIVATE: |
529 | if (vfd->vidioc_enum_fmt_type_private) | 540 | if (vfd->vidioc_enum_fmt_type_private) |
530 | ret=vfd->vidioc_enum_fmt_type_private(file, | 541 | ret=vfd->vidioc_enum_fmt_type_private(file, |
@@ -582,6 +593,10 @@ static int __video_do_ioctl(struct inode *inode, struct file *file, | |||
582 | ret=vfd->vidioc_g_fmt_video_output(file, | 593 | ret=vfd->vidioc_g_fmt_video_output(file, |
583 | fh, f); | 594 | fh, f); |
584 | break; | 595 | break; |
596 | case V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY: | ||
597 | if (vfd->vidioc_g_fmt_output_overlay) | ||
598 | ret=vfd->vidioc_g_fmt_output_overlay(file, fh, f); | ||
599 | break; | ||
585 | case V4L2_BUF_TYPE_VBI_OUTPUT: | 600 | case V4L2_BUF_TYPE_VBI_OUTPUT: |
586 | if (vfd->vidioc_g_fmt_vbi_output) | 601 | if (vfd->vidioc_g_fmt_vbi_output) |
587 | ret=vfd->vidioc_g_fmt_vbi_output(file, fh, f); | 602 | ret=vfd->vidioc_g_fmt_vbi_output(file, fh, f); |
@@ -630,6 +645,10 @@ static int __video_do_ioctl(struct inode *inode, struct file *file, | |||
630 | ret=vfd->vidioc_s_fmt_video_output(file, | 645 | ret=vfd->vidioc_s_fmt_video_output(file, |
631 | fh, f); | 646 | fh, f); |
632 | break; | 647 | break; |
648 | case V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY: | ||
649 | if (vfd->vidioc_s_fmt_output_overlay) | ||
650 | ret=vfd->vidioc_s_fmt_output_overlay(file, fh, f); | ||
651 | break; | ||
633 | case V4L2_BUF_TYPE_VBI_OUTPUT: | 652 | case V4L2_BUF_TYPE_VBI_OUTPUT: |
634 | if (vfd->vidioc_s_fmt_vbi_output) | 653 | if (vfd->vidioc_s_fmt_vbi_output) |
635 | ret=vfd->vidioc_s_fmt_vbi_output(file, | 654 | ret=vfd->vidioc_s_fmt_vbi_output(file, |
@@ -680,6 +699,10 @@ static int __video_do_ioctl(struct inode *inode, struct file *file, | |||
680 | ret=vfd->vidioc_try_fmt_video_output(file, | 699 | ret=vfd->vidioc_try_fmt_video_output(file, |
681 | fh, f); | 700 | fh, f); |
682 | break; | 701 | break; |
702 | case V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY: | ||
703 | if (vfd->vidioc_try_fmt_output_overlay) | ||
704 | ret=vfd->vidioc_try_fmt_output_overlay(file, fh, f); | ||
705 | break; | ||
683 | case V4L2_BUF_TYPE_VBI_OUTPUT: | 706 | case V4L2_BUF_TYPE_VBI_OUTPUT: |
684 | if (vfd->vidioc_try_fmt_vbi_output) | 707 | if (vfd->vidioc_try_fmt_vbi_output) |
685 | ret=vfd->vidioc_try_fmt_vbi_output(file, | 708 | ret=vfd->vidioc_try_fmt_vbi_output(file, |
@@ -1381,6 +1404,11 @@ static int __video_do_ioctl(struct inode *inode, struct file *file, | |||
1381 | case VIDIOC_G_PARM: | 1404 | case VIDIOC_G_PARM: |
1382 | { | 1405 | { |
1383 | struct v4l2_streamparm *p=arg; | 1406 | struct v4l2_streamparm *p=arg; |
1407 | __u32 type=p->type; | ||
1408 | |||
1409 | memset(p,0,sizeof(*p)); | ||
1410 | p->type=type; | ||
1411 | |||
1384 | if (vfd->vidioc_g_parm) { | 1412 | if (vfd->vidioc_g_parm) { |
1385 | ret=vfd->vidioc_g_parm(file, fh, p); | 1413 | ret=vfd->vidioc_g_parm(file, fh, p); |
1386 | } else { | 1414 | } else { |
@@ -1392,8 +1420,6 @@ static int __video_do_ioctl(struct inode *inode, struct file *file, | |||
1392 | v4l2_video_std_construct(&s, vfd->current_norm, | 1420 | v4l2_video_std_construct(&s, vfd->current_norm, |
1393 | v4l2_norm_to_name(vfd->current_norm)); | 1421 | v4l2_norm_to_name(vfd->current_norm)); |
1394 | 1422 | ||
1395 | memset(p,0,sizeof(*p)); | ||
1396 | |||
1397 | p->parm.capture.timeperframe = s.frameperiod; | 1423 | p->parm.capture.timeperframe = s.frameperiod; |
1398 | ret=0; | 1424 | ret=0; |
1399 | } | 1425 | } |
@@ -1509,6 +1535,16 @@ static int __video_do_ioctl(struct inode *inode, struct file *file, | |||
1509 | break; | 1535 | break; |
1510 | } | 1536 | } |
1511 | #endif | 1537 | #endif |
1538 | case VIDIOC_G_CHIP_IDENT: | ||
1539 | { | ||
1540 | struct v4l2_chip_ident *p=arg; | ||
1541 | if (!vfd->vidioc_g_chip_ident) | ||
1542 | break; | ||
1543 | ret=vfd->vidioc_g_chip_ident(file, fh, p); | ||
1544 | if (!ret) | ||
1545 | dbgarg (cmd, "chip_ident=%u, revision=0x%x\n", p->ident, p->revision); | ||
1546 | break; | ||
1547 | } | ||
1512 | } /* switch */ | 1548 | } /* switch */ |
1513 | 1549 | ||
1514 | if (vfd->debug & V4L2_DEBUG_IOCTL_ARG) { | 1550 | if (vfd->debug & V4L2_DEBUG_IOCTL_ARG) { |
diff --git a/drivers/media/video/wm8739.c b/drivers/media/video/wm8739.c index a9b59c35cd67..8f6741a28a47 100644 --- a/drivers/media/video/wm8739.c +++ b/drivers/media/video/wm8739.c | |||
@@ -29,6 +29,7 @@ | |||
29 | #include <linux/i2c-id.h> | 29 | #include <linux/i2c-id.h> |
30 | #include <linux/videodev.h> | 30 | #include <linux/videodev.h> |
31 | #include <media/v4l2-common.h> | 31 | #include <media/v4l2-common.h> |
32 | #include <media/v4l2-chip-ident.h> | ||
32 | 33 | ||
33 | MODULE_DESCRIPTION("wm8739 driver"); | 34 | MODULE_DESCRIPTION("wm8739 driver"); |
34 | MODULE_AUTHOR("T. Adachi, Hans Verkuil"); | 35 | MODULE_AUTHOR("T. Adachi, Hans Verkuil"); |
@@ -236,6 +237,9 @@ static int wm8739_command(struct i2c_client *client, unsigned int cmd, void *arg | |||
236 | return -EINVAL; | 237 | return -EINVAL; |
237 | } | 238 | } |
238 | 239 | ||
240 | case VIDIOC_G_CHIP_IDENT: | ||
241 | return v4l2_chip_ident_i2c_client(client, arg, V4L2_IDENT_WM8739, 0); | ||
242 | |||
239 | case VIDIOC_LOG_STATUS: | 243 | case VIDIOC_LOG_STATUS: |
240 | v4l_info(client, "Frequency: %u Hz\n", state->clock_freq); | 244 | v4l_info(client, "Frequency: %u Hz\n", state->clock_freq); |
241 | v4l_info(client, "Volume L: %02x%s\n", state->vol_l & 0x1f, | 245 | v4l_info(client, "Volume L: %02x%s\n", state->vol_l & 0x1f, |
diff --git a/drivers/media/video/wm8775.c b/drivers/media/video/wm8775.c index d81a88bbe43d..4df5d30d4d09 100644 --- a/drivers/media/video/wm8775.c +++ b/drivers/media/video/wm8775.c | |||
@@ -33,6 +33,7 @@ | |||
33 | #include <linux/i2c-id.h> | 33 | #include <linux/i2c-id.h> |
34 | #include <linux/videodev.h> | 34 | #include <linux/videodev.h> |
35 | #include <media/v4l2-common.h> | 35 | #include <media/v4l2-common.h> |
36 | #include <media/v4l2-chip-ident.h> | ||
36 | 37 | ||
37 | MODULE_DESCRIPTION("wm8775 driver"); | 38 | MODULE_DESCRIPTION("wm8775 driver"); |
38 | MODULE_AUTHOR("Ulf Eklund, Hans Verkuil"); | 39 | MODULE_AUTHOR("Ulf Eklund, Hans Verkuil"); |
@@ -124,6 +125,9 @@ static int wm8775_command(struct i2c_client *client, unsigned int cmd, | |||
124 | wm8775_write(client, R21, 0x100 + state->input); | 125 | wm8775_write(client, R21, 0x100 + state->input); |
125 | break; | 126 | break; |
126 | 127 | ||
128 | case VIDIOC_G_CHIP_IDENT: | ||
129 | return v4l2_chip_ident_i2c_client(client, arg, V4L2_IDENT_WM8775, 0); | ||
130 | |||
127 | case VIDIOC_LOG_STATUS: | 131 | case VIDIOC_LOG_STATUS: |
128 | v4l_info(client, "Input: %d%s\n", state->input, | 132 | v4l_info(client, "Input: %d%s\n", state->input, |
129 | state->muted ? " (muted)" : ""); | 133 | state->muted ? " (muted)" : ""); |
diff --git a/drivers/media/video/zr364xx.c b/drivers/media/video/zr364xx.c new file mode 100644 index 000000000000..b5d3364c94c7 --- /dev/null +++ b/drivers/media/video/zr364xx.c | |||
@@ -0,0 +1,929 @@ | |||
1 | /* | ||
2 | * Zoran 364xx based USB webcam module version 0.72 | ||
3 | * | ||
4 | * Allows you to use your USB webcam with V4L2 applications | ||
5 | * This is still in heavy developpement ! | ||
6 | * | ||
7 | * Copyright (C) 2004 Antoine Jacquet <royale@zerezo.com> | ||
8 | * http://royale.zerezo.com/zr364xx/ | ||
9 | * | ||
10 | * Heavily inspired by usb-skeleton.c, vicam.c, cpia.c and spca50x.c drivers | ||
11 | * V4L2 version inspired by meye.c driver | ||
12 | * | ||
13 | * This program is free software; you can redistribute it and/or modify | ||
14 | * it under the terms of the GNU General Public License as published by | ||
15 | * the Free Software Foundation; either version 2 of the License, or | ||
16 | * (at your option) any later version. | ||
17 | * | ||
18 | * This program is distributed in the hope that it will be useful, | ||
19 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
20 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
21 | * GNU General Public License for more details. | ||
22 | * | ||
23 | * You should have received a copy of the GNU General Public License | ||
24 | * along with this program; if not, write to the Free Software | ||
25 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
26 | */ | ||
27 | |||
28 | |||
29 | #include <linux/version.h> | ||
30 | #include <linux/module.h> | ||
31 | #include <linux/init.h> | ||
32 | #include <linux/usb.h> | ||
33 | #include <linux/vmalloc.h> | ||
34 | #include <linux/slab.h> | ||
35 | #include <linux/proc_fs.h> | ||
36 | #include <linux/highmem.h> | ||
37 | #include <media/v4l2-common.h> | ||
38 | |||
39 | |||
40 | /* Version Information */ | ||
41 | #define DRIVER_VERSION "v0.72" | ||
42 | #define DRIVER_AUTHOR "Antoine Jacquet, http://royale.zerezo.com/" | ||
43 | #define DRIVER_DESC "Zoran 364xx" | ||
44 | |||
45 | |||
46 | /* Camera */ | ||
47 | #define FRAMES 2 | ||
48 | #define MAX_FRAME_SIZE 100000 | ||
49 | #define BUFFER_SIZE 0x1000 | ||
50 | #define CTRL_TIMEOUT 500 | ||
51 | |||
52 | |||
53 | /* Debug macro */ | ||
54 | #define DBG(x...) if (debug) info(x) | ||
55 | |||
56 | |||
57 | /* Init methods, need to find nicer names for these | ||
58 | * the exact names of the chipsets would be the best if someone finds it */ | ||
59 | #define METHOD0 0 | ||
60 | #define METHOD1 1 | ||
61 | #define METHOD2 2 | ||
62 | |||
63 | |||
64 | /* Module parameters */ | ||
65 | static int debug = 0; | ||
66 | static int mode = 0; | ||
67 | |||
68 | |||
69 | /* Module parameters interface */ | ||
70 | module_param(debug, int, 0644); | ||
71 | MODULE_PARM_DESC(debug, "Debug level"); | ||
72 | module_param(mode, int, 0644); | ||
73 | MODULE_PARM_DESC(mode, "0 = 320x240, 1 = 160x120, 2 = 640x480"); | ||
74 | |||
75 | |||
76 | /* Devices supported by this driver | ||
77 | * .driver_info contains the init method used by the camera */ | ||
78 | static struct usb_device_id device_table[] = { | ||
79 | {USB_DEVICE(0x08ca, 0x0109), .driver_info = METHOD0 }, | ||
80 | {USB_DEVICE(0x041e, 0x4024), .driver_info = METHOD0 }, | ||
81 | {USB_DEVICE(0x0d64, 0x0108), .driver_info = METHOD0 }, | ||
82 | {USB_DEVICE(0x0546, 0x3187), .driver_info = METHOD0 }, | ||
83 | {USB_DEVICE(0x0d64, 0x3108), .driver_info = METHOD0 }, | ||
84 | {USB_DEVICE(0x0595, 0x4343), .driver_info = METHOD0 }, | ||
85 | {USB_DEVICE(0x0bb0, 0x500d), .driver_info = METHOD0 }, | ||
86 | {USB_DEVICE(0x0feb, 0x2004), .driver_info = METHOD0 }, | ||
87 | {USB_DEVICE(0x055f, 0xb500), .driver_info = METHOD0 }, | ||
88 | {USB_DEVICE(0x08ca, 0x2062), .driver_info = METHOD2 }, | ||
89 | {USB_DEVICE(0x052b, 0x1a18), .driver_info = METHOD1 }, | ||
90 | {USB_DEVICE(0x04c8, 0x0729), .driver_info = METHOD0 }, | ||
91 | {USB_DEVICE(0x04f2, 0xa208), .driver_info = METHOD0 }, | ||
92 | {USB_DEVICE(0x0784, 0x0040), .driver_info = METHOD1 }, | ||
93 | {USB_DEVICE(0x06d6, 0x0034), .driver_info = METHOD0 }, | ||
94 | {USB_DEVICE(0x0a17, 0x0062), .driver_info = METHOD2 }, | ||
95 | {} /* Terminating entry */ | ||
96 | }; | ||
97 | |||
98 | MODULE_DEVICE_TABLE(usb, device_table); | ||
99 | |||
100 | |||
101 | /* Camera stuff */ | ||
102 | struct zr364xx_camera { | ||
103 | struct usb_device *udev; /* save off the usb device pointer */ | ||
104 | struct usb_interface *interface;/* the interface for this device */ | ||
105 | struct video_device *vdev; /* v4l video device */ | ||
106 | u8 *framebuf; | ||
107 | int nb; | ||
108 | unsigned char *buffer; | ||
109 | int skip; | ||
110 | int brightness; | ||
111 | int width; | ||
112 | int height; | ||
113 | int method; | ||
114 | struct mutex lock; | ||
115 | }; | ||
116 | |||
117 | |||
118 | /* function used to send initialisation commands to the camera */ | ||
119 | static int send_control_msg(struct usb_device *udev, u8 request, u16 value, | ||
120 | u16 index, unsigned char *cp, u16 size) | ||
121 | { | ||
122 | int status; | ||
123 | |||
124 | unsigned char *transfer_buffer = kmalloc(size, GFP_KERNEL); | ||
125 | if (!transfer_buffer) { | ||
126 | info("kmalloc(%d) failed", size); | ||
127 | return -ENOMEM; | ||
128 | } | ||
129 | |||
130 | memcpy(transfer_buffer, cp, size); | ||
131 | |||
132 | status = usb_control_msg(udev, | ||
133 | usb_sndctrlpipe(udev, 0), | ||
134 | request, | ||
135 | USB_DIR_OUT | USB_TYPE_VENDOR | | ||
136 | USB_RECIP_DEVICE, value, index, | ||
137 | transfer_buffer, size, CTRL_TIMEOUT); | ||
138 | |||
139 | kfree(transfer_buffer); | ||
140 | |||
141 | if (status < 0) | ||
142 | info("Failed sending control message, error %d.", status); | ||
143 | |||
144 | return status; | ||
145 | } | ||
146 | |||
147 | |||
148 | /* Control messages sent to the camera to initialize it | ||
149 | * and launch the capture */ | ||
150 | typedef struct { | ||
151 | unsigned int value; | ||
152 | unsigned int size; | ||
153 | unsigned char *bytes; | ||
154 | } message; | ||
155 | |||
156 | /* method 0 */ | ||
157 | static unsigned char m0d1[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; | ||
158 | static unsigned char m0d2[] = { 0, 0, 0, 0, 0, 0 }; | ||
159 | static unsigned char m0d3[] = { 0, 0 }; | ||
160 | static message m0[] = { | ||
161 | {0x1f30, 0, NULL}, | ||
162 | {0xd000, 0, NULL}, | ||
163 | {0x3370, sizeof(m0d1), m0d1}, | ||
164 | {0x2000, 0, NULL}, | ||
165 | {0x2f0f, 0, NULL}, | ||
166 | {0x2610, sizeof(m0d2), m0d2}, | ||
167 | {0xe107, 0, NULL}, | ||
168 | {0x2502, 0, NULL}, | ||
169 | {0x1f70, 0, NULL}, | ||
170 | {0xd000, 0, NULL}, | ||
171 | {0x9a01, sizeof(m0d3), m0d3}, | ||
172 | {-1, -1, NULL} | ||
173 | }; | ||
174 | |||
175 | /* method 1 */ | ||
176 | static unsigned char m1d1[] = { 0xff, 0xff }; | ||
177 | static unsigned char m1d2[] = { 0x00, 0x00 }; | ||
178 | static message m1[] = { | ||
179 | {0x1f30, 0, NULL}, | ||
180 | {0xd000, 0, NULL}, | ||
181 | {0xf000, 0, NULL}, | ||
182 | {0x2000, 0, NULL}, | ||
183 | {0x2f0f, 0, NULL}, | ||
184 | {0x2650, 0, NULL}, | ||
185 | {0xe107, 0, NULL}, | ||
186 | {0x2502, sizeof(m1d1), m1d1}, | ||
187 | {0x1f70, 0, NULL}, | ||
188 | {0xd000, 0, NULL}, | ||
189 | {0xd000, 0, NULL}, | ||
190 | {0xd000, 0, NULL}, | ||
191 | {0x9a01, sizeof(m1d2), m1d2}, | ||
192 | {-1, -1, NULL} | ||
193 | }; | ||
194 | |||
195 | /* method 2 */ | ||
196 | static unsigned char m2d1[] = { 0xff, 0xff }; | ||
197 | static message m2[] = { | ||
198 | {0x1f30, 0, NULL}, | ||
199 | {0xf000, 0, NULL}, | ||
200 | {0x2000, 0, NULL}, | ||
201 | {0x2f0f, 0, NULL}, | ||
202 | {0x2650, 0, NULL}, | ||
203 | {0xe107, 0, NULL}, | ||
204 | {0x2502, sizeof(m2d1), m2d1}, | ||
205 | {0x1f70, 0, NULL}, | ||
206 | {-1, -1, NULL} | ||
207 | }; | ||
208 | |||
209 | /* init table */ | ||
210 | static message *init[3] = { m0, m1, m2 }; | ||
211 | |||
212 | |||
213 | /* JPEG static data in header (Huffman table, etc) */ | ||
214 | static unsigned char header1[] = { | ||
215 | 0xFF, 0xD8, | ||
216 | /* | ||
217 | 0xFF, 0xE0, 0x00, 0x10, 'J', 'F', 'I', 'F', | ||
218 | 0x00, 0x01, 0x01, 0x00, 0x33, 0x8A, 0x00, 0x00, 0x33, 0x88, | ||
219 | */ | ||
220 | 0xFF, 0xDB, 0x00, 0x84 | ||
221 | }; | ||
222 | static unsigned char header2[] = { | ||
223 | 0xFF, 0xC4, 0x00, 0x1F, 0x00, 0x00, 0x01, 0x05, 0x01, 0x01, 0x01, | ||
224 | 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
225 | 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, | ||
226 | 0xFF, 0xC4, 0x00, 0xB5, 0x10, 0x00, 0x02, 0x01, 0x03, 0x03, 0x02, | ||
227 | 0x04, 0x03, 0x05, 0x05, 0x04, 0x04, 0x00, 0x00, 0x01, 0x7D, 0x01, | ||
228 | 0x02, 0x03, 0x00, 0x04, 0x11, 0x05, 0x12, 0x21, 0x31, 0x41, 0x06, | ||
229 | 0x13, 0x51, 0x61, 0x07, 0x22, 0x71, 0x14, 0x32, 0x81, 0x91, 0xA1, | ||
230 | 0x08, 0x23, 0x42, 0xB1, 0xC1, 0x15, 0x52, 0xD1, 0xF0, 0x24, 0x33, | ||
231 | 0x62, 0x72, 0x82, 0x09, 0x0A, 0x16, 0x17, 0x18, 0x19, 0x1A, 0x25, | ||
232 | 0x26, 0x27, 0x28, 0x29, 0x2A, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, | ||
233 | 0x3A, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4A, 0x53, 0x54, | ||
234 | 0x55, 0x56, 0x57, 0x58, 0x59, 0x5A, 0x63, 0x64, 0x65, 0x66, 0x67, | ||
235 | 0x68, 0x69, 0x6A, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7A, | ||
236 | 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8A, 0x92, 0x93, 0x94, | ||
237 | 0x95, 0x96, 0x97, 0x98, 0x99, 0x9A, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6, | ||
238 | 0xA7, 0xA8, 0xA9, 0xAA, 0xB2, 0xB3, 0xB4, 0xB5, 0xB6, 0xB7, 0xB8, | ||
239 | 0xB9, 0xBA, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7, 0xC8, 0xC9, 0xCA, | ||
240 | 0xD2, 0xD3, 0xD4, 0xD5, 0xD6, 0xD7, 0xD8, 0xD9, 0xDA, 0xE1, 0xE2, | ||
241 | 0xE3, 0xE4, 0xE5, 0xE6, 0xE7, 0xE8, 0xE9, 0xEA, 0xF1, 0xF2, 0xF3, | ||
242 | 0xF4, 0xF5, 0xF6, 0xF7, 0xF8, 0xF9, 0xFA, 0xFF, 0xC4, 0x00, 0x1F, | ||
243 | 0x01, 0x00, 0x03, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, | ||
244 | 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x02, 0x03, 0x04, | ||
245 | 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0xFF, 0xC4, 0x00, 0xB5, | ||
246 | 0x11, 0x00, 0x02, 0x01, 0x02, 0x04, 0x04, 0x03, 0x04, 0x07, 0x05, | ||
247 | 0x04, 0x04, 0x00, 0x01, 0x02, 0x77, 0x00, 0x01, 0x02, 0x03, 0x11, | ||
248 | 0x04, 0x05, 0x21, 0x31, 0x06, 0x12, 0x41, 0x51, 0x07, 0x61, 0x71, | ||
249 | 0x13, 0x22, 0x32, 0x81, 0x08, 0x14, 0x42, 0x91, 0xA1, 0xB1, 0xC1, | ||
250 | 0x09, 0x23, 0x33, 0x52, 0xF0, 0x15, 0x62, 0x72, 0xD1, 0x0A, 0x16, | ||
251 | 0x24, 0x34, 0xE1, 0x25, 0xF1, 0x17, 0x18, 0x19, 0x1A, 0x26, 0x27, | ||
252 | 0x28, 0x29, 0x2A, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3A, 0x43, 0x44, | ||
253 | 0x45, 0x46, 0x47, 0x48, 0x49, 0x4A, 0x53, 0x54, 0x55, 0x56, 0x57, | ||
254 | 0x58, 0x59, 0x5A, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6A, | ||
255 | 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7A, 0x82, 0x83, 0x84, | ||
256 | 0x85, 0x86, 0x87, 0x88, 0x89, 0x8A, 0x92, 0x93, 0x94, 0x95, 0x96, | ||
257 | 0x97, 0x98, 0x99, 0x9A, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6, 0xA7, 0xA8, | ||
258 | 0xA9, 0xAA, 0xB2, 0xB3, 0xB4, 0xB5, 0xB6, 0xB7, 0xB8, 0xB9, 0xBA, | ||
259 | 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7, 0xC8, 0xC9, 0xCA, 0xD2, 0xD3, | ||
260 | 0xD4, 0xD5, 0xD6, 0xD7, 0xD8, 0xD9, 0xDA, 0xE2, 0xE3, 0xE4, 0xE5, | ||
261 | 0xE6, 0xE7, 0xE8, 0xE9, 0xEA, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xF7, | ||
262 | 0xF8, 0xF9, 0xFA, 0xFF, 0xC0, 0x00, 0x11, 0x08, 0x00, 0xF0, 0x01, | ||
263 | 0x40, 0x03, 0x01, 0x21, 0x00, 0x02, 0x11, 0x01, 0x03, 0x11, 0x01, | ||
264 | 0xFF, 0xDA, 0x00, 0x0C, 0x03, 0x01, 0x00, 0x02, 0x11, 0x03, 0x11, | ||
265 | 0x00, 0x3F, 0x00 | ||
266 | }; | ||
267 | static unsigned char header3; | ||
268 | |||
269 | |||
270 | |||
271 | /********************/ | ||
272 | /* V4L2 integration */ | ||
273 | /********************/ | ||
274 | |||
275 | /* this function reads a full JPEG picture synchronously | ||
276 | * TODO: do it asynchronously... */ | ||
277 | static int read_frame(struct zr364xx_camera *cam, int framenum) | ||
278 | { | ||
279 | int i, n, temp, head, size, actual_length; | ||
280 | unsigned char *ptr = NULL, *jpeg; | ||
281 | |||
282 | redo: | ||
283 | /* hardware brightness */ | ||
284 | n = send_control_msg(cam->udev, 1, 0x2001, 0, NULL, 0); | ||
285 | temp = (0x60 << 8) + 127 - cam->brightness; | ||
286 | n = send_control_msg(cam->udev, 1, temp, 0, NULL, 0); | ||
287 | |||
288 | /* during the first loop we are going to insert JPEG header */ | ||
289 | head = 0; | ||
290 | /* this is the place in memory where we are going to build | ||
291 | * the JPEG image */ | ||
292 | jpeg = cam->framebuf + framenum * MAX_FRAME_SIZE; | ||
293 | /* read data... */ | ||
294 | do { | ||
295 | n = usb_bulk_msg(cam->udev, | ||
296 | usb_rcvbulkpipe(cam->udev, 0x81), | ||
297 | cam->buffer, BUFFER_SIZE, &actual_length, | ||
298 | CTRL_TIMEOUT); | ||
299 | DBG("buffer : %d %d", cam->buffer[0], cam->buffer[1]); | ||
300 | DBG("bulk : n=%d size=%d", n, actual_length); | ||
301 | if (n < 0) { | ||
302 | info("error reading bulk msg"); | ||
303 | return 0; | ||
304 | } | ||
305 | if (actual_length < 0 || actual_length > BUFFER_SIZE) { | ||
306 | info("wrong number of bytes"); | ||
307 | return 0; | ||
308 | } | ||
309 | |||
310 | /* swap bytes if camera needs it */ | ||
311 | if (cam->method == METHOD0) { | ||
312 | u16 *buf = (u16*)cam->buffer; | ||
313 | for (i = 0; i < BUFFER_SIZE/2; i++) | ||
314 | swab16s(buf + i); | ||
315 | } | ||
316 | |||
317 | /* write the JPEG header */ | ||
318 | if (!head) { | ||
319 | DBG("jpeg header"); | ||
320 | ptr = jpeg; | ||
321 | memcpy(ptr, header1, sizeof(header1)); | ||
322 | ptr += sizeof(header1); | ||
323 | header3 = 0; | ||
324 | memcpy(ptr, &header3, 1); | ||
325 | ptr++; | ||
326 | memcpy(ptr, cam->buffer, 64); | ||
327 | ptr += 64; | ||
328 | header3 = 1; | ||
329 | memcpy(ptr, &header3, 1); | ||
330 | ptr++; | ||
331 | memcpy(ptr, cam->buffer + 64, 64); | ||
332 | ptr += 64; | ||
333 | memcpy(ptr, header2, sizeof(header2)); | ||
334 | ptr += sizeof(header2); | ||
335 | memcpy(ptr, cam->buffer + 128, | ||
336 | actual_length - 128); | ||
337 | ptr += actual_length - 128; | ||
338 | head = 1; | ||
339 | DBG("header : %d %d %d %d %d %d %d %d %d", | ||
340 | cam->buffer[0], cam->buffer[1], cam->buffer[2], | ||
341 | cam->buffer[3], cam->buffer[4], cam->buffer[5], | ||
342 | cam->buffer[6], cam->buffer[7], cam->buffer[8]); | ||
343 | } else { | ||
344 | memcpy(ptr, cam->buffer, actual_length); | ||
345 | ptr += actual_length; | ||
346 | } | ||
347 | } | ||
348 | /* ... until there is no more */ | ||
349 | while (actual_length == BUFFER_SIZE); | ||
350 | |||
351 | /* we skip the 2 first frames which are usually buggy */ | ||
352 | if (cam->skip) { | ||
353 | cam->skip--; | ||
354 | goto redo; | ||
355 | } | ||
356 | |||
357 | /* go back to find the JPEG EOI marker */ | ||
358 | size = ptr - jpeg; | ||
359 | ptr -= 2; | ||
360 | while (ptr > jpeg) { | ||
361 | if (*ptr == 0xFF && *(ptr + 1) == 0xD9 | ||
362 | && *(ptr + 2) == 0xFF) | ||
363 | break; | ||
364 | ptr--; | ||
365 | } | ||
366 | if (ptr == jpeg) | ||
367 | DBG("No EOI marker"); | ||
368 | |||
369 | /* Sometimes there is junk data in the middle of the picture, | ||
370 | * we want to skip this bogus frames */ | ||
371 | while (ptr > jpeg) { | ||
372 | if (*ptr == 0xFF && *(ptr + 1) == 0xFF | ||
373 | && *(ptr + 2) == 0xFF) | ||
374 | break; | ||
375 | ptr--; | ||
376 | } | ||
377 | if (ptr != jpeg) { | ||
378 | DBG("Bogus frame ? %d", cam->nb); | ||
379 | goto redo; | ||
380 | } | ||
381 | |||
382 | DBG("jpeg : %d %d %d %d %d %d %d %d", | ||
383 | jpeg[0], jpeg[1], jpeg[2], jpeg[3], | ||
384 | jpeg[4], jpeg[5], jpeg[6], jpeg[7]); | ||
385 | |||
386 | return size; | ||
387 | } | ||
388 | |||
389 | |||
390 | static ssize_t zr364xx_read(struct file *file, char *buf, size_t cnt, | ||
391 | loff_t * ppos) | ||
392 | { | ||
393 | unsigned long count = cnt; | ||
394 | struct video_device *vdev = video_devdata(file); | ||
395 | struct zr364xx_camera *cam; | ||
396 | |||
397 | DBG("zr364xx_read: read %d bytes.", (int) count); | ||
398 | |||
399 | if (vdev == NULL) | ||
400 | return -ENODEV; | ||
401 | cam = video_get_drvdata(vdev); | ||
402 | |||
403 | if (!buf) | ||
404 | return -EINVAL; | ||
405 | |||
406 | if (!count) | ||
407 | return -EINVAL; | ||
408 | |||
409 | /* NoMan Sux ! */ | ||
410 | count = read_frame(cam, 0); | ||
411 | |||
412 | if (copy_to_user(buf, cam->framebuf, count)) | ||
413 | return -EFAULT; | ||
414 | |||
415 | return count; | ||
416 | } | ||
417 | |||
418 | |||
419 | static int zr364xx_vidioc_querycap(struct file *file, void *priv, | ||
420 | struct v4l2_capability *cap) | ||
421 | { | ||
422 | memset(cap, 0, sizeof(*cap)); | ||
423 | strcpy(cap->driver, DRIVER_DESC); | ||
424 | cap->capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_READWRITE; | ||
425 | return 0; | ||
426 | } | ||
427 | |||
428 | static int zr364xx_vidioc_enum_input(struct file *file, void *priv, | ||
429 | struct v4l2_input *i) | ||
430 | { | ||
431 | if (i->index != 0) | ||
432 | return -EINVAL; | ||
433 | memset(i, 0, sizeof(*i)); | ||
434 | i->index = 0; | ||
435 | strcpy(i->name, DRIVER_DESC " Camera"); | ||
436 | i->type = V4L2_INPUT_TYPE_CAMERA; | ||
437 | return 0; | ||
438 | } | ||
439 | |||
440 | static int zr364xx_vidioc_g_input(struct file *file, void *priv, | ||
441 | unsigned int *i) | ||
442 | { | ||
443 | *i = 0; | ||
444 | return 0; | ||
445 | } | ||
446 | |||
447 | static int zr364xx_vidioc_s_input(struct file *file, void *priv, | ||
448 | unsigned int i) | ||
449 | { | ||
450 | if (i != 0) | ||
451 | return -EINVAL; | ||
452 | return 0; | ||
453 | } | ||
454 | |||
455 | static int zr364xx_vidioc_queryctrl(struct file *file, void *priv, | ||
456 | struct v4l2_queryctrl *c) | ||
457 | { | ||
458 | struct video_device *vdev = video_devdata(file); | ||
459 | struct zr364xx_camera *cam; | ||
460 | |||
461 | if (vdev == NULL) | ||
462 | return -ENODEV; | ||
463 | cam = video_get_drvdata(vdev); | ||
464 | |||
465 | switch (c->id) { | ||
466 | case V4L2_CID_BRIGHTNESS: | ||
467 | c->type = V4L2_CTRL_TYPE_INTEGER; | ||
468 | strcpy(c->name, "Brightness"); | ||
469 | c->minimum = 0; | ||
470 | c->maximum = 127; | ||
471 | c->step = 1; | ||
472 | c->default_value = cam->brightness; | ||
473 | c->flags = 0; | ||
474 | break; | ||
475 | default: | ||
476 | return -EINVAL; | ||
477 | } | ||
478 | return 0; | ||
479 | } | ||
480 | |||
481 | static int zr364xx_vidioc_s_ctrl(struct file *file, void *priv, | ||
482 | struct v4l2_control *c) | ||
483 | { | ||
484 | struct video_device *vdev = video_devdata(file); | ||
485 | struct zr364xx_camera *cam; | ||
486 | |||
487 | if (vdev == NULL) | ||
488 | return -ENODEV; | ||
489 | cam = video_get_drvdata(vdev); | ||
490 | |||
491 | switch (c->id) { | ||
492 | case V4L2_CID_BRIGHTNESS: | ||
493 | cam->brightness = c->value; | ||
494 | break; | ||
495 | default: | ||
496 | return -EINVAL; | ||
497 | } | ||
498 | return 0; | ||
499 | } | ||
500 | |||
501 | static int zr364xx_vidioc_g_ctrl(struct file *file, void *priv, | ||
502 | struct v4l2_control *c) | ||
503 | { | ||
504 | struct video_device *vdev = video_devdata(file); | ||
505 | struct zr364xx_camera *cam; | ||
506 | |||
507 | if (vdev == NULL) | ||
508 | return -ENODEV; | ||
509 | cam = video_get_drvdata(vdev); | ||
510 | |||
511 | switch (c->id) { | ||
512 | case V4L2_CID_BRIGHTNESS: | ||
513 | c->value = cam->brightness; | ||
514 | break; | ||
515 | default: | ||
516 | return -EINVAL; | ||
517 | } | ||
518 | return 0; | ||
519 | } | ||
520 | |||
521 | static int zr364xx_vidioc_enum_fmt_cap(struct file *file, | ||
522 | void *priv, struct v4l2_fmtdesc *f) | ||
523 | { | ||
524 | if (f->index > 0) | ||
525 | return -EINVAL; | ||
526 | if (f->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) | ||
527 | return -EINVAL; | ||
528 | memset(f, 0, sizeof(*f)); | ||
529 | f->index = 0; | ||
530 | f->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; | ||
531 | f->flags = V4L2_FMT_FLAG_COMPRESSED; | ||
532 | strcpy(f->description, "JPEG"); | ||
533 | f->pixelformat = V4L2_PIX_FMT_JPEG; | ||
534 | return 0; | ||
535 | } | ||
536 | |||
537 | static int zr364xx_vidioc_try_fmt_cap(struct file *file, void *priv, | ||
538 | struct v4l2_format *f) | ||
539 | { | ||
540 | struct video_device *vdev = video_devdata(file); | ||
541 | struct zr364xx_camera *cam; | ||
542 | |||
543 | if (vdev == NULL) | ||
544 | return -ENODEV; | ||
545 | cam = video_get_drvdata(vdev); | ||
546 | |||
547 | if (f->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) | ||
548 | return -EINVAL; | ||
549 | if (f->fmt.pix.pixelformat != V4L2_PIX_FMT_JPEG) | ||
550 | return -EINVAL; | ||
551 | if (f->fmt.pix.field != V4L2_FIELD_ANY && | ||
552 | f->fmt.pix.field != V4L2_FIELD_NONE) | ||
553 | return -EINVAL; | ||
554 | f->fmt.pix.field = V4L2_FIELD_NONE; | ||
555 | f->fmt.pix.width = cam->width; | ||
556 | f->fmt.pix.height = cam->height; | ||
557 | f->fmt.pix.bytesperline = f->fmt.pix.width * 2; | ||
558 | f->fmt.pix.sizeimage = f->fmt.pix.height * f->fmt.pix.bytesperline; | ||
559 | f->fmt.pix.colorspace = 0; | ||
560 | f->fmt.pix.priv = 0; | ||
561 | return 0; | ||
562 | } | ||
563 | |||
564 | static int zr364xx_vidioc_g_fmt_cap(struct file *file, void *priv, | ||
565 | struct v4l2_format *f) | ||
566 | { | ||
567 | struct video_device *vdev = video_devdata(file); | ||
568 | struct zr364xx_camera *cam; | ||
569 | |||
570 | if (vdev == NULL) | ||
571 | return -ENODEV; | ||
572 | cam = video_get_drvdata(vdev); | ||
573 | |||
574 | if (f->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) | ||
575 | return -EINVAL; | ||
576 | memset(&f->fmt.pix, 0, sizeof(struct v4l2_pix_format)); | ||
577 | f->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; | ||
578 | f->fmt.pix.pixelformat = V4L2_PIX_FMT_JPEG; | ||
579 | f->fmt.pix.field = V4L2_FIELD_NONE; | ||
580 | f->fmt.pix.width = cam->width; | ||
581 | f->fmt.pix.height = cam->height; | ||
582 | f->fmt.pix.bytesperline = f->fmt.pix.width * 2; | ||
583 | f->fmt.pix.sizeimage = f->fmt.pix.height * f->fmt.pix.bytesperline; | ||
584 | f->fmt.pix.colorspace = 0; | ||
585 | f->fmt.pix.priv = 0; | ||
586 | return 0; | ||
587 | } | ||
588 | |||
589 | static int zr364xx_vidioc_s_fmt_cap(struct file *file, void *priv, | ||
590 | struct v4l2_format *f) | ||
591 | { | ||
592 | struct video_device *vdev = video_devdata(file); | ||
593 | struct zr364xx_camera *cam; | ||
594 | |||
595 | if (vdev == NULL) | ||
596 | return -ENODEV; | ||
597 | cam = video_get_drvdata(vdev); | ||
598 | |||
599 | if (f->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) | ||
600 | return -EINVAL; | ||
601 | if (f->fmt.pix.pixelformat != V4L2_PIX_FMT_JPEG) | ||
602 | return -EINVAL; | ||
603 | if (f->fmt.pix.field != V4L2_FIELD_ANY && | ||
604 | f->fmt.pix.field != V4L2_FIELD_NONE) | ||
605 | return -EINVAL; | ||
606 | f->fmt.pix.field = V4L2_FIELD_NONE; | ||
607 | f->fmt.pix.width = cam->width; | ||
608 | f->fmt.pix.height = cam->height; | ||
609 | f->fmt.pix.bytesperline = f->fmt.pix.width * 2; | ||
610 | f->fmt.pix.sizeimage = f->fmt.pix.height * f->fmt.pix.bytesperline; | ||
611 | f->fmt.pix.colorspace = 0; | ||
612 | f->fmt.pix.priv = 0; | ||
613 | DBG("ok!"); | ||
614 | return 0; | ||
615 | } | ||
616 | |||
617 | static int zr364xx_vidioc_streamon(struct file *file, void *priv, | ||
618 | enum v4l2_buf_type type) | ||
619 | { | ||
620 | return 0; | ||
621 | } | ||
622 | |||
623 | static int zr364xx_vidioc_streamoff(struct file *file, void *priv, | ||
624 | enum v4l2_buf_type type) | ||
625 | { | ||
626 | return 0; | ||
627 | } | ||
628 | |||
629 | |||
630 | /* open the camera */ | ||
631 | static int zr364xx_open(struct inode *inode, struct file *file) | ||
632 | { | ||
633 | struct video_device *vdev = video_devdata(file); | ||
634 | struct zr364xx_camera *cam = video_get_drvdata(vdev); | ||
635 | struct usb_device *udev = cam->udev; | ||
636 | int i, err; | ||
637 | |||
638 | DBG("zr364xx_open"); | ||
639 | |||
640 | cam->skip = 2; | ||
641 | |||
642 | err = video_exclusive_open(inode, file); | ||
643 | if (err < 0) | ||
644 | return err; | ||
645 | |||
646 | if (!cam->framebuf) { | ||
647 | cam->framebuf = vmalloc_32(MAX_FRAME_SIZE * FRAMES); | ||
648 | if (!cam->framebuf) { | ||
649 | info("vmalloc_32 failed!"); | ||
650 | return -ENOMEM; | ||
651 | } | ||
652 | } | ||
653 | |||
654 | mutex_lock(&cam->lock); | ||
655 | for (i = 0; init[cam->method][i].size != -1; i++) { | ||
656 | err = | ||
657 | send_control_msg(udev, 1, init[cam->method][i].value, | ||
658 | 0, init[cam->method][i].bytes, | ||
659 | init[cam->method][i].size); | ||
660 | if (err < 0) { | ||
661 | info("error during open sequence: %d", i); | ||
662 | mutex_unlock(&cam->lock); | ||
663 | return err; | ||
664 | } | ||
665 | } | ||
666 | |||
667 | file->private_data = vdev; | ||
668 | |||
669 | /* Added some delay here, since opening/closing the camera quickly, | ||
670 | * like Ekiga does during its startup, can crash the webcam | ||
671 | */ | ||
672 | mdelay(100); | ||
673 | |||
674 | mutex_unlock(&cam->lock); | ||
675 | return 0; | ||
676 | } | ||
677 | |||
678 | |||
679 | /* release the camera */ | ||
680 | static int zr364xx_release(struct inode *inode, struct file *file) | ||
681 | { | ||
682 | struct video_device *vdev = video_devdata(file); | ||
683 | struct zr364xx_camera *cam; | ||
684 | struct usb_device *udev; | ||
685 | int i, err; | ||
686 | |||
687 | DBG("zr364xx_release"); | ||
688 | |||
689 | if (vdev == NULL) | ||
690 | return -ENODEV; | ||
691 | cam = video_get_drvdata(vdev); | ||
692 | |||
693 | udev = cam->udev; | ||
694 | |||
695 | mutex_lock(&cam->lock); | ||
696 | for (i = 0; i < 2; i++) { | ||
697 | err = | ||
698 | send_control_msg(udev, 1, init[cam->method][i].value, | ||
699 | 0, init[i][cam->method].bytes, | ||
700 | init[cam->method][i].size); | ||
701 | if (err < 0) { | ||
702 | info("error during release sequence"); | ||
703 | mutex_unlock(&cam->lock); | ||
704 | return err; | ||
705 | } | ||
706 | } | ||
707 | |||
708 | file->private_data = NULL; | ||
709 | video_exclusive_release(inode, file); | ||
710 | |||
711 | /* Added some delay here, since opening/closing the camera quickly, | ||
712 | * like Ekiga does during its startup, can crash the webcam | ||
713 | */ | ||
714 | mdelay(100); | ||
715 | |||
716 | mutex_unlock(&cam->lock); | ||
717 | return 0; | ||
718 | } | ||
719 | |||
720 | |||
721 | static int zr364xx_mmap(struct file *file, struct vm_area_struct *vma) | ||
722 | { | ||
723 | void *pos; | ||
724 | unsigned long start = vma->vm_start; | ||
725 | unsigned long size = vma->vm_end - vma->vm_start; | ||
726 | struct video_device *vdev = video_devdata(file); | ||
727 | struct zr364xx_camera *cam; | ||
728 | |||
729 | DBG("zr364xx_mmap: %ld\n", size); | ||
730 | |||
731 | if (vdev == NULL) | ||
732 | return -ENODEV; | ||
733 | cam = video_get_drvdata(vdev); | ||
734 | |||
735 | pos = cam->framebuf; | ||
736 | while (size > 0) { | ||
737 | if (vm_insert_page(vma, start, vmalloc_to_page(pos))) | ||
738 | return -EAGAIN; | ||
739 | start += PAGE_SIZE; | ||
740 | pos += PAGE_SIZE; | ||
741 | if (size > PAGE_SIZE) | ||
742 | size -= PAGE_SIZE; | ||
743 | else | ||
744 | size = 0; | ||
745 | } | ||
746 | |||
747 | return 0; | ||
748 | } | ||
749 | |||
750 | |||
751 | static struct file_operations zr364xx_fops = { | ||
752 | .owner = THIS_MODULE, | ||
753 | .open = zr364xx_open, | ||
754 | .release = zr364xx_release, | ||
755 | .read = zr364xx_read, | ||
756 | .mmap = zr364xx_mmap, | ||
757 | .ioctl = video_ioctl2, | ||
758 | .llseek = no_llseek, | ||
759 | }; | ||
760 | |||
761 | static struct video_device zr364xx_template = { | ||
762 | .owner = THIS_MODULE, | ||
763 | .name = DRIVER_DESC, | ||
764 | .type = VID_TYPE_CAPTURE, | ||
765 | .fops = &zr364xx_fops, | ||
766 | .release = video_device_release, | ||
767 | .minor = -1, | ||
768 | |||
769 | .vidioc_querycap = zr364xx_vidioc_querycap, | ||
770 | .vidioc_enum_fmt_cap = zr364xx_vidioc_enum_fmt_cap, | ||
771 | .vidioc_try_fmt_cap = zr364xx_vidioc_try_fmt_cap, | ||
772 | .vidioc_s_fmt_cap = zr364xx_vidioc_s_fmt_cap, | ||
773 | .vidioc_g_fmt_cap = zr364xx_vidioc_g_fmt_cap, | ||
774 | .vidioc_enum_input = zr364xx_vidioc_enum_input, | ||
775 | .vidioc_g_input = zr364xx_vidioc_g_input, | ||
776 | .vidioc_s_input = zr364xx_vidioc_s_input, | ||
777 | .vidioc_streamon = zr364xx_vidioc_streamon, | ||
778 | .vidioc_streamoff = zr364xx_vidioc_streamoff, | ||
779 | .vidioc_queryctrl = zr364xx_vidioc_queryctrl, | ||
780 | .vidioc_g_ctrl = zr364xx_vidioc_g_ctrl, | ||
781 | .vidioc_s_ctrl = zr364xx_vidioc_s_ctrl, | ||
782 | }; | ||
783 | |||
784 | |||
785 | |||
786 | /*******************/ | ||
787 | /* USB integration */ | ||
788 | /*******************/ | ||
789 | |||
790 | static int zr364xx_probe(struct usb_interface *intf, | ||
791 | const struct usb_device_id *id) | ||
792 | { | ||
793 | struct usb_device *udev = interface_to_usbdev(intf); | ||
794 | struct zr364xx_camera *cam = NULL; | ||
795 | |||
796 | DBG("probing..."); | ||
797 | |||
798 | info(DRIVER_DESC " compatible webcam plugged"); | ||
799 | info("model %04x:%04x detected", udev->descriptor.idVendor, | ||
800 | udev->descriptor.idProduct); | ||
801 | |||
802 | if ((cam = | ||
803 | kmalloc(sizeof(struct zr364xx_camera), GFP_KERNEL)) == NULL) { | ||
804 | info("cam: out of memory !"); | ||
805 | return -ENODEV; | ||
806 | } | ||
807 | memset(cam, 0x00, sizeof(struct zr364xx_camera)); | ||
808 | /* save the init method used by this camera */ | ||
809 | cam->method = id->driver_info; | ||
810 | |||
811 | cam->vdev = video_device_alloc(); | ||
812 | if (cam->vdev == NULL) { | ||
813 | info("cam->vdev: out of memory !"); | ||
814 | kfree(cam); | ||
815 | return -ENODEV; | ||
816 | } | ||
817 | memcpy(cam->vdev, &zr364xx_template, sizeof(zr364xx_template)); | ||
818 | video_set_drvdata(cam->vdev, cam); | ||
819 | if (debug) | ||
820 | cam->vdev->debug = V4L2_DEBUG_IOCTL | V4L2_DEBUG_IOCTL_ARG; | ||
821 | |||
822 | cam->udev = udev; | ||
823 | |||
824 | if ((cam->buffer = kmalloc(BUFFER_SIZE, GFP_KERNEL)) == NULL) { | ||
825 | info("cam->buffer: out of memory !"); | ||
826 | video_device_release(cam->vdev); | ||
827 | kfree(cam); | ||
828 | return -ENODEV; | ||
829 | } | ||
830 | |||
831 | switch (mode) { | ||
832 | case 1: | ||
833 | info("160x120 mode selected"); | ||
834 | cam->width = 160; | ||
835 | cam->height = 120; | ||
836 | break; | ||
837 | case 2: | ||
838 | info("640x480 mode selected"); | ||
839 | cam->width = 640; | ||
840 | cam->height = 480; | ||
841 | break; | ||
842 | default: | ||
843 | info("320x240 mode selected"); | ||
844 | cam->width = 320; | ||
845 | cam->height = 240; | ||
846 | break; | ||
847 | } | ||
848 | |||
849 | m0d1[0] = mode; | ||
850 | m1[2].value = 0xf000 + mode; | ||
851 | m2[1].value = 0xf000 + mode; | ||
852 | header2[437] = cam->height / 256; | ||
853 | header2[438] = cam->height % 256; | ||
854 | header2[439] = cam->width / 256; | ||
855 | header2[440] = cam->width % 256; | ||
856 | |||
857 | cam->nb = 0; | ||
858 | cam->brightness = 64; | ||
859 | mutex_init(&cam->lock); | ||
860 | |||
861 | if (video_register_device(cam->vdev, VFL_TYPE_GRABBER, -1) == -1) { | ||
862 | info("video_register_device failed"); | ||
863 | video_device_release(cam->vdev); | ||
864 | kfree(cam->buffer); | ||
865 | kfree(cam); | ||
866 | return -ENODEV; | ||
867 | } | ||
868 | |||
869 | usb_set_intfdata(intf, cam); | ||
870 | |||
871 | info(DRIVER_DESC " controlling video device %d", cam->vdev->minor); | ||
872 | return 0; | ||
873 | } | ||
874 | |||
875 | |||
876 | static void zr364xx_disconnect(struct usb_interface *intf) | ||
877 | { | ||
878 | struct zr364xx_camera *cam = usb_get_intfdata(intf); | ||
879 | usb_set_intfdata(intf, NULL); | ||
880 | dev_set_drvdata(&intf->dev, NULL); | ||
881 | info(DRIVER_DESC " webcam unplugged"); | ||
882 | if (cam->vdev) | ||
883 | video_unregister_device(cam->vdev); | ||
884 | cam->vdev = NULL; | ||
885 | kfree(cam->buffer); | ||
886 | if (cam->framebuf) | ||
887 | vfree(cam->framebuf); | ||
888 | kfree(cam); | ||
889 | } | ||
890 | |||
891 | |||
892 | |||
893 | /**********************/ | ||
894 | /* Module integration */ | ||
895 | /**********************/ | ||
896 | |||
897 | static struct usb_driver zr364xx_driver = { | ||
898 | .name = "zr364xx", | ||
899 | .probe = zr364xx_probe, | ||
900 | .disconnect = zr364xx_disconnect, | ||
901 | .id_table = device_table | ||
902 | }; | ||
903 | |||
904 | |||
905 | static int __init zr364xx_init(void) | ||
906 | { | ||
907 | int retval; | ||
908 | retval = usb_register(&zr364xx_driver) < 0; | ||
909 | if (retval) | ||
910 | info("usb_register failed!"); | ||
911 | else | ||
912 | info(DRIVER_DESC " module loaded"); | ||
913 | return retval; | ||
914 | } | ||
915 | |||
916 | |||
917 | static void __exit zr364xx_exit(void) | ||
918 | { | ||
919 | info(DRIVER_DESC " module unloaded"); | ||
920 | usb_deregister(&zr364xx_driver); | ||
921 | } | ||
922 | |||
923 | |||
924 | module_init(zr364xx_init); | ||
925 | module_exit(zr364xx_exit); | ||
926 | |||
927 | MODULE_AUTHOR(DRIVER_AUTHOR); | ||
928 | MODULE_DESCRIPTION(DRIVER_DESC); | ||
929 | MODULE_LICENSE("GPL"); | ||