diff options
Diffstat (limited to 'drivers/media/usb/em28xx')
-rw-r--r-- | drivers/media/usb/em28xx/em28xx-audio.c | 16 | ||||
-rw-r--r-- | drivers/media/usb/em28xx/em28xx-cards.c | 33 | ||||
-rw-r--r-- | drivers/media/usb/em28xx/em28xx-i2c.c | 3 | ||||
-rw-r--r-- | drivers/media/usb/em28xx/em28xx-video.c | 124 | ||||
-rw-r--r-- | drivers/media/usb/em28xx/em28xx.h | 8 |
5 files changed, 145 insertions, 39 deletions
diff --git a/drivers/media/usb/em28xx/em28xx-audio.c b/drivers/media/usb/em28xx/em28xx-audio.c index 67481fc82445..49c9b70b632b 100644 --- a/drivers/media/usb/em28xx/em28xx-audio.c +++ b/drivers/media/usb/em28xx/em28xx-audio.c @@ -843,11 +843,11 @@ static int em28xx_audio_urb_init(struct em28xx *dev) dev->adev.transfer_buffer = kcalloc(num_urb, sizeof(*dev->adev.transfer_buffer), - GFP_ATOMIC); + GFP_KERNEL); if (!dev->adev.transfer_buffer) return -ENOMEM; - dev->adev.urb = kcalloc(num_urb, sizeof(*dev->adev.urb), GFP_ATOMIC); + dev->adev.urb = kcalloc(num_urb, sizeof(*dev->adev.urb), GFP_KERNEL); if (!dev->adev.urb) { kfree(dev->adev.transfer_buffer); return -ENOMEM; @@ -860,14 +860,14 @@ static int em28xx_audio_urb_init(struct em28xx *dev) int j, k; void *buf; - urb = usb_alloc_urb(npackets, GFP_ATOMIC); + urb = usb_alloc_urb(npackets, GFP_KERNEL); if (!urb) { em28xx_audio_free_urb(dev); return -ENOMEM; } dev->adev.urb[i] = urb; - buf = usb_alloc_coherent(udev, npackets * ep_size, GFP_ATOMIC, + buf = usb_alloc_coherent(udev, npackets * ep_size, GFP_KERNEL, &urb->transfer_dma); if (!buf) { dev_err(&dev->intf->dev, @@ -939,11 +939,11 @@ static int em28xx_audio_init(struct em28xx *dev) snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_em28xx_pcm_capture); pcm->info_flags = 0; pcm->private_data = dev; - strcpy(pcm->name, "Empia 28xx Capture"); + strscpy(pcm->name, "Empia 28xx Capture", sizeof(pcm->name)); - strcpy(card->driver, "Em28xx-Audio"); - strcpy(card->shortname, "Em28xx Audio"); - strcpy(card->longname, "Empia Em28xx Audio"); + strscpy(card->driver, "Em28xx-Audio", sizeof(card->driver)); + strscpy(card->shortname, "Em28xx Audio", sizeof(card->shortname)); + strscpy(card->longname, "Empia Em28xx Audio", sizeof(card->longname)); INIT_WORK(&adev->wq_trigger, audio_trigger); diff --git a/drivers/media/usb/em28xx/em28xx-cards.c b/drivers/media/usb/em28xx/em28xx-cards.c index 71c829f31d3b..87b887b7604e 100644 --- a/drivers/media/usb/em28xx/em28xx-cards.c +++ b/drivers/media/usb/em28xx/em28xx-cards.c @@ -2141,13 +2141,13 @@ const struct em28xx_board em28xx_boards[] = { .input = { { .type = EM28XX_VMUX_COMPOSITE, .vmux = TVP5150_COMPOSITE1, - .amux = EM28XX_AUDIO_SRC_LINE, + .amux = EM28XX_AMUX_LINE_IN, .gpio = terratec_av350_unmute_gpio, }, { .type = EM28XX_VMUX_SVIDEO, .vmux = TVP5150_SVIDEO, - .amux = EM28XX_AUDIO_SRC_LINE, + .amux = EM28XX_AMUX_LINE_IN, .gpio = terratec_av350_unmute_gpio, } }, }, @@ -3039,6 +3039,9 @@ static int em28xx_hint_board(struct em28xx *dev) static void em28xx_card_setup(struct em28xx *dev) { + int i, j, idx; + bool duplicate_entry; + /* * If the device can be a webcam, seek for a sensor. * If sensor is not found, then it isn't a webcam. @@ -3195,6 +3198,32 @@ static void em28xx_card_setup(struct em28xx *dev) /* Allow override tuner type by a module parameter */ if (tuner >= 0) dev->tuner_type = tuner; + + /* + * Dynamically generate a list of valid audio inputs for this + * specific board, mapping them via enum em28xx_amux. + */ + + idx = 0; + for (i = 0; i < MAX_EM28XX_INPUT; i++) { + if (!INPUT(i)->type) + continue; + + /* Skip already mapped audio inputs */ + duplicate_entry = false; + for (j = 0; j < idx; j++) { + if (INPUT(i)->amux == dev->amux_map[j]) { + duplicate_entry = true; + break; + } + } + if (duplicate_entry) + continue; + + dev->amux_map[idx++] = INPUT(i)->amux; + } + for (; idx < MAX_EM28XX_INPUT; idx++) + dev->amux_map[idx] = EM28XX_AMUX_UNUSED; } void em28xx_setup_xc3028(struct em28xx *dev, struct xc2028_ctrl *ctl) diff --git a/drivers/media/usb/em28xx/em28xx-i2c.c b/drivers/media/usb/em28xx/em28xx-i2c.c index e19d6342e0d0..02c13d71e6c1 100644 --- a/drivers/media/usb/em28xx/em28xx-i2c.c +++ b/drivers/media/usb/em28xx/em28xx-i2c.c @@ -985,7 +985,8 @@ int em28xx_i2c_register(struct em28xx *dev, unsigned int bus, dev->i2c_adap[bus] = em28xx_adap_template; dev->i2c_adap[bus].dev.parent = &dev->intf->dev; - strcpy(dev->i2c_adap[bus].name, dev_name(&dev->intf->dev)); + strscpy(dev->i2c_adap[bus].name, dev_name(&dev->intf->dev), + sizeof(dev->i2c_adap[bus].name)); dev->i2c_bus[bus].bus = bus; dev->i2c_bus[bus].algo_type = algo_type; diff --git a/drivers/media/usb/em28xx/em28xx-video.c b/drivers/media/usb/em28xx/em28xx-video.c index 68571bf36d28..f43717ea831d 100644 --- a/drivers/media/usb/em28xx/em28xx-video.c +++ b/drivers/media/usb/em28xx/em28xx-video.c @@ -1093,6 +1093,8 @@ int em28xx_start_analog_streaming(struct vb2_queue *vq, unsigned int count) em28xx_videodbg("%s\n", __func__); + dev->v4l2->field_count = 0; + /* * Make sure streaming is not already in progress for this type * of filehandle (e.g. video, vbi) @@ -1471,9 +1473,9 @@ static int vidioc_try_fmt_vid_cap(struct file *file, void *priv, fmt = format_by_fourcc(f->fmt.pix.pixelformat); if (!fmt) { - em28xx_videodbg("Fourcc format (%08x) invalid.\n", - f->fmt.pix.pixelformat); - return -EINVAL; + fmt = &format[0]; + em28xx_videodbg("Fourcc format (%08x) invalid. Using default (%08x).\n", + f->fmt.pix.pixelformat, fmt->fourcc); } if (dev->board.is_em2800) { @@ -1666,6 +1668,7 @@ static int vidioc_enum_input(struct file *file, void *priv, { struct em28xx *dev = video_drvdata(file); unsigned int n; + int j; n = i->index; if (n >= MAX_EM28XX_INPUT) @@ -1675,7 +1678,7 @@ static int vidioc_enum_input(struct file *file, void *priv, i->type = V4L2_INPUT_TYPE_CAMERA; - strcpy(i->name, iname[INPUT(n)->type]); + strscpy(i->name, iname[INPUT(n)->type], sizeof(i->name)); if (INPUT(n)->type == EM28XX_VMUX_TELEVISION) i->type = V4L2_INPUT_TYPE_TUNER; @@ -1685,6 +1688,12 @@ static int vidioc_enum_input(struct file *file, void *priv, if (dev->is_webcam) i->capabilities = 0; + /* Dynamically generates an audioset bitmask */ + i->audioset = 0; + for (j = 0; j < MAX_EM28XX_INPUT; j++) + if (dev->amux_map[j] != EM28XX_AMUX_UNUSED) + i->audioset |= 1 << j; + return 0; } @@ -1710,61 +1719,121 @@ static int vidioc_s_input(struct file *file, void *priv, unsigned int i) return 0; } -static int vidioc_g_audio(struct file *file, void *priv, struct v4l2_audio *a) +static int em28xx_fill_audio_input(struct em28xx *dev, + const char *s, + struct v4l2_audio *a, + unsigned int index) { - struct em28xx *dev = video_drvdata(file); + unsigned int idx = dev->amux_map[index]; + + /* + * With msp3400, almost all mappings use the default (amux = 0). + * The only one may use a different value is WinTV USB2, where it + * can also be SCART1 input. + * As it is very doubtful that we would see new boards with msp3400, + * let's just reuse the existing switch. + */ + if (dev->has_msp34xx && idx != EM28XX_AMUX_UNUSED) + idx = EM28XX_AMUX_LINE_IN; - switch (a->index) { + switch (idx) { case EM28XX_AMUX_VIDEO: - strcpy(a->name, "Television"); + strscpy(a->name, "Television", sizeof(a->name)); break; case EM28XX_AMUX_LINE_IN: - strcpy(a->name, "Line In"); + strscpy(a->name, "Line In", sizeof(a->name)); break; case EM28XX_AMUX_VIDEO2: - strcpy(a->name, "Television alt"); + strscpy(a->name, "Television alt", sizeof(a->name)); break; case EM28XX_AMUX_PHONE: - strcpy(a->name, "Phone"); + strscpy(a->name, "Phone", sizeof(a->name)); break; case EM28XX_AMUX_MIC: - strcpy(a->name, "Mic"); + strscpy(a->name, "Mic", sizeof(a->name)); break; case EM28XX_AMUX_CD: - strcpy(a->name, "CD"); + strscpy(a->name, "CD", sizeof(a->name)); break; case EM28XX_AMUX_AUX: - strcpy(a->name, "Aux"); + strscpy(a->name, "Aux", sizeof(a->name)); break; case EM28XX_AMUX_PCM_OUT: - strcpy(a->name, "PCM"); + strscpy(a->name, "PCM", sizeof(a->name)); break; + case EM28XX_AMUX_UNUSED: default: return -EINVAL; } - - a->index = dev->ctl_ainput; + a->index = index; a->capability = V4L2_AUDCAP_STEREO; + em28xx_videodbg("%s: audio input index %d is '%s'\n", + s, a->index, a->name); + return 0; } +static int vidioc_enumaudio(struct file *file, void *fh, struct v4l2_audio *a) +{ + struct em28xx *dev = video_drvdata(file); + + if (a->index >= MAX_EM28XX_INPUT) + return -EINVAL; + + return em28xx_fill_audio_input(dev, __func__, a, a->index); +} + +static int vidioc_g_audio(struct file *file, void *priv, struct v4l2_audio *a) +{ + struct em28xx *dev = video_drvdata(file); + int i; + + for (i = 0; i < MAX_EM28XX_INPUT; i++) + if (dev->ctl_ainput == dev->amux_map[i]) + return em28xx_fill_audio_input(dev, __func__, a, i); + + /* Should never happen! */ + return -EINVAL; +} + static int vidioc_s_audio(struct file *file, void *priv, const struct v4l2_audio *a) { struct em28xx *dev = video_drvdata(file); + int idx, i; if (a->index >= MAX_EM28XX_INPUT) return -EINVAL; - if (!INPUT(a->index)->type) + + idx = dev->amux_map[a->index]; + + if (idx == EM28XX_AMUX_UNUSED) return -EINVAL; - dev->ctl_ainput = INPUT(a->index)->amux; - dev->ctl_aoutput = INPUT(a->index)->aout; + dev->ctl_ainput = idx; + + /* + * FIXME: This is wrong, as different inputs at em28xx_cards + * may have different audio outputs. So, the right thing + * to do is to implement VIDIOC_G_AUDOUT/VIDIOC_S_AUDOUT. + * With the current board definitions, this would work fine, + * as, currently, all boards fit. + */ + for (i = 0; i < MAX_EM28XX_INPUT; i++) + if (idx == dev->amux_map[i]) + break; + if (i == MAX_EM28XX_INPUT) + return -EINVAL; + + dev->ctl_aoutput = INPUT(i)->aout; if (!dev->ctl_aoutput) dev->ctl_aoutput = EM28XX_AOUT_MASTER; + em28xx_videodbg("%s: set audio input to %d\n", __func__, + dev->ctl_ainput); + return 0; } @@ -1776,7 +1845,7 @@ static int vidioc_g_tuner(struct file *file, void *priv, if (t->index != 0) return -EINVAL; - strcpy(t->name, "Tuner"); + strscpy(t->name, "Tuner", sizeof(t->name)); v4l2_device_call_all(&dev->v4l2->v4l2_dev, 0, tuner, g_tuner, t); return 0; @@ -1833,9 +1902,9 @@ static int vidioc_g_chip_info(struct file *file, void *priv, if (chip->match.addr > 1) return -EINVAL; if (chip->match.addr == 1) - strlcpy(chip->name, "ac97", sizeof(chip->name)); + strscpy(chip->name, "ac97", sizeof(chip->name)); else - strlcpy(chip->name, + strscpy(chip->name, dev->v4l2->v4l2_dev.name, sizeof(chip->name)); return 0; } @@ -1920,8 +1989,8 @@ static int vidioc_querycap(struct file *file, void *priv, struct em28xx_v4l2 *v4l2 = dev->v4l2; struct usb_device *udev = interface_to_usbdev(dev->intf); - strlcpy(cap->driver, "em28xx", sizeof(cap->driver)); - strlcpy(cap->card, em28xx_boards[dev->model].name, sizeof(cap->card)); + strscpy(cap->driver, "em28xx", sizeof(cap->driver)); + strscpy(cap->card, em28xx_boards[dev->model].name, sizeof(cap->card)); usb_make_path(udev, cap->bus_info, sizeof(cap->bus_info)); if (vdev->vfl_type == VFL_TYPE_GRABBER) @@ -1954,7 +2023,7 @@ static int vidioc_enum_fmt_vid_cap(struct file *file, void *priv, if (unlikely(f->index >= ARRAY_SIZE(format))) return -EINVAL; - strlcpy(f->description, format[f->index].name, sizeof(f->description)); + strscpy(f->description, format[f->index].name, sizeof(f->description)); f->pixelformat = format[f->index].fourcc; return 0; @@ -2045,7 +2114,7 @@ static int radio_g_tuner(struct file *file, void *priv, if (unlikely(t->index > 0)) return -EINVAL; - strcpy(t->name, "Radio"); + strscpy(t->name, "Radio", sizeof(t->name)); v4l2_device_call_all(&dev->v4l2->v4l2_dev, 0, tuner, g_tuner, t); @@ -2302,6 +2371,7 @@ static const struct v4l2_ioctl_ops video_ioctl_ops = { .vidioc_try_fmt_vbi_cap = vidioc_g_fmt_vbi_cap, .vidioc_s_fmt_vbi_cap = vidioc_g_fmt_vbi_cap, .vidioc_enum_framesizes = vidioc_enum_framesizes, + .vidioc_enumaudio = vidioc_enumaudio, .vidioc_g_audio = vidioc_g_audio, .vidioc_s_audio = vidioc_s_audio, diff --git a/drivers/media/usb/em28xx/em28xx.h b/drivers/media/usb/em28xx/em28xx.h index 953caac025f2..a551072e62ed 100644 --- a/drivers/media/usb/em28xx/em28xx.h +++ b/drivers/media/usb/em28xx/em28xx.h @@ -335,6 +335,9 @@ enum em28xx_usb_audio_type { /** * em28xx_amux - describes the type of audio input used by em28xx * + * @EM28XX_AMUX_UNUSED: + * Used only on em28xx dev->map field, in order to mark an entry + * as unused. * @EM28XX_AMUX_VIDEO: * On devices without AC97, this is the only value that it is currently * allowed. @@ -369,7 +372,8 @@ enum em28xx_usb_audio_type { * same time, via the alsa mux. */ enum em28xx_amux { - EM28XX_AMUX_VIDEO, + EM28XX_AMUX_UNUSED = -1, + EM28XX_AMUX_VIDEO = 0, EM28XX_AMUX_LINE_IN, /* Some less-common mixer setups */ @@ -692,6 +696,8 @@ struct em28xx { unsigned int ctl_input; // selected input unsigned int ctl_ainput;// selected audio input unsigned int ctl_aoutput;// selected audio output + enum em28xx_amux amux_map[MAX_EM28XX_INPUT]; + int mute; int volume; |