[media] staging: media: Remove easycap driver
This driver has been replaced by stk1160. Signed-off-by: Ezequiel Garcia <elezegarcia@gmail.com> Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
This commit is contained in:
parent
9cb2173e6e
commit
062ef0d4bb
|
@ -25,8 +25,6 @@ source "drivers/staging/media/cxd2099/Kconfig"
|
||||||
|
|
||||||
source "drivers/staging/media/dt3155v4l/Kconfig"
|
source "drivers/staging/media/dt3155v4l/Kconfig"
|
||||||
|
|
||||||
source "drivers/staging/media/easycap/Kconfig"
|
|
||||||
|
|
||||||
source "drivers/staging/media/go7007/Kconfig"
|
source "drivers/staging/media/go7007/Kconfig"
|
||||||
|
|
||||||
source "drivers/staging/media/solo6x10/Kconfig"
|
source "drivers/staging/media/solo6x10/Kconfig"
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
obj-$(CONFIG_DVB_AS102) += as102/
|
obj-$(CONFIG_DVB_AS102) += as102/
|
||||||
obj-$(CONFIG_DVB_CXD2099) += cxd2099/
|
obj-$(CONFIG_DVB_CXD2099) += cxd2099/
|
||||||
obj-$(CONFIG_EASYCAP) += easycap/
|
|
||||||
obj-$(CONFIG_LIRC_STAGING) += lirc/
|
obj-$(CONFIG_LIRC_STAGING) += lirc/
|
||||||
obj-$(CONFIG_SOLO6X10) += solo6x10/
|
obj-$(CONFIG_SOLO6X10) += solo6x10/
|
||||||
obj-$(CONFIG_VIDEO_DT3155) += dt3155v4l/
|
obj-$(CONFIG_VIDEO_DT3155) += dt3155v4l/
|
||||||
|
|
|
@ -1,30 +0,0 @@
|
||||||
config EASYCAP
|
|
||||||
tristate "EasyCAP USB ID 05e1:0408 support"
|
|
||||||
depends on USB && VIDEO_DEV && SND
|
|
||||||
select SND_PCM
|
|
||||||
|
|
||||||
---help---
|
|
||||||
This is an integrated audio/video driver for EasyCAP cards with
|
|
||||||
USB ID 05e1:0408. It supports two hardware variants:
|
|
||||||
|
|
||||||
* EasyCAP USB 2.0 Video Adapter with Audio, Model DC60,
|
|
||||||
having input cables labelled CVBS, S-VIDEO, AUDIO(L), AUDIO(R)
|
|
||||||
|
|
||||||
* EasyCAP002 4-Channel USB 2.0 DVR, having input cables labelled
|
|
||||||
1, 2, 3, 4 and an unlabelled input cable for a microphone.
|
|
||||||
|
|
||||||
To compile this driver as a module, choose M here: the
|
|
||||||
module will be called easycap
|
|
||||||
|
|
||||||
config EASYCAP_DEBUG
|
|
||||||
bool "Enable EasyCAP driver debugging"
|
|
||||||
depends on EASYCAP
|
|
||||||
|
|
||||||
---help---
|
|
||||||
This option enables debug printouts
|
|
||||||
|
|
||||||
To enable debug, pass the debug level to the debug module
|
|
||||||
parameter:
|
|
||||||
|
|
||||||
modprobe easycap debug=[0..9]
|
|
||||||
|
|
|
@ -1,10 +0,0 @@
|
||||||
easycap-objs := easycap_main.o
|
|
||||||
easycap-objs += easycap_low.o
|
|
||||||
easycap-objs += easycap_ioctl.o
|
|
||||||
easycap-objs += easycap_settings.o
|
|
||||||
easycap-objs += easycap_testcard.o
|
|
||||||
easycap-objs += easycap_sound.o
|
|
||||||
obj-$(CONFIG_EASYCAP) += easycap.o
|
|
||||||
|
|
||||||
ccflags-y := -Wall
|
|
||||||
|
|
|
@ -1,141 +0,0 @@
|
||||||
|
|
||||||
***********************************************************
|
|
||||||
* EasyCAP USB 2.0 Video Adapter with Audio, Model DC60 *
|
|
||||||
* and *
|
|
||||||
* EasyCAP002 4-Channel USB 2.0 DVR *
|
|
||||||
***********************************************************
|
|
||||||
Mike Thomas <rmthomas@sciolus.org>
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
SUPPORTED HARDWARE
|
|
||||||
------------------
|
|
||||||
|
|
||||||
This driver is intended for use with hardware having USB ID 05e1:0408.
|
|
||||||
Two kinds of EasyCAP have this USB ID, namely:
|
|
||||||
|
|
||||||
* EasyCAP USB 2.0 Video Adapter with Audio, Model DC60,
|
|
||||||
having input cables labelled CVBS, S-VIDEO, AUDIO(L), AUDIO(R)
|
|
||||||
|
|
||||||
* EasyCAP002 4-Channel USB 2.0 DVR, having input cables labelled
|
|
||||||
1, 2, 3, 4 and an unlabelled input cable for a microphone.
|
|
||||||
|
|
||||||
|
|
||||||
BUILD OPTIONS AND DEPENDENCIES
|
|
||||||
------------------------------
|
|
||||||
|
|
||||||
Unless EASYCAP_DEBUG is defined during compilation it will not be possible
|
|
||||||
to select a debug level at the time of module installation.
|
|
||||||
|
|
||||||
|
|
||||||
KNOWN RUNTIME ISSUES
|
|
||||||
--------------------
|
|
||||||
|
|
||||||
(1) Intentionally, this driver will not stream material which is unambiguously
|
|
||||||
identified by the hardware as copy-protected. Normal video output will be
|
|
||||||
present for about a minute but will then freeze when this situation arises.
|
|
||||||
|
|
||||||
(2) The controls for luminance, contrast, saturation, hue and volume may not
|
|
||||||
always work properly.
|
|
||||||
|
|
||||||
(3) Reduced-resolution S-Video seems to suffer from moire artefacts.
|
|
||||||
|
|
||||||
|
|
||||||
INPUT NUMBERING
|
|
||||||
---------------
|
|
||||||
|
|
||||||
For the EasyCAP with S-VIDEO input cable the driver regards a request for
|
|
||||||
inputs numbered 0 or 1 as referring to CVBS and a request for input
|
|
||||||
numbered 5 as referring to S-VIDEO.
|
|
||||||
|
|
||||||
For the EasyCAP with four CVBS inputs the driver expects to be asked for
|
|
||||||
any one of inputs numbered 1,2,3,4. If input 0 is asked for, it is
|
|
||||||
interpreted as input 1.
|
|
||||||
|
|
||||||
|
|
||||||
MODULE PARAMETERS
|
|
||||||
-----------------
|
|
||||||
|
|
||||||
Three module parameters are defined:
|
|
||||||
|
|
||||||
debug the easycap module is configured at diagnostic level n (0 to 9)
|
|
||||||
gain audio gain level n (0 to 31, default is 16)
|
|
||||||
bars whether to display testcard bars when incoming video signal is lost
|
|
||||||
0 => no, 1 => yes (default)
|
|
||||||
|
|
||||||
|
|
||||||
SUPPORTED TV STANDARDS AND RESOLUTIONS
|
|
||||||
--------------------------------------
|
|
||||||
|
|
||||||
The following TV standards are natively supported by the hardware and are
|
|
||||||
usable as (for example) the "norm=" parameter in the mplayer command:
|
|
||||||
|
|
||||||
PAL_BGHIN, NTSC_N_443,
|
|
||||||
PAL_Nc, NTSC_N,
|
|
||||||
SECAM, NTSC_M, NTSC_M_JP,
|
|
||||||
PAL_60, NTSC_443,
|
|
||||||
PAL_M.
|
|
||||||
|
|
||||||
In addition, the driver offers "custom" pseudo-standards with a framerate
|
|
||||||
which is 20% of the usual framerate. These pseudo-standards are named:
|
|
||||||
|
|
||||||
PAL_BGHIN_SLOW, NTSC_N_443_SLOW,
|
|
||||||
PAL_Nc_SLOW, NTSC_N_SLOW,
|
|
||||||
SECAM_SLOW, NTSC_M_SLOW, NTSC_M_JP_SLOW,
|
|
||||||
PAL_60_SLOW, NTSC_443_SLOW,
|
|
||||||
PAL_M_SLOW.
|
|
||||||
|
|
||||||
|
|
||||||
The available picture sizes are:
|
|
||||||
|
|
||||||
at 25 frames per second: 720x576, 704x576, 640x480, 360x288, 320x240;
|
|
||||||
at 30 frames per second: 720x480, 640x480, 360x240, 320x240.
|
|
||||||
|
|
||||||
|
|
||||||
WHAT'S TESTED AND WHAT'S NOT
|
|
||||||
----------------------------
|
|
||||||
|
|
||||||
This driver is known to work with mplayer, mencoder, tvtime, zoneminder,
|
|
||||||
xawtv, gstreamer and sufficiently recent versions of vlc. An interface
|
|
||||||
to ffmpeg is implemented, but serious audio-video synchronization problems
|
|
||||||
remain.
|
|
||||||
|
|
||||||
The driver is designed to support all the TV standards accepted by the
|
|
||||||
hardware, but as yet it has actually been tested on only a few of these.
|
|
||||||
|
|
||||||
I have been unable to test and calibrate the S-video input myself because I
|
|
||||||
do not possess any equipment with S-video output.
|
|
||||||
|
|
||||||
|
|
||||||
UDEV RULES
|
|
||||||
----------
|
|
||||||
|
|
||||||
In order that the special files /dev/easycap0 and /dev/easysnd1 are created
|
|
||||||
with conveniently relaxed permissions when the EasyCAP is plugged in, a file
|
|
||||||
is preferably to be provided in directory /etc/udev/rules.d with content:
|
|
||||||
|
|
||||||
ACTION!="add|change", GOTO="easycap_rules_end"
|
|
||||||
ATTRS{idVendor}=="05e1", ATTRS{idProduct}=="0408", \
|
|
||||||
MODE="0666", OWNER="root", GROUP="root"
|
|
||||||
LABEL="easycap_rules_end"
|
|
||||||
|
|
||||||
|
|
||||||
MODPROBE CONFIGURATION
|
|
||||||
----------------------
|
|
||||||
|
|
||||||
The easycap module is in competition with the module snd-usb-audio for the
|
|
||||||
EasyCAP's audio channel, and its installation can be aided by providing a
|
|
||||||
file in directory /etc/modprobe.d with content:
|
|
||||||
|
|
||||||
options easycap gain=16 bars=1
|
|
||||||
install easycap /sbin/rmmod snd-usb-audio; /sbin/modprobe --ignore-install easycap
|
|
||||||
|
|
||||||
|
|
||||||
ACKNOWLEGEMENTS AND REFERENCES
|
|
||||||
------------------------------
|
|
||||||
This driver makes use of information contained in the Syntek Semicon DC-1125
|
|
||||||
Driver, presently maintained at http://sourceforge.net/projects/syntekdriver/
|
|
||||||
by Nicolas Vivien. Particularly useful has been a patch to the latter driver
|
|
||||||
provided by Ivor Hewitt in January 2009. The NTSC implementation is taken
|
|
||||||
from the work of Ben Trask.
|
|
||||||
|
|
|
@ -1,567 +0,0 @@
|
||||||
/*****************************************************************************
|
|
||||||
* *
|
|
||||||
* easycap.h *
|
|
||||||
* *
|
|
||||||
*****************************************************************************/
|
|
||||||
/*
|
|
||||||
*
|
|
||||||
* Copyright (C) 2010 R.M. Thomas <rmthomas@sciolus.org>
|
|
||||||
*
|
|
||||||
*
|
|
||||||
* This 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.
|
|
||||||
*
|
|
||||||
* The software 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 software; if not, write to the Free Software
|
|
||||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
/*****************************************************************************/
|
|
||||||
/*---------------------------------------------------------------------------*/
|
|
||||||
/*
|
|
||||||
* THE FOLLOWING PARAMETERS ARE UNDEFINED:
|
|
||||||
*
|
|
||||||
* EASYCAP_DEBUG
|
|
||||||
*
|
|
||||||
* IF REQUIRED THEY MUST BE EXTERNALLY DEFINED, FOR EXAMPLE AS COMPILER
|
|
||||||
* OPTIONS.
|
|
||||||
*/
|
|
||||||
/*---------------------------------------------------------------------------*/
|
|
||||||
|
|
||||||
#ifndef __EASYCAP_H__
|
|
||||||
#define __EASYCAP_H__
|
|
||||||
|
|
||||||
/*---------------------------------------------------------------------------*/
|
|
||||||
/*
|
|
||||||
* THESE ARE NORMALLY DEFINED
|
|
||||||
*/
|
|
||||||
/*---------------------------------------------------------------------------*/
|
|
||||||
#define PATIENCE 500
|
|
||||||
#define PERSEVERE
|
|
||||||
/*---------------------------------------------------------------------------*/
|
|
||||||
/*
|
|
||||||
* THESE ARE FOR MAINTENANCE ONLY - NORMALLY UNDEFINED:
|
|
||||||
*/
|
|
||||||
/*---------------------------------------------------------------------------*/
|
|
||||||
#undef EASYCAP_TESTCARD
|
|
||||||
/*---------------------------------------------------------------------------*/
|
|
||||||
#include <linux/kernel.h>
|
|
||||||
#include <linux/errno.h>
|
|
||||||
#include <linux/init.h>
|
|
||||||
#include <linux/slab.h>
|
|
||||||
#include <linux/module.h>
|
|
||||||
#include <linux/kref.h>
|
|
||||||
#include <linux/usb.h>
|
|
||||||
#include <linux/uaccess.h>
|
|
||||||
|
|
||||||
#include <linux/i2c.h>
|
|
||||||
#include <linux/workqueue.h>
|
|
||||||
#include <linux/poll.h>
|
|
||||||
#include <linux/mm.h>
|
|
||||||
#include <linux/fs.h>
|
|
||||||
#include <linux/delay.h>
|
|
||||||
#include <linux/types.h>
|
|
||||||
|
|
||||||
#include <linux/vmalloc.h>
|
|
||||||
#include <linux/sound.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 <media/v4l2-dev.h>
|
|
||||||
#include <media/v4l2-device.h>
|
|
||||||
#include <linux/videodev2.h>
|
|
||||||
#include <linux/soundcard.h>
|
|
||||||
|
|
||||||
/*---------------------------------------------------------------------------*/
|
|
||||||
/* VENDOR, PRODUCT: Syntek Semiconductor Co., Ltd
|
|
||||||
*
|
|
||||||
* EITHER EasyCAP USB 2.0 Video Adapter with Audio, Model No. DC60
|
|
||||||
* with input cabling: AUDIO(L), AUDIO(R), CVBS, S-VIDEO.
|
|
||||||
*
|
|
||||||
* OR EasyCAP 4CHANNEL USB 2.0 DVR, Model No. EasyCAP002
|
|
||||||
* with input cabling: MICROPHONE, CVBS1, CVBS2, CVBS3, CVBS4.
|
|
||||||
*/
|
|
||||||
/*---------------------------------------------------------------------------*/
|
|
||||||
#define USB_EASYCAP_VENDOR_ID 0x05e1
|
|
||||||
#define USB_EASYCAP_PRODUCT_ID 0x0408
|
|
||||||
|
|
||||||
#define EASYCAP_DRIVER_VERSION "0.9.01"
|
|
||||||
#define EASYCAP_DRIVER_DESCRIPTION "easycapdc60"
|
|
||||||
|
|
||||||
#define DONGLE_MANY 8
|
|
||||||
#define INPUT_MANY 6
|
|
||||||
/*---------------------------------------------------------------------------*/
|
|
||||||
/*
|
|
||||||
* DEFAULT LUMINANCE, CONTRAST, SATURATION AND HUE
|
|
||||||
*/
|
|
||||||
/*---------------------------------------------------------------------------*/
|
|
||||||
#define SAA_0A_DEFAULT 0x7F
|
|
||||||
#define SAA_0B_DEFAULT 0x3F
|
|
||||||
#define SAA_0C_DEFAULT 0x2F
|
|
||||||
#define SAA_0D_DEFAULT 0x00
|
|
||||||
/*---------------------------------------------------------------------------*/
|
|
||||||
/*
|
|
||||||
* VIDEO STREAMING PARAMETERS:
|
|
||||||
* USB 2.0 PROVIDES FOR HIGH-BANDWIDTH ENDPOINTS WITH AN UPPER LIMIT
|
|
||||||
* OF 3072 BYTES PER MICROFRAME for wMaxPacketSize.
|
|
||||||
*/
|
|
||||||
/*---------------------------------------------------------------------------*/
|
|
||||||
#define VIDEO_ISOC_BUFFER_MANY 16
|
|
||||||
#define VIDEO_ISOC_ORDER 3
|
|
||||||
#define VIDEO_ISOC_FRAMESPERDESC ((unsigned int) 1 << VIDEO_ISOC_ORDER)
|
|
||||||
#define USB_2_0_MAXPACKETSIZE 3072
|
|
||||||
#if (USB_2_0_MAXPACKETSIZE > PAGE_SIZE)
|
|
||||||
#error video_isoc_buffer[.] will not be big enough
|
|
||||||
#endif
|
|
||||||
#define VIDEO_JUNK_TOLERATE VIDEO_ISOC_BUFFER_MANY
|
|
||||||
#define VIDEO_LOST_TOLERATE 50
|
|
||||||
/*---------------------------------------------------------------------------*/
|
|
||||||
/*
|
|
||||||
* VIDEO BUFFERS
|
|
||||||
*/
|
|
||||||
/*---------------------------------------------------------------------------*/
|
|
||||||
#define FIELD_BUFFER_SIZE (203 * PAGE_SIZE)
|
|
||||||
#define FRAME_BUFFER_SIZE (405 * PAGE_SIZE)
|
|
||||||
#define FIELD_BUFFER_MANY 4
|
|
||||||
#define FRAME_BUFFER_MANY 6
|
|
||||||
/*---------------------------------------------------------------------------*/
|
|
||||||
/*
|
|
||||||
* AUDIO STREAMING PARAMETERS
|
|
||||||
*/
|
|
||||||
/*---------------------------------------------------------------------------*/
|
|
||||||
#define AUDIO_ISOC_BUFFER_MANY 16
|
|
||||||
#define AUDIO_ISOC_ORDER 1
|
|
||||||
#define AUDIO_ISOC_FRAMESPERDESC 32
|
|
||||||
#define AUDIO_ISOC_BUFFER_SIZE (PAGE_SIZE << AUDIO_ISOC_ORDER)
|
|
||||||
/*---------------------------------------------------------------------------*/
|
|
||||||
/*
|
|
||||||
* AUDIO BUFFERS
|
|
||||||
*/
|
|
||||||
/*---------------------------------------------------------------------------*/
|
|
||||||
#define AUDIO_FRAGMENT_MANY 32
|
|
||||||
#define PAGES_PER_AUDIO_FRAGMENT 4
|
|
||||||
/*---------------------------------------------------------------------------*/
|
|
||||||
/*
|
|
||||||
* IT IS ESSENTIAL THAT EVEN-NUMBERED STANDARDS ARE 25 FRAMES PER SECOND,
|
|
||||||
* ODD-NUMBERED STANDARDS ARE 30 FRAMES PER SECOND.
|
|
||||||
* THE NUMBERING OF STANDARDS MUST NOT BE CHANGED WITHOUT DUE CARE. NOT
|
|
||||||
* ONLY MUST THE PARAMETER
|
|
||||||
* STANDARD_MANY
|
|
||||||
* BE CHANGED TO CORRESPOND TO THE NEW NUMBER OF STANDARDS, BUT ALSO THE
|
|
||||||
* NUMBERING MUST REMAIN AN UNBROKEN ASCENDING SEQUENCE: DUMMY STANDARDS
|
|
||||||
* MAY NEED TO BE ADDED. APPROPRIATE CHANGES WILL ALWAYS BE REQUIRED IN
|
|
||||||
* ROUTINE fillin_formats() AND POSSIBLY ELSEWHERE. BEWARE.
|
|
||||||
*/
|
|
||||||
/*---------------------------------------------------------------------------*/
|
|
||||||
#define PAL_BGHIN 0
|
|
||||||
#define PAL_Nc 2
|
|
||||||
#define SECAM 4
|
|
||||||
#define NTSC_N 6
|
|
||||||
#define NTSC_N_443 8
|
|
||||||
#define NTSC_M 1
|
|
||||||
#define NTSC_443 3
|
|
||||||
#define NTSC_M_JP 5
|
|
||||||
#define PAL_60 7
|
|
||||||
#define PAL_M 9
|
|
||||||
#define PAL_BGHIN_SLOW 10
|
|
||||||
#define PAL_Nc_SLOW 12
|
|
||||||
#define SECAM_SLOW 14
|
|
||||||
#define NTSC_N_SLOW 16
|
|
||||||
#define NTSC_N_443_SLOW 18
|
|
||||||
#define NTSC_M_SLOW 11
|
|
||||||
#define NTSC_443_SLOW 13
|
|
||||||
#define NTSC_M_JP_SLOW 15
|
|
||||||
#define PAL_60_SLOW 17
|
|
||||||
#define PAL_M_SLOW 19
|
|
||||||
#define STANDARD_MANY 20
|
|
||||||
/*---------------------------------------------------------------------------*/
|
|
||||||
/*
|
|
||||||
* ENUMS
|
|
||||||
*/
|
|
||||||
/*---------------------------------------------------------------------------*/
|
|
||||||
enum {
|
|
||||||
AT_720x576,
|
|
||||||
AT_704x576,
|
|
||||||
AT_640x480,
|
|
||||||
AT_720x480,
|
|
||||||
AT_360x288,
|
|
||||||
AT_320x240,
|
|
||||||
AT_360x240,
|
|
||||||
RESOLUTION_MANY
|
|
||||||
};
|
|
||||||
enum {
|
|
||||||
FMT_UYVY,
|
|
||||||
FMT_YUY2,
|
|
||||||
FMT_RGB24,
|
|
||||||
FMT_RGB32,
|
|
||||||
FMT_BGR24,
|
|
||||||
FMT_BGR32,
|
|
||||||
PIXELFORMAT_MANY
|
|
||||||
};
|
|
||||||
enum {
|
|
||||||
FIELD_NONE,
|
|
||||||
FIELD_INTERLACED,
|
|
||||||
INTERLACE_MANY
|
|
||||||
};
|
|
||||||
#define SETTINGS_MANY (STANDARD_MANY * \
|
|
||||||
RESOLUTION_MANY * \
|
|
||||||
2 * \
|
|
||||||
PIXELFORMAT_MANY * \
|
|
||||||
INTERLACE_MANY)
|
|
||||||
/*---------------------------------------------------------------------------*/
|
|
||||||
/*
|
|
||||||
* STRUCTURE DEFINITIONS
|
|
||||||
*/
|
|
||||||
/*---------------------------------------------------------------------------*/
|
|
||||||
struct easycap_dongle {
|
|
||||||
struct easycap *peasycap;
|
|
||||||
struct mutex mutex_video;
|
|
||||||
struct mutex mutex_audio;
|
|
||||||
};
|
|
||||||
/*---------------------------------------------------------------------------*/
|
|
||||||
struct data_buffer {
|
|
||||||
struct list_head list_head;
|
|
||||||
void *pgo;
|
|
||||||
void *pto;
|
|
||||||
u16 kount;
|
|
||||||
u16 input;
|
|
||||||
};
|
|
||||||
/*---------------------------------------------------------------------------*/
|
|
||||||
struct data_urb {
|
|
||||||
struct list_head list_head;
|
|
||||||
struct urb *purb;
|
|
||||||
int isbuf;
|
|
||||||
int length;
|
|
||||||
};
|
|
||||||
/*---------------------------------------------------------------------------*/
|
|
||||||
struct easycap_standard {
|
|
||||||
u16 mask;
|
|
||||||
struct v4l2_standard v4l2_standard;
|
|
||||||
};
|
|
||||||
struct easycap_format {
|
|
||||||
u16 mask;
|
|
||||||
char name[128];
|
|
||||||
struct v4l2_format v4l2_format;
|
|
||||||
};
|
|
||||||
struct inputset {
|
|
||||||
int input;
|
|
||||||
int input_ok;
|
|
||||||
int standard_offset;
|
|
||||||
int standard_offset_ok;
|
|
||||||
int format_offset;
|
|
||||||
int format_offset_ok;
|
|
||||||
int brightness;
|
|
||||||
int brightness_ok;
|
|
||||||
int contrast;
|
|
||||||
int contrast_ok;
|
|
||||||
int saturation;
|
|
||||||
int saturation_ok;
|
|
||||||
int hue;
|
|
||||||
int hue_ok;
|
|
||||||
};
|
|
||||||
/*---------------------------------------------------------------------------*/
|
|
||||||
/*
|
|
||||||
* easycap.ilk == 0 => CVBS+S-VIDEO HARDWARE, AUDIO wMaxPacketSize=256
|
|
||||||
* easycap.ilk == 2 => CVBS+S-VIDEO HARDWARE, AUDIO wMaxPacketSize=9
|
|
||||||
* easycap.ilk == 3 => FOUR-CVBS HARDWARE, AUDIO wMaxPacketSize=9
|
|
||||||
*/
|
|
||||||
/*---------------------------------------------------------------------------*/
|
|
||||||
struct easycap {
|
|
||||||
int isdongle;
|
|
||||||
int minor;
|
|
||||||
|
|
||||||
struct video_device video_device;
|
|
||||||
struct v4l2_device v4l2_device;
|
|
||||||
|
|
||||||
int status;
|
|
||||||
unsigned int audio_pages_per_fragment;
|
|
||||||
unsigned int audio_bytes_per_fragment;
|
|
||||||
unsigned int audio_buffer_page_many;
|
|
||||||
|
|
||||||
#define UPSAMPLE
|
|
||||||
#ifdef UPSAMPLE
|
|
||||||
s16 oldaudio;
|
|
||||||
#endif /*UPSAMPLE*/
|
|
||||||
|
|
||||||
int ilk;
|
|
||||||
bool microphone;
|
|
||||||
|
|
||||||
struct usb_device *pusb_device;
|
|
||||||
struct usb_interface *pusb_interface;
|
|
||||||
|
|
||||||
struct kref kref;
|
|
||||||
|
|
||||||
int queued[FRAME_BUFFER_MANY];
|
|
||||||
int done[FRAME_BUFFER_MANY];
|
|
||||||
|
|
||||||
wait_queue_head_t wq_video;
|
|
||||||
wait_queue_head_t wq_audio;
|
|
||||||
wait_queue_head_t wq_trigger;
|
|
||||||
|
|
||||||
int input;
|
|
||||||
int polled;
|
|
||||||
int standard_offset;
|
|
||||||
int format_offset;
|
|
||||||
struct inputset inputset[INPUT_MANY];
|
|
||||||
|
|
||||||
bool ntsc;
|
|
||||||
int fps;
|
|
||||||
int usec;
|
|
||||||
int tolerate;
|
|
||||||
int skip;
|
|
||||||
int skipped;
|
|
||||||
int lost[INPUT_MANY];
|
|
||||||
int merit[180];
|
|
||||||
|
|
||||||
int video_interface;
|
|
||||||
int video_altsetting_on;
|
|
||||||
int video_altsetting_off;
|
|
||||||
int video_endpointnumber;
|
|
||||||
int video_isoc_maxframesize;
|
|
||||||
int video_isoc_buffer_size;
|
|
||||||
int video_isoc_framesperdesc;
|
|
||||||
|
|
||||||
int video_isoc_streaming;
|
|
||||||
int video_isoc_sequence;
|
|
||||||
int video_idle;
|
|
||||||
int video_eof;
|
|
||||||
int video_junk;
|
|
||||||
|
|
||||||
struct data_buffer video_isoc_buffer[VIDEO_ISOC_BUFFER_MANY];
|
|
||||||
struct data_buffer field_buffer[FIELD_BUFFER_MANY]
|
|
||||||
[(FIELD_BUFFER_SIZE/PAGE_SIZE)];
|
|
||||||
struct data_buffer frame_buffer[FRAME_BUFFER_MANY]
|
|
||||||
[(FRAME_BUFFER_SIZE/PAGE_SIZE)];
|
|
||||||
|
|
||||||
struct list_head urb_video_head;
|
|
||||||
struct list_head *purb_video_head;
|
|
||||||
|
|
||||||
u8 cache[8];
|
|
||||||
u8 *pcache;
|
|
||||||
int video_mt;
|
|
||||||
int audio_mt;
|
|
||||||
u32 isequence;
|
|
||||||
|
|
||||||
int vma_many;
|
|
||||||
/*---------------------------------------------------------------------------*/
|
|
||||||
/*
|
|
||||||
* BUFFER INDICATORS
|
|
||||||
*/
|
|
||||||
/*---------------------------------------------------------------------------*/
|
|
||||||
int field_fill; /* Field buffer being filled by easycap_complete(). */
|
|
||||||
/* Bumped only by easycap_complete(). */
|
|
||||||
int field_page; /* Page of field buffer page being filled by */
|
|
||||||
/* easycap_complete(). */
|
|
||||||
int field_read; /* Field buffer to be read by field2frame(). */
|
|
||||||
/* Bumped only by easycap_complete(). */
|
|
||||||
int frame_fill; /* Frame buffer being filled by field2frame(). */
|
|
||||||
/* Bumped only by easycap_dqbuf() when */
|
|
||||||
/* field2frame() has created a complete frame. */
|
|
||||||
int frame_read; /* Frame buffer offered to user by DQBUF. */
|
|
||||||
/* Set only by easycap_dqbuf() to trail frame_fill.*/
|
|
||||||
int frame_lock; /* Flag set to 1 by DQBUF and cleared by QBUF */
|
|
||||||
/*---------------------------------------------------------------------------*/
|
|
||||||
/*
|
|
||||||
* IMAGE PROPERTIES
|
|
||||||
*/
|
|
||||||
/*---------------------------------------------------------------------------*/
|
|
||||||
u32 pixelformat;
|
|
||||||
int width;
|
|
||||||
int height;
|
|
||||||
int bytesperpixel;
|
|
||||||
bool byteswaporder;
|
|
||||||
bool decimatepixel;
|
|
||||||
bool offerfields;
|
|
||||||
int frame_buffer_used;
|
|
||||||
int frame_buffer_many;
|
|
||||||
int videofieldamount;
|
|
||||||
|
|
||||||
int brightness;
|
|
||||||
int contrast;
|
|
||||||
int saturation;
|
|
||||||
int hue;
|
|
||||||
|
|
||||||
int allocation_video_urb;
|
|
||||||
int allocation_video_page;
|
|
||||||
int allocation_video_struct;
|
|
||||||
int registered_video;
|
|
||||||
/*---------------------------------------------------------------------------*/
|
|
||||||
/*
|
|
||||||
* ALSA
|
|
||||||
*/
|
|
||||||
/*---------------------------------------------------------------------------*/
|
|
||||||
struct snd_pcm_hardware alsa_hardware;
|
|
||||||
struct snd_card *psnd_card;
|
|
||||||
struct snd_pcm *psnd_pcm;
|
|
||||||
struct snd_pcm_substream *psubstream;
|
|
||||||
int dma_fill;
|
|
||||||
int dma_next;
|
|
||||||
int dma_read;
|
|
||||||
/*---------------------------------------------------------------------------*/
|
|
||||||
/*
|
|
||||||
* SOUND PROPERTIES
|
|
||||||
*/
|
|
||||||
/*---------------------------------------------------------------------------*/
|
|
||||||
int audio_interface;
|
|
||||||
int audio_altsetting_on;
|
|
||||||
int audio_altsetting_off;
|
|
||||||
int audio_endpointnumber;
|
|
||||||
int audio_isoc_maxframesize;
|
|
||||||
int audio_isoc_buffer_size;
|
|
||||||
int audio_isoc_framesperdesc;
|
|
||||||
|
|
||||||
int audio_isoc_streaming;
|
|
||||||
int audio_idle;
|
|
||||||
int audio_eof;
|
|
||||||
int volume;
|
|
||||||
int mute;
|
|
||||||
s8 gain;
|
|
||||||
|
|
||||||
struct data_buffer audio_isoc_buffer[AUDIO_ISOC_BUFFER_MANY];
|
|
||||||
|
|
||||||
struct list_head urb_audio_head;
|
|
||||||
struct list_head *purb_audio_head;
|
|
||||||
/*---------------------------------------------------------------------------*/
|
|
||||||
/*
|
|
||||||
* BUFFER INDICATORS
|
|
||||||
*/
|
|
||||||
/*---------------------------------------------------------------------------*/
|
|
||||||
int audio_fill; /* Audio buffer being filled by easycap_complete(). */
|
|
||||||
/* Bumped only by easycap_complete(). */
|
|
||||||
int audio_read; /* Audio buffer page being read by easycap_read(). */
|
|
||||||
/* Set by easycap_read() to trail audio_fill by */
|
|
||||||
/* one fragment. */
|
|
||||||
/*---------------------------------------------------------------------------*/
|
|
||||||
/*
|
|
||||||
* SOUND PROPERTIES
|
|
||||||
*/
|
|
||||||
/*---------------------------------------------------------------------------*/
|
|
||||||
int allocation_audio_urb;
|
|
||||||
int allocation_audio_page;
|
|
||||||
int allocation_audio_struct;
|
|
||||||
int registered_audio;
|
|
||||||
|
|
||||||
long long int audio_sample;
|
|
||||||
long long int audio_niveau;
|
|
||||||
long long int audio_square;
|
|
||||||
|
|
||||||
struct data_buffer audio_buffer[];
|
|
||||||
};
|
|
||||||
/*---------------------------------------------------------------------------*/
|
|
||||||
/*
|
|
||||||
* VIDEO FUNCTION PROTOTYPES
|
|
||||||
*/
|
|
||||||
/*^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^*/
|
|
||||||
int easycap_newinput(struct easycap *, int);
|
|
||||||
void easycap_testcard(struct easycap *, int);
|
|
||||||
int easycap_isdongle(struct easycap *);
|
|
||||||
|
|
||||||
long easycap_unlocked_ioctl(struct file *, unsigned int, unsigned long);
|
|
||||||
|
|
||||||
int easycap_video_dqbuf(struct easycap *, int);
|
|
||||||
int easycap_video_submit_urbs(struct easycap *);
|
|
||||||
int easycap_video_kill_urbs(struct easycap *);
|
|
||||||
int easycap_video_fillin_formats(void);
|
|
||||||
|
|
||||||
int adjust_standard(struct easycap *, v4l2_std_id);
|
|
||||||
int adjust_format(struct easycap *, u32, u32, u32, int, bool);
|
|
||||||
int adjust_brightness(struct easycap *, int);
|
|
||||||
int adjust_contrast(struct easycap *, int);
|
|
||||||
int adjust_saturation(struct easycap *, int);
|
|
||||||
int adjust_hue(struct easycap *, int);
|
|
||||||
/*---------------------------------------------------------------------------*/
|
|
||||||
/*
|
|
||||||
* AUDIO FUNCTION PROTOTYPES
|
|
||||||
*/
|
|
||||||
/*---------------------------------------------------------------------------*/
|
|
||||||
int easycap_alsa_probe(struct easycap *);
|
|
||||||
int easycap_audio_kill_urbs(struct easycap *);
|
|
||||||
void easycap_alsa_complete(struct urb *);
|
|
||||||
/*---------------------------------------------------------------------------*/
|
|
||||||
/*
|
|
||||||
* LOW-LEVEL FUNCTION PROTOTYPES
|
|
||||||
*/
|
|
||||||
/*---------------------------------------------------------------------------*/
|
|
||||||
int easycap_audio_gainset(struct usb_device *, s8);
|
|
||||||
int easycap_audio_setup(struct easycap *);
|
|
||||||
|
|
||||||
int easycap_wakeup_device(struct usb_device *);
|
|
||||||
|
|
||||||
int setup_stk(struct usb_device *, bool);
|
|
||||||
int setup_saa(struct usb_device *, bool);
|
|
||||||
int ready_saa(struct usb_device *);
|
|
||||||
int merit_saa(struct usb_device *);
|
|
||||||
int check_vt(struct usb_device *);
|
|
||||||
int select_input(struct usb_device *, int, int);
|
|
||||||
int set_resolution(struct usb_device *, u16, u16, u16, u16);
|
|
||||||
|
|
||||||
int read_saa(struct usb_device *, u16);
|
|
||||||
int write_saa(struct usb_device *, u16, u16);
|
|
||||||
int start_100(struct usb_device *);
|
|
||||||
int stop_100(struct usb_device *);
|
|
||||||
/*---------------------------------------------------------------------------*/
|
|
||||||
|
|
||||||
|
|
||||||
/*---------------------------------------------------------------------------*/
|
|
||||||
/*
|
|
||||||
* MACROS SAM(...) AND JOM(...) ALLOW DIAGNOSTIC OUTPUT TO BE TAGGED WITH
|
|
||||||
* THE IDENTITY OF THE DONGLE TO WHICH IT APPLIES, BUT IF INVOKED WHEN THE
|
|
||||||
* POINTER peasycap IS INVALID AN Oops IS LIKELY, AND ITS CAUSE MAY NOT BE
|
|
||||||
* IMMEDIATELY OBVIOUS FROM A CASUAL READING OF THE SOURCE CODE. BEWARE.
|
|
||||||
*/
|
|
||||||
/*---------------------------------------------------------------------------*/
|
|
||||||
const char *strerror(int err);
|
|
||||||
|
|
||||||
#define SAY(format, args...) do { \
|
|
||||||
printk(KERN_DEBUG "easycap:: %s: " \
|
|
||||||
format, __func__, ##args); \
|
|
||||||
} while (0)
|
|
||||||
#define SAM(format, args...) do { \
|
|
||||||
printk(KERN_DEBUG "easycap::%i%s: " \
|
|
||||||
format, peasycap->isdongle, __func__, ##args);\
|
|
||||||
} while (0)
|
|
||||||
|
|
||||||
#ifdef CONFIG_EASYCAP_DEBUG
|
|
||||||
extern int easycap_debug;
|
|
||||||
#define JOT(n, format, args...) do { \
|
|
||||||
if (n <= easycap_debug) { \
|
|
||||||
printk(KERN_DEBUG "easycap:: %s: " \
|
|
||||||
format, __func__, ##args);\
|
|
||||||
} \
|
|
||||||
} while (0)
|
|
||||||
#define JOM(n, format, args...) do { \
|
|
||||||
if (n <= easycap_debug) { \
|
|
||||||
printk(KERN_DEBUG "easycap::%i%s: " \
|
|
||||||
format, peasycap->isdongle, __func__, ##args);\
|
|
||||||
} \
|
|
||||||
} while (0)
|
|
||||||
|
|
||||||
#else
|
|
||||||
#define JOT(n, format, args...) do {} while (0)
|
|
||||||
#define JOM(n, format, args...) do {} while (0)
|
|
||||||
#endif /* CONFIG_EASYCAP_DEBUG */
|
|
||||||
|
|
||||||
/*---------------------------------------------------------------------------*/
|
|
||||||
|
|
||||||
/*---------------------------------------------------------------------------*/
|
|
||||||
/* globals
|
|
||||||
*/
|
|
||||||
/*---------------------------------------------------------------------------*/
|
|
||||||
|
|
||||||
extern bool easycap_readback;
|
|
||||||
extern const struct easycap_standard easycap_standard[];
|
|
||||||
extern struct easycap_format easycap_format[];
|
|
||||||
extern struct v4l2_queryctrl easycap_control[];
|
|
||||||
extern struct easycap_dongle easycapdc60_dongle[];
|
|
||||||
|
|
||||||
#endif /* !__EASYCAP_H__ */
|
|
File diff suppressed because it is too large
Load diff
|
@ -1,968 +0,0 @@
|
||||||
/*****************************************************************************
|
|
||||||
* *
|
|
||||||
* *
|
|
||||||
* easycap_low.c *
|
|
||||||
* *
|
|
||||||
* *
|
|
||||||
*****************************************************************************/
|
|
||||||
/*
|
|
||||||
*
|
|
||||||
* Copyright (C) 2010 R.M. Thomas <rmthomas@sciolus.org>
|
|
||||||
*
|
|
||||||
*
|
|
||||||
* This 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.
|
|
||||||
*
|
|
||||||
* The software 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 software; if not, write to the Free Software
|
|
||||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
/*****************************************************************************/
|
|
||||||
/*
|
|
||||||
* ACKNOWLEGEMENTS AND REFERENCES
|
|
||||||
* ------------------------------
|
|
||||||
* This driver makes use of register information contained in the Syntek
|
|
||||||
* Semicon DC-1125 driver hosted at
|
|
||||||
* http://sourceforge.net/projects/syntekdriver/.
|
|
||||||
* Particularly useful has been a patch to the latter driver provided by
|
|
||||||
* Ivor Hewitt in January 2009. The NTSC implementation is taken from the
|
|
||||||
* work of Ben Trask.
|
|
||||||
*/
|
|
||||||
/****************************************************************************/
|
|
||||||
|
|
||||||
#include "easycap.h"
|
|
||||||
|
|
||||||
|
|
||||||
#define GET(X, Y, Z) do { \
|
|
||||||
int __rc; \
|
|
||||||
*(Z) = (u16)0; \
|
|
||||||
__rc = regget(X, Y, Z, sizeof(u8)); \
|
|
||||||
if (0 > __rc) { \
|
|
||||||
JOT(8, ":-(%i\n", __LINE__); return __rc; \
|
|
||||||
} \
|
|
||||||
} while (0)
|
|
||||||
|
|
||||||
#define SET(X, Y, Z) do { \
|
|
||||||
int __rc; \
|
|
||||||
__rc = regset(X, Y, Z); \
|
|
||||||
if (0 > __rc) { \
|
|
||||||
JOT(8, ":-(%i\n", __LINE__); return __rc; \
|
|
||||||
} \
|
|
||||||
} while (0)
|
|
||||||
|
|
||||||
/*--------------------------------------------------------------------------*/
|
|
||||||
static const struct stk1160config {
|
|
||||||
u16 reg;
|
|
||||||
u16 set;
|
|
||||||
} stk1160configPAL[] = {
|
|
||||||
{0x000, 0x0098},
|
|
||||||
{0x002, 0x0093},
|
|
||||||
|
|
||||||
{0x001, 0x0003},
|
|
||||||
{0x003, 0x0080},
|
|
||||||
{0x00D, 0x0000},
|
|
||||||
{0x00F, 0x0002},
|
|
||||||
{0x018, 0x0010},
|
|
||||||
{0x019, 0x0000},
|
|
||||||
{0x01A, 0x0014},
|
|
||||||
{0x01B, 0x000E},
|
|
||||||
{0x01C, 0x0046},
|
|
||||||
|
|
||||||
{0x100, 0x0033},
|
|
||||||
{0x103, 0x0000},
|
|
||||||
{0x104, 0x0000},
|
|
||||||
{0x105, 0x0000},
|
|
||||||
{0x106, 0x0000},
|
|
||||||
|
|
||||||
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
|
|
||||||
/*
|
|
||||||
* RESOLUTION 640x480
|
|
||||||
*/
|
|
||||||
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
|
|
||||||
{0x110, 0x0008},
|
|
||||||
{0x111, 0x0000},
|
|
||||||
{0x112, 0x0020},
|
|
||||||
{0x113, 0x0000},
|
|
||||||
{0x114, 0x0508},
|
|
||||||
{0x115, 0x0005},
|
|
||||||
{0x116, 0x0110},
|
|
||||||
{0x117, 0x0001},
|
|
||||||
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
|
|
||||||
|
|
||||||
{0x202, 0x000F},
|
|
||||||
{0x203, 0x004A},
|
|
||||||
{0x2FF, 0x0000},
|
|
||||||
|
|
||||||
{0xFFF, 0xFFFF}
|
|
||||||
};
|
|
||||||
/*--------------------------------------------------------------------------*/
|
|
||||||
static const struct stk1160config stk1160configNTSC[] = {
|
|
||||||
{0x000, 0x0098},
|
|
||||||
{0x002, 0x0093},
|
|
||||||
|
|
||||||
{0x001, 0x0003},
|
|
||||||
{0x003, 0x0080},
|
|
||||||
{0x00D, 0x0000},
|
|
||||||
{0x00F, 0x0002},
|
|
||||||
{0x018, 0x0010},
|
|
||||||
{0x019, 0x0000},
|
|
||||||
{0x01A, 0x0014},
|
|
||||||
{0x01B, 0x000E},
|
|
||||||
{0x01C, 0x0046},
|
|
||||||
|
|
||||||
{0x100, 0x0033},
|
|
||||||
{0x103, 0x0000},
|
|
||||||
{0x104, 0x0000},
|
|
||||||
{0x105, 0x0000},
|
|
||||||
{0x106, 0x0000},
|
|
||||||
|
|
||||||
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
|
|
||||||
/*
|
|
||||||
* RESOLUTION 640x480
|
|
||||||
*/
|
|
||||||
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
|
|
||||||
{0x110, 0x0008},
|
|
||||||
{0x111, 0x0000},
|
|
||||||
{0x112, 0x0003},
|
|
||||||
{0x113, 0x0000},
|
|
||||||
{0x114, 0x0508},
|
|
||||||
{0x115, 0x0005},
|
|
||||||
{0x116, 0x00F3},
|
|
||||||
{0x117, 0x0000},
|
|
||||||
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
|
|
||||||
|
|
||||||
{0x202, 0x000F},
|
|
||||||
{0x203, 0x004A},
|
|
||||||
{0x2FF, 0x0000},
|
|
||||||
|
|
||||||
{0xFFF, 0xFFFF}
|
|
||||||
};
|
|
||||||
/*--------------------------------------------------------------------------*/
|
|
||||||
static const struct saa7113config {
|
|
||||||
u8 reg;
|
|
||||||
u8 set;
|
|
||||||
} saa7113configPAL[] = {
|
|
||||||
{0x01, 0x08},
|
|
||||||
{0x02, 0x80},
|
|
||||||
{0x03, 0x33},
|
|
||||||
{0x04, 0x00},
|
|
||||||
{0x05, 0x00},
|
|
||||||
{0x06, 0xE9},
|
|
||||||
{0x07, 0x0D},
|
|
||||||
{0x08, 0x38},
|
|
||||||
{0x09, 0x00},
|
|
||||||
{0x0A, SAA_0A_DEFAULT},
|
|
||||||
{0x0B, SAA_0B_DEFAULT},
|
|
||||||
{0x0C, SAA_0C_DEFAULT},
|
|
||||||
{0x0D, SAA_0D_DEFAULT},
|
|
||||||
{0x0E, 0x01},
|
|
||||||
{0x0F, 0x36},
|
|
||||||
{0x10, 0x00},
|
|
||||||
{0x11, 0x0C},
|
|
||||||
{0x12, 0xE7},
|
|
||||||
{0x13, 0x00},
|
|
||||||
{0x15, 0x00},
|
|
||||||
{0x16, 0x00},
|
|
||||||
{0x40, 0x02},
|
|
||||||
{0x41, 0xFF},
|
|
||||||
{0x42, 0xFF},
|
|
||||||
{0x43, 0xFF},
|
|
||||||
{0x44, 0xFF},
|
|
||||||
{0x45, 0xFF},
|
|
||||||
{0x46, 0xFF},
|
|
||||||
{0x47, 0xFF},
|
|
||||||
{0x48, 0xFF},
|
|
||||||
{0x49, 0xFF},
|
|
||||||
{0x4A, 0xFF},
|
|
||||||
{0x4B, 0xFF},
|
|
||||||
{0x4C, 0xFF},
|
|
||||||
{0x4D, 0xFF},
|
|
||||||
{0x4E, 0xFF},
|
|
||||||
{0x4F, 0xFF},
|
|
||||||
{0x50, 0xFF},
|
|
||||||
{0x51, 0xFF},
|
|
||||||
{0x52, 0xFF},
|
|
||||||
{0x53, 0xFF},
|
|
||||||
{0x54, 0xFF},
|
|
||||||
{0x55, 0xFF},
|
|
||||||
{0x56, 0xFF},
|
|
||||||
{0x57, 0xFF},
|
|
||||||
{0x58, 0x40},
|
|
||||||
{0x59, 0x54},
|
|
||||||
{0x5A, 0x07},
|
|
||||||
{0x5B, 0x83},
|
|
||||||
|
|
||||||
{0xFF, 0xFF}
|
|
||||||
};
|
|
||||||
/*--------------------------------------------------------------------------*/
|
|
||||||
static const struct saa7113config saa7113configNTSC[] = {
|
|
||||||
{0x01, 0x08},
|
|
||||||
{0x02, 0x80},
|
|
||||||
{0x03, 0x33},
|
|
||||||
{0x04, 0x00},
|
|
||||||
{0x05, 0x00},
|
|
||||||
{0x06, 0xE9},
|
|
||||||
{0x07, 0x0D},
|
|
||||||
{0x08, 0x78},
|
|
||||||
{0x09, 0x00},
|
|
||||||
{0x0A, SAA_0A_DEFAULT},
|
|
||||||
{0x0B, SAA_0B_DEFAULT},
|
|
||||||
{0x0C, SAA_0C_DEFAULT},
|
|
||||||
{0x0D, SAA_0D_DEFAULT},
|
|
||||||
{0x0E, 0x01},
|
|
||||||
{0x0F, 0x36},
|
|
||||||
{0x10, 0x00},
|
|
||||||
{0x11, 0x0C},
|
|
||||||
{0x12, 0xE7},
|
|
||||||
{0x13, 0x00},
|
|
||||||
{0x15, 0x00},
|
|
||||||
{0x16, 0x00},
|
|
||||||
{0x40, 0x82},
|
|
||||||
{0x41, 0xFF},
|
|
||||||
{0x42, 0xFF},
|
|
||||||
{0x43, 0xFF},
|
|
||||||
{0x44, 0xFF},
|
|
||||||
{0x45, 0xFF},
|
|
||||||
{0x46, 0xFF},
|
|
||||||
{0x47, 0xFF},
|
|
||||||
{0x48, 0xFF},
|
|
||||||
{0x49, 0xFF},
|
|
||||||
{0x4A, 0xFF},
|
|
||||||
{0x4B, 0xFF},
|
|
||||||
{0x4C, 0xFF},
|
|
||||||
{0x4D, 0xFF},
|
|
||||||
{0x4E, 0xFF},
|
|
||||||
{0x4F, 0xFF},
|
|
||||||
{0x50, 0xFF},
|
|
||||||
{0x51, 0xFF},
|
|
||||||
{0x52, 0xFF},
|
|
||||||
{0x53, 0xFF},
|
|
||||||
{0x54, 0xFF},
|
|
||||||
{0x55, 0xFF},
|
|
||||||
{0x56, 0xFF},
|
|
||||||
{0x57, 0xFF},
|
|
||||||
{0x58, 0x40},
|
|
||||||
{0x59, 0x54},
|
|
||||||
{0x5A, 0x0A},
|
|
||||||
{0x5B, 0x83},
|
|
||||||
|
|
||||||
{0xFF, 0xFF}
|
|
||||||
};
|
|
||||||
|
|
||||||
static int regget(struct usb_device *pusb_device,
|
|
||||||
u16 index, void *reg, int reg_size)
|
|
||||||
{
|
|
||||||
int rc;
|
|
||||||
|
|
||||||
if (!pusb_device)
|
|
||||||
return -ENODEV;
|
|
||||||
|
|
||||||
rc = usb_control_msg(pusb_device, usb_rcvctrlpipe(pusb_device, 0),
|
|
||||||
0x00,
|
|
||||||
(USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE),
|
|
||||||
0x00,
|
|
||||||
index, reg, reg_size, 50000);
|
|
||||||
|
|
||||||
return rc;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int regset(struct usb_device *pusb_device, u16 index, u16 value)
|
|
||||||
{
|
|
||||||
int rc;
|
|
||||||
|
|
||||||
if (!pusb_device)
|
|
||||||
return -ENODEV;
|
|
||||||
|
|
||||||
rc = usb_control_msg(pusb_device, usb_sndctrlpipe(pusb_device, 0),
|
|
||||||
0x01,
|
|
||||||
(USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE),
|
|
||||||
value, index, NULL, 0, 500);
|
|
||||||
|
|
||||||
if (rc < 0)
|
|
||||||
return rc;
|
|
||||||
|
|
||||||
if (easycap_readback) {
|
|
||||||
u16 igot = 0;
|
|
||||||
rc = regget(pusb_device, index, &igot, sizeof(igot));
|
|
||||||
igot = 0xFF & igot;
|
|
||||||
switch (index) {
|
|
||||||
case 0x000:
|
|
||||||
case 0x500:
|
|
||||||
case 0x502:
|
|
||||||
case 0x503:
|
|
||||||
case 0x504:
|
|
||||||
case 0x506:
|
|
||||||
case 0x507:
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 0x204:
|
|
||||||
case 0x205:
|
|
||||||
case 0x350:
|
|
||||||
case 0x351:
|
|
||||||
if (igot)
|
|
||||||
JOT(8, "unexpected 0x%02X "
|
|
||||||
"for STK register 0x%03X\n",
|
|
||||||
igot, index);
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
if ((0xFF & value) != igot)
|
|
||||||
JOT(8, "unexpected 0x%02X != 0x%02X "
|
|
||||||
"for STK register 0x%03X\n",
|
|
||||||
igot, value, index);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return rc;
|
|
||||||
}
|
|
||||||
/*--------------------------------------------------------------------------*/
|
|
||||||
/*
|
|
||||||
* FUNCTION wait_i2c() RETURNS 0 ON SUCCESS
|
|
||||||
*/
|
|
||||||
/*--------------------------------------------------------------------------*/
|
|
||||||
static int wait_i2c(struct usb_device *p)
|
|
||||||
{
|
|
||||||
u16 get0;
|
|
||||||
u8 igot;
|
|
||||||
const int max = 2;
|
|
||||||
int k;
|
|
||||||
|
|
||||||
if (!p)
|
|
||||||
return -ENODEV;
|
|
||||||
|
|
||||||
for (k = 0; k < max; k++) {
|
|
||||||
GET(p, 0x0201, &igot); get0 = igot;
|
|
||||||
switch (get0) {
|
|
||||||
case 0x04:
|
|
||||||
case 0x01:
|
|
||||||
return 0;
|
|
||||||
case 0x00:
|
|
||||||
msleep(20);
|
|
||||||
continue;
|
|
||||||
default:
|
|
||||||
return get0 - 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/****************************************************************************/
|
|
||||||
int write_saa(struct usb_device *p, u16 reg0, u16 set0)
|
|
||||||
{
|
|
||||||
if (!p)
|
|
||||||
return -ENODEV;
|
|
||||||
SET(p, 0x200, 0x00);
|
|
||||||
SET(p, 0x204, reg0);
|
|
||||||
SET(p, 0x205, set0);
|
|
||||||
SET(p, 0x200, 0x01);
|
|
||||||
return wait_i2c(p);
|
|
||||||
}
|
|
||||||
/****************************************************************************/
|
|
||||||
/*--------------------------------------------------------------------------*/
|
|
||||||
/*
|
|
||||||
* REGISTER 500: SETTING VALUE TO 0x008B READS FROM VT1612A (?)
|
|
||||||
* REGISTER 500: SETTING VALUE TO 0x008C WRITES TO VT1612A
|
|
||||||
* REGISTER 502: LEAST SIGNIFICANT BYTE OF VALUE TO SET
|
|
||||||
* REGISTER 503: MOST SIGNIFICANT BYTE OF VALUE TO SET
|
|
||||||
* REGISTER 504: TARGET ADDRESS ON VT1612A
|
|
||||||
*/
|
|
||||||
/*--------------------------------------------------------------------------*/
|
|
||||||
static int write_vt(struct usb_device *p, u16 reg0, u16 set0)
|
|
||||||
{
|
|
||||||
u8 igot;
|
|
||||||
u16 got502, got503;
|
|
||||||
u16 set502, set503;
|
|
||||||
|
|
||||||
if (!p)
|
|
||||||
return -ENODEV;
|
|
||||||
SET(p, 0x0504, reg0);
|
|
||||||
SET(p, 0x0500, 0x008B);
|
|
||||||
|
|
||||||
GET(p, 0x0502, &igot); got502 = (0xFF & igot);
|
|
||||||
GET(p, 0x0503, &igot); got503 = (0xFF & igot);
|
|
||||||
|
|
||||||
JOT(16, "write_vt(., 0x%04X, 0x%04X): was 0x%04X\n",
|
|
||||||
reg0, set0, ((got503 << 8) | got502));
|
|
||||||
|
|
||||||
set502 = (0x00FF & set0);
|
|
||||||
set503 = ((0xFF00 & set0) >> 8);
|
|
||||||
|
|
||||||
SET(p, 0x0504, reg0);
|
|
||||||
SET(p, 0x0502, set502);
|
|
||||||
SET(p, 0x0503, set503);
|
|
||||||
SET(p, 0x0500, 0x008C);
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
/****************************************************************************/
|
|
||||||
/*--------------------------------------------------------------------------*/
|
|
||||||
/*
|
|
||||||
* REGISTER 500: SETTING VALUE TO 0x008B READS FROM VT1612A (?)
|
|
||||||
* REGISTER 500: SETTING VALUE TO 0x008C WRITES TO VT1612A
|
|
||||||
* REGISTER 502: LEAST SIGNIFICANT BYTE OF VALUE TO GET
|
|
||||||
* REGISTER 503: MOST SIGNIFICANT BYTE OF VALUE TO GET
|
|
||||||
* REGISTER 504: TARGET ADDRESS ON VT1612A
|
|
||||||
*/
|
|
||||||
/*--------------------------------------------------------------------------*/
|
|
||||||
static int read_vt(struct usb_device *p, u16 reg0)
|
|
||||||
{
|
|
||||||
u8 igot;
|
|
||||||
u16 got502, got503;
|
|
||||||
|
|
||||||
if (!p)
|
|
||||||
return -ENODEV;
|
|
||||||
SET(p, 0x0504, reg0);
|
|
||||||
SET(p, 0x0500, 0x008B);
|
|
||||||
|
|
||||||
GET(p, 0x0502, &igot); got502 = (0xFF & igot);
|
|
||||||
GET(p, 0x0503, &igot); got503 = (0xFF & igot);
|
|
||||||
|
|
||||||
JOT(16, "read_vt(., 0x%04X): has 0x%04X\n",
|
|
||||||
reg0, ((got503 << 8) | got502));
|
|
||||||
|
|
||||||
return (got503 << 8) | got502;
|
|
||||||
}
|
|
||||||
/****************************************************************************/
|
|
||||||
/*--------------------------------------------------------------------------*/
|
|
||||||
/*
|
|
||||||
* THESE APPEAR TO HAVE NO EFFECT ON EITHER VIDEO OR AUDIO.
|
|
||||||
*/
|
|
||||||
/*--------------------------------------------------------------------------*/
|
|
||||||
static int write_300(struct usb_device *p)
|
|
||||||
{
|
|
||||||
if (!p)
|
|
||||||
return -ENODEV;
|
|
||||||
SET(p, 0x300, 0x0012);
|
|
||||||
SET(p, 0x350, 0x002D);
|
|
||||||
SET(p, 0x351, 0x0001);
|
|
||||||
SET(p, 0x352, 0x0000);
|
|
||||||
SET(p, 0x353, 0x0000);
|
|
||||||
SET(p, 0x300, 0x0080);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
/****************************************************************************/
|
|
||||||
/****************************************************************************/
|
|
||||||
int setup_stk(struct usb_device *p, bool ntsc)
|
|
||||||
{
|
|
||||||
int i;
|
|
||||||
const struct stk1160config *cfg;
|
|
||||||
if (!p)
|
|
||||||
return -ENODEV;
|
|
||||||
cfg = (ntsc) ? stk1160configNTSC : stk1160configPAL;
|
|
||||||
for (i = 0; cfg[i].reg != 0xFFF; i++)
|
|
||||||
SET(p, cfg[i].reg, cfg[i].set);
|
|
||||||
|
|
||||||
write_300(p);
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
/****************************************************************************/
|
|
||||||
int setup_saa(struct usb_device *p, bool ntsc)
|
|
||||||
{
|
|
||||||
int i, rc;
|
|
||||||
const struct saa7113config *cfg;
|
|
||||||
if (!p)
|
|
||||||
return -ENODEV;
|
|
||||||
cfg = (ntsc) ? saa7113configNTSC : saa7113configPAL;
|
|
||||||
for (i = 0; cfg[i].reg != 0xFF; i++) {
|
|
||||||
rc = write_saa(p, cfg[i].reg, cfg[i].set);
|
|
||||||
if (rc)
|
|
||||||
dev_err(&p->dev,
|
|
||||||
"Failed to set SAA register %d", cfg[i].reg);
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
/****************************************************************************/
|
|
||||||
int merit_saa(struct usb_device *p)
|
|
||||||
{
|
|
||||||
int rc;
|
|
||||||
|
|
||||||
if (!p)
|
|
||||||
return -ENODEV;
|
|
||||||
rc = read_saa(p, 0x1F);
|
|
||||||
return ((0 > rc) || (0x02 & rc)) ? 1 : 0;
|
|
||||||
}
|
|
||||||
/****************************************************************************/
|
|
||||||
int ready_saa(struct usb_device *p)
|
|
||||||
{
|
|
||||||
int j, rc, rate;
|
|
||||||
const int max = 5, marktime = PATIENCE/5;
|
|
||||||
/*--------------------------------------------------------------------------*/
|
|
||||||
/*
|
|
||||||
* RETURNS 0 FOR INTERLACED 50 Hz
|
|
||||||
* 1 FOR NON-INTERLACED 50 Hz
|
|
||||||
* 2 FOR INTERLACED 60 Hz
|
|
||||||
* 3 FOR NON-INTERLACED 60 Hz
|
|
||||||
*/
|
|
||||||
/*--------------------------------------------------------------------------*/
|
|
||||||
if (!p)
|
|
||||||
return -ENODEV;
|
|
||||||
j = 0;
|
|
||||||
while (max > j) {
|
|
||||||
rc = read_saa(p, 0x1F);
|
|
||||||
if (0 <= rc) {
|
|
||||||
if (0 == (0x40 & rc))
|
|
||||||
break;
|
|
||||||
if (1 == (0x01 & rc))
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
msleep(marktime);
|
|
||||||
j++;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (max == j)
|
|
||||||
return -1;
|
|
||||||
|
|
||||||
if (0x20 & rc) {
|
|
||||||
rate = 2;
|
|
||||||
JOT(8, "hardware detects 60 Hz\n");
|
|
||||||
} else {
|
|
||||||
rate = 0;
|
|
||||||
JOT(8, "hardware detects 50 Hz\n");
|
|
||||||
}
|
|
||||||
if (0x80 & rc)
|
|
||||||
JOT(8, "hardware detects interlacing\n");
|
|
||||||
else {
|
|
||||||
rate++;
|
|
||||||
JOT(8, "hardware detects no interlacing\n");
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
/****************************************************************************/
|
|
||||||
int read_saa(struct usb_device *p, u16 reg0)
|
|
||||||
{
|
|
||||||
u8 igot;
|
|
||||||
|
|
||||||
if (!p)
|
|
||||||
return -ENODEV;
|
|
||||||
SET(p, 0x208, reg0);
|
|
||||||
SET(p, 0x200, 0x20);
|
|
||||||
if (0 != wait_i2c(p))
|
|
||||||
return -1;
|
|
||||||
igot = 0;
|
|
||||||
GET(p, 0x0209, &igot);
|
|
||||||
return igot;
|
|
||||||
}
|
|
||||||
/****************************************************************************/
|
|
||||||
static int read_stk(struct usb_device *p, u32 reg0)
|
|
||||||
{
|
|
||||||
u8 igot;
|
|
||||||
|
|
||||||
if (!p)
|
|
||||||
return -ENODEV;
|
|
||||||
igot = 0;
|
|
||||||
GET(p, reg0, &igot);
|
|
||||||
return igot;
|
|
||||||
}
|
|
||||||
int select_input(struct usb_device *p, int input, int mode)
|
|
||||||
{
|
|
||||||
int ir;
|
|
||||||
|
|
||||||
if (!p)
|
|
||||||
return -ENODEV;
|
|
||||||
stop_100(p);
|
|
||||||
switch (input) {
|
|
||||||
case 0:
|
|
||||||
case 1: {
|
|
||||||
if (0 != write_saa(p, 0x02, 0x80))
|
|
||||||
SAY("ERROR: failed to set SAA register 0x02 "
|
|
||||||
"for input %i\n", input);
|
|
||||||
|
|
||||||
SET(p, 0x0000, 0x0098);
|
|
||||||
SET(p, 0x0002, 0x0078);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case 2: {
|
|
||||||
if (0 != write_saa(p, 0x02, 0x80))
|
|
||||||
SAY("ERROR: failed to set SAA register 0x02 "
|
|
||||||
"for input %i\n", input);
|
|
||||||
|
|
||||||
SET(p, 0x0000, 0x0090);
|
|
||||||
SET(p, 0x0002, 0x0078);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case 3: {
|
|
||||||
if (0 != write_saa(p, 0x02, 0x80))
|
|
||||||
SAY("ERROR: failed to set SAA register 0x02 "
|
|
||||||
" for input %i\n", input);
|
|
||||||
|
|
||||||
SET(p, 0x0000, 0x0088);
|
|
||||||
SET(p, 0x0002, 0x0078);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case 4: {
|
|
||||||
if (0 != write_saa(p, 0x02, 0x80)) {
|
|
||||||
SAY("ERROR: failed to set SAA register 0x02 "
|
|
||||||
"for input %i\n", input);
|
|
||||||
}
|
|
||||||
SET(p, 0x0000, 0x0080);
|
|
||||||
SET(p, 0x0002, 0x0078);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case 5: {
|
|
||||||
if (9 != mode)
|
|
||||||
mode = 7;
|
|
||||||
switch (mode) {
|
|
||||||
case 7: {
|
|
||||||
if (0 != write_saa(p, 0x02, 0x87))
|
|
||||||
SAY("ERROR: failed to set SAA register 0x02 "
|
|
||||||
"for input %i\n", input);
|
|
||||||
|
|
||||||
if (0 != write_saa(p, 0x05, 0xFF))
|
|
||||||
SAY("ERROR: failed to set SAA register 0x05 "
|
|
||||||
"for input %i\n", input);
|
|
||||||
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case 9: {
|
|
||||||
if (0 != write_saa(p, 0x02, 0x89))
|
|
||||||
SAY("ERROR: failed to set SAA register 0x02 "
|
|
||||||
"for input %i\n", input);
|
|
||||||
|
|
||||||
if (0 != write_saa(p, 0x05, 0x00))
|
|
||||||
SAY("ERROR: failed to set SAA register 0x05 "
|
|
||||||
"for input %i\n", input);
|
|
||||||
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
SAY("MISTAKE: bad mode: %i\n", mode);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (0 != write_saa(p, 0x04, 0x00))
|
|
||||||
SAY("ERROR: failed to set SAA register 0x04 "
|
|
||||||
"for input %i\n", input);
|
|
||||||
|
|
||||||
if (0 != write_saa(p, 0x09, 0x80))
|
|
||||||
SAY("ERROR: failed to set SAA register 0x09 "
|
|
||||||
"for input %i\n", input);
|
|
||||||
|
|
||||||
SET(p, 0x0002, 0x0093);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
SAY("ERROR: bad input: %i\n", input);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
ir = read_stk(p, 0x00);
|
|
||||||
JOT(8, "STK register 0x00 has 0x%02X\n", ir);
|
|
||||||
ir = read_saa(p, 0x02);
|
|
||||||
JOT(8, "SAA register 0x02 has 0x%02X\n", ir);
|
|
||||||
|
|
||||||
start_100(p);
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
/****************************************************************************/
|
|
||||||
int set_resolution(struct usb_device *p,
|
|
||||||
u16 set0, u16 set1, u16 set2, u16 set3)
|
|
||||||
{
|
|
||||||
u16 u0x0111, u0x0113, u0x0115, u0x0117;
|
|
||||||
|
|
||||||
if (!p)
|
|
||||||
return -ENODEV;
|
|
||||||
u0x0111 = ((0xFF00 & set0) >> 8);
|
|
||||||
u0x0113 = ((0xFF00 & set1) >> 8);
|
|
||||||
u0x0115 = ((0xFF00 & set2) >> 8);
|
|
||||||
u0x0117 = ((0xFF00 & set3) >> 8);
|
|
||||||
|
|
||||||
SET(p, 0x0110, (0x00FF & set0));
|
|
||||||
SET(p, 0x0111, u0x0111);
|
|
||||||
SET(p, 0x0112, (0x00FF & set1));
|
|
||||||
SET(p, 0x0113, u0x0113);
|
|
||||||
SET(p, 0x0114, (0x00FF & set2));
|
|
||||||
SET(p, 0x0115, u0x0115);
|
|
||||||
SET(p, 0x0116, (0x00FF & set3));
|
|
||||||
SET(p, 0x0117, u0x0117);
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
/****************************************************************************/
|
|
||||||
int start_100(struct usb_device *p)
|
|
||||||
{
|
|
||||||
u16 get116, get117, get0;
|
|
||||||
u8 igot116, igot117, igot;
|
|
||||||
|
|
||||||
if (!p)
|
|
||||||
return -ENODEV;
|
|
||||||
GET(p, 0x0116, &igot116);
|
|
||||||
get116 = igot116;
|
|
||||||
GET(p, 0x0117, &igot117);
|
|
||||||
get117 = igot117;
|
|
||||||
SET(p, 0x0116, 0x0000);
|
|
||||||
SET(p, 0x0117, 0x0000);
|
|
||||||
|
|
||||||
GET(p, 0x0100, &igot);
|
|
||||||
get0 = igot;
|
|
||||||
SET(p, 0x0100, (0x80 | get0));
|
|
||||||
|
|
||||||
SET(p, 0x0116, get116);
|
|
||||||
SET(p, 0x0117, get117);
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
/****************************************************************************/
|
|
||||||
int stop_100(struct usb_device *p)
|
|
||||||
{
|
|
||||||
u16 get0;
|
|
||||||
u8 igot;
|
|
||||||
|
|
||||||
if (!p)
|
|
||||||
return -ENODEV;
|
|
||||||
GET(p, 0x0100, &igot);
|
|
||||||
get0 = igot;
|
|
||||||
SET(p, 0x0100, (0x7F & get0));
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
/****************************************************************************/
|
|
||||||
/****************************************************************************/
|
|
||||||
/*****************************************************************************/
|
|
||||||
int easycap_wakeup_device(struct usb_device *pusb_device)
|
|
||||||
{
|
|
||||||
if (!pusb_device)
|
|
||||||
return -ENODEV;
|
|
||||||
|
|
||||||
return usb_control_msg(pusb_device, usb_sndctrlpipe(pusb_device, 0),
|
|
||||||
USB_REQ_SET_FEATURE,
|
|
||||||
USB_DIR_OUT | USB_TYPE_STANDARD | USB_RECIP_DEVICE,
|
|
||||||
USB_DEVICE_REMOTE_WAKEUP,
|
|
||||||
0, NULL, 0, 50000);
|
|
||||||
}
|
|
||||||
/*****************************************************************************/
|
|
||||||
int easycap_audio_setup(struct easycap *peasycap)
|
|
||||||
{
|
|
||||||
struct usb_device *pusb_device;
|
|
||||||
u8 buffer[1];
|
|
||||||
int rc, id1, id2;
|
|
||||||
/*---------------------------------------------------------------------------*/
|
|
||||||
/*
|
|
||||||
* IMPORTANT:
|
|
||||||
* THE MESSAGE OF TYPE (USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE)
|
|
||||||
* CAUSES MUTING IF THE VALUE 0x0100 IS SENT.
|
|
||||||
* TO ENABLE AUDIO THE VALUE 0x0200 MUST BE SENT.
|
|
||||||
*/
|
|
||||||
/*---------------------------------------------------------------------------*/
|
|
||||||
const u8 request = 0x01;
|
|
||||||
const u8 requesttype = USB_DIR_OUT |
|
|
||||||
USB_TYPE_CLASS |
|
|
||||||
USB_RECIP_INTERFACE;
|
|
||||||
const u16 value_unmute = 0x0200;
|
|
||||||
const u16 index = 0x0301;
|
|
||||||
const u16 length = 1;
|
|
||||||
|
|
||||||
if (!peasycap)
|
|
||||||
return -EFAULT;
|
|
||||||
|
|
||||||
pusb_device = peasycap->pusb_device;
|
|
||||||
if (!pusb_device)
|
|
||||||
return -ENODEV;
|
|
||||||
|
|
||||||
JOM(8, "%02X %02X %02X %02X %02X %02X %02X %02X\n",
|
|
||||||
requesttype, request,
|
|
||||||
(0x00FF & value_unmute),
|
|
||||||
(0xFF00 & value_unmute) >> 8,
|
|
||||||
(0x00FF & index),
|
|
||||||
(0xFF00 & index) >> 8,
|
|
||||||
(0x00FF & length),
|
|
||||||
(0xFF00 & length) >> 8);
|
|
||||||
|
|
||||||
buffer[0] = 0x01;
|
|
||||||
|
|
||||||
rc = usb_control_msg(pusb_device, usb_sndctrlpipe(pusb_device, 0),
|
|
||||||
request, requesttype, value_unmute,
|
|
||||||
index, &buffer[0], length, 50000);
|
|
||||||
|
|
||||||
JOT(8, "0x%02X=buffer\n", buffer[0]);
|
|
||||||
if (rc != (int)length) {
|
|
||||||
switch (rc) {
|
|
||||||
case -EPIPE:
|
|
||||||
SAY("usb_control_msg returned -EPIPE\n");
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
SAY("ERROR: usb_control_msg returned %i\n", rc);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
/*--------------------------------------------------------------------------*/
|
|
||||||
/*
|
|
||||||
* REGISTER 500: SETTING VALUE TO 0x0094 RESETS AUDIO CONFIGURATION ???
|
|
||||||
* REGISTER 506: ANALOGUE AUDIO ATTENTUATOR ???
|
|
||||||
* FOR THE CVBS+S-VIDEO HARDWARE:
|
|
||||||
* SETTING VALUE TO 0x0000 GIVES QUIET SOUND.
|
|
||||||
* THE UPPER BYTE SEEMS TO HAVE NO EFFECT.
|
|
||||||
* FOR THE FOUR-CVBS HARDWARE:
|
|
||||||
* SETTING VALUE TO 0x0000 SEEMS TO HAVE NO EFFECT.
|
|
||||||
* REGISTER 507: ANALOGUE AUDIO PREAMPLIFIER ON/OFF ???
|
|
||||||
* FOR THE CVBS-S-VIDEO HARDWARE:
|
|
||||||
* SETTING VALUE TO 0x0001 GIVES VERY LOUD, DISTORTED SOUND.
|
|
||||||
* THE UPPER BYTE SEEMS TO HAVE NO EFFECT.
|
|
||||||
*/
|
|
||||||
/*--------------------------------------------------------------------------*/
|
|
||||||
SET(pusb_device, 0x0500, 0x0094);
|
|
||||||
SET(pusb_device, 0x0500, 0x008C);
|
|
||||||
SET(pusb_device, 0x0506, 0x0001);
|
|
||||||
SET(pusb_device, 0x0507, 0x0000);
|
|
||||||
id1 = read_vt(pusb_device, 0x007C);
|
|
||||||
id2 = read_vt(pusb_device, 0x007E);
|
|
||||||
SAM("0x%04X:0x%04X is audio vendor id\n", id1, id2);
|
|
||||||
/*---------------------------------------------------------------------------*/
|
|
||||||
/*
|
|
||||||
* SELECT AUDIO SOURCE "LINE IN" AND SET THE AUDIO GAIN.
|
|
||||||
*/
|
|
||||||
/*---------------------------------------------------------------------------*/
|
|
||||||
if (easycap_audio_gainset(pusb_device, peasycap->gain))
|
|
||||||
SAY("ERROR: audio_gainset() failed\n");
|
|
||||||
check_vt(pusb_device);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
/*****************************************************************************/
|
|
||||||
int check_vt(struct usb_device *pusb_device)
|
|
||||||
{
|
|
||||||
int igot;
|
|
||||||
|
|
||||||
if (!pusb_device)
|
|
||||||
return -ENODEV;
|
|
||||||
igot = read_vt(pusb_device, 0x0002);
|
|
||||||
if (0 > igot)
|
|
||||||
SAY("ERROR: failed to read VT1612A register 0x02\n");
|
|
||||||
if (0x8000 & igot)
|
|
||||||
SAY("register 0x%02X muted\n", 0x02);
|
|
||||||
|
|
||||||
igot = read_vt(pusb_device, 0x000E);
|
|
||||||
if (0 > igot)
|
|
||||||
SAY("ERROR: failed to read VT1612A register 0x0E\n");
|
|
||||||
if (0x8000 & igot)
|
|
||||||
SAY("register 0x%02X muted\n", 0x0E);
|
|
||||||
|
|
||||||
igot = read_vt(pusb_device, 0x0010);
|
|
||||||
if (0 > igot)
|
|
||||||
SAY("ERROR: failed to read VT1612A register 0x10\n");
|
|
||||||
if (0x8000 & igot)
|
|
||||||
SAY("register 0x%02X muted\n", 0x10);
|
|
||||||
|
|
||||||
igot = read_vt(pusb_device, 0x0012);
|
|
||||||
if (0 > igot)
|
|
||||||
SAY("ERROR: failed to read VT1612A register 0x12\n");
|
|
||||||
if (0x8000 & igot)
|
|
||||||
SAY("register 0x%02X muted\n", 0x12);
|
|
||||||
|
|
||||||
igot = read_vt(pusb_device, 0x0014);
|
|
||||||
if (0 > igot)
|
|
||||||
SAY("ERROR: failed to read VT1612A register 0x14\n");
|
|
||||||
if (0x8000 & igot)
|
|
||||||
SAY("register 0x%02X muted\n", 0x14);
|
|
||||||
|
|
||||||
igot = read_vt(pusb_device, 0x0016);
|
|
||||||
if (0 > igot)
|
|
||||||
SAY("ERROR: failed to read VT1612A register 0x16\n");
|
|
||||||
if (0x8000 & igot)
|
|
||||||
SAY("register 0x%02X muted\n", 0x16);
|
|
||||||
|
|
||||||
igot = read_vt(pusb_device, 0x0018);
|
|
||||||
if (0 > igot)
|
|
||||||
SAY("ERROR: failed to read VT1612A register 0x18\n");
|
|
||||||
if (0x8000 & igot)
|
|
||||||
SAY("register 0x%02X muted\n", 0x18);
|
|
||||||
|
|
||||||
igot = read_vt(pusb_device, 0x001C);
|
|
||||||
if (0 > igot)
|
|
||||||
SAY("ERROR: failed to read VT1612A register 0x1C\n");
|
|
||||||
if (0x8000 & igot)
|
|
||||||
SAY("register 0x%02X muted\n", 0x1C);
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
/*****************************************************************************/
|
|
||||||
/*---------------------------------------------------------------------------*/
|
|
||||||
/* NOTE: THIS DOES INCREASE THE VOLUME DRAMATICALLY:
|
|
||||||
* audio_gainset(pusb_device, 0x000F);
|
|
||||||
*
|
|
||||||
* loud dB register 0x10 dB register 0x1C dB total
|
|
||||||
* 0 -34.5 0 -34.5
|
|
||||||
* .. .... . ....
|
|
||||||
* 15 10.5 0 10.5
|
|
||||||
* 16 12.0 0 12.0
|
|
||||||
* 17 12.0 1.5 13.5
|
|
||||||
* .. .... .... ....
|
|
||||||
* 31 12.0 22.5 34.5
|
|
||||||
*/
|
|
||||||
/*---------------------------------------------------------------------------*/
|
|
||||||
int easycap_audio_gainset(struct usb_device *pusb_device, s8 loud)
|
|
||||||
{
|
|
||||||
int igot;
|
|
||||||
u8 tmp;
|
|
||||||
u16 mute;
|
|
||||||
|
|
||||||
if (!pusb_device)
|
|
||||||
return -ENODEV;
|
|
||||||
if (0 > loud)
|
|
||||||
loud = 0;
|
|
||||||
if (31 < loud)
|
|
||||||
loud = 31;
|
|
||||||
|
|
||||||
write_vt(pusb_device, 0x0002, 0x8000);
|
|
||||||
/*---------------------------------------------------------------------------*/
|
|
||||||
igot = read_vt(pusb_device, 0x000E);
|
|
||||||
if (0 > igot) {
|
|
||||||
SAY("ERROR: failed to read VT1612A register 0x0E\n");
|
|
||||||
mute = 0x0000;
|
|
||||||
} else
|
|
||||||
mute = 0x8000 & ((unsigned int)igot);
|
|
||||||
mute = 0;
|
|
||||||
|
|
||||||
if (16 > loud)
|
|
||||||
tmp = 0x01 | (0x001F & (((u8)(15 - loud)) << 1));
|
|
||||||
else
|
|
||||||
tmp = 0;
|
|
||||||
|
|
||||||
JOT(8, "0x%04X=(mute|tmp) for VT1612A register 0x0E\n", mute | tmp);
|
|
||||||
write_vt(pusb_device, 0x000E, (mute | tmp));
|
|
||||||
/*---------------------------------------------------------------------------*/
|
|
||||||
igot = read_vt(pusb_device, 0x0010);
|
|
||||||
if (0 > igot) {
|
|
||||||
SAY("ERROR: failed to read VT1612A register 0x10\n");
|
|
||||||
mute = 0x0000;
|
|
||||||
} else
|
|
||||||
mute = 0x8000 & ((unsigned int)igot);
|
|
||||||
mute = 0;
|
|
||||||
|
|
||||||
JOT(8, "0x%04X=(mute|tmp|(tmp<<8)) for VT1612A register 0x10,...0x18\n",
|
|
||||||
mute | tmp | (tmp << 8));
|
|
||||||
write_vt(pusb_device, 0x0010, (mute | tmp | (tmp << 8)));
|
|
||||||
write_vt(pusb_device, 0x0012, (mute | tmp | (tmp << 8)));
|
|
||||||
write_vt(pusb_device, 0x0014, (mute | tmp | (tmp << 8)));
|
|
||||||
write_vt(pusb_device, 0x0016, (mute | tmp | (tmp << 8)));
|
|
||||||
write_vt(pusb_device, 0x0018, (mute | tmp | (tmp << 8)));
|
|
||||||
/*---------------------------------------------------------------------------*/
|
|
||||||
igot = read_vt(pusb_device, 0x001C);
|
|
||||||
if (0 > igot) {
|
|
||||||
SAY("ERROR: failed to read VT1612A register 0x1C\n");
|
|
||||||
mute = 0x0000;
|
|
||||||
} else
|
|
||||||
mute = 0x8000 & ((unsigned int)igot);
|
|
||||||
mute = 0;
|
|
||||||
|
|
||||||
if (16 <= loud)
|
|
||||||
tmp = 0x000F & (u8)(loud - 16);
|
|
||||||
else
|
|
||||||
tmp = 0;
|
|
||||||
|
|
||||||
JOT(8, "0x%04X=(mute|tmp|(tmp<<8)) for VT1612A register 0x1C\n",
|
|
||||||
mute | tmp | (tmp << 8));
|
|
||||||
write_vt(pusb_device, 0x001C, (mute | tmp | (tmp << 8)));
|
|
||||||
write_vt(pusb_device, 0x001A, 0x0404);
|
|
||||||
write_vt(pusb_device, 0x0002, 0x0000);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
/*****************************************************************************/
|
|
File diff suppressed because it is too large
Load diff
|
@ -1,696 +0,0 @@
|
||||||
/******************************************************************************
|
|
||||||
* *
|
|
||||||
* easycap_settings.c *
|
|
||||||
* *
|
|
||||||
******************************************************************************/
|
|
||||||
/*
|
|
||||||
*
|
|
||||||
* Copyright (C) 2010 R.M. Thomas <rmthomas@sciolus.org>
|
|
||||||
*
|
|
||||||
*
|
|
||||||
* This 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.
|
|
||||||
*
|
|
||||||
* The software 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 software; if not, write to the Free Software
|
|
||||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
/*****************************************************************************/
|
|
||||||
|
|
||||||
#include "easycap.h"
|
|
||||||
|
|
||||||
/*---------------------------------------------------------------------------*/
|
|
||||||
/*
|
|
||||||
* THE LEAST SIGNIFICANT BIT OF easycap_standard.mask HAS MEANING:
|
|
||||||
* 0 => 25 fps
|
|
||||||
* 1 => 30 fps
|
|
||||||
*
|
|
||||||
* THE MOST SIGNIFICANT BIT OF easycap_standard.mask HAS MEANING:
|
|
||||||
* 0 => full framerate
|
|
||||||
* 1 => 20% framerate
|
|
||||||
*/
|
|
||||||
/*---------------------------------------------------------------------------*/
|
|
||||||
const struct easycap_standard easycap_standard[] = {
|
|
||||||
{
|
|
||||||
.mask = 0x00FF & PAL_BGHIN ,
|
|
||||||
.v4l2_standard = {
|
|
||||||
.index = PAL_BGHIN,
|
|
||||||
.id = (V4L2_STD_PAL_B |
|
|
||||||
V4L2_STD_PAL_G | V4L2_STD_PAL_H |
|
|
||||||
V4L2_STD_PAL_I | V4L2_STD_PAL_N),
|
|
||||||
.name = "PAL_BGHIN",
|
|
||||||
.frameperiod = {1, 25},
|
|
||||||
.framelines = 625,
|
|
||||||
.reserved = {0, 0, 0, 0}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
|
|
||||||
{
|
|
||||||
.mask = 0x00FF & NTSC_N_443 ,
|
|
||||||
.v4l2_standard = {
|
|
||||||
.index = NTSC_N_443,
|
|
||||||
.id = V4L2_STD_UNKNOWN,
|
|
||||||
.name = "NTSC_N_443",
|
|
||||||
.frameperiod = {1, 25},
|
|
||||||
.framelines = 480,
|
|
||||||
.reserved = {0, 0, 0, 0}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
|
|
||||||
{
|
|
||||||
.mask = 0x00FF & PAL_Nc ,
|
|
||||||
.v4l2_standard = {
|
|
||||||
.index = PAL_Nc,
|
|
||||||
.id = V4L2_STD_PAL_Nc,
|
|
||||||
.name = "PAL_Nc",
|
|
||||||
.frameperiod = {1, 25},
|
|
||||||
.framelines = 625,
|
|
||||||
.reserved = {0, 0, 0, 0}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
|
|
||||||
{
|
|
||||||
.mask = 0x00FF & NTSC_N ,
|
|
||||||
.v4l2_standard = {
|
|
||||||
.index = NTSC_N,
|
|
||||||
.id = V4L2_STD_UNKNOWN,
|
|
||||||
.name = "NTSC_N",
|
|
||||||
.frameperiod = {1, 25},
|
|
||||||
.framelines = 525,
|
|
||||||
.reserved = {0, 0, 0, 0}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
|
|
||||||
{
|
|
||||||
.mask = 0x00FF & SECAM ,
|
|
||||||
.v4l2_standard = {
|
|
||||||
.index = SECAM,
|
|
||||||
.id = V4L2_STD_SECAM,
|
|
||||||
.name = "SECAM",
|
|
||||||
.frameperiod = {1, 25},
|
|
||||||
.framelines = 625,
|
|
||||||
.reserved = {0, 0, 0, 0}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
|
|
||||||
{
|
|
||||||
.mask = 0x00FF & NTSC_M ,
|
|
||||||
.v4l2_standard = {
|
|
||||||
.index = NTSC_M,
|
|
||||||
.id = V4L2_STD_NTSC_M,
|
|
||||||
.name = "NTSC_M",
|
|
||||||
.frameperiod = {1, 30},
|
|
||||||
.framelines = 525,
|
|
||||||
.reserved = {0, 0, 0, 0}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
|
|
||||||
{
|
|
||||||
.mask = 0x00FF & NTSC_M_JP ,
|
|
||||||
.v4l2_standard = {
|
|
||||||
.index = NTSC_M_JP,
|
|
||||||
.id = V4L2_STD_NTSC_M_JP,
|
|
||||||
.name = "NTSC_M_JP",
|
|
||||||
.frameperiod = {1, 30},
|
|
||||||
.framelines = 525,
|
|
||||||
.reserved = {0, 0, 0, 0}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
|
|
||||||
{
|
|
||||||
.mask = 0x00FF & PAL_60 ,
|
|
||||||
.v4l2_standard = {
|
|
||||||
.index = PAL_60,
|
|
||||||
.id = V4L2_STD_PAL_60,
|
|
||||||
.name = "PAL_60",
|
|
||||||
.frameperiod = {1, 30},
|
|
||||||
.framelines = 525,
|
|
||||||
.reserved = {0, 0, 0, 0}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
|
|
||||||
{
|
|
||||||
.mask = 0x00FF & NTSC_443 ,
|
|
||||||
.v4l2_standard = {
|
|
||||||
.index = NTSC_443,
|
|
||||||
.id = V4L2_STD_NTSC_443,
|
|
||||||
.name = "NTSC_443",
|
|
||||||
.frameperiod = {1, 30},
|
|
||||||
.framelines = 525,
|
|
||||||
.reserved = {0, 0, 0, 0}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
|
|
||||||
{
|
|
||||||
.mask = 0x00FF & PAL_M ,
|
|
||||||
.v4l2_standard = {
|
|
||||||
.index = PAL_M,
|
|
||||||
.id = V4L2_STD_PAL_M,
|
|
||||||
.name = "PAL_M",
|
|
||||||
.frameperiod = {1, 30},
|
|
||||||
.framelines = 525,
|
|
||||||
.reserved = {0, 0, 0, 0}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
|
|
||||||
{
|
|
||||||
.mask = 0x8000 | (0x00FF & PAL_BGHIN_SLOW),
|
|
||||||
.v4l2_standard = {
|
|
||||||
.index = PAL_BGHIN_SLOW,
|
|
||||||
.id = (V4L2_STD_PAL_B | V4L2_STD_PAL_G |
|
|
||||||
V4L2_STD_PAL_H |
|
|
||||||
V4L2_STD_PAL_I | V4L2_STD_PAL_N |
|
|
||||||
(((v4l2_std_id)0x01) << 32)),
|
|
||||||
.name = "PAL_BGHIN_SLOW",
|
|
||||||
.frameperiod = {1, 5},
|
|
||||||
.framelines = 625,
|
|
||||||
.reserved = {0, 0, 0, 0}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
|
|
||||||
{
|
|
||||||
.mask = 0x8000 | (0x00FF & NTSC_N_443_SLOW),
|
|
||||||
.v4l2_standard = {
|
|
||||||
.index = NTSC_N_443_SLOW,
|
|
||||||
.id = (V4L2_STD_UNKNOWN | (((v4l2_std_id)0x11) << 32)),
|
|
||||||
.name = "NTSC_N_443_SLOW",
|
|
||||||
.frameperiod = {1, 5},
|
|
||||||
.framelines = 480,
|
|
||||||
.reserved = {0, 0, 0, 0}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
|
|
||||||
{
|
|
||||||
.mask = 0x8000 | (0x00FF & PAL_Nc_SLOW),
|
|
||||||
.v4l2_standard = {
|
|
||||||
.index = PAL_Nc_SLOW,
|
|
||||||
.id = (V4L2_STD_PAL_Nc | (((v4l2_std_id)0x01) << 32)),
|
|
||||||
.name = "PAL_Nc_SLOW",
|
|
||||||
.frameperiod = {1, 5},
|
|
||||||
.framelines = 625,
|
|
||||||
.reserved = {0, 0, 0, 0}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
|
|
||||||
{
|
|
||||||
.mask = 0x8000 | (0x00FF & NTSC_N_SLOW),
|
|
||||||
.v4l2_standard = {
|
|
||||||
.index = NTSC_N_SLOW,
|
|
||||||
.id = (V4L2_STD_UNKNOWN | (((v4l2_std_id)0x21) << 32)),
|
|
||||||
.name = "NTSC_N_SLOW",
|
|
||||||
.frameperiod = {1, 5},
|
|
||||||
.framelines = 525,
|
|
||||||
.reserved = {0, 0, 0, 0}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
|
|
||||||
{
|
|
||||||
.mask = 0x8000 | (0x00FF & SECAM_SLOW),
|
|
||||||
.v4l2_standard = {
|
|
||||||
.index = SECAM_SLOW,
|
|
||||||
.id = (V4L2_STD_SECAM | (((v4l2_std_id)0x01) << 32)),
|
|
||||||
.name = "SECAM_SLOW",
|
|
||||||
.frameperiod = {1, 5},
|
|
||||||
.framelines = 625,
|
|
||||||
.reserved = {0, 0, 0, 0}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
|
|
||||||
{
|
|
||||||
.mask = 0x8000 | (0x00FF & NTSC_M_SLOW),
|
|
||||||
.v4l2_standard = {
|
|
||||||
.index = NTSC_M_SLOW,
|
|
||||||
.id = (V4L2_STD_NTSC_M | (((v4l2_std_id)0x01) << 32)),
|
|
||||||
.name = "NTSC_M_SLOW",
|
|
||||||
.frameperiod = {1, 6},
|
|
||||||
.framelines = 525,
|
|
||||||
.reserved = {0, 0, 0, 0}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
|
|
||||||
{
|
|
||||||
.mask = 0x8000 | (0x00FF & NTSC_M_JP_SLOW),
|
|
||||||
.v4l2_standard = {
|
|
||||||
.index = NTSC_M_JP_SLOW,
|
|
||||||
.id = (V4L2_STD_NTSC_M_JP |
|
|
||||||
(((v4l2_std_id)0x01) << 32)),
|
|
||||||
.name = "NTSC_M_JP_SLOW",
|
|
||||||
.frameperiod = {1, 6},
|
|
||||||
.framelines = 525,
|
|
||||||
.reserved = {0, 0, 0, 0}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
|
|
||||||
{
|
|
||||||
.mask = 0x8000 | (0x00FF & PAL_60_SLOW),
|
|
||||||
.v4l2_standard = {
|
|
||||||
.index = PAL_60_SLOW,
|
|
||||||
.id = (V4L2_STD_PAL_60 | (((v4l2_std_id)0x01) << 32)),
|
|
||||||
.name = "PAL_60_SLOW",
|
|
||||||
.frameperiod = {1, 6},
|
|
||||||
.framelines = 525,
|
|
||||||
.reserved = {0, 0, 0, 0}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
|
|
||||||
{
|
|
||||||
.mask = 0x8000 | (0x00FF & NTSC_443_SLOW),
|
|
||||||
.v4l2_standard = {
|
|
||||||
.index = NTSC_443_SLOW,
|
|
||||||
.id = (V4L2_STD_NTSC_443 | (((v4l2_std_id)0x01) << 32)),
|
|
||||||
.name = "NTSC_443_SLOW",
|
|
||||||
.frameperiod = {1, 6},
|
|
||||||
.framelines = 525,
|
|
||||||
.reserved = {0, 0, 0, 0}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
|
|
||||||
{
|
|
||||||
.mask = 0x8000 | (0x00FF & PAL_M_SLOW),
|
|
||||||
.v4l2_standard = {
|
|
||||||
.index = PAL_M_SLOW,
|
|
||||||
.id = (V4L2_STD_PAL_M | (((v4l2_std_id)0x01) << 32)),
|
|
||||||
.name = "PAL_M_SLOW",
|
|
||||||
.frameperiod = {1, 6},
|
|
||||||
.framelines = 525,
|
|
||||||
.reserved = {0, 0, 0, 0}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
|
|
||||||
{
|
|
||||||
.mask = 0xFFFF
|
|
||||||
}
|
|
||||||
};
|
|
||||||
/*---------------------------------------------------------------------------*/
|
|
||||||
/*
|
|
||||||
* THE 16-BIT easycap_format.mask HAS MEANING:
|
|
||||||
* (least significant) BIT 0: 0 => PAL, 25 FPS; 1 => NTSC, 30 FPS
|
|
||||||
* BITS 2-4: RESERVED FOR DIFFERENTIATING STANDARDS
|
|
||||||
* BITS 5-7: NUMBER OF BYTES PER PIXEL
|
|
||||||
* BIT 8: 0 => NATIVE BYTE ORDER; 1 => SWAPPED
|
|
||||||
* BITS 9-10: RESERVED FOR OTHER BYTE PERMUTATIONS
|
|
||||||
* BIT 11: 0 => UNDECIMATED; 1 => DECIMATED
|
|
||||||
* BIT 12: 0 => OFFER FRAMES; 1 => OFFER FIELDS
|
|
||||||
* BIT 13: 0 => FULL FRAMERATE; 1 => REDUCED
|
|
||||||
* (most significant) BITS 14-15: RESERVED FOR OTHER FIELD/FRAME OPTIONS
|
|
||||||
* IT FOLLOWS THAT:
|
|
||||||
* bytesperpixel IS ((0x00E0 & easycap_format.mask) >> 5)
|
|
||||||
* byteswaporder IS true IF (0 != (0x0100 & easycap_format.mask))
|
|
||||||
*
|
|
||||||
* decimatepixel IS true IF (0 != (0x0800 & easycap_format.mask))
|
|
||||||
*
|
|
||||||
* offerfields IS true IF (0 != (0x1000 & easycap_format.mask))
|
|
||||||
*/
|
|
||||||
/*---------------------------------------------------------------------------*/
|
|
||||||
|
|
||||||
struct easycap_format easycap_format[1 + SETTINGS_MANY];
|
|
||||||
|
|
||||||
int easycap_video_fillin_formats(void)
|
|
||||||
{
|
|
||||||
const char *name1, *name2, *name3, *name4;
|
|
||||||
struct v4l2_format *fmt;
|
|
||||||
int i, j, k, m, n;
|
|
||||||
u32 width, height, pixelformat, bytesperline, sizeimage;
|
|
||||||
u16 mask1, mask2, mask3, mask4;
|
|
||||||
enum v4l2_field field;
|
|
||||||
enum v4l2_colorspace colorspace;
|
|
||||||
|
|
||||||
for (i = 0, n = 0; i < STANDARD_MANY; i++) {
|
|
||||||
mask1 = 0x0000;
|
|
||||||
switch (i) {
|
|
||||||
case PAL_BGHIN: {
|
|
||||||
mask1 = 0x1F & PAL_BGHIN;
|
|
||||||
name1 = "PAL_BGHIN";
|
|
||||||
colorspace = V4L2_COLORSPACE_470_SYSTEM_BG;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case SECAM: {
|
|
||||||
mask1 = 0x1F & SECAM;
|
|
||||||
name1 = "SECAM";
|
|
||||||
colorspace = V4L2_COLORSPACE_470_SYSTEM_BG;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case PAL_Nc: {
|
|
||||||
mask1 = 0x1F & PAL_Nc;
|
|
||||||
name1 = "PAL_Nc";
|
|
||||||
colorspace = V4L2_COLORSPACE_470_SYSTEM_BG;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case PAL_60: {
|
|
||||||
mask1 = 0x1F & PAL_60;
|
|
||||||
name1 = "PAL_60";
|
|
||||||
colorspace = V4L2_COLORSPACE_470_SYSTEM_BG;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case PAL_M: {
|
|
||||||
mask1 = 0x1F & PAL_M;
|
|
||||||
name1 = "PAL_M";
|
|
||||||
colorspace = V4L2_COLORSPACE_470_SYSTEM_BG;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case NTSC_M: {
|
|
||||||
mask1 = 0x1F & NTSC_M;
|
|
||||||
name1 = "NTSC_M";
|
|
||||||
colorspace = V4L2_COLORSPACE_470_SYSTEM_M;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case NTSC_443: {
|
|
||||||
mask1 = 0x1F & NTSC_443;
|
|
||||||
name1 = "NTSC_443";
|
|
||||||
colorspace = V4L2_COLORSPACE_470_SYSTEM_M;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case NTSC_M_JP: {
|
|
||||||
mask1 = 0x1F & NTSC_M_JP;
|
|
||||||
name1 = "NTSC_M_JP";
|
|
||||||
colorspace = V4L2_COLORSPACE_470_SYSTEM_M;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case NTSC_N: {
|
|
||||||
mask1 = 0x1F & NTSC_M;
|
|
||||||
name1 = "NTSC_N";
|
|
||||||
colorspace = V4L2_COLORSPACE_470_SYSTEM_M;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case NTSC_N_443: {
|
|
||||||
mask1 = 0x1F & NTSC_N_443;
|
|
||||||
name1 = "NTSC_N_443";
|
|
||||||
colorspace = V4L2_COLORSPACE_470_SYSTEM_M;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case PAL_BGHIN_SLOW: {
|
|
||||||
mask1 = 0x001F & PAL_BGHIN_SLOW;
|
|
||||||
mask1 |= 0x0200;
|
|
||||||
name1 = "PAL_BGHIN_SLOW";
|
|
||||||
colorspace = V4L2_COLORSPACE_470_SYSTEM_BG;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case SECAM_SLOW: {
|
|
||||||
mask1 = 0x001F & SECAM_SLOW;
|
|
||||||
mask1 |= 0x0200;
|
|
||||||
name1 = "SECAM_SLOW";
|
|
||||||
colorspace = V4L2_COLORSPACE_470_SYSTEM_BG;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case PAL_Nc_SLOW: {
|
|
||||||
mask1 = 0x001F & PAL_Nc_SLOW;
|
|
||||||
mask1 |= 0x0200;
|
|
||||||
name1 = "PAL_Nc_SLOW";
|
|
||||||
colorspace = V4L2_COLORSPACE_470_SYSTEM_BG;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case PAL_60_SLOW: {
|
|
||||||
mask1 = 0x001F & PAL_60_SLOW;
|
|
||||||
mask1 |= 0x0200;
|
|
||||||
name1 = "PAL_60_SLOW";
|
|
||||||
colorspace = V4L2_COLORSPACE_470_SYSTEM_BG;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case PAL_M_SLOW: {
|
|
||||||
mask1 = 0x001F & PAL_M_SLOW;
|
|
||||||
mask1 |= 0x0200;
|
|
||||||
name1 = "PAL_M_SLOW";
|
|
||||||
colorspace = V4L2_COLORSPACE_470_SYSTEM_BG;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case NTSC_M_SLOW: {
|
|
||||||
mask1 = 0x001F & NTSC_M_SLOW;
|
|
||||||
mask1 |= 0x0200;
|
|
||||||
name1 = "NTSC_M_SLOW";
|
|
||||||
colorspace = V4L2_COLORSPACE_470_SYSTEM_M;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case NTSC_443_SLOW: {
|
|
||||||
mask1 = 0x001F & NTSC_443_SLOW;
|
|
||||||
mask1 |= 0x0200;
|
|
||||||
name1 = "NTSC_443_SLOW";
|
|
||||||
colorspace = V4L2_COLORSPACE_470_SYSTEM_M;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case NTSC_M_JP_SLOW: {
|
|
||||||
mask1 = 0x001F & NTSC_M_JP_SLOW;
|
|
||||||
mask1 |= 0x0200;
|
|
||||||
name1 = "NTSC_M_JP_SLOW";
|
|
||||||
colorspace = V4L2_COLORSPACE_470_SYSTEM_M;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case NTSC_N_SLOW: {
|
|
||||||
mask1 = 0x001F & NTSC_N_SLOW;
|
|
||||||
mask1 |= 0x0200;
|
|
||||||
name1 = "NTSC_N_SLOW";
|
|
||||||
colorspace = V4L2_COLORSPACE_470_SYSTEM_M;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case NTSC_N_443_SLOW: {
|
|
||||||
mask1 = 0x001F & NTSC_N_443_SLOW;
|
|
||||||
mask1 |= 0x0200;
|
|
||||||
name1 = "NTSC_N_443_SLOW";
|
|
||||||
colorspace = V4L2_COLORSPACE_470_SYSTEM_M;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (j = 0; j < RESOLUTION_MANY; j++) {
|
|
||||||
mask2 = 0x0000;
|
|
||||||
switch (j) {
|
|
||||||
case AT_720x576: {
|
|
||||||
if (0x1 & mask1)
|
|
||||||
continue;
|
|
||||||
name2 = "_AT_720x576";
|
|
||||||
width = 720;
|
|
||||||
height = 576;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case AT_704x576: {
|
|
||||||
if (0x1 & mask1)
|
|
||||||
continue;
|
|
||||||
name2 = "_AT_704x576";
|
|
||||||
width = 704;
|
|
||||||
height = 576;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case AT_640x480: {
|
|
||||||
name2 = "_AT_640x480";
|
|
||||||
width = 640;
|
|
||||||
height = 480;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case AT_720x480: {
|
|
||||||
if (!(0x1 & mask1))
|
|
||||||
continue;
|
|
||||||
name2 = "_AT_720x480";
|
|
||||||
width = 720;
|
|
||||||
height = 480;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case AT_360x288: {
|
|
||||||
if (0x1 & mask1)
|
|
||||||
continue;
|
|
||||||
name2 = "_AT_360x288";
|
|
||||||
width = 360;
|
|
||||||
height = 288;
|
|
||||||
mask2 = 0x0800;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case AT_320x240: {
|
|
||||||
name2 = "_AT_320x240";
|
|
||||||
width = 320;
|
|
||||||
height = 240;
|
|
||||||
mask2 = 0x0800;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case AT_360x240: {
|
|
||||||
if (!(0x1 & mask1))
|
|
||||||
continue;
|
|
||||||
name2 = "_AT_360x240";
|
|
||||||
width = 360;
|
|
||||||
height = 240;
|
|
||||||
mask2 = 0x0800;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
return -2;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (k = 0; k < PIXELFORMAT_MANY; k++) {
|
|
||||||
mask3 = 0x0000;
|
|
||||||
switch (k) {
|
|
||||||
case FMT_UYVY: {
|
|
||||||
name3 = __stringify(FMT_UYVY);
|
|
||||||
pixelformat = V4L2_PIX_FMT_UYVY;
|
|
||||||
mask3 |= (0x02 << 5);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case FMT_YUY2: {
|
|
||||||
name3 = __stringify(FMT_YUY2);
|
|
||||||
pixelformat = V4L2_PIX_FMT_YUYV;
|
|
||||||
mask3 |= (0x02 << 5);
|
|
||||||
mask3 |= 0x0100;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case FMT_RGB24: {
|
|
||||||
name3 = __stringify(FMT_RGB24);
|
|
||||||
pixelformat = V4L2_PIX_FMT_RGB24;
|
|
||||||
mask3 |= (0x03 << 5);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case FMT_RGB32: {
|
|
||||||
name3 = __stringify(FMT_RGB32);
|
|
||||||
pixelformat = V4L2_PIX_FMT_RGB32;
|
|
||||||
mask3 |= (0x04 << 5);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case FMT_BGR24: {
|
|
||||||
name3 = __stringify(FMT_BGR24);
|
|
||||||
pixelformat = V4L2_PIX_FMT_BGR24;
|
|
||||||
mask3 |= (0x03 << 5);
|
|
||||||
mask3 |= 0x0100;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case FMT_BGR32: {
|
|
||||||
name3 = __stringify(FMT_BGR32);
|
|
||||||
pixelformat = V4L2_PIX_FMT_BGR32;
|
|
||||||
mask3 |= (0x04 << 5);
|
|
||||||
mask3 |= 0x0100;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
return -3;
|
|
||||||
}
|
|
||||||
bytesperline = width * ((mask3 & 0x00E0) >> 5);
|
|
||||||
sizeimage = bytesperline * height;
|
|
||||||
|
|
||||||
for (m = 0; m < INTERLACE_MANY; m++) {
|
|
||||||
mask4 = 0x0000;
|
|
||||||
switch (m) {
|
|
||||||
case FIELD_NONE: {
|
|
||||||
name4 = "-n";
|
|
||||||
field = V4L2_FIELD_NONE;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case FIELD_INTERLACED: {
|
|
||||||
name4 = "-i";
|
|
||||||
mask4 |= 0x1000;
|
|
||||||
field = V4L2_FIELD_INTERLACED;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
return -4;
|
|
||||||
}
|
|
||||||
if (SETTINGS_MANY <= n)
|
|
||||||
return -5;
|
|
||||||
|
|
||||||
strcpy(easycap_format[n].name, name1);
|
|
||||||
strcat(easycap_format[n].name, name2);
|
|
||||||
strcat(easycap_format[n].name, "_");
|
|
||||||
strcat(easycap_format[n].name, name3);
|
|
||||||
strcat(easycap_format[n].name, name4);
|
|
||||||
easycap_format[n].mask =
|
|
||||||
mask1 | mask2 | mask3 | mask4;
|
|
||||||
fmt = &easycap_format[n].v4l2_format;
|
|
||||||
|
|
||||||
fmt->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
|
|
||||||
fmt->fmt.pix.width = width;
|
|
||||||
fmt->fmt.pix.height = height;
|
|
||||||
fmt->fmt.pix.pixelformat = pixelformat;
|
|
||||||
fmt->fmt.pix.field = field;
|
|
||||||
fmt->fmt.pix.bytesperline = bytesperline;
|
|
||||||
fmt->fmt.pix.sizeimage = sizeimage;
|
|
||||||
fmt->fmt.pix.colorspace = colorspace;
|
|
||||||
fmt->fmt.pix.priv = 0;
|
|
||||||
n++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if ((1 + SETTINGS_MANY) <= n)
|
|
||||||
return -6;
|
|
||||||
easycap_format[n].mask = 0xFFFF;
|
|
||||||
return n;
|
|
||||||
}
|
|
||||||
/*---------------------------------------------------------------------------*/
|
|
||||||
struct v4l2_queryctrl easycap_control[] = {
|
|
||||||
{
|
|
||||||
.id = V4L2_CID_BRIGHTNESS,
|
|
||||||
.type = V4L2_CTRL_TYPE_INTEGER,
|
|
||||||
.name = "Brightness",
|
|
||||||
.minimum = 0,
|
|
||||||
.maximum = 255,
|
|
||||||
.step = 1,
|
|
||||||
.default_value = SAA_0A_DEFAULT,
|
|
||||||
.flags = 0,
|
|
||||||
.reserved = {0, 0}
|
|
||||||
},
|
|
||||||
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
|
|
||||||
{
|
|
||||||
.id = V4L2_CID_CONTRAST,
|
|
||||||
.type = V4L2_CTRL_TYPE_INTEGER,
|
|
||||||
.name = "Contrast",
|
|
||||||
.minimum = 0,
|
|
||||||
.maximum = 255,
|
|
||||||
.step = 1,
|
|
||||||
.default_value = SAA_0B_DEFAULT + 128,
|
|
||||||
.flags = 0,
|
|
||||||
.reserved = {0, 0}
|
|
||||||
},
|
|
||||||
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
|
|
||||||
{
|
|
||||||
.id = V4L2_CID_SATURATION,
|
|
||||||
.type = V4L2_CTRL_TYPE_INTEGER,
|
|
||||||
.name = "Saturation",
|
|
||||||
.minimum = 0,
|
|
||||||
.maximum = 255,
|
|
||||||
.step = 1,
|
|
||||||
.default_value = SAA_0C_DEFAULT + 128,
|
|
||||||
.flags = 0,
|
|
||||||
.reserved = {0, 0}
|
|
||||||
},
|
|
||||||
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
|
|
||||||
{
|
|
||||||
.id = V4L2_CID_HUE,
|
|
||||||
.type = V4L2_CTRL_TYPE_INTEGER,
|
|
||||||
.name = "Hue",
|
|
||||||
.minimum = 0,
|
|
||||||
.maximum = 255,
|
|
||||||
.step = 1,
|
|
||||||
.default_value = SAA_0D_DEFAULT + 128,
|
|
||||||
.flags = 0,
|
|
||||||
.reserved = {0, 0}
|
|
||||||
},
|
|
||||||
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
|
|
||||||
{
|
|
||||||
.id = V4L2_CID_AUDIO_VOLUME,
|
|
||||||
.type = V4L2_CTRL_TYPE_INTEGER,
|
|
||||||
.name = "Volume",
|
|
||||||
.minimum = 0,
|
|
||||||
.maximum = 31,
|
|
||||||
.step = 1,
|
|
||||||
.default_value = 16,
|
|
||||||
.flags = 0,
|
|
||||||
.reserved = {0, 0}
|
|
||||||
},
|
|
||||||
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
|
|
||||||
{
|
|
||||||
.id = V4L2_CID_AUDIO_MUTE,
|
|
||||||
.type = V4L2_CTRL_TYPE_BOOLEAN,
|
|
||||||
.name = "Mute",
|
|
||||||
.default_value = true,
|
|
||||||
.flags = 0,
|
|
||||||
.reserved = {0, 0}
|
|
||||||
},
|
|
||||||
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
|
|
||||||
{
|
|
||||||
.id = 0xFFFFFFFF
|
|
||||||
}
|
|
||||||
};
|
|
||||||
/*****************************************************************************/
|
|
|
@ -1,750 +0,0 @@
|
||||||
/******************************************************************************
|
|
||||||
* *
|
|
||||||
* easycap_sound.c *
|
|
||||||
* *
|
|
||||||
* Audio driver for EasyCAP USB2.0 Video Capture Device DC60 *
|
|
||||||
* *
|
|
||||||
* *
|
|
||||||
******************************************************************************/
|
|
||||||
/*
|
|
||||||
*
|
|
||||||
* Copyright (C) 2010 R.M. Thomas <rmthomas@sciolus.org>
|
|
||||||
*
|
|
||||||
*
|
|
||||||
* This 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.
|
|
||||||
*
|
|
||||||
* The software 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 software; if not, write to the Free Software
|
|
||||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
/*****************************************************************************/
|
|
||||||
|
|
||||||
#include "easycap.h"
|
|
||||||
|
|
||||||
/*--------------------------------------------------------------------------*/
|
|
||||||
/*
|
|
||||||
* PARAMETERS USED WHEN REGISTERING THE AUDIO INTERFACE
|
|
||||||
*/
|
|
||||||
/*--------------------------------------------------------------------------*/
|
|
||||||
static const struct snd_pcm_hardware alsa_hardware = {
|
|
||||||
.info = SNDRV_PCM_INFO_BLOCK_TRANSFER |
|
|
||||||
SNDRV_PCM_INFO_MMAP |
|
|
||||||
SNDRV_PCM_INFO_INTERLEAVED |
|
|
||||||
SNDRV_PCM_INFO_MMAP_VALID,
|
|
||||||
.formats = SNDRV_PCM_FMTBIT_S16_LE,
|
|
||||||
.rates = SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000,
|
|
||||||
.rate_min = 32000,
|
|
||||||
.rate_max = 48000,
|
|
||||||
.channels_min = 2,
|
|
||||||
.channels_max = 2,
|
|
||||||
.buffer_bytes_max = PAGE_SIZE *
|
|
||||||
PAGES_PER_AUDIO_FRAGMENT *
|
|
||||||
AUDIO_FRAGMENT_MANY,
|
|
||||||
.period_bytes_min = PAGE_SIZE * PAGES_PER_AUDIO_FRAGMENT,
|
|
||||||
.period_bytes_max = PAGE_SIZE * PAGES_PER_AUDIO_FRAGMENT * 2,
|
|
||||||
.periods_min = AUDIO_FRAGMENT_MANY,
|
|
||||||
.periods_max = AUDIO_FRAGMENT_MANY * 2,
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
/*---------------------------------------------------------------------------*/
|
|
||||||
/*
|
|
||||||
* SUBMIT ALL AUDIO URBS.
|
|
||||||
*/
|
|
||||||
/*---------------------------------------------------------------------------*/
|
|
||||||
static int easycap_audio_submit_urbs(struct easycap *peasycap)
|
|
||||||
{
|
|
||||||
struct data_urb *pdata_urb;
|
|
||||||
struct urb *purb;
|
|
||||||
struct list_head *plist_head;
|
|
||||||
int j, isbad, nospc, m, rc;
|
|
||||||
int isbuf;
|
|
||||||
|
|
||||||
if (!peasycap->purb_audio_head) {
|
|
||||||
SAM("ERROR: peasycap->urb_audio_head uninitialized\n");
|
|
||||||
return -EFAULT;
|
|
||||||
}
|
|
||||||
if (!peasycap->pusb_device) {
|
|
||||||
SAM("ERROR: peasycap->pusb_device is NULL\n");
|
|
||||||
return -EFAULT;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (peasycap->audio_isoc_streaming) {
|
|
||||||
JOM(4, "already streaming audio urbs\n");
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
JOM(4, "initial submission of all audio urbs\n");
|
|
||||||
rc = usb_set_interface(peasycap->pusb_device,
|
|
||||||
peasycap->audio_interface,
|
|
||||||
peasycap->audio_altsetting_on);
|
|
||||||
JOM(8, "usb_set_interface(.,%i,%i) returned %i\n",
|
|
||||||
peasycap->audio_interface,
|
|
||||||
peasycap->audio_altsetting_on, rc);
|
|
||||||
|
|
||||||
isbad = 0;
|
|
||||||
nospc = 0;
|
|
||||||
m = 0;
|
|
||||||
list_for_each(plist_head, peasycap->purb_audio_head) {
|
|
||||||
pdata_urb = list_entry(plist_head, struct data_urb, list_head);
|
|
||||||
if (pdata_urb && pdata_urb->purb) {
|
|
||||||
purb = pdata_urb->purb;
|
|
||||||
isbuf = pdata_urb->isbuf;
|
|
||||||
|
|
||||||
purb->interval = 1;
|
|
||||||
purb->dev = peasycap->pusb_device;
|
|
||||||
purb->pipe = usb_rcvisocpipe(peasycap->pusb_device,
|
|
||||||
peasycap->audio_endpointnumber);
|
|
||||||
purb->transfer_flags = URB_ISO_ASAP;
|
|
||||||
purb->transfer_buffer = peasycap->audio_isoc_buffer[isbuf].pgo;
|
|
||||||
purb->transfer_buffer_length = peasycap->audio_isoc_buffer_size;
|
|
||||||
purb->complete = easycap_alsa_complete;
|
|
||||||
purb->context = peasycap;
|
|
||||||
purb->start_frame = 0;
|
|
||||||
purb->number_of_packets = peasycap->audio_isoc_framesperdesc;
|
|
||||||
for (j = 0; j < peasycap->audio_isoc_framesperdesc; j++) {
|
|
||||||
purb->iso_frame_desc[j].offset = j * peasycap->audio_isoc_maxframesize;
|
|
||||||
purb->iso_frame_desc[j].length = peasycap->audio_isoc_maxframesize;
|
|
||||||
}
|
|
||||||
|
|
||||||
rc = usb_submit_urb(purb, GFP_KERNEL);
|
|
||||||
if (rc) {
|
|
||||||
isbad++;
|
|
||||||
SAM("ERROR: usb_submit_urb() failed"
|
|
||||||
" for urb with rc: -%s: %d\n",
|
|
||||||
strerror(rc), rc);
|
|
||||||
} else {
|
|
||||||
m++;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
isbad++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (nospc) {
|
|
||||||
SAM("-ENOSPC=usb_submit_urb() for %i urbs\n", nospc);
|
|
||||||
SAM("..... possibly inadequate USB bandwidth\n");
|
|
||||||
peasycap->audio_eof = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (isbad)
|
|
||||||
easycap_audio_kill_urbs(peasycap);
|
|
||||||
else
|
|
||||||
peasycap->audio_isoc_streaming = m;
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
/*---------------------------------------------------------------------------*/
|
|
||||||
/*
|
|
||||||
* COMMON AUDIO INITIALIZATION
|
|
||||||
*/
|
|
||||||
/*---------------------------------------------------------------------------*/
|
|
||||||
static int easycap_sound_setup(struct easycap *peasycap)
|
|
||||||
{
|
|
||||||
int rc;
|
|
||||||
|
|
||||||
JOM(4, "starting initialization\n");
|
|
||||||
|
|
||||||
if (!peasycap) {
|
|
||||||
SAY("ERROR: peasycap is NULL.\n");
|
|
||||||
return -EFAULT;
|
|
||||||
}
|
|
||||||
if (!peasycap->pusb_device) {
|
|
||||||
SAM("ERROR: peasycap->pusb_device is NULL\n");
|
|
||||||
return -ENODEV;
|
|
||||||
}
|
|
||||||
JOM(16, "0x%08lX=peasycap->pusb_device\n", (long int)peasycap->pusb_device);
|
|
||||||
|
|
||||||
rc = easycap_audio_setup(peasycap);
|
|
||||||
JOM(8, "audio_setup() returned %i\n", rc);
|
|
||||||
|
|
||||||
if (!peasycap->pusb_device) {
|
|
||||||
SAM("ERROR: peasycap->pusb_device has become NULL\n");
|
|
||||||
return -ENODEV;
|
|
||||||
}
|
|
||||||
/*---------------------------------------------------------------------------*/
|
|
||||||
if (!peasycap->pusb_device) {
|
|
||||||
SAM("ERROR: peasycap->pusb_device has become NULL\n");
|
|
||||||
return -ENODEV;
|
|
||||||
}
|
|
||||||
rc = usb_set_interface(peasycap->pusb_device, peasycap->audio_interface,
|
|
||||||
peasycap->audio_altsetting_on);
|
|
||||||
JOM(8, "usb_set_interface(.,%i,%i) returned %i\n", peasycap->audio_interface,
|
|
||||||
peasycap->audio_altsetting_on, rc);
|
|
||||||
|
|
||||||
rc = easycap_wakeup_device(peasycap->pusb_device);
|
|
||||||
JOM(8, "wakeup_device() returned %i\n", rc);
|
|
||||||
|
|
||||||
peasycap->audio_eof = 0;
|
|
||||||
peasycap->audio_idle = 0;
|
|
||||||
|
|
||||||
easycap_audio_submit_urbs(peasycap);
|
|
||||||
|
|
||||||
JOM(4, "finished initialization\n");
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
/*****************************************************************************/
|
|
||||||
/*---------------------------------------------------------------------------*/
|
|
||||||
/*
|
|
||||||
* ON COMPLETION OF AN AUDIO URB ITS DATA IS COPIED TO THE DAM BUFFER
|
|
||||||
* PROVIDED peasycap->audio_idle IS ZERO. REGARDLESS OF THIS BEING TRUE,
|
|
||||||
* IT IS RESUBMITTED PROVIDED peasycap->audio_isoc_streaming IS NOT ZERO.
|
|
||||||
*/
|
|
||||||
/*---------------------------------------------------------------------------*/
|
|
||||||
void easycap_alsa_complete(struct urb *purb)
|
|
||||||
{
|
|
||||||
struct easycap *peasycap;
|
|
||||||
struct snd_pcm_substream *pss;
|
|
||||||
struct snd_pcm_runtime *prt;
|
|
||||||
int dma_bytes, fragment_bytes;
|
|
||||||
int isfragment;
|
|
||||||
u8 *p1, *p2;
|
|
||||||
s16 tmp;
|
|
||||||
int i, j, more, much, rc;
|
|
||||||
#ifdef UPSAMPLE
|
|
||||||
int k;
|
|
||||||
s16 oldaudio, newaudio, delta;
|
|
||||||
#endif /*UPSAMPLE*/
|
|
||||||
|
|
||||||
JOT(16, "\n");
|
|
||||||
|
|
||||||
if (!purb) {
|
|
||||||
SAY("ERROR: purb is NULL\n");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
peasycap = purb->context;
|
|
||||||
if (!peasycap) {
|
|
||||||
SAY("ERROR: peasycap is NULL\n");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
much = 0;
|
|
||||||
if (peasycap->audio_idle) {
|
|
||||||
JOM(16, "%i=audio_idle %i=audio_isoc_streaming\n",
|
|
||||||
peasycap->audio_idle, peasycap->audio_isoc_streaming);
|
|
||||||
if (peasycap->audio_isoc_streaming)
|
|
||||||
goto resubmit;
|
|
||||||
}
|
|
||||||
/*---------------------------------------------------------------------------*/
|
|
||||||
pss = peasycap->psubstream;
|
|
||||||
if (!pss)
|
|
||||||
goto resubmit;
|
|
||||||
prt = pss->runtime;
|
|
||||||
if (!prt)
|
|
||||||
goto resubmit;
|
|
||||||
dma_bytes = (int)prt->dma_bytes;
|
|
||||||
if (0 == dma_bytes)
|
|
||||||
goto resubmit;
|
|
||||||
fragment_bytes = 4 * ((int)prt->period_size);
|
|
||||||
if (0 == fragment_bytes)
|
|
||||||
goto resubmit;
|
|
||||||
/* -------------------------------------------------------------------------*/
|
|
||||||
if (purb->status) {
|
|
||||||
if ((-ESHUTDOWN == purb->status) || (-ENOENT == purb->status)) {
|
|
||||||
JOM(16, "urb status -ESHUTDOWN or -ENOENT\n");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
SAM("ERROR: non-zero urb status: -%s: %d\n",
|
|
||||||
strerror(purb->status), purb->status);
|
|
||||||
goto resubmit;
|
|
||||||
}
|
|
||||||
/*---------------------------------------------------------------------------*/
|
|
||||||
/*
|
|
||||||
* PROCEED HERE WHEN NO ERROR
|
|
||||||
*/
|
|
||||||
/*---------------------------------------------------------------------------*/
|
|
||||||
|
|
||||||
#ifdef UPSAMPLE
|
|
||||||
oldaudio = peasycap->oldaudio;
|
|
||||||
#endif /*UPSAMPLE*/
|
|
||||||
|
|
||||||
for (i = 0; i < purb->number_of_packets; i++) {
|
|
||||||
if (purb->iso_frame_desc[i].status < 0) {
|
|
||||||
SAM("-%s: %d\n",
|
|
||||||
strerror(purb->iso_frame_desc[i].status),
|
|
||||||
purb->iso_frame_desc[i].status);
|
|
||||||
}
|
|
||||||
if (purb->iso_frame_desc[i].status) {
|
|
||||||
JOM(12, "discarding audio samples because "
|
|
||||||
"%i=purb->iso_frame_desc[i].status\n",
|
|
||||||
purb->iso_frame_desc[i].status);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
more = purb->iso_frame_desc[i].actual_length;
|
|
||||||
if (more == 0) {
|
|
||||||
peasycap->audio_mt++;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (0 > more) {
|
|
||||||
SAM("MISTAKE: more is negative\n");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (peasycap->audio_mt) {
|
|
||||||
JOM(12, "%4i empty audio urb frames\n",
|
|
||||||
peasycap->audio_mt);
|
|
||||||
peasycap->audio_mt = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
p1 = (u8 *)(purb->transfer_buffer +
|
|
||||||
purb->iso_frame_desc[i].offset);
|
|
||||||
|
|
||||||
/*
|
|
||||||
* COPY more BYTES FROM ISOC BUFFER
|
|
||||||
* TO THE DMA BUFFER, CONVERTING
|
|
||||||
* 8-BIT MONO TO 16-BIT SIGNED
|
|
||||||
* LITTLE-ENDIAN SAMPLES IF NECESSARY
|
|
||||||
*/
|
|
||||||
while (more) {
|
|
||||||
much = dma_bytes - peasycap->dma_fill;
|
|
||||||
if (0 > much) {
|
|
||||||
SAM("MISTAKE: much is negative\n");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (0 == much) {
|
|
||||||
peasycap->dma_fill = 0;
|
|
||||||
peasycap->dma_next = fragment_bytes;
|
|
||||||
JOM(8, "wrapped dma buffer\n");
|
|
||||||
}
|
|
||||||
if (!peasycap->microphone) {
|
|
||||||
if (much > more)
|
|
||||||
much = more;
|
|
||||||
memcpy(prt->dma_area + peasycap->dma_fill,
|
|
||||||
p1, much);
|
|
||||||
p1 += much;
|
|
||||||
more -= much;
|
|
||||||
} else {
|
|
||||||
#ifdef UPSAMPLE
|
|
||||||
if (much % 16)
|
|
||||||
JOM(8, "MISTAKE? much"
|
|
||||||
" is not divisible by 16\n");
|
|
||||||
if (much > (16 * more))
|
|
||||||
much = 16 * more;
|
|
||||||
p2 = (u8 *)(prt->dma_area + peasycap->dma_fill);
|
|
||||||
|
|
||||||
for (j = 0; j < (much / 16); j++) {
|
|
||||||
newaudio = ((int) *p1) - 128;
|
|
||||||
newaudio = 128 * newaudio;
|
|
||||||
|
|
||||||
delta = (newaudio - oldaudio) / 4;
|
|
||||||
tmp = oldaudio + delta;
|
|
||||||
|
|
||||||
for (k = 0; k < 4; k++) {
|
|
||||||
*p2 = (0x00FF & tmp);
|
|
||||||
*(p2 + 1) = (0xFF00 & tmp) >> 8;
|
|
||||||
p2 += 2;
|
|
||||||
*p2 = (0x00FF & tmp);
|
|
||||||
*(p2 + 1) = (0xFF00 & tmp) >> 8;
|
|
||||||
p2 += 2;
|
|
||||||
tmp += delta;
|
|
||||||
}
|
|
||||||
p1++;
|
|
||||||
more--;
|
|
||||||
oldaudio = tmp;
|
|
||||||
}
|
|
||||||
#else /*!UPSAMPLE*/
|
|
||||||
if (much > (2 * more))
|
|
||||||
much = 2 * more;
|
|
||||||
p2 = (u8 *)(prt->dma_area + peasycap->dma_fill);
|
|
||||||
|
|
||||||
for (j = 0; j < (much / 2); j++) {
|
|
||||||
tmp = ((int) *p1) - 128;
|
|
||||||
tmp = 128 * tmp;
|
|
||||||
*p2 = (0x00FF & tmp);
|
|
||||||
*(p2 + 1) = (0xFF00 & tmp) >> 8;
|
|
||||||
p1++;
|
|
||||||
p2 += 2;
|
|
||||||
more--;
|
|
||||||
}
|
|
||||||
#endif /*UPSAMPLE*/
|
|
||||||
}
|
|
||||||
peasycap->dma_fill += much;
|
|
||||||
if (peasycap->dma_fill >= peasycap->dma_next) {
|
|
||||||
isfragment = peasycap->dma_fill / fragment_bytes;
|
|
||||||
if (0 > isfragment) {
|
|
||||||
SAM("MISTAKE: isfragment is negative\n");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
peasycap->dma_read = (isfragment - 1) * fragment_bytes;
|
|
||||||
peasycap->dma_next = (isfragment + 1) * fragment_bytes;
|
|
||||||
if (dma_bytes < peasycap->dma_next)
|
|
||||||
peasycap->dma_next = fragment_bytes;
|
|
||||||
|
|
||||||
if (0 <= peasycap->dma_read) {
|
|
||||||
JOM(8, "snd_pcm_period_elapsed(), %i="
|
|
||||||
"isfragment\n", isfragment);
|
|
||||||
snd_pcm_period_elapsed(pss);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifdef UPSAMPLE
|
|
||||||
peasycap->oldaudio = oldaudio;
|
|
||||||
#endif /*UPSAMPLE*/
|
|
||||||
|
|
||||||
}
|
|
||||||
/*---------------------------------------------------------------------------*/
|
|
||||||
/*
|
|
||||||
* RESUBMIT THIS URB
|
|
||||||
*/
|
|
||||||
/*---------------------------------------------------------------------------*/
|
|
||||||
resubmit:
|
|
||||||
if (peasycap->audio_isoc_streaming == 0)
|
|
||||||
return;
|
|
||||||
|
|
||||||
rc = usb_submit_urb(purb, GFP_ATOMIC);
|
|
||||||
if (rc) {
|
|
||||||
if ((-ENODEV != rc) && (-ENOENT != rc)) {
|
|
||||||
SAM("ERROR: while %i=audio_idle, usb_submit_urb failed "
|
|
||||||
"with rc: -%s :%d\n",
|
|
||||||
peasycap->audio_idle, strerror(rc), rc);
|
|
||||||
}
|
|
||||||
if (0 < peasycap->audio_isoc_streaming)
|
|
||||||
peasycap->audio_isoc_streaming--;
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
/*****************************************************************************/
|
|
||||||
static int easycap_alsa_open(struct snd_pcm_substream *pss)
|
|
||||||
{
|
|
||||||
struct snd_pcm *psnd_pcm;
|
|
||||||
struct snd_card *psnd_card;
|
|
||||||
struct easycap *peasycap;
|
|
||||||
|
|
||||||
JOT(4, "\n");
|
|
||||||
if (!pss) {
|
|
||||||
SAY("ERROR: pss is NULL\n");
|
|
||||||
return -EFAULT;
|
|
||||||
}
|
|
||||||
psnd_pcm = pss->pcm;
|
|
||||||
if (!psnd_pcm) {
|
|
||||||
SAY("ERROR: psnd_pcm is NULL\n");
|
|
||||||
return -EFAULT;
|
|
||||||
}
|
|
||||||
psnd_card = psnd_pcm->card;
|
|
||||||
if (!psnd_card) {
|
|
||||||
SAY("ERROR: psnd_card is NULL\n");
|
|
||||||
return -EFAULT;
|
|
||||||
}
|
|
||||||
|
|
||||||
peasycap = psnd_card->private_data;
|
|
||||||
if (!peasycap) {
|
|
||||||
SAY("ERROR: peasycap is NULL\n");
|
|
||||||
return -EFAULT;
|
|
||||||
}
|
|
||||||
if (peasycap->psnd_card != psnd_card) {
|
|
||||||
SAM("ERROR: bad peasycap->psnd_card\n");
|
|
||||||
return -EFAULT;
|
|
||||||
}
|
|
||||||
if (peasycap->psubstream) {
|
|
||||||
SAM("ERROR: bad peasycap->psubstream\n");
|
|
||||||
return -EFAULT;
|
|
||||||
}
|
|
||||||
pss->private_data = peasycap;
|
|
||||||
peasycap->psubstream = pss;
|
|
||||||
pss->runtime->hw = peasycap->alsa_hardware;
|
|
||||||
pss->runtime->private_data = peasycap;
|
|
||||||
pss->private_data = peasycap;
|
|
||||||
|
|
||||||
if (0 != easycap_sound_setup(peasycap)) {
|
|
||||||
JOM(4, "ending unsuccessfully\n");
|
|
||||||
return -EFAULT;
|
|
||||||
}
|
|
||||||
JOM(4, "ending successfully\n");
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
/*****************************************************************************/
|
|
||||||
static int easycap_alsa_close(struct snd_pcm_substream *pss)
|
|
||||||
{
|
|
||||||
struct easycap *peasycap;
|
|
||||||
|
|
||||||
JOT(4, "\n");
|
|
||||||
if (!pss) {
|
|
||||||
SAY("ERROR: pss is NULL\n");
|
|
||||||
return -EFAULT;
|
|
||||||
}
|
|
||||||
peasycap = snd_pcm_substream_chip(pss);
|
|
||||||
if (!peasycap) {
|
|
||||||
SAY("ERROR: peasycap is NULL\n");
|
|
||||||
return -EFAULT;
|
|
||||||
}
|
|
||||||
pss->private_data = NULL;
|
|
||||||
peasycap->psubstream = NULL;
|
|
||||||
JOT(4, "ending successfully\n");
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
/*****************************************************************************/
|
|
||||||
static int easycap_alsa_vmalloc(struct snd_pcm_substream *pss, size_t sz)
|
|
||||||
{
|
|
||||||
struct snd_pcm_runtime *prt;
|
|
||||||
JOT(4, "\n");
|
|
||||||
|
|
||||||
if (!pss) {
|
|
||||||
SAY("ERROR: pss is NULL\n");
|
|
||||||
return -EFAULT;
|
|
||||||
}
|
|
||||||
prt = pss->runtime;
|
|
||||||
if (!prt) {
|
|
||||||
SAY("ERROR: substream.runtime is NULL\n");
|
|
||||||
return -EFAULT;
|
|
||||||
}
|
|
||||||
if (prt->dma_area) {
|
|
||||||
if (prt->dma_bytes > sz)
|
|
||||||
return 0;
|
|
||||||
vfree(prt->dma_area);
|
|
||||||
}
|
|
||||||
prt->dma_area = vmalloc(sz);
|
|
||||||
if (!prt->dma_area)
|
|
||||||
return -ENOMEM;
|
|
||||||
prt->dma_bytes = sz;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
/*****************************************************************************/
|
|
||||||
static int easycap_alsa_hw_params(struct snd_pcm_substream *pss,
|
|
||||||
struct snd_pcm_hw_params *phw)
|
|
||||||
{
|
|
||||||
int rc;
|
|
||||||
|
|
||||||
JOT(4, "%i\n", (params_buffer_bytes(phw)));
|
|
||||||
if (!pss) {
|
|
||||||
SAY("ERROR: pss is NULL\n");
|
|
||||||
return -EFAULT;
|
|
||||||
}
|
|
||||||
rc = easycap_alsa_vmalloc(pss, params_buffer_bytes(phw));
|
|
||||||
if (rc)
|
|
||||||
return rc;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
/*****************************************************************************/
|
|
||||||
static int easycap_alsa_hw_free(struct snd_pcm_substream *pss)
|
|
||||||
{
|
|
||||||
struct snd_pcm_runtime *prt;
|
|
||||||
JOT(4, "\n");
|
|
||||||
|
|
||||||
if (!pss) {
|
|
||||||
SAY("ERROR: pss is NULL\n");
|
|
||||||
return -EFAULT;
|
|
||||||
}
|
|
||||||
prt = pss->runtime;
|
|
||||||
if (!prt) {
|
|
||||||
SAY("ERROR: substream.runtime is NULL\n");
|
|
||||||
return -EFAULT;
|
|
||||||
}
|
|
||||||
if (prt->dma_area) {
|
|
||||||
JOT(8, "prt->dma_area = %p\n", prt->dma_area);
|
|
||||||
vfree(prt->dma_area);
|
|
||||||
prt->dma_area = NULL;
|
|
||||||
} else
|
|
||||||
JOT(8, "dma_area already freed\n");
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
/*****************************************************************************/
|
|
||||||
static int easycap_alsa_prepare(struct snd_pcm_substream *pss)
|
|
||||||
{
|
|
||||||
struct easycap *peasycap;
|
|
||||||
struct snd_pcm_runtime *prt;
|
|
||||||
|
|
||||||
JOT(4, "\n");
|
|
||||||
if (!pss) {
|
|
||||||
SAY("ERROR: pss is NULL\n");
|
|
||||||
return -EFAULT;
|
|
||||||
}
|
|
||||||
prt = pss->runtime;
|
|
||||||
peasycap = snd_pcm_substream_chip(pss);
|
|
||||||
if (!peasycap) {
|
|
||||||
SAY("ERROR: peasycap is NULL\n");
|
|
||||||
return -EFAULT;
|
|
||||||
}
|
|
||||||
|
|
||||||
JOM(16, "ALSA decides %8i Hz=rate\n", pss->runtime->rate);
|
|
||||||
JOM(16, "ALSA decides %8ld =period_size\n", pss->runtime->period_size);
|
|
||||||
JOM(16, "ALSA decides %8i =periods\n", pss->runtime->periods);
|
|
||||||
JOM(16, "ALSA decides %8ld =buffer_size\n", pss->runtime->buffer_size);
|
|
||||||
JOM(16, "ALSA decides %8zd =dma_bytes\n", pss->runtime->dma_bytes);
|
|
||||||
JOM(16, "ALSA decides %8ld =boundary\n", pss->runtime->boundary);
|
|
||||||
JOM(16, "ALSA decides %8i =period_step\n", pss->runtime->period_step);
|
|
||||||
JOM(16, "ALSA decides %8i =sample_bits\n", pss->runtime->sample_bits);
|
|
||||||
JOM(16, "ALSA decides %8i =frame_bits\n", pss->runtime->frame_bits);
|
|
||||||
JOM(16, "ALSA decides %8ld =min_align\n", pss->runtime->min_align);
|
|
||||||
JOM(12, "ALSA decides %8ld =hw_ptr_base\n", pss->runtime->hw_ptr_base);
|
|
||||||
JOM(12, "ALSA decides %8ld =hw_ptr_interrupt\n",
|
|
||||||
pss->runtime->hw_ptr_interrupt);
|
|
||||||
|
|
||||||
if (prt->dma_bytes != 4 * ((int)prt->period_size) * ((int)prt->periods)) {
|
|
||||||
SAY("MISTAKE: unexpected ALSA parameters\n");
|
|
||||||
return -ENOENT;
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
/*****************************************************************************/
|
|
||||||
static int easycap_alsa_ack(struct snd_pcm_substream *pss)
|
|
||||||
{
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
/*****************************************************************************/
|
|
||||||
static int easycap_alsa_trigger(struct snd_pcm_substream *pss, int cmd)
|
|
||||||
{
|
|
||||||
struct easycap *peasycap;
|
|
||||||
|
|
||||||
JOT(4, "%i=cmd cf %i=START %i=STOP\n", cmd, SNDRV_PCM_TRIGGER_START,
|
|
||||||
SNDRV_PCM_TRIGGER_STOP);
|
|
||||||
if (!pss) {
|
|
||||||
SAY("ERROR: pss is NULL\n");
|
|
||||||
return -EFAULT;
|
|
||||||
}
|
|
||||||
peasycap = snd_pcm_substream_chip(pss);
|
|
||||||
if (!peasycap) {
|
|
||||||
SAY("ERROR: peasycap is NULL\n");
|
|
||||||
return -EFAULT;
|
|
||||||
}
|
|
||||||
switch (cmd) {
|
|
||||||
case SNDRV_PCM_TRIGGER_START: {
|
|
||||||
peasycap->audio_idle = 0;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case SNDRV_PCM_TRIGGER_STOP: {
|
|
||||||
peasycap->audio_idle = 1;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
return -EINVAL;
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
/*****************************************************************************/
|
|
||||||
static snd_pcm_uframes_t easycap_alsa_pointer(struct snd_pcm_substream *pss)
|
|
||||||
{
|
|
||||||
struct easycap *peasycap;
|
|
||||||
snd_pcm_uframes_t offset;
|
|
||||||
|
|
||||||
JOT(16, "\n");
|
|
||||||
if (!pss) {
|
|
||||||
SAY("ERROR: pss is NULL\n");
|
|
||||||
return -EFAULT;
|
|
||||||
}
|
|
||||||
peasycap = snd_pcm_substream_chip(pss);
|
|
||||||
if (!peasycap) {
|
|
||||||
SAY("ERROR: peasycap is NULL\n");
|
|
||||||
return -EFAULT;
|
|
||||||
}
|
|
||||||
if ((0 != peasycap->audio_eof) || (0 != peasycap->audio_idle)) {
|
|
||||||
JOM(8, "returning -EIO because "
|
|
||||||
"%i=audio_idle %i=audio_eof\n",
|
|
||||||
peasycap->audio_idle, peasycap->audio_eof);
|
|
||||||
return -EIO;
|
|
||||||
}
|
|
||||||
/*---------------------------------------------------------------------------*/
|
|
||||||
if (0 > peasycap->dma_read) {
|
|
||||||
JOM(8, "returning -EBUSY\n");
|
|
||||||
return -EBUSY;
|
|
||||||
}
|
|
||||||
offset = ((snd_pcm_uframes_t)peasycap->dma_read)/4;
|
|
||||||
JOM(8, "ALSA decides %8i =hw_ptr_base\n", (int)pss->runtime->hw_ptr_base);
|
|
||||||
JOM(8, "ALSA decides %8i =hw_ptr_interrupt\n",
|
|
||||||
(int)pss->runtime->hw_ptr_interrupt);
|
|
||||||
JOM(8, "%7i=offset %7i=dma_read %7i=dma_next\n",
|
|
||||||
(int)offset, peasycap->dma_read, peasycap->dma_next);
|
|
||||||
return offset;
|
|
||||||
}
|
|
||||||
/*****************************************************************************/
|
|
||||||
static struct page *
|
|
||||||
easycap_alsa_page(struct snd_pcm_substream *pss, unsigned long offset)
|
|
||||||
{
|
|
||||||
return vmalloc_to_page(pss->runtime->dma_area + offset);
|
|
||||||
}
|
|
||||||
/*****************************************************************************/
|
|
||||||
|
|
||||||
static struct snd_pcm_ops easycap_alsa_pcm_ops = {
|
|
||||||
.open = easycap_alsa_open,
|
|
||||||
.close = easycap_alsa_close,
|
|
||||||
.ioctl = snd_pcm_lib_ioctl,
|
|
||||||
.hw_params = easycap_alsa_hw_params,
|
|
||||||
.hw_free = easycap_alsa_hw_free,
|
|
||||||
.prepare = easycap_alsa_prepare,
|
|
||||||
.ack = easycap_alsa_ack,
|
|
||||||
.trigger = easycap_alsa_trigger,
|
|
||||||
.pointer = easycap_alsa_pointer,
|
|
||||||
.page = easycap_alsa_page,
|
|
||||||
};
|
|
||||||
|
|
||||||
/*****************************************************************************/
|
|
||||||
/*---------------------------------------------------------------------------*/
|
|
||||||
/*
|
|
||||||
* THE FUNCTION snd_card_create() HAS THIS_MODULE AS AN ARGUMENT. THIS
|
|
||||||
* MEANS MODULE easycap. BEWARE.
|
|
||||||
*/
|
|
||||||
/*---------------------------------------------------------------------------*/
|
|
||||||
int easycap_alsa_probe(struct easycap *peasycap)
|
|
||||||
{
|
|
||||||
int rc;
|
|
||||||
struct snd_card *psnd_card;
|
|
||||||
struct snd_pcm *psnd_pcm;
|
|
||||||
|
|
||||||
if (!peasycap) {
|
|
||||||
SAY("ERROR: peasycap is NULL\n");
|
|
||||||
return -ENODEV;
|
|
||||||
}
|
|
||||||
if (0 > peasycap->minor) {
|
|
||||||
SAY("ERROR: no minor\n");
|
|
||||||
return -ENODEV;
|
|
||||||
}
|
|
||||||
|
|
||||||
peasycap->alsa_hardware = alsa_hardware;
|
|
||||||
if (peasycap->microphone) {
|
|
||||||
peasycap->alsa_hardware.rates = SNDRV_PCM_RATE_32000;
|
|
||||||
peasycap->alsa_hardware.rate_min = 32000;
|
|
||||||
peasycap->alsa_hardware.rate_max = 32000;
|
|
||||||
} else {
|
|
||||||
peasycap->alsa_hardware.rates = SNDRV_PCM_RATE_48000;
|
|
||||||
peasycap->alsa_hardware.rate_min = 48000;
|
|
||||||
peasycap->alsa_hardware.rate_max = 48000;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (0 != snd_card_create(SNDRV_DEFAULT_IDX1, "easycap_alsa",
|
|
||||||
THIS_MODULE, 0, &psnd_card)) {
|
|
||||||
SAY("ERROR: Cannot do ALSA snd_card_create()\n");
|
|
||||||
return -EFAULT;
|
|
||||||
}
|
|
||||||
|
|
||||||
sprintf(&psnd_card->id[0], "EasyALSA%i", peasycap->minor);
|
|
||||||
strcpy(&psnd_card->driver[0], EASYCAP_DRIVER_DESCRIPTION);
|
|
||||||
strcpy(&psnd_card->shortname[0], "easycap_alsa");
|
|
||||||
sprintf(&psnd_card->longname[0], "%s", &psnd_card->shortname[0]);
|
|
||||||
|
|
||||||
psnd_card->dev = &peasycap->pusb_device->dev;
|
|
||||||
psnd_card->private_data = peasycap;
|
|
||||||
peasycap->psnd_card = psnd_card;
|
|
||||||
|
|
||||||
rc = snd_pcm_new(psnd_card, "easycap_pcm", 0, 0, 1, &psnd_pcm);
|
|
||||||
if (rc) {
|
|
||||||
SAM("ERROR: Cannot do ALSA snd_pcm_new()\n");
|
|
||||||
snd_card_free(psnd_card);
|
|
||||||
return -EFAULT;
|
|
||||||
}
|
|
||||||
|
|
||||||
snd_pcm_set_ops(psnd_pcm, SNDRV_PCM_STREAM_CAPTURE,
|
|
||||||
&easycap_alsa_pcm_ops);
|
|
||||||
psnd_pcm->info_flags = 0;
|
|
||||||
strcpy(&psnd_pcm->name[0], &psnd_card->id[0]);
|
|
||||||
psnd_pcm->private_data = peasycap;
|
|
||||||
peasycap->psnd_pcm = psnd_pcm;
|
|
||||||
peasycap->psubstream = NULL;
|
|
||||||
|
|
||||||
rc = snd_card_register(psnd_card);
|
|
||||||
if (rc) {
|
|
||||||
SAM("ERROR: Cannot do ALSA snd_card_register()\n");
|
|
||||||
snd_card_free(psnd_card);
|
|
||||||
return -EFAULT;
|
|
||||||
}
|
|
||||||
|
|
||||||
SAM("registered %s\n", &psnd_card->id[0]);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
|
@ -1,155 +0,0 @@
|
||||||
/******************************************************************************
|
|
||||||
* *
|
|
||||||
* easycap_testcard.c *
|
|
||||||
* *
|
|
||||||
******************************************************************************/
|
|
||||||
/*
|
|
||||||
*
|
|
||||||
* Copyright (C) 2010 R.M. Thomas <rmthomas@sciolus.org>
|
|
||||||
*
|
|
||||||
*
|
|
||||||
* This 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.
|
|
||||||
*
|
|
||||||
* The software 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 software; if not, write to the Free Software
|
|
||||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
/*****************************************************************************/
|
|
||||||
|
|
||||||
#include "easycap.h"
|
|
||||||
|
|
||||||
/*****************************************************************************/
|
|
||||||
#define TESTCARD_BYTESPERLINE (2 * 720)
|
|
||||||
void
|
|
||||||
easycap_testcard(struct easycap *peasycap, int field)
|
|
||||||
{
|
|
||||||
int total;
|
|
||||||
int y, u, v, r, g, b;
|
|
||||||
unsigned char uyvy[4];
|
|
||||||
int i1, line, k, m, n, more, much, barwidth, barheight;
|
|
||||||
unsigned char bfbar[TESTCARD_BYTESPERLINE / 8], *p1, *p2;
|
|
||||||
struct data_buffer *pfield_buffer;
|
|
||||||
|
|
||||||
if (!peasycap) {
|
|
||||||
SAY("ERROR: peasycap is NULL\n");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
JOM(8, "%i=field\n", field);
|
|
||||||
switch (peasycap->width) {
|
|
||||||
case 720:
|
|
||||||
case 360: {
|
|
||||||
barwidth = (2 * 720) / 8;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case 704:
|
|
||||||
case 352: {
|
|
||||||
barwidth = (2 * 704) / 8;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case 640:
|
|
||||||
case 320: {
|
|
||||||
barwidth = (2 * 640) / 8;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
default: {
|
|
||||||
SAM("ERROR: cannot set barwidth\n");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (TESTCARD_BYTESPERLINE < barwidth) {
|
|
||||||
SAM("ERROR: barwidth is too large\n");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
switch (peasycap->height) {
|
|
||||||
case 576:
|
|
||||||
case 288: {
|
|
||||||
barheight = 576;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case 480:
|
|
||||||
case 240: {
|
|
||||||
barheight = 480;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
default: {
|
|
||||||
SAM("ERROR: cannot set barheight\n");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
total = 0;
|
|
||||||
k = field;
|
|
||||||
m = 0;
|
|
||||||
n = 0;
|
|
||||||
|
|
||||||
for (line = 0; line < (barheight / 2); line++) {
|
|
||||||
for (i1 = 0; i1 < 8; i1++) {
|
|
||||||
r = (i1 * 256)/8;
|
|
||||||
g = (i1 * 256)/8;
|
|
||||||
b = (i1 * 256)/8;
|
|
||||||
|
|
||||||
y = 299*r/1000 + 587*g/1000 + 114*b/1000 ;
|
|
||||||
u = -147*r/1000 - 289*g/1000 + 436*b/1000 ;
|
|
||||||
u = u + 128;
|
|
||||||
v = 615*r/1000 - 515*g/1000 - 100*b/1000 ;
|
|
||||||
v = v + 128;
|
|
||||||
|
|
||||||
uyvy[0] = 0xFF & u ;
|
|
||||||
uyvy[1] = 0xFF & y ;
|
|
||||||
uyvy[2] = 0xFF & v ;
|
|
||||||
uyvy[3] = 0xFF & y ;
|
|
||||||
|
|
||||||
p1 = &bfbar[0];
|
|
||||||
while (p1 < &bfbar[barwidth]) {
|
|
||||||
*p1++ = uyvy[0] ;
|
|
||||||
*p1++ = uyvy[1] ;
|
|
||||||
*p1++ = uyvy[2] ;
|
|
||||||
*p1++ = uyvy[3] ;
|
|
||||||
total += 4;
|
|
||||||
}
|
|
||||||
|
|
||||||
p1 = &bfbar[0];
|
|
||||||
more = barwidth;
|
|
||||||
|
|
||||||
while (more) {
|
|
||||||
if ((FIELD_BUFFER_SIZE/PAGE_SIZE) <= m) {
|
|
||||||
SAM("ERROR: bad m reached\n");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (PAGE_SIZE < n) {
|
|
||||||
SAM("ERROR: bad n reached\n");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (0 > more) {
|
|
||||||
SAM("ERROR: internal fault\n");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
much = PAGE_SIZE - n;
|
|
||||||
if (much > more)
|
|
||||||
much = more;
|
|
||||||
pfield_buffer = &peasycap->field_buffer[k][m];
|
|
||||||
p2 = pfield_buffer->pgo + n;
|
|
||||||
memcpy(p2, p1, much);
|
|
||||||
|
|
||||||
p1 += much;
|
|
||||||
n += much;
|
|
||||||
more -= much;
|
|
||||||
if (PAGE_SIZE == n) {
|
|
||||||
m++;
|
|
||||||
n = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
|
Loading…
Reference in a new issue