#include "bttvp.h"
#include <media/v4l2-common.h>
#include <media/tvaudio.h>
+#include <media/msp3400.h>
#include <linux/dma-mapping.h>
audio_mux(struct bttv *btv, int input, int mute)
{
int gpio_val, signal;
- struct v4l2_audio aud_input;
struct v4l2_control ctrl;
struct i2c_client *c;
- memset(&aud_input, 0, sizeof(aud_input));
gpio_inout(bttv_tvcards[btv->c.type].gpiomask,
bttv_tvcards[btv->c.type].gpiomask);
signal = btread(BT848_DSTATUS) & BT848_DSTATUS_HLOC;
gpio_val = bttv_tvcards[btv->c.type].gpiomute;
else
gpio_val = bttv_tvcards[btv->c.type].gpiomux[input];
- aud_input.index = btv->audio;
gpio_bits(bttv_tvcards[btv->c.type].gpiomask, gpio_val);
if (bttv_gpio)
return 0;
ctrl.id = V4L2_CID_AUDIO_MUTE;
- /* take automute into account, just btv->mute is not enough */
- ctrl.value = mute;
+ ctrl.value = btv->mute;
bttv_call_i2c_clients(btv, VIDIOC_S_CTRL, &ctrl);
c = btv->i2c_msp34xx_client;
- if (c)
- c->driver->command(c, VIDIOC_S_AUDIO, &aud_input);
+ if (c) {
+ struct v4l2_routing route;
+
+ /* Note: the inputs tuner/radio/extern/intern are translated
+ to msp routings. This assumes common behavior for all msp3400
+ based TV cards. When this assumption fails, then the
+ specific MSP routing must be added to the card table.
+ For now this is sufficient. */
+ switch (input) {
+ case TVAUDIO_INPUT_RADIO:
+ route.input = MSP_INPUT(MSP_IN_SCART2, MSP_IN_TUNER1,
+ MSP_DSP_IN_SCART, MSP_DSP_IN_SCART);
+ break;
+ case TVAUDIO_INPUT_EXTERN:
+ route.input = MSP_INPUT(MSP_IN_SCART1, MSP_IN_TUNER1,
+ MSP_DSP_IN_SCART, MSP_DSP_IN_SCART);
+ break;
+ case TVAUDIO_INPUT_INTERN:
+ /* Yes, this is the same input as for RADIO. I doubt
+ if this is ever used. The only board with an INTERN
+ input is the BTTV_BOARD_AVERMEDIA98. I wonder how
+ that was tested. My guess is that the whole INTERN
+ input does not work. */
+ route.input = MSP_INPUT(MSP_IN_SCART2, MSP_IN_TUNER1,
+ MSP_DSP_IN_SCART, MSP_DSP_IN_SCART);
+ break;
+ case TVAUDIO_INPUT_TUNER:
+ default:
+ route.input = MSP_INPUT_DEFAULT;
+ break;
+ }
+ route.output = MSP_OUTPUT_DEFAULT;
+ c->driver->command(c, VIDIOC_INT_S_AUDIO_ROUTING, &route);
+ }
c = btv->i2c_tvaudio_client;
- if (c)
- c->driver->command(c, VIDIOC_S_AUDIO, &aud_input);
+ if (c) {
+ struct v4l2_routing route;
+
+ route.input = input;
+ route.output = 0;
+ c->driver->command(c, VIDIOC_INT_S_AUDIO_ROUTING, &route);
+ }
return 0;
}
static void
i2c_vidiocschan(struct bttv *btv)
{
- struct video_channel c;
+ v4l2_std_id std = bttv_tvnorms[btv->tvnorm].v4l2_id;
- memset(&c,0,sizeof(c));
- c.norm = btv->tvnorm;
- c.channel = btv->input;
- bttv_call_i2c_clients(btv,VIDIOCSCHAN,&c);
+ bttv_call_i2c_clients(btv, VIDIOC_S_STD, &std);
if (btv->c.type == BTTV_BOARD_VOODOOTV_FM)
- bttv_tda9880_setnorm(btv,c.norm);
+ bttv_tda9880_setnorm(btv,btv->tvnorm);
}
static int
break;
if (i == BTTV_CTLS)
return -EINVAL;
- if (i >= 4 && i <= 8) {
+ if (btv->audio_hook && i >= 4 && i <= 8) {
memset(&va,0,sizeof(va));
- bttv_call_i2c_clients(btv, VIDIOCGAUDIO, &va);
- if (btv->audio_hook)
- btv->audio_hook(btv,&va,0);
+ btv->audio_hook(btv,&va,0);
+ switch (c->id) {
+ case V4L2_CID_AUDIO_MUTE:
+ c->value = (VIDEO_AUDIO_MUTE & va.flags) ? 1 : 0;
+ break;
+ case V4L2_CID_AUDIO_VOLUME:
+ c->value = va.volume;
+ break;
+ case V4L2_CID_AUDIO_BALANCE:
+ c->value = va.balance;
+ break;
+ case V4L2_CID_AUDIO_BASS:
+ c->value = va.bass;
+ break;
+ case V4L2_CID_AUDIO_TREBLE:
+ c->value = va.treble;
+ break;
+ }
+ return 0;
}
switch (c->id) {
case V4L2_CID_BRIGHTNESS:
break;
case V4L2_CID_AUDIO_MUTE:
- c->value = (VIDEO_AUDIO_MUTE & va.flags) ? 1 : 0;
- break;
case V4L2_CID_AUDIO_VOLUME:
- c->value = va.volume;
- break;
case V4L2_CID_AUDIO_BALANCE:
- c->value = va.balance;
- break;
case V4L2_CID_AUDIO_BASS:
- c->value = va.bass;
- break;
case V4L2_CID_AUDIO_TREBLE:
- c->value = va.treble;
+ bttv_call_i2c_clients(btv,VIDIOC_G_CTRL,c);
break;
case V4L2_CID_PRIVATE_CHROMA_AGC:
break;
if (i == BTTV_CTLS)
return -EINVAL;
- if (i >= 4 && i <= 8) {
+ if (btv->audio_hook && i >= 4 && i <= 8) {
memset(&va,0,sizeof(va));
- bttv_call_i2c_clients(btv, VIDIOCGAUDIO, &va);
- if (btv->audio_hook)
- btv->audio_hook(btv,&va,0);
+ btv->audio_hook(btv,&va,0);
+ switch (c->id) {
+ case V4L2_CID_AUDIO_MUTE:
+ if (c->value) {
+ va.flags |= VIDEO_AUDIO_MUTE;
+ audio_mute(btv, 1);
+ } else {
+ va.flags &= ~VIDEO_AUDIO_MUTE;
+ audio_mute(btv, 0);
+ }
+ break;
+
+ case V4L2_CID_AUDIO_VOLUME:
+ va.volume = c->value;
+ break;
+ case V4L2_CID_AUDIO_BALANCE:
+ va.balance = c->value;
+ break;
+ case V4L2_CID_AUDIO_BASS:
+ va.bass = c->value;
+ break;
+ case V4L2_CID_AUDIO_TREBLE:
+ va.treble = c->value;
+ break;
+ }
+ btv->audio_hook(btv,&va,1);
+ return 0;
}
switch (c->id) {
case V4L2_CID_BRIGHTNESS:
bt848_sat(btv,c->value);
break;
case V4L2_CID_AUDIO_MUTE:
- if (c->value) {
- va.flags |= VIDEO_AUDIO_MUTE;
- audio_mute(btv, 1);
- } else {
- va.flags &= ~VIDEO_AUDIO_MUTE;
- audio_mute(btv, 0);
- }
- break;
-
+ audio_mute(btv, c->value);
+ /* fall through */
case V4L2_CID_AUDIO_VOLUME:
- va.volume = c->value;
- break;
case V4L2_CID_AUDIO_BALANCE:
- va.balance = c->value;
- break;
case V4L2_CID_AUDIO_BASS:
- va.bass = c->value;
- break;
case V4L2_CID_AUDIO_TREBLE:
- va.treble = c->value;
+ bttv_call_i2c_clients(btv,VIDIOC_S_CTRL,c);
break;
case V4L2_CID_PRIVATE_CHROMA_AGC:
default:
return -EINVAL;
}
- if (i >= 4 && i <= 8) {
- bttv_call_i2c_clients(btv, VIDIOCSAUDIO, &va);
- if (btv->audio_hook)
- btv->audio_hook(btv,&va,1);
- }
return 0;
}
}
case VIDIOCSFREQ:
{
- unsigned long *freq = arg;
+ struct v4l2_frequency freq;
+
+ memset(&freq, 0, sizeof(freq));
+ freq.frequency = *(unsigned long *)arg;
mutex_lock(&btv->lock);
- btv->freq=*freq;
- bttv_call_i2c_clients(btv,VIDIOCSFREQ,freq);
+ freq.type = btv->radio_user ? V4L2_TUNER_RADIO : V4L2_TUNER_ANALOG_TV;
+ btv->freq = *(unsigned long *)arg;
+ bttv_call_i2c_clients(btv,VIDIOC_S_FREQUENCY,&freq);
if (btv->has_matchbox && btv->radio_user)
- tea5757_set_freq(btv,*freq);
+ tea5757_set_freq(btv,*(unsigned long *)arg);
mutex_unlock(&btv->lock);
return 0;
}
memset(i,0,sizeof(*i));
i->index = n;
i->type = V4L2_INPUT_TYPE_CAMERA;
- i->audioset = 0;
+ i->audioset = 1;
if (i->index == bttv_tvcards[btv->c.type].tuner) {
sprintf(i->name, "Television");
i->type = V4L2_INPUT_TYPE_TUNER;
return -EINVAL;
mutex_lock(&btv->lock);
memset(t,0,sizeof(*t));
+ t->rxsubchans = V4L2_TUNER_SUB_MONO;
+ bttv_call_i2c_clients(btv, VIDIOC_G_TUNER, t);
strcpy(t->name, "Television");
- t->type = V4L2_TUNER_ANALOG_TV;
t->capability = V4L2_TUNER_CAP_NORM;
- t->rxsubchans = V4L2_TUNER_SUB_MONO;
+ t->type = V4L2_TUNER_ANALOG_TV;
if (btread(BT848_DSTATUS)&BT848_DSTATUS_HLOC)
t->signal = 0xffff;
- {
- struct video_tuner tuner;
-
- memset(&tuner, 0, sizeof (tuner));
- tuner.rangehigh = 0xffffffffUL;
- bttv_call_i2c_clients(btv, VIDIOCGTUNER, &tuner);
- t->rangelow = tuner.rangelow;
- t->rangehigh = tuner.rangehigh;
- }
- {
+
+ if (btv->audio_hook) {
/* Hmmm ... */
struct video_audio va;
memset(&va, 0, sizeof(struct video_audio));
- bttv_call_i2c_clients(btv, VIDIOCGAUDIO, &va);
- if (btv->audio_hook)
- btv->audio_hook(btv,&va,0);
+ btv->audio_hook(btv,&va,0);
+ t->audmode = V4L2_TUNER_MODE_MONO;
+ t->rxsubchans = V4L2_TUNER_SUB_MONO;
if(va.mode & VIDEO_SOUND_STEREO) {
- t->audmode = V4L2_TUNER_MODE_STEREO;
- t->rxsubchans |= V4L2_TUNER_SUB_STEREO;
+ t->audmode = V4L2_TUNER_MODE_STEREO;
+ t->rxsubchans = V4L2_TUNER_SUB_STEREO;
}
- if(va.mode & VIDEO_SOUND_LANG1) {
+ if(va.mode & VIDEO_SOUND_LANG2) {
t->audmode = V4L2_TUNER_MODE_LANG1;
t->rxsubchans = V4L2_TUNER_SUB_LANG1
| V4L2_TUNER_SUB_LANG2;
if (0 != t->index)
return -EINVAL;
mutex_lock(&btv->lock);
- {
+ bttv_call_i2c_clients(btv, VIDIOC_S_TUNER, t);
+ if (btv->audio_hook) {
struct video_audio va;
memset(&va, 0, sizeof(struct video_audio));
- bttv_call_i2c_clients(btv, VIDIOCGAUDIO, &va);
if (t->audmode == V4L2_TUNER_MODE_MONO)
va.mode = VIDEO_SOUND_MONO;
- else if (t->audmode == V4L2_TUNER_MODE_STEREO)
+ else if (t->audmode == V4L2_TUNER_MODE_STEREO ||
+ t->audmode == V4L2_TUNER_MODE_LANG1_LANG2)
va.mode = VIDEO_SOUND_STEREO;
else if (t->audmode == V4L2_TUNER_MODE_LANG1)
va.mode = VIDEO_SOUND_LANG1;
else if (t->audmode == V4L2_TUNER_MODE_LANG2)
va.mode = VIDEO_SOUND_LANG2;
- bttv_call_i2c_clients(btv, VIDIOCSAUDIO, &va);
- if (btv->audio_hook)
- btv->audio_hook(btv,&va,1);
+ btv->audio_hook(btv,&va,1);
}
mutex_unlock(&btv->lock);
return 0;
return -EINVAL;
mutex_lock(&btv->lock);
btv->freq = f->frequency;
- bttv_call_i2c_clients(btv,VIDIOCSFREQ,&btv->freq);
+ bttv_call_i2c_clients(btv,VIDIOC_S_FREQUENCY,f);
if (btv->has_matchbox && btv->radio_user)
tea5757_set_freq(btv,btv->freq);
mutex_unlock(&btv->lock);
}
case VIDIOC_LOG_STATUS:
{
+ printk(KERN_INFO "bttv%d: ================= START STATUS CARD #%d =================\n", btv->c.nr, btv->c.nr);
bttv_call_i2c_clients(btv, VIDIOC_LOG_STATUS, NULL);
+ printk(KERN_INFO "bttv%d: ================== END STATUS CARD #%d ==================\n", btv->c.nr, btv->c.nr);
return 0;
}
fbuf->bytesperline = btv->fbuf.fmt.bytesperline;
if (fh->ovfmt)
fbuf->depth = fh->ovfmt->depth;
+ else {
+ if (fbuf->width)
+ fbuf->depth = ((fbuf->bytesperline<<3)
+ + (fbuf->width-1) )
+ /fbuf->width;
+ else
+ fbuf->depth = 0;
+ }
return 0;
}
case VIDIOCSFBUF:
return 0;
}
*c = bttv_ctls[i];
- if (i >= 4 && i <= 8) {
+ if (btv->audio_hook && i >= 4 && i <= 8) {
struct video_audio va;
memset(&va,0,sizeof(va));
- bttv_call_i2c_clients(btv, VIDIOCGAUDIO, &va);
- if (btv->audio_hook)
- btv->audio_hook(btv,&va,0);
+ btv->audio_hook(btv,&va,0);
switch (bttv_ctls[i].id) {
case V4L2_CID_AUDIO_VOLUME:
if (!(va.flags & VIDEO_AUDIO_VOLUME))
return videobuf_mmap_mapper(bttv_queue(fh),vma);
}
-static struct file_operations bttv_fops =
+static const struct file_operations bttv_fops =
{
.owner = THIS_MODULE,
.open = bttv_open,
return cmd.result;
}
-static struct file_operations radio_fops =
+static const struct file_operations radio_fops =
{
.owner = THIS_MODULE,
.open = radio_open,
spin_unlock(&btv->s_lock);
}
-static irqreturn_t bttv_irq(int irq, void *dev_id, struct pt_regs * regs)
+static irqreturn_t bttv_irq(int irq, void *dev_id)
{
u32 stat,astat;
u32 dstat;
goto err;
printk(KERN_INFO "bttv%d: registered device video%d\n",
btv->c.nr,btv->video_dev->minor & 0x1f);
- video_device_create_file(btv->video_dev, &class_device_attr_card);
+ if (class_device_create_file(&btv->video_dev->class_dev,
+ &class_device_attr_card)<0) {
+ printk(KERN_ERR "bttv%d: class_device_create_file 'card' "
+ "failed\n", btv->c.nr);
+ goto err;
+ }
/* vbi */
btv->vbi_dev = vdev_init(btv, &bttv_vbi_template, "vbi");
if (!request_mem_region(pci_resource_start(dev,0),
pci_resource_len(dev,0),
btv->c.name)) {
- printk(KERN_WARNING "bttv%d: can't request iomem (0x%lx).\n",
- btv->c.nr, pci_resource_start(dev,0));
+ printk(KERN_WARNING "bttv%d: can't request iomem (0x%llx).\n",
+ btv->c.nr,
+ (unsigned long long)pci_resource_start(dev,0));
return -EBUSY;
}
pci_set_master(dev);
pci_read_config_byte(dev, PCI_LATENCY_TIMER, &lat);
printk(KERN_INFO "bttv%d: Bt%d (rev %d) at %s, ",
bttv_num,btv->id, btv->revision, pci_name(dev));
- printk("irq: %d, latency: %d, mmio: 0x%lx\n",
- btv->c.pci->irq, lat, pci_resource_start(dev,0));
+ printk("irq: %d, latency: %d, mmio: 0x%llx\n",
+ btv->c.pci->irq, lat,
+ (unsigned long long)pci_resource_start(dev,0));
schedule();
- btv->bt848_mmio=ioremap(pci_resource_start(dev,0), 0x1000);
- if (NULL == ioremap(pci_resource_start(dev,0), 0x1000)) {
+ btv->bt848_mmio = ioremap(pci_resource_start(dev, 0), 0x1000);
+ if (NULL == btv->bt848_mmio) {
printk("bttv%d: ioremap() failed\n", btv->c.nr);
result = -EIO;
goto fail1;
/* disable irqs, register irq handler */
btwrite(0, BT848_INT_MASK);
result = request_irq(btv->c.pci->irq, bttv_irq,
- SA_SHIRQ | SA_INTERRUPT,btv->c.name,(void *)btv);
+ IRQF_SHARED | IRQF_DISABLED,btv->c.name,(void *)btv);
if (result < 0) {
printk(KERN_ERR "bttv%d: can't get IRQ %d\n",
bttv_num,btv->c.pci->irq);
return;
}
+#ifdef CONFIG_PM
static int bttv_suspend(struct pci_dev *pci_dev, pm_message_t state)
{
struct bttv *btv = pci_get_drvdata(pci_dev);
spin_unlock_irqrestore(&btv->s_lock,flags);
return 0;
}
+#endif
static struct pci_device_id bttv_pci_tbl[] = {
{PCI_VENDOR_ID_BROOKTREE, PCI_DEVICE_ID_BT848,
.id_table = bttv_pci_tbl,
.probe = bttv_probe,
.remove = __devexit_p(bttv_remove),
+#ifdef CONFIG_PM
.suspend = bttv_suspend,
.resume = bttv_resume,
+#endif
};
static int bttv_init_module(void)
{
+ int ret;
+
bttv_num = 0;
printk(KERN_INFO "bttv: driver version %d.%d.%d loaded\n",
bttv_check_chipset();
- bus_register(&bttv_sub_bus_type);
+ ret = bus_register(&bttv_sub_bus_type);
+ if (ret < 0) {
+ printk(KERN_WARNING "bttv: bus_register error: %d\n", ret);
+ return ret;
+ }
return pci_register_driver(&bttv_pci_driver);
}