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 an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.