From: Thierry Merle <thierry.merle@free.fr>
To: Chris Grove <dj_gerbil@tiscali.co.uk>
Cc: video4linux-list@redhat.com
Subject: Re: Hauppauge WinTV USB Model 566 PAL-I
Date: Tue, 02 Dec 2008 21:26:11 +0100 [thread overview]
Message-ID: <493599E3.1040806@free.fr> (raw)
In-Reply-To: <00bf01c95402$ae3c6070$0ab52150$@co.uk>
[-- Attachment #1: Type: text/plain, Size: 4334 bytes --]
Chris Grove a écrit :
> -----Original Message-----
> From: Thierry Merle [mailto:thierry.merle@free.fr]
> Sent: 01 December 2008 21:06
> To: Chris Grove
> Subject: Re: Hauppauge WinTV USB Model 566 PAL-I
>
> Chris Grove wrote:
>> -----Original Message-----
>> From: Thierry Merle [mailto:thierry.merle@free.fr]
>> Sent: 30 November 2008 21:13
>> To: Chris Grove
>> Cc: video4linux-list@redhat.com
>> Subject: Re: Hauppauge WinTV USB Model 566 PAL-I
>>
>> Chris Grove wrote:
>>> A further, slightly interesting development is that the s-video input
>>> works fine with no interference at all, also the TV picture in fine
>>> in
>> windows.
>>> Just thought that might help with a solution.
>>>
>> Right, this helps. We can deduce this does not come from the
>> decompression algorithm since it is the same whether the TV input or
>> the s-video input is selected.
>> I suspect a tda9887/saa7113 interface problem but just my intuition.
>> As it works under windows, can you do an usbsnoop
>> (http://www.linuxtv.org/v4lwiki/index.php/Usbsnoop)
>> Just open the TV application, let it tune the channel and stop the
>> application immediately in order to have a minimal capture file.
>>
>> For the audio over USB, in the ancient times I developed a audio
>> extension for usbvision. I don't even know what I did from it. I can
>> look for it if you want. I will need to sweep the dust (compilation
>> errors and so on) but should work.
>>
>> P.S.: this thread is really hard to follow now... please reply under
>> my answer so that we will be able to read that again :)
>>
>> Hi, yea sorry about that, Outlook always starts at the top of the message.
>> Anyway, I've used USB Snoop and ended up with a 45Mb file. Now I'm
>> guessing you don't need all of it so there is a portion of it below my
>> answer. As for the audio-over-usb, yes please, I wouldn't mind a look
>> at the code if you can find it. Anyway here's that sample, Thanks for the
> help.
> I found the audio-over-usb code (see attached). The code may need some
> cleanups and can cause kernel oops.
> The USB snoops need to be analyzed. Can you put it on a site so that I can
> download it?
> Nevertheless you can read what I wrote when I was programming the
> audio-over-usb driver here:
> http://thierry.merle.free.fr/articles.php?lng=en&pg=82
> The page was translated to English using google translate so there may be
> some problems of understanding :) For some more information about the
> usbvision chip, I wrote a page here:
> http://thierry.merle.free.fr/articles.php?lng=en&pg=68
>
> As a first step, I will look at the register accesses. They begin with a
> line like this:
> 00000000: 00000000: 42 33 00 00
> With the datasheet I can understand what the windows driver is setting.
>
> [SNIP]
>
>> -- URB_FUNCTION_CONTROL_TRANSFER:
>> PipeHandle = 8ac23cfc [endpoint 0x00000001]
>> TransferFlags = 00000000 (USBD_TRANSFER_DIRECTION_OUT,
>> ~USBD_SHORT_TRANSFER_OK)
>> TransferBufferLength = 00000001
>> TransferBuffer = a1745938
>> TransferBufferMDL = 00000000
>> 00000000: 30
>> UrbLink = 00000000
>> SetupPacket =
>> 00000000: 42 33 00 00 07 00 01 00
> For example here you have a register programming #07 (SER_MODE from the
> NT1004 datasheet).
> Value is 0x30 (TransferBufferMDL line). Means MODE=3.
> This is just for the example, this one is not interesting.
> There are other registers more interesting but I should have the complete
> log to find out.
>
> You may have sent me the sufficient data to investigate but in doubt give me
> the complete logs.
> Of course you can look at the problem if you are interested.
>
> Thanks
> Thierry
>
> Hi Thierry, Thanks for the links to you code, I'll download it and have a
> look. Here's hoping I can work out what's going on in it. I've uploaded the
> whole of the log to my skydrive, the link is below.
> http://cid-19380f9184511dde.skydrive.live.com/browse.aspx/Public
> To be honest I'm only a learner when it comes to linux and c++ programming,
> I'm more of a basic programmer so I need all the help I can get my hands on.
> Thanks in advance for all your help. Chris.
>
>
Sorry I forgot to attach the patch of audio-over-usb :)
It applies on the v4l-dvb tree and creates an optional module for audio.
Thierry
[-- Attachment #2: audio-over-usb.patch --]
[-- Type: text/plain, Size: 26544 bytes --]
# HG changeset patch
# User tmerle@lugdush.houroukhai.org
# Date 1187638538 -7200
# Node ID 543ee2df05e084be0142b9b290807a4d6c1eba59
# Parent b2e361a866a551424a7a71772347f2c1ca9990bd
usbvision: audio over USB
From: Thierry Merle <thierry.merle@free.fr>
This enables the audio over USB for usbvision that are capable to transmit
the audio data over the USB cable, to get rid of the line-in audio cable.
The quality is poor (16KHz stereo) compared to the line-in audio (44KHz stereo).
Signed-off-by: Thierry Merle <thierry.merle@free.fr>
diff -r b2e361a866a5 -r 543ee2df05e0 linux/drivers/media/video/usbvision/Kconfig
--- a/linux/drivers/media/video/usbvision/Kconfig Mon Jun 18 22:09:25 2007 +0200
+++ b/linux/drivers/media/video/usbvision/Kconfig Mon Aug 20 21:35:38 2007 +0200
@@ -10,3 +10,13 @@ config VIDEO_USBVISION
To compile this driver as a module, choose M here: the
module will be called usbvision.
+
+config VIDEO_USBVISION_AUDIO
+ tristate "Audio support for USB video devices based on Nogatech NT1003/1004/1005"
+ depends on USB && I2C
+ select VIDEO_USBVISION
+ ---help---
+ This is an audio driver for usbvision based usb video devices.
+
+ To compile this driver as a module, choose M here: the
+ module will be called usbvision-audio.
diff -r b2e361a866a5 -r 543ee2df05e0 linux/drivers/media/video/usbvision/Makefile
--- a/linux/drivers/media/video/usbvision/Makefile Mon Jun 18 22:09:25 2007 +0200
+++ b/linux/drivers/media/video/usbvision/Makefile Mon Aug 20 21:35:38 2007 +0200
@@ -1,5 +1,6 @@ usbvision-objs := usbvision-core.o usbv
usbvision-objs := usbvision-core.o usbvision-video.o usbvision-i2c.o usbvision-cards.o
obj-$(CONFIG_VIDEO_USBVISION) += usbvision.o
+obj-$(CONFIG_VIDEO_USBVISION_AUDIO) += usbvision-audio.o
EXTRA_CFLAGS += -Idrivers/media/video
diff -r b2e361a866a5 -r 543ee2df05e0 linux/drivers/media/video/usbvision/usbvision-audio.c
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/linux/drivers/media/video/usbvision/usbvision-audio.c Mon Aug 20 21:35:38 2007 +0200
@@ -0,0 +1,450 @@
+/*
+ * Nogatech usbvision NT100x audio extension
+ *
+ * Copyright (c) 2007 Thierry Merle <thierry.merle@free.fr>
+ * parameters taken from a patch from Hal Finkel.
+ *
+ * This driver is based on Markus Rechberger's em28xx-audio driver
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/kernel.h>
+#include <linux/usb.h>
+#include <linux/init.h>
+#include <linux/sound.h>
+#include <linux/spinlock.h>
+#include <linux/soundcard.h>
+#include <linux/slab.h>
+#include <linux/vmalloc.h>
+#include <linux/proc_fs.h>
+#include <linux/moduleparam.h>
+
+#include <sound/driver.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/info.h>
+#include <sound/initval.h>
+#include <sound/control.h>
+#include "usbvision.h"
+
+static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX;
+static int usbvision_cmd(struct usb_usbvision *dev, int cmd,int arg);
+
+#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,16)
+static int snd_pcm_alloc_vmalloc_buffer(snd_pcm_substream_t *subs, size_t size)
+#else
+static int snd_pcm_alloc_vmalloc_buffer(struct snd_pcm_substream *subs, size_t size)
+#endif
+{
+#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,16)
+ snd_pcm_runtime_t *runtime = subs->runtime;
+#else
+ struct snd_pcm_runtime *runtime = subs->runtime;
+#endif
+ if(runtime->dma_area){
+ if(runtime->dma_bytes > size)
+ return 0;
+ vfree(runtime->dma_area);
+ }
+ runtime->dma_area = vmalloc(size);
+ if(!runtime ->dma_area)
+ return -ENOMEM;
+ runtime->dma_bytes = size;
+ return 0;
+}
+
+#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,16)
+static snd_pcm_hardware_t snd_usbvision_hw_capture = {
+#else
+static struct snd_pcm_hardware snd_usbvision_hw_capture = {
+#endif
+ .info = SNDRV_PCM_INFO_BLOCK_TRANSFER | SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_MMAP_VALID,
+ .formats = SNDRV_PCM_FMTBIT_U8|SNDRV_PCM_FMTBIT_U16_LE,
+ .rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000,
+ .rate_min = 8000,
+ .rate_max = 16000,
+ .channels_min = 1,
+ .channels_max = 2,
+ .buffer_bytes_max = 62720,
+ .period_bytes_min = 12544,
+ .period_bytes_max = 12544,
+ .periods_min = 2,
+ .periods_max = 12544,
+};
+
+
+#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,16)
+static int snd_usbvision_capture_open(snd_pcm_substream_t *substream)
+#else
+static int snd_usbvision_capture_open(struct snd_pcm_substream *substream)
+#endif
+{
+ struct usb_usbvision *dev = snd_pcm_substream_chip(substream);
+#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,16)
+ snd_pcm_runtime_t *runtime = substream->runtime;
+#else
+ struct snd_pcm_runtime *runtime = substream->runtime;
+#endif
+ runtime->hw = snd_usbvision_hw_capture;
+ snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS);
+ dev->adev->capture_pcm_substream = substream;
+ runtime->private_data = dev;
+ return 0;
+}
+
+#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,16)
+static int snd_usbvision_pcm_close(snd_pcm_substream_t *substream)
+#else
+static int snd_usbvision_pcm_close(struct snd_pcm_substream *substream)
+#endif
+{
+ return 0;
+}
+
+#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,16)
+static int snd_usbvision_hw_capture_params(snd_pcm_substream_t *substream, snd_pcm_hw_params_t *hw_params)
+#else
+static int snd_usbvision_hw_capture_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *hw_params)
+#endif
+{
+ unsigned int channels, rate, format;
+ int ret;
+ ret = snd_pcm_alloc_vmalloc_buffer(substream, params_buffer_bytes(hw_params));
+ format = params_format(hw_params);
+ rate = params_rate(hw_params);
+ channels = params_channels(hw_params);
+ /* TODO: set up usbvision audio chip to deliver the correct audio format, current default is 48000hz multiplexed => 96000hz mono
+ which shouldn't matter since analogue TV only supports mono*/
+ return 0;
+}
+
+#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,16)
+static int snd_usbvision_hw_capture_free(snd_pcm_substream_t *substream)
+#else
+static int snd_usbvision_hw_capture_free(struct snd_pcm_substream *substream)
+#endif
+{
+ struct usb_usbvision *dev = snd_pcm_substream_chip(substream);
+ if(dev->adev->capture_stream==Stream_On){
+ dev->adev->users--;
+ usbvision_cmd(dev,USBVISION_CAPTURE_STREAM_EN,0);
+ }
+ return 0;
+}
+
+#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,16)
+static int snd_usbvision_prepare(snd_pcm_substream_t *substream)
+#else
+static int snd_usbvision_prepare(struct snd_pcm_substream *substream)
+#endif
+{
+ return 0;
+}
+
+#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,16)
+static int snd_usbvision_capture_trigger(snd_pcm_substream_t *substream, int cmd)
+#else
+static int snd_usbvision_capture_trigger(struct snd_pcm_substream *substream, int cmd)
+#endif
+{
+ struct usb_usbvision *dev = snd_pcm_substream_chip(substream);
+ switch(cmd){
+ case SNDRV_PCM_TRIGGER_START:
+ usbvision_cmd(dev,USBVISION_CAPTURE_STREAM_EN,1);
+ return 0;
+ case SNDRV_PCM_TRIGGER_STOP:
+ return 0;
+ default:
+ return -EINVAL;
+ }
+}
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0) || LINUX_VERSION_CODE > KERNEL_VERSION(2,6,18)
+static void usbvision_audio_isocirq(struct urb *urb)
+{
+#else
+static void usbvision_audio_isocirq(struct urb *urb, struct pt_regs *regs)
+{
+#endif
+ struct usb_usbvision *dev=urb->context;
+ int i;
+ unsigned int oldptr;
+ unsigned long flags;
+ int period_elapsed = 0;
+ int status;
+ unsigned char *cp;
+ unsigned int stride;
+#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,16)
+ snd_pcm_substream_t *substream;
+ snd_pcm_runtime_t *runtime;
+#else
+ struct snd_pcm_substream *substream;
+ struct snd_pcm_runtime *runtime;
+#endif
+ if(dev->adev->capture_pcm_substream){
+ substream=dev->adev->capture_pcm_substream;
+ runtime=substream->runtime;
+
+ stride = runtime->frame_bits >> 3;
+ for(i=0;i<urb->number_of_packets;i++){
+ int length=urb->iso_frame_desc[i].actual_length/stride;
+ cp=(unsigned char *) urb->transfer_buffer + urb->iso_frame_desc[i].offset;
+
+ if(!length)
+ continue;
+
+ spin_lock_irqsave(&dev->adev->slock, flags);
+ oldptr = dev->adev->hwptr_done_capture;
+ dev->adev->hwptr_done_capture +=length;
+ if(dev->adev->hwptr_done_capture >= runtime->buffer_size)
+ dev->adev->hwptr_done_capture -= runtime->buffer_size;
+
+ dev->adev->capture_transfer_done += length;
+ if(dev->adev->capture_transfer_done >= runtime->period_size){
+ dev->adev->capture_transfer_done -= runtime->period_size;
+ period_elapsed=1;
+ }
+ spin_unlock_irqrestore(&dev->adev->slock, flags);
+
+ if(oldptr + length >= runtime->buffer_size){
+ unsigned int cnt = runtime->buffer_size-oldptr-1;
+ memcpy(runtime->dma_area+oldptr*stride, cp , cnt*stride);
+ memcpy(runtime->dma_area, cp + cnt, length*stride - cnt*stride);
+ } else {
+ memcpy(runtime->dma_area+oldptr*stride, cp, length*stride);
+ }
+ }
+ if(period_elapsed){
+ snd_pcm_period_elapsed(substream);
+ }
+ }
+ urb->status = 0;
+ if((status = usb_submit_urb(urb, GFP_ATOMIC))){
+ err("%s: resubmit of audio urb failed (error=%i)\n", __FUNCTION__, status);
+ }
+ return;
+}
+
+static int usbvision_isoc_audio_deinit(struct usb_usbvision *dev)
+{
+ int i;
+ for(i=0;i<USBVISION_AUDIO_BUFS;i++){
+ usb_kill_urb(dev->adev->urb[i]);
+ usb_free_urb(dev->adev->urb[i]);
+ dev->adev->urb[i]=NULL;
+ }
+ return 0;
+}
+
+static int usbvision_init_audio_isoc(struct usb_usbvision *dev){
+ int i;
+ int errCode;
+ const int sb_size=USBVISION_NUM_AUDIO_PACKETS * USBVISION_AUDIO_MAX_PACKET_SIZE;
+ for(i=0;i<USBVISION_AUDIO_BUFS;i++){
+ struct urb *urb;
+ int j,k;
+ dev->adev->transfer_buffer[i]=kmalloc(sb_size,GFP_ATOMIC);
+ if(!dev->adev->transfer_buffer[i]){
+ return -ENOMEM;
+ }
+ memset(dev->adev->transfer_buffer[i],0x80,sb_size);
+ urb = usb_alloc_urb(USBVISION_NUM_AUDIO_PACKETS,GFP_ATOMIC);
+ if(urb){
+ urb->dev=dev->dev;
+ urb->context=dev;
+ urb->pipe=usb_rcvisocpipe(dev->dev,0x83);
+ urb->transfer_flags = URB_ISO_ASAP;
+ urb->transfer_buffer = dev->adev->transfer_buffer[i];
+ urb->interval=1;
+ urb->complete = usbvision_audio_isocirq;
+ urb->number_of_packets = USBVISION_NUM_AUDIO_PACKETS;
+ urb->transfer_buffer_length = sb_size;
+ for(j=k=0; j<USBVISION_NUM_AUDIO_PACKETS;j++,k+=USBVISION_AUDIO_MAX_PACKET_SIZE){
+ urb->iso_frame_desc[j].offset = k;
+ urb->iso_frame_desc[j].length=USBVISION_AUDIO_MAX_PACKET_SIZE;
+ }
+ dev->adev->urb[i]=urb;
+ } else {
+ return -ENOMEM;
+ }
+ }
+ for(i=0;i<USBVISION_AUDIO_BUFS;i++){
+ errCode = usb_submit_urb(dev->adev->urb[i], GFP_ATOMIC);
+ if (errCode){
+ usbvision_isoc_audio_deinit(dev);
+ return errCode;
+ }
+ }
+ return 0;
+}
+
+
+static int usbvision_cmd(struct usb_usbvision *dev, int cmd,int arg){
+ switch(cmd){
+ case USBVISION_CAPTURE_STREAM_EN:
+ if(dev->adev->capture_stream == Stream_Off && arg==1){
+ dev->adev->users++;
+ dev->adev->capture_stream=Stream_On;
+ usbvision_init_audio_isoc(dev);
+ } else if (dev->adev->capture_stream==Stream_On && arg==0){
+ dev->adev->capture_stream=Stream_Off;
+ usbvision_isoc_audio_deinit(dev);
+ } else {
+ printk("An underrun occured very likely... ignoring it\n");
+ }
+ return 0;
+ default:
+ return -EINVAL;
+ }
+}
+
+
+#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,16)
+static snd_pcm_uframes_t snd_usbvision_capture_pointer(snd_pcm_substream_t *substream)
+#else
+static snd_pcm_uframes_t snd_usbvision_capture_pointer(struct snd_pcm_substream *substream)
+#endif
+{
+ struct usb_usbvision *dev;
+ snd_pcm_uframes_t hwptr_done;
+ dev = snd_pcm_substream_chip(substream);
+ hwptr_done = dev->adev->hwptr_done_capture;
+ return hwptr_done;
+}
+
+#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,16)
+static struct page *snd_pcm_get_vmalloc_page(snd_pcm_substream_t *subs,
+ unsigned long offset)
+#else
+static struct page *snd_pcm_get_vmalloc_page(struct snd_pcm_substream *subs,
+ unsigned long offset)
+#endif
+{
+ void *pageptr = subs->runtime->dma_area + offset;
+ return vmalloc_to_page(pageptr);
+}
+
+
+#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,16)
+static snd_pcm_ops_t snd_usbvision_pcm_capture = {
+#else
+static struct snd_pcm_ops snd_usbvision_pcm_capture = {
+#endif
+ .open = snd_usbvision_capture_open,
+ .close = snd_usbvision_pcm_close,
+ .ioctl = snd_pcm_lib_ioctl,
+ .hw_params = snd_usbvision_hw_capture_params,
+ .hw_free = snd_usbvision_hw_capture_free,
+ .prepare = snd_usbvision_prepare,
+ .trigger = snd_usbvision_capture_trigger,
+ .pointer = snd_usbvision_capture_pointer,
+ .page = snd_pcm_get_vmalloc_page,
+};
+
+
+static int usbvision_audio_init(struct usb_usbvision *dev){
+ struct usbvision_audio *adev;
+#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,16)
+ snd_pcm_t *pcm;
+ snd_card_t *card;
+#else
+ struct snd_pcm *pcm;
+ struct snd_card *card;
+#endif
+ static int devnr;
+ int ret;
+ int err;
+ printk("usbvision-audio.c: probing for usbvision audio for usb\n");
+ printk("usbvision-audio.c: Copyright (C) 2006 Markus Rechberger\n");
+ adev=kzalloc(sizeof(*adev),GFP_KERNEL);
+ if(!adev){
+ printk("usbvision-audio.c: out of memory\n");
+ return -1;
+ }
+ card = snd_card_new(index[devnr], "Usbvision Audio", THIS_MODULE,0);
+ if(card==NULL){
+ kfree(adev);
+ return -ENOMEM;
+ }
+
+ spin_lock_init(&adev->slock);
+ ret=snd_pcm_new(card, "Usbvision Audio", 0, 0, 1, &pcm);
+ snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_usbvision_pcm_capture);
+ pcm->info_flags = 0;
+ pcm->private_data = dev;
+ strcpy(pcm->name,"Usbvision Capture");
+ strcpy(card->driver, "Nogatech Usbvision Audio");
+ strcpy(card->shortname, "Usbvision Audio");
+ strcpy(card->longname,"Nogatech Usbvision Audio");
+
+ if((err = snd_card_register(card))<0){
+ snd_card_free(card);
+ return -ENOMEM;
+ }
+ adev->sndcard=card;
+ adev->udev=dev->dev;
+ dev->adev=adev;
+ return 0;
+}
+
+static int usbvision_audio_fini(struct usb_usbvision *dev){
+ if(dev==NULL)
+ return 0;
+ if(dev->adev){
+ snd_card_free(dev->adev->sndcard);
+ kfree(dev->adev);
+ dev->adev=NULL;
+ }
+ return 0;
+}
+
+static struct usbvision_ops audio_ops = {
+ .id = USBVISION_AUDIO,
+ .name = "Usbvision Audio Extension",
+ .init = usbvision_audio_init,
+ .fini = usbvision_audio_fini,
+};
+
+static int __init usbvision_alsa_register(void)
+{
+ request_module("usbvision");
+ request_module("tuner");
+ return usbvision_register_extension(&audio_ops);
+}
+
+static void __exit usbvision_alsa_unregister(void)
+{
+ usbvision_unregister_extension(&audio_ops);
+}
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Thierry Merle <thierry.merle@free.fr>");
+MODULE_DESCRIPTION("Usbvision Audio driver");
+
+module_init(usbvision_alsa_register);
+module_exit(usbvision_alsa_unregister);
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-basic-offset: 8
+ * End:
+ */
diff -r b2e361a866a5 -r 543ee2df05e0 linux/drivers/media/video/usbvision/usbvision-core.c
--- a/linux/drivers/media/video/usbvision/usbvision-core.c Mon Jun 18 22:09:25 2007 +0200
+++ b/linux/drivers/media/video/usbvision/usbvision-core.c Mon Aug 20 21:35:38 2007 +0200
@@ -2706,6 +2706,9 @@ int usbvision_muxsel(struct usb_usbvisio
return 0;
}
+
+EXPORT_SYMBOL(usbvision_write_reg);
+
/*
* Overrides for Emacs so that we follow Linus's tabbing style.
* ---------------------------------------------------------------------------
diff -r b2e361a866a5 -r 543ee2df05e0 linux/drivers/media/video/usbvision/usbvision-video.c
--- a/linux/drivers/media/video/usbvision/usbvision-video.c Mon Jun 18 22:09:25 2007 +0200
+++ b/linux/drivers/media/video/usbvision/usbvision-video.c Mon Aug 20 21:35:38 2007 +0200
@@ -101,6 +101,11 @@ USBVISION_DRIVER_VERSION_PATCHLEVEL)
"." __stringify(USBVISION_DRIVER_VERSION_MINOR)\
"." __stringify(USBVISION_DRIVER_VERSION_PATCHLEVEL)
+/* Extension management stuff */
+static LIST_HEAD(usbvision_extension_devlist);
+static DEFINE_MUTEX(usbvision_extension_devlist_lock);
+static struct usb_usbvision *usbvisionDevice = NULL;
+
#define ENABLE_HEXDUMP 0 /* Enable if you need it */
@@ -138,6 +143,8 @@ static struct usbvision_v4l2_format_st u
/* Function prototypes */
static void usbvision_release(struct usb_usbvision *usbvision);
+static void usbvision_init_extensions(struct usb_usbvision *usbvision);
+static void usbvision_fini_extensions(struct usb_usbvision *usbvision);
/* Default initalization of device driver parameters */
/* Set the default format for ISOC endpoint */
@@ -1789,6 +1796,7 @@ static struct usb_usbvision *usbvision_a
}
#endif
+ usbvisionDevice = usbvision;
usbvision->dev = dev;
init_MUTEX(&usbvision->lock); /* to 1 == available */
@@ -1846,6 +1854,7 @@ static void usbvision_release(struct usb
}
kfree(usbvision);
+ usbvisionDevice = NULL;
PDEBUG(DBG_PROBE, "success");
}
@@ -1898,6 +1907,7 @@ static int __devinit usbvision_probe(str
struct usb_device *dev = usb_get_dev(interface_to_usbdev(intf));
struct usb_interface *uif;
__u8 ifnum = intf->altsetting->desc.bInterfaceNumber;
+ __u8 numEndpoints = intf->altsetting->desc.bNumEndpoints;
const struct usb_host_interface *interface;
struct usb_usbvision *usbvision = NULL;
const struct usb_endpoint_descriptor *endpoint;
@@ -1921,6 +1931,7 @@ static int __devinit usbvision_probe(str
interface = &dev->actconfig->interface[ifnum]->altsetting[0];
}
endpoint = &interface->endpoint[1].desc;
+
if ((endpoint->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) !=
USB_ENDPOINT_XFER_ISOC) {
err("%s: interface %d. has non-ISO endpoint!",
@@ -1941,6 +1952,8 @@ static int __devinit usbvision_probe(str
return -ENOMEM;
}
+ usbvision->video_endp = endpoint->bEndpointAddress;
+
if (dev->descriptor.bNumConfigurations > 1) {
usbvision->bridgeType = BRIDGE_NT1004;
} else if (model == DAZZLE_DVC_90_REV_1_SECAM) {
@@ -1987,13 +2000,13 @@ static int __devinit usbvision_probe(str
usbvision->remove_pending = 0;
usbvision->iface = ifnum;
usbvision->ifaceAlt = 0;
- usbvision->video_endp = endpoint->bEndpointAddress;
usbvision->isocPacketSize = 0;
usbvision->usb_bandwidth = 0;
usbvision->user = 0;
usbvision->streaming = Stream_Off;
usbvision_register_video(usbvision);
usbvision_configure_video(usbvision);
+ usbvision_init_extensions(usbvision);
up(&usbvision->lock);
@@ -2044,6 +2057,8 @@ static void __devexit usbvision_disconne
// At this time we ask to cancel outstanding URBs
usbvision_stop_isoc(usbvision);
+
+ usbvision_fini_extensions(usbvision);
if (usbvision->power) {
usbvision_i2c_unregister(usbvision);
@@ -2074,6 +2089,66 @@ static void __devexit usbvision_disconne
#endif
}
+static void usbvision_init_extensions(struct usb_usbvision *usbvision)
+{
+ struct list_head *pos=NULL;
+ struct usbvision_ops *ops=NULL;
+
+ PDEBUG(DBG_PROBE, "Initialize extensions");
+
+ mutex_lock(&usbvision_extension_devlist_lock);
+ if(!list_empty(&usbvision_extension_devlist)){
+ list_for_each(pos, &usbvision_extension_devlist){
+ ops=list_entry(pos,struct usbvision_ops, next);
+ ops->init(usbvision);
+ }
+ }
+ mutex_unlock(&usbvision_extension_devlist_lock);
+}
+
+static void usbvision_fini_extensions(struct usb_usbvision *usbvision)
+{
+ struct list_head *pos=NULL;
+ struct usbvision_ops *ops=NULL;
+
+ PDEBUG(DBG_PROBE, "Propagate the uninit to extensions");
+
+ mutex_lock(&usbvision_extension_devlist_lock);
+ if(!list_empty(&usbvision_extension_devlist)){
+ list_for_each(pos, &usbvision_extension_devlist){
+ ops=list_entry(pos,struct usbvision_ops, next);
+ ops->fini(usbvision);
+ }
+ }
+ mutex_unlock(&usbvision_extension_devlist_lock);
+}
+
+int usbvision_register_extension(struct usbvision_ops *ops)
+{
+ mutex_lock(&usbvision_extension_devlist_lock);
+ list_add_tail(&ops->next,&usbvision_extension_devlist);
+ printk("Usbvision: Added (%s) extension\n",ops->name);
+ if(usbvisionDevice) {
+ if(ops->init(usbvisionDevice)<0) {
+ printk("usbvision: error on init of (%s) extension\n",ops->name);
+ }
+ else printk("Usbvision: Initialized (%s) extension\n",ops->name);
+ }
+ mutex_unlock(&usbvision_extension_devlist_lock);
+ return 0;
+}
+
+void usbvision_unregister_extension(struct usbvision_ops *ops)
+{
+ mutex_lock(&usbvision_extension_devlist_lock);
+ printk("Usbvision: Removed (%s) extension\n",ops->name);
+ list_del(&ops->next);
+ if(usbvisionDevice)
+ ops->fini(usbvisionDevice);
+ mutex_unlock(&usbvision_extension_devlist_lock);
+ printk("Usbvision: Removed (%s) extension\n",ops->name);
+}
+
static struct usb_driver usbvision_driver = {
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,31)) && \
(LINUX_VERSION_CODE < KERNEL_VERSION(2,6,16))
@@ -2127,6 +2202,8 @@ static void __exit usbvision_exit(void)
module_init(usbvision_init);
module_exit(usbvision_exit);
+EXPORT_SYMBOL(usbvision_register_extension);
+EXPORT_SYMBOL(usbvision_unregister_extension);
/*
* Overrides for Emacs so that we follow Linus's tabbing style.
diff -r b2e361a866a5 -r 543ee2df05e0 linux/drivers/media/video/usbvision/usbvision.h
--- a/linux/drivers/media/video/usbvision/usbvision.h Mon Jun 18 22:09:25 2007 +0200
+++ b/linux/drivers/media/video/usbvision/usbvision.h Mon Aug 20 21:35:38 2007 +0200
@@ -37,12 +37,22 @@
#include <media/v4l2-common.h>
#include <media/tuner.h>
#include <linux/videodev2.h>
+/* ALSA stuff */
+#include <linux/soundcard.h>
+#include <sound/driver.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
#define USBVISION_DEBUG /* Turn on debug messages */
#ifndef VID_HARDWARE_USBVISION
#define VID_HARDWARE_USBVISION 34 /* USBVision Video Grabber */
#endif
+
+#define USBVISION_VIDEO 0x01
+#define USBVISION_VBI 0x02
+#define USBVISION_AUDIO 0x04
#define USBVISION_PWR_REG 0x00
#define USBVISION_SSPND_EN (1 << 1)
@@ -122,6 +132,19 @@
#define USBVISION_BUF_THR 0x30
#define USBVISION_DVI_YUV 0x31
#define USBVISION_AUDIO_CONT 0x32
+ #define USBVISION_AUDIO_EN (1 << 0)
+ #define USBVISION_BULK_EN (1 << 1)
+ #define USBVISION_AUDIO_8B (0 << 2)
+ #define USBVISION_AUDIO_12B (1 << 2)
+ #define USBVISION_AUDIO_14B (2 << 2)
+ #define USBVISION_AUDIO_16B (3 << 2)
+ #define USBVISION_AUDIO_MONO (0 << 4)
+ #define USBVISION_AUDIO_STEREO (1 << 4)
+ #define USBVISION_SAMP_8K (0 << 5)
+ #define USBVISION_SAMP_16K (1 << 5)
+ #define USBVISION_BITCLOCK_64 (1 << 6)
+ #define USBVISION_BITCLOCK_1644 (2 << 6)
+ #define USBVISION_BITCLOCK_2048 (3 << 6)
#define USBVISION_AUD_PK_LEN 0x33
#define USBVISION_BLK_PK_LEN 0x34
#define USBVISION_PCM_THR1 0x38
@@ -150,6 +173,12 @@
#define USBVISION_NUM_HEADERMARKER 20
#define USBVISION_NUMFRAMES 3 /* Maximum number of frames an application can get */
#define USBVISION_NUMSBUF 2 /* Dimensioning the USB S buffering */
+
+/* usbvision sound stuff */
+#define USBVISION_AUDIO_BUFS 5
+#define USBVISION_NUM_AUDIO_PACKETS 32
+#define USBVISION_AUDIO_MAX_PACKET_SIZE 66 /* static value */
+#define USBVISION_CAPTURE_STREAM_EN 1
#define USBVISION_POWEROFF_TIME 3 * (HZ) // 3 seconds
@@ -355,6 +384,34 @@ struct usbvision_device_data_st {
__s16 Y_Offset;
};
+struct usbvision_audio {
+ char name[50];
+ char *transfer_buffer[USBVISION_AUDIO_BUFS];
+ struct urb *urb[USBVISION_AUDIO_BUFS];
+ struct usb_device *udev;
+ unsigned int capture_transfer_done; /* byte amount of acquired data (in bytes) */
+#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,16)
+ snd_pcm_substream_t *capture_pcm_substream;
+#else
+ struct snd_pcm_substream *capture_pcm_substream;
+#endif
+ unsigned int hwptr_done_capture; /* pointer to the beginning of a new period available (in bytes) */
+#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,16)
+ snd_card_t *sndcard;
+#else
+ struct snd_card *sndcard;
+#endif
+ int users;
+ enum StreamState capture_stream;
+ /* low-level register parameters stuff */
+ unsigned char channels;
+ unsigned char samp_rate;
+ unsigned char bits_per_sample;
+ unsigned char bit_clk_freq;
+
+ spinlock_t slock;
+};
+
/* Declared on usbvision-cards.c */
extern struct usbvision_device_data_st usbvision_device_data[];
extern struct usb_device_id usbvision_table[];
@@ -363,6 +420,7 @@ struct usb_usbvision {
struct video_device *vdev; /* Video Device */
struct video_device *rdev; /* Radio Device */
struct video_device *vbi; /* VBI Device */
+ struct usbvision_audio *adev; /* Audio over USB */
/* i2c Declaration Section*/
struct i2c_adapter i2c_adap;
@@ -440,6 +498,7 @@ struct usb_usbvision {
unsigned int ctl_input; /* selected input */
v4l2_std_id tvnormId; /* selected tv norm */
unsigned char video_endp; /* 0x82 for USBVISION devices based */
+ unsigned char audio_endp; /* 0x83 for USBVISION devices based */
// Decompression stuff:
unsigned char *IntraFrameBuffer; /* Buffer for reference frame */
@@ -472,6 +531,14 @@ struct usb_usbvision {
int ComprBlockTypes[4];
};
+/* usbvision extension management part */
+struct usbvision_ops {
+ struct list_head next;
+ char *name;
+ int id;
+ int (*init)(struct usb_usbvision *);
+ int (*fini)(struct usb_usbvision *);
+};
/* --------------------------------------------------------------- */
/* defined in usbvision-i2c.c */
@@ -519,6 +586,10 @@ void usbvision_reset_powerOffTimer(struc
void usbvision_reset_powerOffTimer(struct usb_usbvision *usbvision);
int usbvision_power_off(struct usb_usbvision *usbvision);
int usbvision_power_on(struct usb_usbvision *usbvision);
+
+/* defined in usbvision-video.c */
+int usbvision_register_extension(struct usbvision_ops *dev);
+void usbvision_unregister_extension(struct usbvision_ops *dev);
#endif /* __LINUX_USBVISION_H */
[-- Attachment #3: Type: text/plain, Size: 164 bytes --]
--
video4linux-list mailing list
Unsubscribe mailto:video4linux-list-request@redhat.com?subject=unsubscribe
https://www.redhat.com/mailman/listinfo/video4linux-list
next prev parent reply other threads:[~2008-12-02 20:26 UTC|newest]
Thread overview: 15+ messages / expand[flat|nested] mbox.gz Atom feed top
2008-11-28 11:55 Hauppauge WinTV USB Model 566 PAL-I Chris Grove
2008-11-29 16:54 ` Chris Grove
2008-11-29 21:02 ` Thierry Merle
2008-11-30 14:04 ` Chris Grove
2008-11-30 15:10 ` Thierry Merle
2008-11-30 15:43 ` Chris Grove
2008-11-30 20:30 ` Chris Grove
2008-11-30 21:12 ` Thierry Merle
[not found] ` <000301c95341$504c5810$f0e50830$@co.uk>
[not found] ` <493451C5.9010406@free.fr>
2008-12-01 22:18 ` Chris Grove
2008-12-02 20:26 ` Thierry Merle [this message]
2008-12-02 22:00 ` Thierry Merle
2008-12-03 0:26 ` Chris Grove
2008-12-03 6:26 ` Thierry Merle
2008-12-03 9:03 ` Chris Grove
-- strict thread matches above, loose matches on Subject: below --
2008-11-29 18:24 CityK
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=493599E3.1040806@free.fr \
--to=thierry.merle@free.fr \
--cc=dj_gerbil@tiscali.co.uk \
--cc=video4linux-list@redhat.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox