Commit 702422bd authored by R.M. Thomas's avatar R.M. Thomas Committed by Greg Kroah-Hartman

Staging: easycap: add easycap driver

This adds the easycap USB video adapter driver to
the staging directory.
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@suse.de>
parent 178f16db
......@@ -149,5 +149,7 @@ source "drivers/staging/mrst-touchscreen/Kconfig"
source "drivers/staging/msm/Kconfig"
source "drivers/staging/easycap/Kconfig"
endif # !STAGING_EXCLUDE_BUILD
endif # STAGING
......@@ -55,3 +55,4 @@ obj-$(CONFIG_ADIS16255) += adis16255/
obj-$(CONFIG_FB_XGI) += xgifb/
obj-$(CONFIG_TOUCHSCREEN_MRSTOUCH) += mrst-touchscreen/
obj-$(CONFIG_MSM_STAGING) += msm/
obj-$(CONFIG_EASYCAP) += easycap/
config EASYCAP
tristate "EasyCAP USB ID 05e1:0408 support"
---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
obj-$(CONFIG_EASYCAP) += easycap.o
easycap-objs := easycap_main.o easycap_low.o easycap_sound.o
easycap-objs += easycap_ioctl.o easycap_settings.o
easycap-objs += easycap_testcard.o
EXTRA_CFLAGS += -Wall
# Impose all or none of the following:
EXTRA_CFLAGS += -DEASYCAP_IS_VIDEODEV_CLIENT
EXTRA_CFLAGS += -DEASYCAP_NEEDS_V4L2_DEVICE_H
EXTRA_CFLAGS += -DEASYCAP_NEEDS_V4L2_FOPS
***********************************************************
* 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
------------------------------
If the parameter EASYCAP_IS_VIDEODEV_CLIENT is undefined during compilation
the built module is entirely independent of the videodev module, and when
the EasyCAP is physically plugged into a USB port the special files
/dev/easycap0 and /dev/easysnd1 are created as video and sound sources
respectively.
If the parameter EASYCAP_IS_VIDEODEV_CLIENT is defined during compilation
the built easycap module is configured to register with the videodev module,
in which case the special files created when the EasyCAP is plugged in are
/dev/video0 and /dev/easysnd0. Use of the easycap module as a client of
the videodev module has received very little testing as of June 2010.
KNOWN BUILD PROBLEMS
--------------------
(1) Recent gcc versions may generate the message:
warning: the frame size of .... bytes is larger than 1024 bytes
This warning can be suppressed by specifying in the Makefile:
EXTRA_CFLAGS += -Wframe-larger-than=8192
but it would be preferable to remove the cause of the warning.
KNOWN RUNTIME ISSUES
--------------------
(1) Randomly (maybe 5 to 10% of occasions) the driver fails to produce any
output at start-up. Closing mplayer (or whatever the user program is) and
restarting it restores normal performance without any other remedial action
being necessary. The reason for this is not known.
(2) Intentionally, this driver will not stream material which is unambiguously
identified by the hardware as copy-protected. The video output will freeze
within about a minute when this situation arises.
(3) The controls for luminance, contrast, saturation, hue and volume may not
always work properly.
(4) Reduced-resolution S-Video seems to suffer from moire artefacts. No
attempt has yet been made to rememdy this.
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.
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 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.
This driver does not understand the V4L1 IOCTL commands, so programs such
as camorama are not compatible. There are reports that the driver does
work with sufficiently recent (V4L2) versions of zoneminder, but I have not
attempted to confirm this myself.
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"
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.
/*****************************************************************************
* *
* 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
* EASYCAP_IS_VIDEODEV_CLIENT
* EASYCAP_NEEDS_USBVIDEO_H
* EASYCAP_NEEDS_V4L2_DEVICE_H
* EASYCAP_NEEDS_V4L2_FOPS
*
* IF REQUIRED THEY MUST BE EXTERNALLY DEFINED, FOR EXAMPLE AS COMPILER
* OPTIONS.
*/
/*---------------------------------------------------------------------------*/
#if (!defined(EASYCAP_H))
#define EASYCAP_H
#if defined(EASYCAP_DEBUG)
#if (9 < EASYCAP_DEBUG)
#error Debug levels 0 to 9 are okay.\
To achieve higher levels, remove this trap manually from easycap.h
#endif
#endif /*EASYCAP_DEBUG*/
/*---------------------------------------------------------------------------*/
/*
* THESE ARE FOR MAINTENANCE ONLY - NORMALLY UNDEFINED:
*/
/*---------------------------------------------------------------------------*/
#undef PREFER_NTSC
#undef EASYCAP_TESTCARD
#undef EASYCAP_TESTTONE
#undef LOCKFRAME
#undef NOREADBACK
#undef AUDIOTIME
/*---------------------------------------------------------------------------*/
/*
*
* DEFINE BRIDGER TO ACTIVATE THE ROUTINE FOR BRIDGING VIDEOTAPE DROPOUTS.
*
* *** UNDER DEVELOPMENT/TESTING - NOT READY YET!***
*
*/
/*---------------------------------------------------------------------------*/
#undef BRIDGER
/*---------------------------------------------------------------------------*/
#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/smp_lock.h>
#include <linux/usb.h>
#include <linux/uaccess.h>
#include <linux/i2c.h>
#include <linux/version.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>
/*vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv*/
#if defined(EASYCAP_IS_VIDEODEV_CLIENT)
#if (!defined(__OLD_VIDIOC_))
#define __OLD_VIDIOC_
#endif /* !defined(__OLD_VIDIOC_) */
#include <media/v4l2-dev.h>
#if defined(EASYCAP_NEEDS_V4L2_DEVICE_H)
#include <media/v4l2-device.h>
#endif /*EASYCAP_NEEDS_V4L2_DEVICE_H*/
#endif /*EASYCAP_IS_VIDEODEV_CLIENT*/
/*^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^*/
#if (!defined(__OLD_VIDIOC_))
#define __OLD_VIDIOC_
#endif /* !defined(__OLD_VIDIOC_) */
#include <linux/videodev2.h>
#include <linux/soundcard.h>
#if defined(EASYCAP_NEEDS_USBVIDEO_H)
#include <config/video/usbvideo.h>
#endif /*EASYCAP_NEEDS_USBVIDEO_H*/
#if (!defined(PAGE_SIZE))
#error "PAGE_SIZE not defined"
#endif
#define STRINGIZE_AGAIN(x) #x
#define STRINGIZE(x) STRINGIZE_AGAIN(x)
/*---------------------------------------------------------------------------*/
/* 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.8"
#define EASYCAP_DRIVER_DESCRIPTION "easycapdc60"
#define USB_SKEL_MINOR_BASE 192
#define VIDEO_DEVICE_MANY 8
/*---------------------------------------------------------------------------*/
/*
* 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
/*---------------------------------------------------------------------------*/
/*
* 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 3
#define AUDIO_ISOC_BUFFER_SIZE (PAGE_SIZE << AUDIO_ISOC_ORDER)
/*---------------------------------------------------------------------------*/
/*
* AUDIO BUFFERS
*/
/*---------------------------------------------------------------------------*/
#define AUDIO_FRAGMENT_MANY 32
/*---------------------------------------------------------------------------*/
/*
* STRUCTURE DEFINITIONS
*/
/*---------------------------------------------------------------------------*/
struct data_buffer {
struct list_head list_head;
void *pgo;
void *pto;
__u16 kount;
};
/*---------------------------------------------------------------------------*/
struct data_urb {
struct list_head list_head;
struct urb *purb;
int isbuf;
int length;
};
/*---------------------------------------------------------------------------*/
/*
* 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 ilk;
bool microphone;
/*vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv*/
#if defined(EASYCAP_IS_VIDEODEV_CLIENT)
struct video_device *pvideo_device;
#endif /*EASYCAP_IS_VIDEODEV_CLIENT*/
/*^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^*/
struct usb_device *pusb_device;
struct usb_interface *pusb_interface;
struct kref kref;
struct mutex mutex_mmap_video[FRAME_BUFFER_MANY];
struct mutex mutex_timeval0;
struct mutex mutex_timeval1;
int queued[FRAME_BUFFER_MANY];
int done[FRAME_BUFFER_MANY];
wait_queue_head_t wq_video;
wait_queue_head_t wq_audio;
int input;
int polled;
int standard_offset;
int format_offset;
int fps;
int usec;
int tolerate;
int merit[180];
struct timeval timeval0;
struct timeval timeval1;
struct timeval timeval2;
struct timeval timeval7;
long long int dnbydt;
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;
int fudge;
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;
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;
__u32 field;
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;
/*---------------------------------------------------------------------------*/
/*
* 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;
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 easysnd_complete(). */
/* Bumped only by easysnd_complete(). */
int audio_read; /* Audio buffer page being read by easysnd_read(). */
/* Set by easysnd_read() to trail audio_fill by */
/* one fragment. */
/*---------------------------------------------------------------------------*/
/*
* SOUND PROPERTIES
*/
/*---------------------------------------------------------------------------*/
int audio_buffer_many;
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[];
};
/*---------------------------------------------------------------------------*/
struct easycap_standard {
__u16 mask;
struct v4l2_standard v4l2_standard;
};
struct easycap_format {
__u16 mask;
char name[128];
struct v4l2_format v4l2_format;
};
/*---------------------------------------------------------------------------*/
/*
* VIDEO FUNCTION PROTOTYPES
*/
/*---------------------------------------------------------------------------*/
void easycap_complete(struct urb *);
int easycap_open(struct inode *, struct file *);
int easycap_release(struct inode *, struct file *);
int easycap_ioctl(struct inode *, struct file *, \
unsigned int, unsigned long);
/*vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv*/
#if defined(EASYCAP_IS_VIDEODEV_CLIENT)
int easycap_open_noinode(struct file *);
int easycap_release_noinode(struct file *);
long easycap_ioctl_noinode(struct file *, \
unsigned int, unsigned long);
int videodev_release(struct video_device *);
#endif /*EASYCAP_IS_VIDEODEV_CLIENT*/
/*^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^*/
unsigned int easycap_poll(struct file *, poll_table *);
int easycap_mmap(struct file *, struct vm_area_struct *);
int easycap_usb_probe(struct usb_interface *, \
const struct usb_device_id *);
void easycap_usb_disconnect(struct usb_interface *);
void easycap_delete(struct kref *);
void easycap_vma_open(struct vm_area_struct *);
void easycap_vma_close(struct vm_area_struct *);
int easycap_vma_fault(struct vm_area_struct *, struct vm_fault *);
int easycap_dqbuf(struct easycap *, int);
int submit_video_urbs(struct easycap *);
int kill_video_urbs(struct easycap *);
int field2frame(struct easycap *);
int redaub(struct easycap *, void *, void *, \
int, int, __u8, __u8, bool);
void debrief(struct easycap *);
void sayreadonly(struct easycap *);
void easycap_testcard(struct easycap *, int);
int explain_ioctl(__u32);
int explain_cid(__u32);
int 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);
int adjust_volume(struct easycap *, int);
/*---------------------------------------------------------------------------*/
/*
* AUDIO FUNCTION PROTOTYPES
*/
/*---------------------------------------------------------------------------*/
void easysnd_complete(struct urb *);
ssize_t easysnd_read(struct file *, char __user *, size_t, loff_t *);
int easysnd_open(struct inode *, struct file *);
int easysnd_release(struct inode *, struct file *);
int easysnd_ioctl(struct inode *, struct file *, \
unsigned int, unsigned long);
unsigned int easysnd_poll(struct file *, poll_table *);
void easysnd_delete(struct kref *);
int submit_audio_urbs(struct easycap *);
int kill_audio_urbs(struct easycap *);
void easysnd_testtone(struct easycap *, int);
int audio_setup(struct easycap *);
/*---------------------------------------------------------------------------*/
/*
* LOW-LEVEL FUNCTION PROTOTYPES
*/
/*---------------------------------------------------------------------------*/
int audio_gainget(struct usb_device *);
int audio_gainset(struct usb_device *, __s8);
int set_interface(struct usb_device *, __u16);
int wakeup_device(struct usb_device *);
int confirm_resolution(struct usb_device *);
int confirm_stream(struct usb_device *);
int setup_stk(struct usb_device *);
int setup_saa(struct usb_device *);
int setup_vt(struct usb_device *);
int check_stk(struct usb_device *);
int check_saa(struct usb_device *);
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 read_stk(struct usb_device *, __u32);
int write_saa(struct usb_device *, __u16, __u16);
int wait_i2c(struct usb_device *);
int write_000(struct usb_device *, __u16, __u16);
int start_100(struct usb_device *);
int stop_100(struct usb_device *);
int write_300(struct usb_device *);
int read_vt(struct usb_device *, __u16);
int write_vt(struct usb_device *, __u16, __u16);
int set2to78(struct usb_device *);
int set2to93(struct usb_device *);
int regset(struct usb_device *, __u16, __u16);
int regget(struct usb_device *, __u16, void *);
/*---------------------------------------------------------------------------*/
struct signed_div_result {
long long int quotient;
unsigned long long int remainder;
} signed_div(long long int, long long int);
/*---------------------------------------------------------------------------*/
/*
* 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 STANDARD_MANY 10
/*---------------------------------------------------------------------------*/
/*
* 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,
FIELD_ALTERNATE,
INTERLACE_MANY
};
#define SETTINGS_MANY (STANDARD_MANY * \
RESOLUTION_MANY * \
2 * \
PIXELFORMAT_MANY * \
INTERLACE_MANY)
/*---------------------------------------------------------------------------*/
/*
* MACROS
*/
/*---------------------------------------------------------------------------*/
#define GET(X, Y, Z) do { \
int rc; \
*(Z) = (__u16)0; \
rc = regget(X, Y, Z); \
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)
/*---------------------------------------------------------------------------*/
#define SAY(format, args...) do { \
printk(KERN_DEBUG "easycap: %s: " format, __func__, ##args); \
} while (0)
#if defined(EASYCAP_DEBUG)
#define JOT(n, format, args...) do { \
if (n <= easycap_debug) { \
printk(KERN_DEBUG "easycap: %s: " format, __func__, ##args); \
} \
} while (0)
#else
#define JOT(n, format, args...) do {} while (0)
#endif /*EASYCAP_DEBUG*/
#define POUT JOT(8, ":-(in file %s line %4i\n", __FILE__, __LINE__)
#define MICROSECONDS(X, Y) \
((1000000*((long long int)(X.tv_sec - Y.tv_sec))) + \
(long long int)(X.tv_usec - Y.tv_usec))
/*---------------------------------------------------------------------------*/
/*
* (unsigned char *)P pointer to next byte pair
* (long int *)X pointer to accumulating count
* (long int *)Y pointer to accumulating sum
* (long long int *)Z pointer to accumulating sum of squares
*/
/*---------------------------------------------------------------------------*/
#define SUMMER(P, X, Y, Z) do { \
unsigned char *p; \
unsigned int u0, u1, u2; \
long int s; \
p = (unsigned char *)(P); \
u0 = (unsigned int) (*p); \
u1 = (unsigned int) (*(p + 1)); \
u2 = (unsigned int) ((u1 << 8) | u0); \
if (0x8000 & u2) \
s = -(long int)(0x7FFF & (~u2)); \
else \
s = (long int)(0x7FFF & u2); \
*((X)) += (long int) 1; \
*((Y)) += (long int) s; \
*((Z)) += ((long long int)(s) * (long long int)(s)); \
} while (0)
/*---------------------------------------------------------------------------*/
#endif /*EASYCAP_H*/
/*****************************************************************************
* *
* easycap_debug.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
*
*/
/*****************************************************************************/
extern int easycap_debug;
/******************************************************************************
* *
* easycap_ioctl.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"
#include "easycap_debug.h"
#include "easycap_standard.h"
#include "easycap_ioctl.h"
/*--------------------------------------------------------------------------*/
/*
* UNLESS THERE IS A PREMATURE ERROR RETURN THIS ROUTINE UPDATES THE
* FOLLOWING:
* peasycap->standard_offset
* peasycap->fps
* peasycap->usec
* peasycap->tolerate
*/
/*---------------------------------------------------------------------------*/
int adjust_standard(struct easycap *peasycap, v4l2_std_id std_id)
{
struct easycap_standard *peasycap_standard;
__u16 reg, set;
int ir, rc, need;
unsigned int itwas, isnow;
if ((struct usb_device *)NULL == peasycap->pusb_device) {
SAY("ERROR: peasycap->pusb_device is NULL\n");
return -EFAULT;
}
peasycap_standard = &easycap_standard[0];
while (0xFFFF != peasycap_standard->mask) {
if (std_id & peasycap_standard->v4l2_standard.id)
break;
peasycap_standard++;
}
if (0xFFFF == peasycap_standard->mask) {
SAY("ERROR: 0x%08X=std_id: standard not found\n", \
(unsigned int)std_id);
return -EINVAL;
}
SAY("user requests standard: %s\n", \
&(peasycap_standard->v4l2_standard.name[0]));
if (peasycap->standard_offset == \
(int)(peasycap_standard - &easycap_standard[0])) {
SAY("requested standard already in effect\n");
return 0;
}
peasycap->standard_offset = (int)(peasycap_standard - &easycap_standard[0]);
peasycap->fps = peasycap_standard->v4l2_standard.frameperiod.denominator / \
peasycap_standard->v4l2_standard.frameperiod.numerator;
if (!peasycap->fps) {
SAY("MISTAKE: frames-per-second is zero\n");
return -EFAULT;
}
JOT(8, "%i frames-per-second\n", peasycap->fps);
peasycap->usec = 1000000 / (2 * peasycap->fps);
peasycap->tolerate = 1000 * (25 / peasycap->fps);
kill_video_urbs(peasycap);
/*--------------------------------------------------------------------------*/
/*
* SAA7113H DATASHEET PAGE 44, TABLE 42
*/
/*--------------------------------------------------------------------------*/
need = 0; itwas = 0; reg = 0x00; set = 0x00;
switch (peasycap_standard->mask & 0x000F) {
case NTSC_M_JP: {
reg = 0x0A; set = 0x95;
ir = read_saa(peasycap->pusb_device, reg);
if (0 > ir)
SAY("ERROR: cannot read SAA register 0x%02X\n", reg);
else
itwas = (unsigned int)ir;
set2to78(peasycap->pusb_device);
rc = write_saa(peasycap->pusb_device, reg, set);
if (0 != rc)
SAY("ERROR: failed to set SAA register " \
"0x%02X to 0x%02X for JP standard\n", reg, set);
else {
isnow = (unsigned int)read_saa(peasycap->pusb_device, reg);
if (0 > ir)
JOT(8, "SAA register 0x%02X changed " \
"to 0x%02X\n", reg, isnow);
else
JOT(8, "SAA register 0x%02X changed " \
"from 0x%02X to 0x%02X\n", reg, itwas, isnow);
set2to78(peasycap->pusb_device);
}
reg = 0x0B; set = 0x48;
ir = read_saa(peasycap->pusb_device, reg);
if (0 > ir)
SAY("ERROR: cannot read SAA register 0x%02X\n", reg);
else
itwas = (unsigned int)ir;
set2to78(peasycap->pusb_device);
rc = write_saa(peasycap->pusb_device, reg, set);
if (0 != rc)
SAY("ERROR: failed to set SAA register 0x%02X to 0x%02X " \
"for JP standard\n", reg, set);
else {
isnow = (unsigned int)read_saa(peasycap->pusb_device, reg);
if (0 > ir)
JOT(8, "SAA register 0x%02X changed " \
"to 0x%02X\n", reg, isnow);
else
JOT(8, "SAA register 0x%02X changed " \
"from 0x%02X to 0x%02X\n", reg, itwas, isnow);
set2to78(peasycap->pusb_device);
}
/*--------------------------------------------------------------------------*/
/*
* NOTE: NO break HERE: RUN ON TO NEXT CASE
*/
/*--------------------------------------------------------------------------*/
}
case NTSC_M:
case PAL_BGHIN: {
reg = 0x0E; set = 0x01; need = 1; break;
}
case NTSC_N_443:
case PAL_60: {
reg = 0x0E; set = 0x11; need = 1; break;
}
case NTSC_443:
case PAL_Nc: {
reg = 0x0E; set = 0x21; need = 1; break;
}
case NTSC_N:
case PAL_M: {
reg = 0x0E; set = 0x31; need = 1; break;
}
case SECAM: {
reg = 0x0E; set = 0x51; need = 1; break;
}
default:
break;
}
/*--------------------------------------------------------------------------*/
if (need) {
ir = read_saa(peasycap->pusb_device, reg);
if (0 > ir)
SAY("ERROR: failed to read SAA register 0x%02X\n", reg);
else
itwas = (unsigned int)ir;
set2to78(peasycap->pusb_device);
rc = write_saa(peasycap->pusb_device, reg, set);
if (0 != write_saa(peasycap->pusb_device, reg, set)) {
SAY("ERROR: failed to set SAA register " \
"0x%02X to 0x%02X for table 42\n", reg, set);
} else {
isnow = (unsigned int)read_saa(peasycap->pusb_device, reg);
if (0 > ir)
JOT(8, "SAA register 0x%02X changed " \
"to 0x%02X\n", reg, isnow);
else
JOT(8, "SAA register 0x%02X changed " \
"from 0x%02X to 0x%02X\n", reg, itwas, isnow);
}
}
/*--------------------------------------------------------------------------*/
/*
* SAA7113H DATASHEET PAGE 41
*/
/*--------------------------------------------------------------------------*/
reg = 0x08;
ir = read_saa(peasycap->pusb_device, reg);
if (0 > ir)
SAY("ERROR: failed to read SAA register 0x%02X " \
"so cannot reset\n", reg);
else {
itwas = (unsigned int)ir;
if (peasycap_standard->mask & 0x0001)
set = itwas | 0x40 ;
else
set = itwas & ~0x40 ;
set2to78(peasycap->pusb_device);
rc = write_saa(peasycap->pusb_device, reg, set);
if (0 != rc)
SAY("ERROR: failed to set SAA register 0x%02X to 0x%02X\n", reg, set);
else {
isnow = (unsigned int)read_saa(peasycap->pusb_device, reg);
if (0 > ir)
JOT(8, "SAA register 0x%02X changed to 0x%02X\n", reg, isnow);
else
JOT(8, "SAA register 0x%02X changed " \
"from 0x%02X to 0x%02X\n", reg, itwas, isnow);
}
}
/*--------------------------------------------------------------------------*/
/*
* SAA7113H DATASHEET PAGE 51, TABLE 57
*/
/*---------------------------------------------------------------------------*/
reg = 0x40;
ir = read_saa(peasycap->pusb_device, reg);
if (0 > ir)
SAY("ERROR: failed to read SAA register 0x%02X " \
"so cannot reset\n", reg);
else {
itwas = (unsigned int)ir;
if (peasycap_standard->mask & 0x0001)
set = itwas | 0x80 ;
else
set = itwas & ~0x80 ;
set2to78(peasycap->pusb_device);
rc = write_saa(peasycap->pusb_device, reg, set);
if (0 != rc)
SAY("ERROR: failed to set SAA register 0x%02X to 0x%02X\n", reg, set);
else {
isnow = (unsigned int)read_saa(peasycap->pusb_device, reg);
if (0 > ir)
JOT(8, "SAA register 0x%02X changed to 0x%02X\n", reg, isnow);
else
JOT(8, "SAA register 0x%02X changed " \
"from 0x%02X to 0x%02X\n", reg, itwas, isnow);
}
}
/*--------------------------------------------------------------------------*/
/*
* SAA7113H DATASHEET PAGE 53, TABLE 66
*/
/*--------------------------------------------------------------------------*/
reg = 0x5A;
ir = read_saa(peasycap->pusb_device, reg);
if (0 > ir)
SAY("ERROR: failed to read SAA register 0x%02X but continuing\n", reg);
itwas = (unsigned int)ir;
if (peasycap_standard->mask & 0x0001)
set = 0x0A ;
else
set = 0x07 ;
set2to78(peasycap->pusb_device);
if (0 != write_saa(peasycap->pusb_device, reg, set))
SAY("ERROR: failed to set SAA register 0x%02X to 0x%02X\n", \
reg, set);
else {
isnow = (unsigned int)read_saa(peasycap->pusb_device, reg);
if (0 > ir)
JOT(8, "SAA register 0x%02X changed "
"to 0x%02X\n", reg, isnow);
else
JOT(8, "SAA register 0x%02X changed "
"from 0x%02X to 0x%02X\n", reg, itwas, isnow);
}
if (0 != check_saa(peasycap->pusb_device))
SAY("ERROR: check_saa() failed\n");
return 0;
}
/*****************************************************************************/
/*--------------------------------------------------------------------------*/
/*
* THE ALGORITHM FOR RESPONDING TO THE VIDIO_S_FMT IOCTL DEPENDS ON THE
* CURRENT VALUE OF peasycap->standard_offset.
* PROVIDED THE ARGUMENT try IS false AND THERE IS NO PREMATURE ERROR RETURN
* THIS ROUTINE UPDATES THE FOLLOWING:
* peasycap->format_offset
* peasycap->pixelformat
* peasycap->field
* peasycap->height
* peasycap->width
* peasycap->bytesperpixel
* peasycap->byteswaporder
* peasycap->decimatepixel
* peasycap->frame_buffer_used
* peasycap->videofieldamount
* peasycap->offerfields
*
* IF SUCCESSFUL THE FUNCTION RETURNS THE OFFSET IN easycap_format[]
* IDENTIFYING THE FORMAT WHICH IS TO RETURNED TO THE USER.
* ERRORS RETURN A NEGATIVE NUMBER.
*/
/*--------------------------------------------------------------------------*/
int adjust_format(struct easycap *peasycap, \
__u32 width, __u32 height, __u32 pixelformat, int field, bool try)
{
struct easycap_format *peasycap_format, *peasycap_best_format;
__u16 mask;
struct usb_device *p;
int miss, multiplier, best;
char bf[5], *pc;
__u32 uc;
if ((struct easycap *)NULL == peasycap) {
SAY("ERROR: peasycap is NULL\n");
return -EFAULT;
}
p = peasycap->pusb_device;
if ((struct usb_device *)NULL == p) {
SAY("ERROR: peaycap->pusb_device is NULL\n");
return -EFAULT;
}
pc = &bf[0];
uc = pixelformat; memcpy((void *)pc, (void *)(&uc), 4); bf[4] = 0;
mask = easycap_standard[peasycap->standard_offset].mask;
SAY("sought: %ix%i,%s(0x%08X),%i=field,0x%02X=std mask\n", \
width, height, pc, pixelformat, field, mask);
if (V4L2_FIELD_ANY == field) {
field = V4L2_FIELD_INTERLACED;
SAY("prefer: V4L2_FIELD_INTERLACED=field, was V4L2_FIELD_ANY\n");
}
peasycap_best_format = (struct easycap_format *)NULL;
peasycap_format = &easycap_format[0];
while (0 != peasycap_format->v4l2_format.fmt.pix.width) {
JOT(16, ".> %i %i 0x%08X %ix%i\n", \
peasycap_format->mask & 0x01,
peasycap_format->v4l2_format.fmt.pix.field,
peasycap_format->v4l2_format.fmt.pix.pixelformat,
peasycap_format->v4l2_format.fmt.pix.width,
peasycap_format->v4l2_format.fmt.pix.height);
if (((peasycap_format->mask & 0x0F) == (mask & 0x0F)) && \
(peasycap_format->v4l2_format.fmt.pix.field == field) && \
(peasycap_format->v4l2_format.fmt.pix.pixelformat == \
pixelformat) && \
(peasycap_format->v4l2_format.fmt.pix.width == width) && \
(peasycap_format->v4l2_format.fmt.pix.height == height)) {
peasycap_best_format = peasycap_format;
break;
}
peasycap_format++;
}
if (0 == peasycap_format->v4l2_format.fmt.pix.width) {
SAY("cannot do: %ix%i with standard mask 0x%02X\n", \
width, height, mask);
peasycap_format = &easycap_format[0]; best = -1;
while (0 != peasycap_format->v4l2_format.fmt.pix.width) {
if (((peasycap_format->mask & 0x0F) == (mask & 0x0F)) && \
(peasycap_format->v4l2_format.fmt.pix\
.field == field) && \
(peasycap_format->v4l2_format.fmt.pix\
.pixelformat == pixelformat)) {
miss = abs(peasycap_format->\
v4l2_format.fmt.pix.width - width);
if ((best > miss) || (best < 0)) {
best = miss;
peasycap_best_format = peasycap_format;
if (!miss)
break;
}
}
peasycap_format++;
}
if (-1 == best) {
SAY("cannot do %ix... with standard mask 0x%02X\n", \
width, mask);
SAY("cannot do ...x%i with standard mask 0x%02X\n", \
height, mask);
SAY(" %ix%i unmatched\n", width, height);
return peasycap->format_offset;
}
}
if ((struct easycap_format *)NULL == peasycap_best_format) {
SAY("MISTAKE: peasycap_best_format is NULL");
return -EINVAL;
}
peasycap_format = peasycap_best_format;
/*...........................................................................*/
if (true == try)
return (int)(peasycap_best_format - &easycap_format[0]);
/*...........................................................................*/
if (false != try) {
SAY("MISTAKE: true==try where is should be false\n");
return -EINVAL;
}
SAY("actioning: %ix%i %s\n", \
peasycap_format->v4l2_format.fmt.pix.width, \
peasycap_format->v4l2_format.fmt.pix.height,
&peasycap_format->name[0]);
peasycap->height = peasycap_format->v4l2_format.fmt.pix.height;
peasycap->width = peasycap_format->v4l2_format.fmt.pix.width;
peasycap->pixelformat = peasycap_format->v4l2_format.fmt.pix.pixelformat;
peasycap->field = peasycap_format->v4l2_format.fmt.pix.field;
peasycap->format_offset = (int)(peasycap_format - &easycap_format[0]);
peasycap->bytesperpixel = (0x00F0 & peasycap_format->mask) >> 4 ;
if (0x0100 & peasycap_format->mask)
peasycap->byteswaporder = true;
else
peasycap->byteswaporder = false;
if (0x0800 & peasycap_format->mask)
peasycap->decimatepixel = true;
else
peasycap->decimatepixel = false;
if (0x1000 & peasycap_format->mask)
peasycap->offerfields = true;
else
peasycap->offerfields = false;
if (true == peasycap->decimatepixel)
multiplier = 2;
else
multiplier = 1;
peasycap->videofieldamount = multiplier * peasycap->width * \
multiplier * peasycap->height;
peasycap->frame_buffer_used = peasycap->bytesperpixel * \
peasycap->width * peasycap->height;
if (true == peasycap->offerfields) {
SAY("WARNING: %i=peasycap->field is untested: " \
"please report problems\n", peasycap->field);
/*
* FIXME ---- THIS IS UNTESTED, MAY BE (AND PROBABLY IS) INCORRECT:
*
* peasycap->frame_buffer_used = peasycap->frame_buffer_used / 2;
*
* SO DO NOT RISK IT YET.
*
*/
}
kill_video_urbs(peasycap);
/*---------------------------------------------------------------------------*/
/*
* PAL
*/
/*---------------------------------------------------------------------------*/
if (0 == (0x01 & peasycap_format->mask)) {
if (((720 == peasycap_format->v4l2_format.fmt.pix.width) && \
(576 == \
peasycap_format->v4l2_format.fmt.pix.height)) || \
((360 == \
peasycap_format->v4l2_format.fmt.pix.width) && \
(288 == \
peasycap_format->v4l2_format.fmt.pix.height))) {
if (0 != set_resolution(p, 0x0000, 0x0001, 0x05A0, 0x0121)) {
SAY("ERROR: set_resolution() failed\n");
return -EINVAL;
}
} else if ((704 == peasycap_format->v4l2_format.fmt.pix.width) && \
(576 == peasycap_format->v4l2_format.fmt.pix.height)) {
if (0 != set_resolution(p, 0x0004, 0x0001, 0x0584, 0x0121)) {
SAY("ERROR: set_resolution() failed\n");
return -EINVAL;
}
} else if (((640 == peasycap_format->v4l2_format.fmt.pix.width) && \
(480 == \
peasycap_format->v4l2_format.fmt.pix.height)) || \
((320 == \
peasycap_format->v4l2_format.fmt.pix.width) && \
(240 == \
peasycap_format->v4l2_format.fmt.pix.height))) {
if (0 != set_resolution(p, 0x0014, 0x0020, 0x0514, 0x0110)) {
SAY("ERROR: set_resolution() failed\n");
return -EINVAL;
}
} else {
SAY("MISTAKE: bad format, cannot set resolution\n");
return -EINVAL;
}
/*---------------------------------------------------------------------------*/
/*
* NTSC
*/
/*---------------------------------------------------------------------------*/
} else {
if (((720 == peasycap_format->v4l2_format.fmt.pix.width) && \
(480 == \
peasycap_format->v4l2_format.fmt.pix.height)) || \
((360 == \
peasycap_format->v4l2_format.fmt.pix.width) && \
(240 == \
peasycap_format->v4l2_format.fmt.pix.height))) {
if (0 != set_resolution(p, 0x0000, 0x0003, 0x05A0, 0x00F3)) {
SAY("ERROR: set_resolution() failed\n");
return -EINVAL;
}
} else if (((640 == peasycap_format->v4l2_format.fmt.pix.width) && \
(480 == \
peasycap_format->v4l2_format.fmt.pix.height)) || \
((320 == \
peasycap_format->v4l2_format.fmt.pix.width) && \
(240 == \
peasycap_format->v4l2_format.fmt.pix.height))) {
if (0 != set_resolution(p, 0x0014, 0x0003, 0x0514, 0x00F3)) {
SAY("ERROR: set_resolution() failed\n");
return -EINVAL;
}
} else {
SAY("MISTAKE: bad format, cannot set resolution\n");
return -EINVAL;
}
}
/*---------------------------------------------------------------------------*/
check_stk(peasycap->pusb_device);
return (int)(peasycap_best_format - &easycap_format[0]);
}
/*****************************************************************************/
int adjust_brightness(struct easycap *peasycap, int value)
{
unsigned int mood;
int i1;
if ((struct usb_device *)NULL == peasycap->pusb_device) {
SAY("ERROR: peasycap->pusb_device is NULL\n");
return -EFAULT;
}
i1 = 0;
while (0xFFFFFFFF != easycap_control[i1].id) {
if (V4L2_CID_BRIGHTNESS == easycap_control[i1].id) {
if ((easycap_control[i1].minimum > value) || \
(easycap_control[i1].maximum < value))
value = easycap_control[i1].default_value;
peasycap->brightness = value;
mood = 0x00FF & (unsigned int)peasycap->brightness;
set2to78(peasycap->pusb_device);
if (!write_saa(peasycap->pusb_device, 0x0A, mood)) {
SAY("adjusting brightness to 0x%02X\n", mood);
return 0;
} else {
SAY("WARNING: failed to adjust brightness " \
"to 0x%02X\n", mood);
return -ENOENT;
}
set2to78(peasycap->pusb_device);
break;
}
i1++;
}
SAY("WARNING: failed to adjust brightness: control not found\n");
return -ENOENT;
}
/*****************************************************************************/
int adjust_contrast(struct easycap *peasycap, int value)
{
unsigned int mood;
int i1;
if ((struct usb_device *)NULL == peasycap->pusb_device) {
SAY("ERROR: peasycap->pusb_device is NULL\n");
return -EFAULT;
}
i1 = 0;
while (0xFFFFFFFF != easycap_control[i1].id) {
if (V4L2_CID_CONTRAST == easycap_control[i1].id) {
if ((easycap_control[i1].minimum > value) || \
(easycap_control[i1].maximum < value))
value = easycap_control[i1].default_value;
peasycap->contrast = value;
mood = 0x00FF & (unsigned int) (peasycap->contrast - 128);
set2to78(peasycap->pusb_device);
if (!write_saa(peasycap->pusb_device, 0x0B, mood)) {
SAY("adjusting contrast to 0x%02X\n", mood);
return 0;
} else {
SAY("WARNING: failed to adjust contrast to " \
"0x%02X\n", mood);
return -ENOENT;
}
set2to78(peasycap->pusb_device);
break;
}
i1++;
}
SAY("WARNING: failed to adjust contrast: control not found\n");
return -ENOENT;
}
/*****************************************************************************/
int adjust_saturation(struct easycap *peasycap, int value)
{
unsigned int mood;
int i1;
if ((struct usb_device *)NULL == peasycap->pusb_device) {
SAY("ERROR: peasycap->pusb_device is NULL\n");
return -EFAULT;
}
i1 = 0;
while (0xFFFFFFFF != easycap_control[i1].id) {
if (V4L2_CID_SATURATION == easycap_control[i1].id) {
if ((easycap_control[i1].minimum > value) || \
(easycap_control[i1].maximum < value))
value = easycap_control[i1].default_value;
peasycap->saturation = value;
mood = 0x00FF & (unsigned int) (peasycap->saturation - 128);
set2to78(peasycap->pusb_device);
if (!write_saa(peasycap->pusb_device, 0x0C, mood)) {
SAY("adjusting saturation to 0x%02X\n", mood);
return 0;
} else {
SAY("WARNING: failed to adjust saturation to " \
"0x%02X\n", mood);
return -ENOENT;
}
break;
set2to78(peasycap->pusb_device);
}
i1++;
}
SAY("WARNING: failed to adjust saturation: control not found\n");
return -ENOENT;
}
/*****************************************************************************/
int adjust_hue(struct easycap *peasycap, int value)
{
unsigned int mood;
int i1, i2;
if ((struct usb_device *)NULL == peasycap->pusb_device) {
SAY("ERROR: peasycap->pusb_device is NULL\n");
return -EFAULT;
}
i1 = 0;
while (0xFFFFFFFF != easycap_control[i1].id) {
if (V4L2_CID_HUE == easycap_control[i1].id) {
if ((easycap_control[i1].minimum > value) || \
(easycap_control[i1].maximum < value))
value = easycap_control[i1].default_value;
peasycap->hue = value;
i2 = peasycap->hue - 128;
mood = 0x00FF & ((int) i2);
set2to78(peasycap->pusb_device);
if (!write_saa(peasycap->pusb_device, 0x0D, mood)) {
SAY("adjusting hue to 0x%02X\n", mood);
return 0;
} else {
SAY("WARNING: failed to adjust hue to 0x%02X\n", mood);
return -ENOENT;
}
set2to78(peasycap->pusb_device);
break;
}
i1++;
}
SAY("WARNING: failed to adjust hue: control not found\n");
return -ENOENT;
}
/*****************************************************************************/
int adjust_volume(struct easycap *peasycap, int value)
{
__s8 mood;
int i1;
if ((struct usb_device *)NULL == peasycap->pusb_device) {
SAY("ERROR: peasycap->pusb_device is NULL\n");
return -EFAULT;
}
i1 = 0;
while (0xFFFFFFFF != easycap_control[i1].id) {
if (V4L2_CID_AUDIO_VOLUME == easycap_control[i1].id) {
if ((easycap_control[i1].minimum > value) || \
(easycap_control[i1].maximum < value))
value = easycap_control[i1].default_value;
peasycap->volume = value;
mood = (16 > peasycap->volume) ? 16 : \
((31 < peasycap->volume) ? 31 : \
(__s8) peasycap->volume);
if (!audio_gainset(peasycap->pusb_device, mood)) {
SAY("adjusting volume to 0x%01X\n", mood);
return 0;
} else {
SAY("WARNING: failed to adjust volume to " \
"0x%1X\n", mood);
return -ENOENT;
}
break;
}
i1++;
}
SAY("WARNING: failed to adjust volume: control not found\n");
return -ENOENT;
}
/*****************************************************************************/
/*---------------------------------------------------------------------------*/
/*
* AN ALTERNATIVE METHOD OF MUTING MIGHT SEEM TO BE:
* usb_set_interface(peasycap->pusb_device, \
* peasycap->audio_interface, \
* peasycap->audio_altsetting_off);
* HOWEVER, AFTER THIS COMMAND IS ISSUED ALL SUBSEQUENT URBS RECEIVE STATUS
* -ESHUTDOWN. THE HANDLER ROUTINE easysnd_complete() DECLINES TO RESUBMIT
* THE URB AND THE PIPELINE COLLAPSES IRRETRIEVABLY. BEWARE.
*/
/*---------------------------------------------------------------------------*/
int adjust_mute(struct easycap *peasycap, int value)
{
int i1;
if ((struct usb_device *)NULL == peasycap->pusb_device) {
SAY("ERROR: peasycap->pusb_device is NULL\n");
return -EFAULT;
}
i1 = 0;
while (0xFFFFFFFF != easycap_control[i1].id) {
if (V4L2_CID_AUDIO_MUTE == easycap_control[i1].id) {
peasycap->mute = value;
switch (peasycap->mute) {
case 1: {
peasycap->audio_idle = 1;
peasycap->timeval0.tv_sec = 0;
SAY("adjusting mute: %i=peasycap->audio_idle\n", \
peasycap->audio_idle);
return 0;
}
default: {
peasycap->audio_idle = 0;
SAY("adjusting mute: %i=peasycap->audio_idle\n", \
peasycap->audio_idle);
return 0;
}
}
break;
}
i1++;
}
SAY("WARNING: failed to adjust mute: control not found\n");
return -ENOENT;
}
/****************************************************************************/
/*vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv*/
#if defined(EASYCAP_IS_VIDEODEV_CLIENT)
long
easycap_ioctl_noinode(struct file *file, unsigned int cmd, unsigned long arg)\
{
return easycap_ioctl((struct inode *)NULL, file, cmd, arg);
}
#endif /*EASYCAP_IS_VIDEODEV_CLIENT*/
/*^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^*/
/*--------------------------------------------------------------------------*/
int easycap_ioctl(struct inode *inode, struct file *file, \
unsigned int cmd, unsigned long arg)
{
static struct easycap *peasycap;
static struct usb_device *p;
static __u32 isequence;
peasycap = (struct easycap *)file->private_data;
if (NULL == peasycap) {
SAY("ERROR: peasycap is NULL\n");
return -1;
}
p = peasycap->pusb_device;
if ((struct usb_device *)NULL == p) {
SAY("ERROR: peasycap->pusb_device is NULL\n");
return -EFAULT;
}
/*---------------------------------------------------------------------------*/
/*
* MOST OF THE VARIABLES DECLARED static IN THE case{} BLOCKS BELOW ARE SO
* DECLARED SIMPLY TO AVOID A COMPILER WARNING OF THE KIND:
* easycap_ioctl.c: warning:
* the frame size of ... bytes is larger than 1024 bytes
*/
/*---------------------------------------------------------------------------*/
switch (cmd) {
case VIDIOC_QUERYCAP: {
static struct v4l2_capability v4l2_capability;
static char version[16], *p1, *p2;
static int i, rc, k[3];
static long lng;
JOT(8, "VIDIOC_QUERYCAP\n");
if (16 <= strlen(EASYCAP_DRIVER_VERSION)) {
SAY("ERROR: bad driver version string\n"); return -EINVAL;
}
strcpy(&version[0], EASYCAP_DRIVER_VERSION);
for (i = 0; i < 3; i++)
k[i] = 0;
p2 = &version[0]; i = 0;
while (*p2) {
p1 = p2;
while (*p2 && ('.' != *p2))
p2++;
if (*p2)
*p2++ = 0;
if (3 > i) {
rc = (int) strict_strtol(p1, 10, &lng);
if (0 != rc) {
SAY("ERROR: %i=strict_strtol(%s,.,,)\n", \
rc, p1);
return -EINVAL;
}
k[i] = (int)lng;
}
i++;
}
memset(&v4l2_capability, 0, sizeof(struct v4l2_capability));
strlcpy(&v4l2_capability.driver[0], "easycap", \
sizeof(v4l2_capability.driver));
v4l2_capability.capabilities = \
V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING | \
V4L2_CAP_AUDIO | V4L2_CAP_READWRITE;
v4l2_capability.version = KERNEL_VERSION(k[0], k[1], k[2]);
JOT(8, "v4l2_capability.version=(%i,%i,%i)\n", k[0], k[1], k[2]);
strlcpy(&v4l2_capability.card[0], "EasyCAP DC60", \
sizeof(v4l2_capability.card));
if (usb_make_path(peasycap->pusb_device, &v4l2_capability.bus_info[0],\
sizeof(v4l2_capability.bus_info)) < 0) {
strlcpy(&v4l2_capability.bus_info[0], "EasyCAP bus_info", \
sizeof(v4l2_capability.bus_info));
JOT(8, "%s=v4l2_capability.bus_info\n", \
&v4l2_capability.bus_info[0]);
}
if (0 != copy_to_user((void __user *)arg, &v4l2_capability, \
sizeof(struct v4l2_capability))) {
POUT;
return -EFAULT;
}
break;
}
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
case VIDIOC_ENUMINPUT: {
static struct v4l2_input v4l2_input;
static __u32 index;
JOT(8, "VIDIOC_ENUMINPUT\n");
if (0 != copy_from_user(&v4l2_input, (void __user *)arg, \
sizeof(struct v4l2_input))) {
POUT;
return -EFAULT;
}
index = v4l2_input.index;
memset(&v4l2_input, 0, sizeof(struct v4l2_input));
switch (index) {
case 0: {
v4l2_input.index = index;
strcpy(&v4l2_input.name[0], "CVBS0");
v4l2_input.type = V4L2_INPUT_TYPE_CAMERA;
v4l2_input.audioset = 0x01;
v4l2_input.tuner = 0;
v4l2_input.std = V4L2_STD_PAL | V4L2_STD_SECAM | \
V4L2_STD_NTSC ;
v4l2_input.status = 0;
JOT(8, "%i=index: %s\n", index, &v4l2_input.name[0]);
break;
}
case 1: {
v4l2_input.index = index;
strcpy(&v4l2_input.name[0], "CVBS1");
v4l2_input.type = V4L2_INPUT_TYPE_CAMERA;
v4l2_input.audioset = 0x01;
v4l2_input.tuner = 0;
v4l2_input.std = V4L2_STD_PAL | V4L2_STD_SECAM | \
V4L2_STD_NTSC ;
v4l2_input.status = 0;
JOT(8, "%i=index: %s\n", index, &v4l2_input.name[0]);
break;
}
case 2: {
v4l2_input.index = index;
strcpy(&v4l2_input.name[0], "CVBS2");
v4l2_input.type = V4L2_INPUT_TYPE_CAMERA;
v4l2_input.audioset = 0x01;
v4l2_input.tuner = 0;
v4l2_input.std = V4L2_STD_PAL | V4L2_STD_SECAM | \
V4L2_STD_NTSC ;
v4l2_input.status = 0;
JOT(8, "%i=index: %s\n", index, &v4l2_input.name[0]);
break;
}
case 3: {
v4l2_input.index = index;
strcpy(&v4l2_input.name[0], "CVBS3");
v4l2_input.type = V4L2_INPUT_TYPE_CAMERA;
v4l2_input.audioset = 0x01;
v4l2_input.tuner = 0;
v4l2_input.std = V4L2_STD_PAL | V4L2_STD_SECAM | \
V4L2_STD_NTSC ;
v4l2_input.status = 0;
JOT(8, "%i=index: %s\n", index, &v4l2_input.name[0]);
break;
}
case 4: {
v4l2_input.index = index;
strcpy(&v4l2_input.name[0], "CVBS4");
v4l2_input.type = V4L2_INPUT_TYPE_CAMERA;
v4l2_input.audioset = 0x01;
v4l2_input.tuner = 0;
v4l2_input.std = V4L2_STD_PAL | V4L2_STD_SECAM | \
V4L2_STD_NTSC ;
v4l2_input.status = 0;
JOT(8, "%i=index: %s\n", index, &v4l2_input.name[0]);
break;
}
case 5: {
v4l2_input.index = index;
strcpy(&v4l2_input.name[0], "S-VIDEO");
v4l2_input.type = V4L2_INPUT_TYPE_CAMERA;
v4l2_input.audioset = 0x01;
v4l2_input.tuner = 0;
v4l2_input.std = V4L2_STD_PAL | V4L2_STD_SECAM | \
V4L2_STD_NTSC ;
v4l2_input.status = 0;
JOT(8, "%i=index: %s\n", index, &v4l2_input.name[0]);
break;
}
default: {
JOT(8, "%i=index: exhausts inputs\n", index);
return -EINVAL;
}
}
if (0 != copy_to_user((void __user *)arg, &v4l2_input, \
sizeof(struct v4l2_input))) {
POUT;
return -EFAULT;
}
break;
}
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
case VIDIOC_G_INPUT: {
static __u32 index;
JOT(8, "VIDIOC_G_INPUT\n");
index = (__u32)peasycap->input;
JOT(8, "user is told: %i\n", index);
if (0 != copy_to_user((void __user *)arg, &index, sizeof(__u32))) {
POUT;
return -EFAULT;
}
break;
}
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
case VIDIOC_S_INPUT:
{
static __u32 index;
JOT(8, "VIDIOC_S_INPUT\n");
if (0 != copy_from_user(&index, (void __user *)arg, sizeof(__u32))) {
POUT;
return -EFAULT;
}
JOT(8, "user requests input %i\n", index);
if ((int)index == peasycap->input) {
SAY("requested input already in effect\n");
break;
}
if ((0 > index) || (5 < index)) {
JOT(8, "ERROR: bad requested input: %i\n", index);
return -EINVAL;
}
peasycap->input = (int)index;
select_input(peasycap->pusb_device, peasycap->input, 9);
break;
}
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
case VIDIOC_ENUMAUDIO: {
JOT(8, "VIDIOC_ENUMAUDIO\n");
return -EINVAL;
}
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
case VIDIOC_ENUMAUDOUT: {
static struct v4l2_audioout v4l2_audioout;
JOT(8, "VIDIOC_ENUMAUDOUT\n");
if (0 != copy_from_user(&v4l2_audioout, (void __user *)arg, \
sizeof(struct v4l2_audioout))) {
POUT;
return -EFAULT;
}
if (0 != v4l2_audioout.index)
return -EINVAL;
memset(&v4l2_audioout, 0, sizeof(struct v4l2_audioout));
v4l2_audioout.index = 0;
strcpy(&v4l2_audioout.name[0], "Soundtrack");
if (0 != copy_to_user((void __user *)arg, &v4l2_audioout, \
sizeof(struct v4l2_audioout))) {
POUT;
return -EFAULT;
}
break;
}
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
case VIDIOC_QUERYCTRL: {
static int i1;
static struct v4l2_queryctrl v4l2_queryctrl;
JOT(8, "VIDIOC_QUERYCTRL\n");
if (0 != copy_from_user(&v4l2_queryctrl, (void __user *)arg, \
sizeof(struct v4l2_queryctrl))) {
POUT;
return -EFAULT;
}
i1 = 0;
while (0xFFFFFFFF != easycap_control[i1].id) {
if (easycap_control[i1].id == v4l2_queryctrl.id) {
JOT(8, "VIDIOC_QUERYCTRL %s=easycap_control[%i]" \
".name\n", &easycap_control[i1].name[0], i1);
memcpy(&v4l2_queryctrl, &easycap_control[i1], \
sizeof(struct v4l2_queryctrl));
break;
}
i1++;
}
if (0xFFFFFFFF == easycap_control[i1].id) {
JOT(8, "%i=index: exhausts controls\n", i1);
return -EINVAL;
}
if (0 != copy_to_user((void __user *)arg, &v4l2_queryctrl, \
sizeof(struct v4l2_queryctrl))) {
POUT;
return -EFAULT;
}
break;
}
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
case VIDIOC_QUERYMENU: {
JOT(8, "VIDIOC_QUERYMENU unsupported\n");
return -EINVAL;
break;
}
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
case VIDIOC_G_CTRL: {
static struct v4l2_control v4l2_control;
JOT(8, "VIDIOC_G_CTRL\n");
if (0 != copy_from_user(&v4l2_control, (void __user *)arg, \
sizeof(struct v4l2_control))) {
POUT;
return -EFAULT;
}
switch (v4l2_control.id) {
case V4L2_CID_BRIGHTNESS: {
v4l2_control.value = peasycap->brightness;
JOT(8, "user enquires brightness: %i\n", v4l2_control.value);
break;
}
case V4L2_CID_CONTRAST: {
v4l2_control.value = peasycap->contrast;
JOT(8, "user enquires contrast: %i\n", v4l2_control.value);
break;
}
case V4L2_CID_SATURATION: {
v4l2_control.value = peasycap->saturation;
JOT(8, "user enquires saturation: %i\n", v4l2_control.value);
break;
}
case V4L2_CID_HUE: {
v4l2_control.value = peasycap->hue;
JOT(8, "user enquires hue: %i\n", v4l2_control.value);
break;
}
case V4L2_CID_AUDIO_VOLUME: {
v4l2_control.value = peasycap->volume;
JOT(8, "user enquires volume: %i\n", v4l2_control.value);
break;
}
case V4L2_CID_AUDIO_MUTE: {
if (1 == peasycap->mute)
v4l2_control.value = true;
else
v4l2_control.value = false;
JOT(8, "user enquires mute: %i\n", v4l2_control.value);
break;
}
default: {
SAY("ERROR: unknown V4L2 control: 0x%08X=id\n", \
v4l2_control.id);
explain_cid(v4l2_control.id);
return -EINVAL;
}
}
if (0 != copy_to_user((void __user *)arg, &v4l2_control, \
sizeof(struct v4l2_control))) {
POUT;
return -EFAULT;
}
break;
}
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
#if defined(VIDIOC_S_CTRL_OLD)
case VIDIOC_S_CTRL_OLD: {
JOT(8, "VIDIOC_S_CTRL_OLD required at least for xawtv\n");
}
#endif /*VIDIOC_S_CTRL_OLD*/
case VIDIOC_S_CTRL:
{
static struct v4l2_control v4l2_control;
JOT(8, "VIDIOC_S_CTRL\n");
if (0 != copy_from_user(&v4l2_control, (void __user *)arg, \
sizeof(struct v4l2_control))) {
POUT;
return -EFAULT;
}
switch (v4l2_control.id) {
case V4L2_CID_BRIGHTNESS: {
JOT(8, "user requests brightness %i\n", v4l2_control.value);
if (0 != adjust_brightness(peasycap, v4l2_control.value))
;
break;
}
case V4L2_CID_CONTRAST: {
JOT(8, "user requests contrast %i\n", v4l2_control.value);
if (0 != adjust_contrast(peasycap, v4l2_control.value))
;
break;
}
case V4L2_CID_SATURATION: {
JOT(8, "user requests saturation %i\n", v4l2_control.value);
if (0 != adjust_saturation(peasycap, v4l2_control.value))
;
break;
}
case V4L2_CID_HUE: {
JOT(8, "user requests hue %i\n", v4l2_control.value);
if (0 != adjust_hue(peasycap, v4l2_control.value))
;
break;
}
case V4L2_CID_AUDIO_VOLUME: {
JOT(8, "user requests volume %i\n", v4l2_control.value);
if (0 != adjust_volume(peasycap, v4l2_control.value))
;
break;
}
case V4L2_CID_AUDIO_MUTE: {
int mute;
JOT(8, "user requests mute %i\n", v4l2_control.value);
if (true == v4l2_control.value)
mute = 1;
else
mute = 0;
if (0 != adjust_mute(peasycap, mute))
SAY("WARNING: failed to adjust mute to %i\n", mute);
break;
}
default: {
SAY("ERROR: unknown V4L2 control: 0x%08X=id\n", \
v4l2_control.id);
explain_cid(v4l2_control.id);
return -EINVAL;
}
}
break;
}
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
case VIDIOC_S_EXT_CTRLS: {
JOT(8, "VIDIOC_S_EXT_CTRLS unsupported\n");
return -EINVAL;
}
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
case VIDIOC_ENUM_FMT: {
static __u32 index;
static struct v4l2_fmtdesc v4l2_fmtdesc;
JOT(8, "VIDIOC_ENUM_FMT\n");
if (0 != copy_from_user(&v4l2_fmtdesc, (void __user *)arg, \
sizeof(struct v4l2_fmtdesc))) {
POUT;
return -EFAULT;
}
index = v4l2_fmtdesc.index;
memset(&v4l2_fmtdesc, 0, sizeof(struct v4l2_fmtdesc));
v4l2_fmtdesc.index = index;
v4l2_fmtdesc.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
switch (index) {
case 0: {
v4l2_fmtdesc.flags = 0;
strcpy(&v4l2_fmtdesc.description[0], "uyvy");
v4l2_fmtdesc.pixelformat = V4L2_PIX_FMT_UYVY;
JOT(8, "%i=index: %s\n", index, &v4l2_fmtdesc.description[0]);
break;
}
case 1: {
v4l2_fmtdesc.flags = 0;
strcpy(&v4l2_fmtdesc.description[0], "yuy2");
v4l2_fmtdesc.pixelformat = V4L2_PIX_FMT_YUYV;
JOT(8, "%i=index: %s\n", index, &v4l2_fmtdesc.description[0]);
break;
}
case 2: {
v4l2_fmtdesc.flags = 0;
strcpy(&v4l2_fmtdesc.description[0], "rgb24");
v4l2_fmtdesc.pixelformat = V4L2_PIX_FMT_RGB24;
JOT(8, "%i=index: %s\n", index, &v4l2_fmtdesc.description[0]);
break;
}
case 3: {
v4l2_fmtdesc.flags = 0;
strcpy(&v4l2_fmtdesc.description[0], "rgb32");
v4l2_fmtdesc.pixelformat = V4L2_PIX_FMT_RGB32;
JOT(8, "%i=index: %s\n", index, &v4l2_fmtdesc.description[0]);
break;
}
case 4: {
v4l2_fmtdesc.flags = 0;
strcpy(&v4l2_fmtdesc.description[0], "bgr24");
v4l2_fmtdesc.pixelformat = V4L2_PIX_FMT_BGR24;
JOT(8, "%i=index: %s\n", index, &v4l2_fmtdesc.description[0]);
break;
}
case 5: {
v4l2_fmtdesc.flags = 0;
strcpy(&v4l2_fmtdesc.description[0], "bgr32");
v4l2_fmtdesc.pixelformat = V4L2_PIX_FMT_BGR32;
JOT(8, "%i=index: %s\n", index, &v4l2_fmtdesc.description[0]);
break;
}
default: {
JOT(8, "%i=index: exhausts formats\n", index);
return -EINVAL;
}
}
if (0 != copy_to_user((void __user *)arg, &v4l2_fmtdesc, \
sizeof(struct v4l2_fmtdesc))) {
POUT;
return -EFAULT;
}
break;
}
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
case VIDIOC_ENUM_FRAMESIZES: {
JOT(8, "VIDIOC_ENUM_FRAMESIZES unsupported\n");
return -EINVAL;
}
case VIDIOC_ENUM_FRAMEINTERVALS: {
JOT(8, "VIDIOC_ENUM_FRAME_INTERVALS unsupported\n");
return -EINVAL;
}
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
case VIDIOC_G_FMT: {
static struct v4l2_format v4l2_format;
static struct v4l2_pix_format v4l2_pix_format;
JOT(8, "VIDIOC_G_FMT\n");
if (0 != copy_from_user(&v4l2_format, (void __user *)arg, \
sizeof(struct v4l2_format))) {
POUT;
return -EFAULT;
}
if (v4l2_format.type != V4L2_BUF_TYPE_VIDEO_CAPTURE) {
POUT;
return -EINVAL;
}
memset(&v4l2_pix_format, 0, sizeof(struct v4l2_pix_format));
v4l2_format.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
memcpy(&(v4l2_format.fmt.pix), \
&(easycap_format[peasycap->format_offset]\
.v4l2_format.fmt.pix), sizeof(v4l2_pix_format));
JOT(8, "user is told: %s\n", \
&easycap_format[peasycap->format_offset].name[0]);
if (0 != copy_to_user((void __user *)arg, &v4l2_format, \
sizeof(struct v4l2_format))) {
POUT;
return -EFAULT;
}
break;
}
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
case VIDIOC_TRY_FMT:
case VIDIOC_S_FMT: {
static struct v4l2_format v4l2_format;
static struct v4l2_pix_format v4l2_pix_format;
static bool try;
static int best_format;
if (VIDIOC_TRY_FMT == cmd) {
JOT(8, "VIDIOC_TRY_FMT\n");
try = true;
} else {
JOT(8, "VIDIOC_S_FMT\n");
try = false;
}
if (0 != copy_from_user(&v4l2_format, (void __user *)arg, \
sizeof(struct v4l2_format))) {
POUT;
return -EFAULT;
}
best_format = adjust_format(peasycap, \
v4l2_format.fmt.pix.width, \
v4l2_format.fmt.pix.height, \
v4l2_format.fmt.pix.pixelformat, \
v4l2_format.fmt.pix.field, \
try);
if (0 > best_format) {
JOT(8, "WARNING: adjust_format() returned %i\n", best_format);
return -ENOENT;
}
/*...........................................................................*/
memset(&v4l2_pix_format, 0, sizeof(struct v4l2_pix_format));
v4l2_format.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
memcpy(&(v4l2_format.fmt.pix), &(easycap_format[best_format]\
.v4l2_format.fmt.pix), sizeof(v4l2_pix_format));
JOT(8, "user is told: %s\n", &easycap_format[best_format].name[0]);
if (0 != copy_to_user((void __user *)arg, &v4l2_format, \
sizeof(struct v4l2_format))) {
POUT;
return -EFAULT;
}
break;
}
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
case VIDIOC_CROPCAP: {
static struct v4l2_cropcap v4l2_cropcap;
JOT(8, "VIDIOC_CROPCAP\n");
if (0 != copy_from_user(&v4l2_cropcap, (void __user *)arg, \
sizeof(struct v4l2_cropcap))) {
POUT;
return -EFAULT;
}
if (v4l2_cropcap.type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
JOT(8, "v4l2_cropcap.type != V4L2_BUF_TYPE_VIDEO_CAPTURE\n");
memset(&v4l2_cropcap, 0, sizeof(struct v4l2_cropcap));
v4l2_cropcap.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
v4l2_cropcap.bounds.left = 0;
v4l2_cropcap.bounds.top = 0;
v4l2_cropcap.bounds.width = peasycap->width;
v4l2_cropcap.bounds.height = peasycap->height;
v4l2_cropcap.defrect.left = 0;
v4l2_cropcap.defrect.top = 0;
v4l2_cropcap.defrect.width = peasycap->width;
v4l2_cropcap.defrect.height = peasycap->height;
v4l2_cropcap.pixelaspect.numerator = 1;
v4l2_cropcap.pixelaspect.denominator = 1;
JOT(8, "user is told: %ix%i\n", peasycap->width, peasycap->height);
if (0 != copy_to_user((void __user *)arg, &v4l2_cropcap, \
sizeof(struct v4l2_cropcap))) {
POUT;
return -EFAULT;
}
break;
}
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
case VIDIOC_G_CROP:
case VIDIOC_S_CROP: {
JOT(8, "VIDIOC_G_CROP|VIDIOC_S_CROP unsupported\n");
return -EINVAL;
}
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
case VIDIOC_QUERYSTD: {
JOT(8, "VIDIOC_QUERYSTD: " \
"EasyCAP is incapable of detecting standard\n");
return -EINVAL;
break;
}
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
/*---------------------------------------------------------------------------*/
/*
* THE MANIPULATIONS INVOLVING last0,last1,last2,last3 CONSTITUTE A WORKAROUND
* FOR WHAT APPEARS TO BE A BUG IN 64-BIT mplayer.
* NOT NEEDED, BUT HOPEFULLY HARMLESS, FOR 32-BIT mplayer.
*/
/*---------------------------------------------------------------------------*/
case VIDIOC_ENUMSTD: {
static int last0 = -1, last1 = -1, last2 = -1, last3 = -1;
static struct v4l2_standard v4l2_standard;
static __u32 index;
static struct easycap_standard *peasycap_standard;
JOT(8, "VIDIOC_ENUMSTD\n");
if (0 != copy_from_user(&v4l2_standard, (void __user *)arg, \
sizeof(struct v4l2_standard))) {
POUT;
return -EFAULT;
}
index = v4l2_standard.index;
last3 = last2; last2 = last1; last1 = last0; last0 = index;
if ((index == last3) && (index == last2) && \
(index == last1) && (index == last0)) {
index++;
last3 = last2; last2 = last1; last1 = last0; last0 = index;
}
memset(&v4l2_standard, 0, sizeof(struct v4l2_standard));
peasycap_standard = &easycap_standard[0];
while (0xFFFF != peasycap_standard->mask) {
if ((int)(peasycap_standard - &easycap_standard[0]) == index)
break;
peasycap_standard++;
}
if (0xFFFF == peasycap_standard->mask) {
JOT(8, "%i=index: exhausts standards\n", index);
return -EINVAL;
}
JOT(8, "%i=index: %s\n", index, \
&(peasycap_standard->v4l2_standard.name[0]));
peasycap_standard->v4l2_standard.index = index;
v4l2_standard.index = index;
if (0 != copy_to_user((void __user *)arg, \
&(peasycap_standard->v4l2_standard), \
sizeof(struct v4l2_standard))) {
POUT;
return -EFAULT;
}
break;
}
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
case VIDIOC_G_STD: {
static v4l2_std_id std_id;
static struct easycap_standard *peasycap_standard;
JOT(8, "VIDIOC_G_STD\n");
if (0 != copy_from_user(&std_id, (void __user *)arg, \
sizeof(v4l2_std_id))) {
POUT;
return -EFAULT;
}
peasycap_standard = &easycap_standard[peasycap->standard_offset];
std_id = peasycap_standard->v4l2_standard.id;
JOT(8, "user is told: %s\n", \
&peasycap_standard->v4l2_standard.name[0]);
if (0 != copy_to_user((void __user *)arg, &std_id, \
sizeof(v4l2_std_id))) {
POUT;
return -EFAULT;
}
break;
}
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
case VIDIOC_S_STD: {
static v4l2_std_id std_id;
static int rc;
JOT(8, "VIDIOC_S_STD\n");
if (0 != copy_from_user(&std_id, (void __user *)arg, \
sizeof(v4l2_std_id))) {
POUT;
return -EFAULT;
}
rc = adjust_standard(peasycap, std_id);
if (0 > rc) {
JOT(8, "WARNING: adjust_standard() returned %i\n", rc);
return -ENOENT;
}
break;
}
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
case VIDIOC_REQBUFS: {
static int nbuffers;
static struct v4l2_requestbuffers v4l2_requestbuffers;
JOT(8, "VIDIOC_REQBUFS\n");
if (0 != copy_from_user(&v4l2_requestbuffers, (void __user *)arg, \
sizeof(struct v4l2_requestbuffers))) {
POUT;
return -EFAULT;
}
if (v4l2_requestbuffers.type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
return -EINVAL;
if (v4l2_requestbuffers.memory != V4L2_MEMORY_MMAP) {
POUT;
return -EINVAL;
}
nbuffers = v4l2_requestbuffers.count;
JOT(8, " User requests %i buffers ...\n", nbuffers);
if (nbuffers < 2)
nbuffers = 2;
if (nbuffers > FRAME_BUFFER_MANY)
nbuffers = FRAME_BUFFER_MANY;
if (v4l2_requestbuffers.count == nbuffers) {
JOT(8, " ... agree to %i buffers\n", \
nbuffers);
} else {
JOT(8, " ... insist on %i buffers\n", \
nbuffers);
v4l2_requestbuffers.count = nbuffers;
}
peasycap->frame_buffer_many = nbuffers;
if (0 != copy_to_user((void __user *)arg, &v4l2_requestbuffers, \
sizeof(struct v4l2_requestbuffers))) {
POUT;
return -EFAULT;
}
break;
}
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
case VIDIOC_QUERYBUF: {
static __u32 index;
static struct v4l2_buffer v4l2_buffer;
JOT(8, "VIDIOC_QUERYBUF\n");
if (peasycap->video_eof) {
JOT(8, "returning -1 because %i=video_eof\n", \
peasycap->video_eof);
return -1;
}
if (0 != copy_from_user(&v4l2_buffer, (void __user *)arg, \
sizeof(struct v4l2_buffer))) {
POUT;
return -EFAULT;
}
if (v4l2_buffer.type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
return -EINVAL;
index = v4l2_buffer.index;
if (index < 0 || index >= peasycap->frame_buffer_many)
return -EINVAL;
memset(&v4l2_buffer, 0, sizeof(struct v4l2_buffer));
v4l2_buffer.index = index;
v4l2_buffer.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
v4l2_buffer.bytesused = peasycap->frame_buffer_used;
v4l2_buffer.flags = V4L2_BUF_FLAG_MAPPED | \
peasycap->done[index] | \
peasycap->queued[index];
v4l2_buffer.field = peasycap->field;
v4l2_buffer.memory = V4L2_MEMORY_MMAP;
v4l2_buffer.m.offset = index * FRAME_BUFFER_SIZE;
v4l2_buffer.length = FRAME_BUFFER_SIZE;
JOT(16, " %10i=index\n", v4l2_buffer.index);
JOT(16, " 0x%08X=type\n", v4l2_buffer.type);
JOT(16, " %10i=bytesused\n", v4l2_buffer.bytesused);
JOT(16, " 0x%08X=flags\n", v4l2_buffer.flags);
JOT(16, " %10i=field\n", v4l2_buffer.field);
JOT(16, " %10li=timestamp.tv_usec\n", \
(long)v4l2_buffer.timestamp.tv_usec);
JOT(16, " %10i=sequence\n", v4l2_buffer.sequence);
JOT(16, " 0x%08X=memory\n", v4l2_buffer.memory);
JOT(16, " %10i=m.offset\n", v4l2_buffer.m.offset);
JOT(16, " %10i=length\n", v4l2_buffer.length);
if (0 != copy_to_user((void __user *)arg, &v4l2_buffer, \
sizeof(struct v4l2_buffer))) {
POUT;
return -EFAULT;
}
break;
}
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
case VIDIOC_QBUF: {
static struct v4l2_buffer v4l2_buffer;
JOT(8, "VIDIOC_QBUF\n");
if (0 != copy_from_user(&v4l2_buffer, (void __user *)arg, \
sizeof(struct v4l2_buffer))) {
POUT;
return -EFAULT;
}
if (v4l2_buffer.type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
return -EINVAL;
if (v4l2_buffer.memory != V4L2_MEMORY_MMAP)
return -EINVAL;
if (v4l2_buffer.index < 0 || \
(v4l2_buffer.index >= peasycap->frame_buffer_many))
return -EINVAL;
v4l2_buffer.flags = V4L2_BUF_FLAG_MAPPED | V4L2_BUF_FLAG_QUEUED;
peasycap->done[v4l2_buffer.index] = 0;
peasycap->queued[v4l2_buffer.index] = V4L2_BUF_FLAG_QUEUED;
if (0 != copy_to_user((void __user *)arg, &v4l2_buffer, \
sizeof(struct v4l2_buffer))) {
POUT;
return -EFAULT;
}
JOT(8, "..... user queueing frame buffer %i\n", \
(int)v4l2_buffer.index);
peasycap->frame_lock = 0;
break;
}
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
case VIDIOC_DQBUF:
{
#if defined(AUDIOTIME)
static struct signed_div_result sdr;
static long long int above, below, dnbydt, fudge, sll;
static unsigned long long int ull;
static struct timeval timeval0;
struct timeval timeval1;
#endif /*AUDIOTIME*/
static struct timeval timeval, timeval2;
static int i, j;
static struct v4l2_buffer v4l2_buffer;
JOT(8, "VIDIOC_DQBUF\n");
if ((peasycap->video_idle) || (peasycap->video_eof)) {
JOT(8, "returning -EIO because " \
"%i=video_idle %i=video_eof\n", \
peasycap->video_idle, peasycap->video_eof);
return -EIO;
}
if (0 != copy_from_user(&v4l2_buffer, (void __user *)arg, \
sizeof(struct v4l2_buffer))) {
POUT;
return -EFAULT;
}
if (v4l2_buffer.type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
return -EINVAL;
if (!peasycap->video_isoc_streaming) {
JOT(16, "returning -EIO because video urbs not streaming\n");
return -EIO;
}
/*---------------------------------------------------------------------------*/
/*
* IF THE USER HAS PREVIOUSLY CALLED easycap_poll(), AS DETERMINED BY FINDING
* THE FLAG peasycap->polled SET, THERE MUST BE NO FURTHER WAIT HERE. IN THIS
* CASE, JUST CHOOSE THE FRAME INDICATED BY peasycap->frame_read
*/
/*---------------------------------------------------------------------------*/
if (!peasycap->polled) {
if (-EIO == easycap_dqbuf(peasycap, 0))
return -EIO;
} else {
if (peasycap->video_eof)
return -EIO;
}
if (V4L2_BUF_FLAG_DONE != peasycap->done[peasycap->frame_read]) {
SAY("ERROR: V4L2_BUF_FLAG_DONE != 0x%08X\n", \
peasycap->done[peasycap->frame_read]);
}
peasycap->polled = 0;
if (!(isequence % 10)) {
for (i = 0; i < 179; i++)
peasycap->merit[i] = peasycap->merit[i+1];
peasycap->merit[179] = merit_saa(peasycap->pusb_device);
j = 0;
for (i = 0; i < 180; i++)
j += peasycap->merit[i];
if (90 < j) {
SAY("easycap driver shutting down " \
"on condition blue\n");
peasycap->video_eof = 1; peasycap->audio_eof = 1;
}
}
v4l2_buffer.index = peasycap->frame_read;
v4l2_buffer.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
v4l2_buffer.bytesused = peasycap->frame_buffer_used;
v4l2_buffer.flags = V4L2_BUF_FLAG_MAPPED | V4L2_BUF_FLAG_DONE;
v4l2_buffer.field = peasycap->field;
if (V4L2_FIELD_ALTERNATE == v4l2_buffer.field)
v4l2_buffer.field = \
0x000F & (peasycap->\
frame_buffer[peasycap->frame_read][0].kount);
do_gettimeofday(&timeval);
timeval2 = timeval;
#if defined(AUDIOTIME)
if (!peasycap->timeval0.tv_sec) {
timeval0 = timeval;
timeval1 = timeval;
timeval2 = timeval;
dnbydt = 192000;
if (mutex_lock_interruptible(&(peasycap->mutex_timeval0)))
return -ERESTARTSYS;
peasycap->timeval0 = timeval0;
mutex_unlock(&(peasycap->mutex_timeval0));
} else {
if (mutex_lock_interruptible(&(peasycap->mutex_timeval1)))
return -ERESTARTSYS;
dnbydt = peasycap->dnbydt;
timeval1 = peasycap->timeval1;
mutex_unlock(&(peasycap->mutex_timeval1));
above = dnbydt * MICROSECONDS(timeval, timeval1);
below = 192000;
sdr = signed_div(above, below);
above = sdr.quotient + timeval1.tv_usec - 350000;
below = 1000000;
sdr = signed_div(above, below);
timeval2.tv_usec = sdr.remainder;
timeval2.tv_sec = timeval1.tv_sec + sdr.quotient;
}
if (!(isequence % 500)) {
fudge = ((long long int)(1000000)) * \
((long long int)(timeval.tv_sec - \
timeval2.tv_sec)) + \
(long long int)(timeval.tv_usec - \
timeval2.tv_usec);
sdr = signed_div(fudge, 1000);
sll = sdr.quotient;
ull = sdr.remainder;
SAY("%5lli.%-3lli=ms timestamp fudge\n", sll, ull);
}
#endif /*AUDIOTIME*/
v4l2_buffer.timestamp = timeval2;
v4l2_buffer.sequence = isequence++;
v4l2_buffer.memory = V4L2_MEMORY_MMAP;
v4l2_buffer.m.offset = v4l2_buffer.index * FRAME_BUFFER_SIZE;
v4l2_buffer.length = FRAME_BUFFER_SIZE;
JOT(16, " %10i=index\n", v4l2_buffer.index);
JOT(16, " 0x%08X=type\n", v4l2_buffer.type);
JOT(16, " %10i=bytesused\n", v4l2_buffer.bytesused);
JOT(16, " 0x%08X=flags\n", v4l2_buffer.flags);
JOT(16, " %10i=field\n", v4l2_buffer.field);
JOT(16, " %10li=timestamp.tv_usec\n", \
(long)v4l2_buffer.timestamp.tv_usec);
JOT(16, " %10i=sequence\n", v4l2_buffer.sequence);
JOT(16, " 0x%08X=memory\n", v4l2_buffer.memory);
JOT(16, " %10i=m.offset\n", v4l2_buffer.m.offset);
JOT(16, " %10i=length\n", v4l2_buffer.length);
if (0 != copy_to_user((void __user *)arg, &v4l2_buffer, \
sizeof(struct v4l2_buffer))) {
POUT;
return -EFAULT;
}
JOT(8, "..... user is offered frame buffer %i\n", \
peasycap->frame_read);
peasycap->frame_lock = 1;
if (peasycap->frame_read == peasycap->frame_fill) {
if (peasycap->frame_lock) {
JOT(8, "ERROR: filling frame buffer " \
"while offered to user\n");
}
}
break;
}
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
/*---------------------------------------------------------------------------*/
/*
* AUDIO URBS HAVE ALREADY BEEN SUBMITTED WHEN THIS COMMAND IS RECEIVED;
* VIDEO URBS HAVE NOT.
*/
/*---------------------------------------------------------------------------*/
case VIDIOC_STREAMON: {
static int i;
JOT(8, "VIDIOC_STREAMON\n");
isequence = 0;
for (i = 0; i < 180; i++)
peasycap->merit[i] = 0;
if ((struct usb_device *)NULL == peasycap->pusb_device) {
SAY("ERROR: peasycap->pusb_device is NULL\n");
return -EFAULT;
}
submit_video_urbs(peasycap);
peasycap->video_idle = 0;
peasycap->audio_idle = 0;
peasycap->video_eof = 0;
peasycap->audio_eof = 0;
break;
}
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
case VIDIOC_STREAMOFF: {
JOT(8, "VIDIOC_STREAMOFF\n");
if ((struct usb_device *)NULL == peasycap->pusb_device) {
SAY("ERROR: peasycap->pusb_device is NULL\n");
return -EFAULT;
}
peasycap->video_idle = 1;
peasycap->audio_idle = 1; peasycap->timeval0.tv_sec = 0;
/*---------------------------------------------------------------------------*/
/*
* IF THE WAIT QUEUES ARE NOT CLEARED IN RESPONSE TO THE STREAMOFF COMMAND
* THE USERSPACE PROGRAM, E.G. mplayer, MAY HANG ON EXIT. BEWARE.
*/
/*---------------------------------------------------------------------------*/
JOT(8, "calling wake_up on wq_video and wq_audio\n");
wake_up_interruptible(&(peasycap->wq_video));
wake_up_interruptible(&(peasycap->wq_audio));
/*---------------------------------------------------------------------------*/
break;
}
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
case VIDIOC_G_PARM: {
static struct v4l2_streamparm v4l2_streamparm;
JOT(8, "VIDIOC_G_PARM\n");
if (0 != copy_from_user(&v4l2_streamparm, (void __user *)arg, \
sizeof(struct v4l2_streamparm))) {
POUT;
return -EFAULT;
}
if (v4l2_streamparm.type != V4L2_BUF_TYPE_VIDEO_CAPTURE) {
POUT;
return -EINVAL;
}
v4l2_streamparm.parm.capture.capability = 0;
v4l2_streamparm.parm.capture.capturemode = 0;
v4l2_streamparm.parm.capture.timeperframe.numerator = 1;
v4l2_streamparm.parm.capture.timeperframe.denominator = 30;
v4l2_streamparm.parm.capture.readbuffers = peasycap->frame_buffer_many;
v4l2_streamparm.parm.capture.extendedmode = 0;
if (0 != copy_to_user((void __user *)arg, &v4l2_streamparm, \
sizeof(struct v4l2_streamparm))) {
POUT;
return -EFAULT;
}
break;
}
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
case VIDIOC_S_PARM: {
JOT(8, "VIDIOC_S_PARM unsupported\n");
return -EINVAL;
}
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
case VIDIOC_G_AUDIO: {
JOT(8, "VIDIOC_G_AUDIO unsupported\n");
return -EINVAL;
}
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
case VIDIOC_S_AUDIO: {
JOT(8, "VIDIOC_S_AUDIO unsupported\n");
return -EINVAL;
}
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
case VIDIOC_S_TUNER: {
JOT(8, "VIDIOC_S_TUNER unsupported\n");
return -EINVAL;
}
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
case VIDIOC_G_FBUF:
case VIDIOC_S_FBUF:
case VIDIOC_OVERLAY: {
JOT(8, "VIDIOC_G_FBUF|VIDIOC_S_FBUF|VIDIOC_OVERLAY unsupported\n");
return -EINVAL;
}
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
case VIDIOC_G_TUNER: {
JOT(8, "VIDIOC_G_TUNER unsupported\n");
return -EINVAL;
}
case VIDIOC_G_FREQUENCY:
case VIDIOC_S_FREQUENCY: {
JOT(8, "VIDIOC_G_FREQUENCY|VIDIOC_S_FREQUENCY unsupported\n");
return -EINVAL;
}
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
default: {
JOT(8, "ERROR: unrecognized V4L2 IOCTL command: 0x%08X\n", cmd);
explain_ioctl(cmd);
POUT;
return -ENOIOCTLCMD;
}
}
return 0;
}
/****************************************************************************/
/*vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv*/
#if defined(EASYCAP_IS_VIDEODEV_CLIENT)
long
easysnd_ioctl_noinode(struct file *file, unsigned int cmd, unsigned long arg)
{
return easysnd_ioctl((struct inode *)NULL, file, cmd, arg);
}
#endif /*EASYCAP_IS_VIDEODEV_CLIENT*/
/*^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^*/
/*--------------------------------------------------------------------------*/
int easysnd_ioctl(struct inode *inode, struct file *file, \
unsigned int cmd, unsigned long arg)
{
struct easycap *peasycap;
struct usb_device *p;
peasycap = (struct easycap *)file->private_data;
if (NULL == peasycap) {
SAY("ERROR: peasycap is NULL.\n");
return -1;
}
p = peasycap->pusb_device;
/*---------------------------------------------------------------------------*/
switch (cmd) {
case SNDCTL_DSP_GETCAPS: {
int caps;
JOT(8, "SNDCTL_DSP_GETCAPS\n");
if (true == peasycap->microphone)
caps = 0x02400000;
else
caps = 0x04400000;
if (0 != copy_to_user((void __user *)arg, &caps, sizeof(int)))
return -EFAULT;
break;
}
case SNDCTL_DSP_GETFMTS: {
int incoming;
JOT(8, "SNDCTL_DSP_GETFMTS\n");
if (true == peasycap->microphone)
incoming = AFMT_S16_LE;
else
incoming = AFMT_S16_LE;
if (0 != copy_to_user((void __user *)arg, &incoming, sizeof(int)))
return -EFAULT;
break;
}
case SNDCTL_DSP_SETFMT: {
int incoming, outgoing;
JOT(8, "SNDCTL_DSP_SETFMT\n");
if (0 != copy_from_user(&incoming, (void __user *)arg, sizeof(int)))
return -EFAULT;
JOT(8, "........... %i=incoming\n", incoming);
if (true == peasycap->microphone)
outgoing = AFMT_S16_LE;
else
outgoing = AFMT_S16_LE;
if (incoming != outgoing) {
JOT(8, "........... %i=outgoing\n", outgoing);
JOT(8, " cf. %i=AFMT_S16_LE\n", AFMT_S16_LE);
JOT(8, " cf. %i=AFMT_U8\n", AFMT_U8);
if (0 != copy_to_user((void __user *)arg, &outgoing, \
sizeof(int)))
return -EFAULT;
return -EINVAL ;
}
break;
}
case SNDCTL_DSP_STEREO: {
int incoming;
JOT(8, "SNDCTL_DSP_STEREO\n");
if (0 != copy_from_user(&incoming, (void __user *)arg, sizeof(int)))
return -EFAULT;
JOT(8, "........... %i=incoming\n", incoming);
if (true == peasycap->microphone)
incoming = 0;
else
incoming = 1;
if (0 != copy_to_user((void __user *)arg, &incoming, sizeof(int)))
return -EFAULT;
break;
}
case SNDCTL_DSP_SPEED: {
int incoming;
JOT(8, "SNDCTL_DSP_SPEED\n");
if (0 != copy_from_user(&incoming, (void __user *)arg, sizeof(int)))
return -EFAULT;
JOT(8, "........... %i=incoming\n", incoming);
if (true == peasycap->microphone)
incoming = 8000;
else
incoming = 48000;
if (0 != copy_to_user((void __user *)arg, &incoming, sizeof(int)))
return -EFAULT;
break;
}
case SNDCTL_DSP_GETTRIGGER: {
int incoming;
JOT(8, "SNDCTL_DSP_GETTRIGGER\n");
if (0 != copy_from_user(&incoming, (void __user *)arg, sizeof(int)))
return -EFAULT;
JOT(8, "........... %i=incoming\n", incoming);
incoming = PCM_ENABLE_INPUT;
if (0 != copy_to_user((void __user *)arg, &incoming, sizeof(int)))
return -EFAULT;
break;
}
case SNDCTL_DSP_SETTRIGGER: {
int incoming;
JOT(8, "SNDCTL_DSP_SETTRIGGER\n");
if (0 != copy_from_user(&incoming, (void __user *)arg, sizeof(int)))
return -EFAULT;
JOT(8, "........... %i=incoming\n", incoming);
JOT(8, "........... cf 0x%x=PCM_ENABLE_INPUT " \
"0x%x=PCM_ENABLE_OUTPUT\n", \
PCM_ENABLE_INPUT, PCM_ENABLE_OUTPUT);
;
;
;
;
break;
}
case SNDCTL_DSP_GETBLKSIZE: {
int incoming;
JOT(8, "SNDCTL_DSP_GETBLKSIZE\n");
if (0 != copy_from_user(&incoming, (void __user *)arg, sizeof(int)))
return -EFAULT;
JOT(8, "........... %i=incoming\n", incoming);
incoming = audio_bytes_per_fragment;
if (0 != copy_to_user((void __user *)arg, &incoming, sizeof(int)))
return -EFAULT;
break;
}
case SNDCTL_DSP_GETISPACE: {
struct audio_buf_info audio_buf_info;
JOT(8, "SNDCTL_DSP_GETISPACE\n");
audio_buf_info.bytes = audio_bytes_per_fragment;
audio_buf_info.fragments = 1;
audio_buf_info.fragsize = 0;
audio_buf_info.fragstotal = 0;
if (0 != copy_to_user((void __user *)arg, &audio_buf_info, \
sizeof(int)))
return -EFAULT;
break;
}
default: {
JOT(8, "ERROR: unrecognized DSP IOCTL command: 0x%08X\n", cmd);
POUT;
return -ENOIOCTLCMD;
}
}
return 0;
}
/*****************************************************************************/
int explain_ioctl(__u32 wot)
{
int k;
/*---------------------------------------------------------------------------*/
/*
* THE DATA FOR THE ARRAY mess BELOW WERE CONSTRUCTED BY RUNNING THE FOLLOWING
* SHELL SCRIPT:
* #
* cat /usr/src/linux-headers-`uname -r`/include/linux/videodev2.h | \
* grep "^#define VIDIOC_" - | grep -v "_OLD" - | \
* sed -e "s,_IO.*$,,;p" | sed -e "N;s,\n,, " | \
* sed -e "s/^#define / {/;s/#define /, \"/;s/$/\"},/" | \
* sed -e "s, ,,g;s, ,,g" >ioctl.tmp
* echo "{0xFFFFFFFF,\"\"}" >>ioctl.tmp
* exit 0
* #
* AND REINSTATING THE EXCISED "_OLD" CASES WERE LATER MANUALLY.
*
* THE DATA FOR THE ARRAY mess1 BELOW WERE CONSTRUCTED BY RUNNING THE FOLLOWING
* SHELL SCRIPT:
* cat /usr/src/linux-headers-`uname -r`/include/linux/videodev.h | \
* grep "^#define VIDIOC" - | grep -v "_OLD" - | \
* sed -e "s,_IO.*$,,;p" | sed -e "N;s,\n,, " | \
* sed -e "s/^#define / {/;s/#define /, \"/;s/$/\"},/" | \
* sed -e "s, ,,g;s, ,,g" >ioctl.tmp
* echo "{0xFFFFFFFF,\"\"}" >>ioctl.tmp
* exit 0
* #
*/
/*---------------------------------------------------------------------------*/
static struct mess {
__u32 command;
char name[64];
} mess[] = {
#if defined(VIDIOC_QUERYCAP)
{VIDIOC_QUERYCAP, "VIDIOC_QUERYCAP"},
#endif
#if defined(VIDIOC_RESERVED)
{VIDIOC_RESERVED, "VIDIOC_RESERVED"},
#endif
#if defined(VIDIOC_ENUM_FMT)
{VIDIOC_ENUM_FMT, "VIDIOC_ENUM_FMT"},
#endif
#if defined(VIDIOC_G_FMT)
{VIDIOC_G_FMT, "VIDIOC_G_FMT"},
#endif
#if defined(VIDIOC_S_FMT)
{VIDIOC_S_FMT, "VIDIOC_S_FMT"},
#endif
#if defined(VIDIOC_REQBUFS)
{VIDIOC_REQBUFS, "VIDIOC_REQBUFS"},
#endif
#if defined(VIDIOC_QUERYBUF)
{VIDIOC_QUERYBUF, "VIDIOC_QUERYBUF"},
#endif
#if defined(VIDIOC_G_FBUF)
{VIDIOC_G_FBUF, "VIDIOC_G_FBUF"},
#endif
#if defined(VIDIOC_S_FBUF)
{VIDIOC_S_FBUF, "VIDIOC_S_FBUF"},
#endif
#if defined(VIDIOC_OVERLAY)
{VIDIOC_OVERLAY, "VIDIOC_OVERLAY"},
#endif
#if defined(VIDIOC_QBUF)
{VIDIOC_QBUF, "VIDIOC_QBUF"},
#endif
#if defined(VIDIOC_DQBUF)
{VIDIOC_DQBUF, "VIDIOC_DQBUF"},
#endif
#if defined(VIDIOC_STREAMON)
{VIDIOC_STREAMON, "VIDIOC_STREAMON"},
#endif
#if defined(VIDIOC_STREAMOFF)
{VIDIOC_STREAMOFF, "VIDIOC_STREAMOFF"},
#endif
#if defined(VIDIOC_G_PARM)
{VIDIOC_G_PARM, "VIDIOC_G_PARM"},
#endif
#if defined(VIDIOC_S_PARM)
{VIDIOC_S_PARM, "VIDIOC_S_PARM"},
#endif
#if defined(VIDIOC_G_STD)
{VIDIOC_G_STD, "VIDIOC_G_STD"},
#endif
#if defined(VIDIOC_S_STD)
{VIDIOC_S_STD, "VIDIOC_S_STD"},
#endif
#if defined(VIDIOC_ENUMSTD)
{VIDIOC_ENUMSTD, "VIDIOC_ENUMSTD"},
#endif
#if defined(VIDIOC_ENUMINPUT)
{VIDIOC_ENUMINPUT, "VIDIOC_ENUMINPUT"},
#endif
#if defined(VIDIOC_G_CTRL)
{VIDIOC_G_CTRL, "VIDIOC_G_CTRL"},
#endif
#if defined(VIDIOC_S_CTRL)
{VIDIOC_S_CTRL, "VIDIOC_S_CTRL"},
#endif
#if defined(VIDIOC_G_TUNER)
{VIDIOC_G_TUNER, "VIDIOC_G_TUNER"},
#endif
#if defined(VIDIOC_S_TUNER)
{VIDIOC_S_TUNER, "VIDIOC_S_TUNER"},
#endif
#if defined(VIDIOC_G_AUDIO)
{VIDIOC_G_AUDIO, "VIDIOC_G_AUDIO"},
#endif
#if defined(VIDIOC_S_AUDIO)
{VIDIOC_S_AUDIO, "VIDIOC_S_AUDIO"},
#endif
#if defined(VIDIOC_QUERYCTRL)
{VIDIOC_QUERYCTRL, "VIDIOC_QUERYCTRL"},
#endif
#if defined(VIDIOC_QUERYMENU)
{VIDIOC_QUERYMENU, "VIDIOC_QUERYMENU"},
#endif
#if defined(VIDIOC_G_INPUT)
{VIDIOC_G_INPUT, "VIDIOC_G_INPUT"},
#endif
#if defined(VIDIOC_S_INPUT)
{VIDIOC_S_INPUT, "VIDIOC_S_INPUT"},
#endif
#if defined(VIDIOC_G_OUTPUT)
{VIDIOC_G_OUTPUT, "VIDIOC_G_OUTPUT"},
#endif
#if defined(VIDIOC_S_OUTPUT)
{VIDIOC_S_OUTPUT, "VIDIOC_S_OUTPUT"},
#endif
#if defined(VIDIOC_ENUMOUTPUT)
{VIDIOC_ENUMOUTPUT, "VIDIOC_ENUMOUTPUT"},
#endif
#if defined(VIDIOC_G_AUDOUT)
{VIDIOC_G_AUDOUT, "VIDIOC_G_AUDOUT"},
#endif
#if defined(VIDIOC_S_AUDOUT)
{VIDIOC_S_AUDOUT, "VIDIOC_S_AUDOUT"},
#endif
#if defined(VIDIOC_G_MODULATOR)
{VIDIOC_G_MODULATOR, "VIDIOC_G_MODULATOR"},
#endif
#if defined(VIDIOC_S_MODULATOR)
{VIDIOC_S_MODULATOR, "VIDIOC_S_MODULATOR"},
#endif
#if defined(VIDIOC_G_FREQUENCY)
{VIDIOC_G_FREQUENCY, "VIDIOC_G_FREQUENCY"},
#endif
#if defined(VIDIOC_S_FREQUENCY)
{VIDIOC_S_FREQUENCY, "VIDIOC_S_FREQUENCY"},
#endif
#if defined(VIDIOC_CROPCAP)
{VIDIOC_CROPCAP, "VIDIOC_CROPCAP"},
#endif
#if defined(VIDIOC_G_CROP)
{VIDIOC_G_CROP, "VIDIOC_G_CROP"},
#endif
#if defined(VIDIOC_S_CROP)
{VIDIOC_S_CROP, "VIDIOC_S_CROP"},
#endif
#if defined(VIDIOC_G_JPEGCOMP)
{VIDIOC_G_JPEGCOMP, "VIDIOC_G_JPEGCOMP"},
#endif
#if defined(VIDIOC_S_JPEGCOMP)
{VIDIOC_S_JPEGCOMP, "VIDIOC_S_JPEGCOMP"},
#endif
#if defined(VIDIOC_QUERYSTD)
{VIDIOC_QUERYSTD, "VIDIOC_QUERYSTD"},
#endif
#if defined(VIDIOC_TRY_FMT)
{VIDIOC_TRY_FMT, "VIDIOC_TRY_FMT"},
#endif
#if defined(VIDIOC_ENUMAUDIO)
{VIDIOC_ENUMAUDIO, "VIDIOC_ENUMAUDIO"},
#endif
#if defined(VIDIOC_ENUMAUDOUT)
{VIDIOC_ENUMAUDOUT, "VIDIOC_ENUMAUDOUT"},
#endif
#if defined(VIDIOC_G_PRIORITY)
{VIDIOC_G_PRIORITY, "VIDIOC_G_PRIORITY"},
#endif
#if defined(VIDIOC_S_PRIORITY)
{VIDIOC_S_PRIORITY, "VIDIOC_S_PRIORITY"},
#endif
#if defined(VIDIOC_G_SLICED_VBI_CAP)
{VIDIOC_G_SLICED_VBI_CAP, "VIDIOC_G_SLICED_VBI_CAP"},
#endif
#if defined(VIDIOC_LOG_STATUS)
{VIDIOC_LOG_STATUS, "VIDIOC_LOG_STATUS"},
#endif
#if defined(VIDIOC_G_EXT_CTRLS)
{VIDIOC_G_EXT_CTRLS, "VIDIOC_G_EXT_CTRLS"},
#endif
#if defined(VIDIOC_S_EXT_CTRLS)
{VIDIOC_S_EXT_CTRLS, "VIDIOC_S_EXT_CTRLS"},
#endif
#if defined(VIDIOC_TRY_EXT_CTRLS)
{VIDIOC_TRY_EXT_CTRLS, "VIDIOC_TRY_EXT_CTRLS"},
#endif
#if defined(VIDIOC_ENUM_FRAMESIZES)
{VIDIOC_ENUM_FRAMESIZES, "VIDIOC_ENUM_FRAMESIZES"},
#endif
#if defined(VIDIOC_ENUM_FRAMEINTERVALS)
{VIDIOC_ENUM_FRAMEINTERVALS, "VIDIOC_ENUM_FRAMEINTERVALS"},
#endif
#if defined(VIDIOC_G_ENC_INDEX)
{VIDIOC_G_ENC_INDEX, "VIDIOC_G_ENC_INDEX"},
#endif
#if defined(VIDIOC_ENCODER_CMD)
{VIDIOC_ENCODER_CMD, "VIDIOC_ENCODER_CMD"},
#endif
#if defined(VIDIOC_TRY_ENCODER_CMD)
{VIDIOC_TRY_ENCODER_CMD, "VIDIOC_TRY_ENCODER_CMD"},
#endif
#if defined(VIDIOC_G_CHIP_IDENT)
{VIDIOC_G_CHIP_IDENT, "VIDIOC_G_CHIP_IDENT"},
#endif
#if defined(VIDIOC_OVERLAY_OLD)
{VIDIOC_OVERLAY_OLD, "VIDIOC_OVERLAY_OLD"},
#endif
#if defined(VIDIOC_S_PARM_OLD)
{VIDIOC_S_PARM_OLD, "VIDIOC_S_PARM_OLD"},
#endif
#if defined(VIDIOC_S_CTRL_OLD)
{VIDIOC_S_CTRL_OLD, "VIDIOC_S_CTRL_OLD"},
#endif
#if defined(VIDIOC_G_AUDIO_OLD)
{VIDIOC_G_AUDIO_OLD, "VIDIOC_G_AUDIO_OLD"},
#endif
#if defined(VIDIOC_G_AUDOUT_OLD)
{VIDIOC_G_AUDOUT_OLD, "VIDIOC_G_AUDOUT_OLD"},
#endif
#if defined(VIDIOC_CROPCAP_OLD)
{VIDIOC_CROPCAP_OLD, "VIDIOC_CROPCAP_OLD"},
#endif
{0xFFFFFFFF, ""}
};
static struct mess mess1[] = \
{
#if defined(VIDIOCGCAP)
{VIDIOCGCAP, "VIDIOCGCAP"},
#endif
#if defined(VIDIOCGCHAN)
{VIDIOCGCHAN, "VIDIOCGCHAN"},
#endif
#if defined(VIDIOCSCHAN)
{VIDIOCSCHAN, "VIDIOCSCHAN"},
#endif
#if defined(VIDIOCGTUNER)
{VIDIOCGTUNER, "VIDIOCGTUNER"},
#endif
#if defined(VIDIOCSTUNER)
{VIDIOCSTUNER, "VIDIOCSTUNER"},
#endif
#if defined(VIDIOCGPICT)
{VIDIOCGPICT, "VIDIOCGPICT"},
#endif
#if defined(VIDIOCSPICT)
{VIDIOCSPICT, "VIDIOCSPICT"},
#endif
#if defined(VIDIOCCAPTURE)
{VIDIOCCAPTURE, "VIDIOCCAPTURE"},
#endif
#if defined(VIDIOCGWIN)
{VIDIOCGWIN, "VIDIOCGWIN"},
#endif
#if defined(VIDIOCSWIN)
{VIDIOCSWIN, "VIDIOCSWIN"},
#endif
#if defined(VIDIOCGFBUF)
{VIDIOCGFBUF, "VIDIOCGFBUF"},
#endif
#if defined(VIDIOCSFBUF)
{VIDIOCSFBUF, "VIDIOCSFBUF"},
#endif
#if defined(VIDIOCKEY)
{VIDIOCKEY, "VIDIOCKEY"},
#endif
#if defined(VIDIOCGFREQ)
{VIDIOCGFREQ, "VIDIOCGFREQ"},
#endif
#if defined(VIDIOCSFREQ)
{VIDIOCSFREQ, "VIDIOCSFREQ"},
#endif
#if defined(VIDIOCGAUDIO)
{VIDIOCGAUDIO, "VIDIOCGAUDIO"},
#endif
#if defined(VIDIOCSAUDIO)
{VIDIOCSAUDIO, "VIDIOCSAUDIO"},
#endif
#if defined(VIDIOCSYNC)
{VIDIOCSYNC, "VIDIOCSYNC"},
#endif
#if defined(VIDIOCMCAPTURE)
{VIDIOCMCAPTURE, "VIDIOCMCAPTURE"},
#endif
#if defined(VIDIOCGMBUF)
{VIDIOCGMBUF, "VIDIOCGMBUF"},
#endif
#if defined(VIDIOCGUNIT)
{VIDIOCGUNIT, "VIDIOCGUNIT"},
#endif
#if defined(VIDIOCGCAPTURE)
{VIDIOCGCAPTURE, "VIDIOCGCAPTURE"},
#endif
#if defined(VIDIOCSCAPTURE)
{VIDIOCSCAPTURE, "VIDIOCSCAPTURE"},
#endif
#if defined(VIDIOCSPLAYMODE)
{VIDIOCSPLAYMODE, "VIDIOCSPLAYMODE"},
#endif
#if defined(VIDIOCSWRITEMODE)
{VIDIOCSWRITEMODE, "VIDIOCSWRITEMODE"},
#endif
#if defined(VIDIOCGPLAYINFO)
{VIDIOCGPLAYINFO, "VIDIOCGPLAYINFO"},
#endif
#if defined(VIDIOCSMICROCODE)
{VIDIOCSMICROCODE, "VIDIOCSMICROCODE"},
#endif
{0xFFFFFFFF, ""}
};
k = 0;
while (mess[k].name[0]) {
if (wot == mess[k].command) {
JOT(8, "ioctl 0x%08X is %s\n", \
mess[k].command, &mess[k].name[0]);
return 0;
}
k++;
}
JOT(8, "ioctl 0x%08X is not in videodev2.h\n", wot);
k = 0;
while (mess1[k].name[0]) {
if (wot == mess1[k].command) {
JOT(8, "ioctl 0x%08X is %s (V4L1)\n", \
mess1[k].command, &mess1[k].name[0]);
return 0;
}
k++;
}
JOT(8, "ioctl 0x%08X is not in videodev.h\n", wot);
return -1;
}
/*****************************************************************************/
int explain_cid(__u32 wot)
{
int k;
/*---------------------------------------------------------------------------*/
/*
* THE DATA FOR THE ARRAY mess BELOW WERE CONSTRUCTED BY RUNNING THE FOLLOWING
* SHELL SCRIPT:
* #
* cat /usr/src/linux-headers-`uname -r`/include/linux/videodev2.h | \
* grep "^#define V4L2_CID_" | \
* sed -e "s,(.*$,,;p" | sed -e "N;s,\n,, " | \
* sed -e "s/^#define / {/;s/#define /, \"/;s/$/\"},/" | \
* sed -e "s, ,,g;s, ,,g" | grep -v "_BASE" | grep -v "MPEG" >cid.tmp
* echo "{0xFFFFFFFF,\"\"}" >>cid.tmp
* exit 0
* #
*/
/*---------------------------------------------------------------------------*/
static struct mess
{
__u32 command;
char name[64];
} mess[] = {
#if defined(V4L2_CID_USER_CLASS)
{V4L2_CID_USER_CLASS, "V4L2_CID_USER_CLASS"},
#endif
#if defined(V4L2_CID_BRIGHTNESS)
{V4L2_CID_BRIGHTNESS, "V4L2_CID_BRIGHTNESS"},
#endif
#if defined(V4L2_CID_CONTRAST)
{V4L2_CID_CONTRAST, "V4L2_CID_CONTRAST"},
#endif
#if defined(V4L2_CID_SATURATION)
{V4L2_CID_SATURATION, "V4L2_CID_SATURATION"},
#endif
#if defined(V4L2_CID_HUE)
{V4L2_CID_HUE, "V4L2_CID_HUE"},
#endif
#if defined(V4L2_CID_AUDIO_VOLUME)
{V4L2_CID_AUDIO_VOLUME, "V4L2_CID_AUDIO_VOLUME"},
#endif
#if defined(V4L2_CID_AUDIO_BALANCE)
{V4L2_CID_AUDIO_BALANCE, "V4L2_CID_AUDIO_BALANCE"},
#endif
#if defined(V4L2_CID_AUDIO_BASS)
{V4L2_CID_AUDIO_BASS, "V4L2_CID_AUDIO_BASS"},
#endif
#if defined(V4L2_CID_AUDIO_TREBLE)
{V4L2_CID_AUDIO_TREBLE, "V4L2_CID_AUDIO_TREBLE"},
#endif
#if defined(V4L2_CID_AUDIO_MUTE)
{V4L2_CID_AUDIO_MUTE, "V4L2_CID_AUDIO_MUTE"},
#endif
#if defined(V4L2_CID_AUDIO_LOUDNESS)
{V4L2_CID_AUDIO_LOUDNESS, "V4L2_CID_AUDIO_LOUDNESS"},
#endif
#if defined(V4L2_CID_BLACK_LEVEL)
{V4L2_CID_BLACK_LEVEL, "V4L2_CID_BLACK_LEVEL"},
#endif
#if defined(V4L2_CID_AUTO_WHITE_BALANCE)
{V4L2_CID_AUTO_WHITE_BALANCE, "V4L2_CID_AUTO_WHITE_BALANCE"},
#endif
#if defined(V4L2_CID_DO_WHITE_BALANCE)
{V4L2_CID_DO_WHITE_BALANCE, "V4L2_CID_DO_WHITE_BALANCE"},
#endif
#if defined(V4L2_CID_RED_BALANCE)
{V4L2_CID_RED_BALANCE, "V4L2_CID_RED_BALANCE"},
#endif
#if defined(V4L2_CID_BLUE_BALANCE)
{V4L2_CID_BLUE_BALANCE, "V4L2_CID_BLUE_BALANCE"},
#endif
#if defined(V4L2_CID_GAMMA)
{V4L2_CID_GAMMA, "V4L2_CID_GAMMA"},
#endif
#if defined(V4L2_CID_WHITENESS)
{V4L2_CID_WHITENESS, "V4L2_CID_WHITENESS"},
#endif
#if defined(V4L2_CID_EXPOSURE)
{V4L2_CID_EXPOSURE, "V4L2_CID_EXPOSURE"},
#endif
#if defined(V4L2_CID_AUTOGAIN)
{V4L2_CID_AUTOGAIN, "V4L2_CID_AUTOGAIN"},
#endif
#if defined(V4L2_CID_GAIN)
{V4L2_CID_GAIN, "V4L2_CID_GAIN"},
#endif
#if defined(V4L2_CID_HFLIP)
{V4L2_CID_HFLIP, "V4L2_CID_HFLIP"},
#endif
#if defined(V4L2_CID_VFLIP)
{V4L2_CID_VFLIP, "V4L2_CID_VFLIP"},
#endif
#if defined(V4L2_CID_HCENTER)
{V4L2_CID_HCENTER, "V4L2_CID_HCENTER"},
#endif
#if defined(V4L2_CID_VCENTER)
{V4L2_CID_VCENTER, "V4L2_CID_VCENTER"},
#endif
#if defined(V4L2_CID_POWER_LINE_FREQUENCY)
{V4L2_CID_POWER_LINE_FREQUENCY, "V4L2_CID_POWER_LINE_FREQUENCY"},
#endif
#if defined(V4L2_CID_HUE_AUTO)
{V4L2_CID_HUE_AUTO, "V4L2_CID_HUE_AUTO"},
#endif
#if defined(V4L2_CID_WHITE_BALANCE_TEMPERATURE)
{V4L2_CID_WHITE_BALANCE_TEMPERATURE, "V4L2_CID_WHITE_BALANCE_TEMPERATURE"},
#endif
#if defined(V4L2_CID_SHARPNESS)
{V4L2_CID_SHARPNESS, "V4L2_CID_SHARPNESS"},
#endif
#if defined(V4L2_CID_BACKLIGHT_COMPENSATION)
{V4L2_CID_BACKLIGHT_COMPENSATION, "V4L2_CID_BACKLIGHT_COMPENSATION"},
#endif
#if defined(V4L2_CID_CHROMA_AGC)
{V4L2_CID_CHROMA_AGC, "V4L2_CID_CHROMA_AGC"},
#endif
#if defined(V4L2_CID_COLOR_KILLER)
{V4L2_CID_COLOR_KILLER, "V4L2_CID_COLOR_KILLER"},
#endif
#if defined(V4L2_CID_LASTP1)
{V4L2_CID_LASTP1, "V4L2_CID_LASTP1"},
#endif
#if defined(V4L2_CID_CAMERA_CLASS)
{V4L2_CID_CAMERA_CLASS, "V4L2_CID_CAMERA_CLASS"},
#endif
#if defined(V4L2_CID_EXPOSURE_AUTO)
{V4L2_CID_EXPOSURE_AUTO, "V4L2_CID_EXPOSURE_AUTO"},
#endif
#if defined(V4L2_CID_EXPOSURE_ABSOLUTE)
{V4L2_CID_EXPOSURE_ABSOLUTE, "V4L2_CID_EXPOSURE_ABSOLUTE"},
#endif
#if defined(V4L2_CID_EXPOSURE_AUTO_PRIORITY)
{V4L2_CID_EXPOSURE_AUTO_PRIORITY, "V4L2_CID_EXPOSURE_AUTO_PRIORITY"},
#endif
#if defined(V4L2_CID_PAN_RELATIVE)
{V4L2_CID_PAN_RELATIVE, "V4L2_CID_PAN_RELATIVE"},
#endif
#if defined(V4L2_CID_TILT_RELATIVE)
{V4L2_CID_TILT_RELATIVE, "V4L2_CID_TILT_RELATIVE"},
#endif
#if defined(V4L2_CID_PAN_RESET)
{V4L2_CID_PAN_RESET, "V4L2_CID_PAN_RESET"},
#endif
#if defined(V4L2_CID_TILT_RESET)
{V4L2_CID_TILT_RESET, "V4L2_CID_TILT_RESET"},
#endif
#if defined(V4L2_CID_PAN_ABSOLUTE)
{V4L2_CID_PAN_ABSOLUTE, "V4L2_CID_PAN_ABSOLUTE"},
#endif
#if defined(V4L2_CID_TILT_ABSOLUTE)
{V4L2_CID_TILT_ABSOLUTE, "V4L2_CID_TILT_ABSOLUTE"},
#endif
#if defined(V4L2_CID_FOCUS_ABSOLUTE)
{V4L2_CID_FOCUS_ABSOLUTE, "V4L2_CID_FOCUS_ABSOLUTE"},
#endif
#if defined(V4L2_CID_FOCUS_RELATIVE)
{V4L2_CID_FOCUS_RELATIVE, "V4L2_CID_FOCUS_RELATIVE"},
#endif
#if defined(V4L2_CID_FOCUS_AUTO)
{V4L2_CID_FOCUS_AUTO, "V4L2_CID_FOCUS_AUTO"},
#endif
{0xFFFFFFFF, ""}
};
k = 0;
while (mess[k].name[0]) {
if (wot == mess[k].command) {
JOT(8, "ioctl 0x%08X is %s\n", \
mess[k].command, &mess[k].name[0]);
return 0;
}
k++;
}
JOT(8, "cid 0x%08X is not in videodev2.h\n", wot);
return -1;
}
/*****************************************************************************/
/*****************************************************************************
* *
* easycap_ioctl.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
*
*/
/*****************************************************************************/
extern struct easycap_format easycap_format[];
extern struct v4l2_queryctrl easycap_control[];
extern unsigned int audio_bytes_per_fragment;
/*****************************************************************************
* *
* *
* 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_debug.h"
#include "easycap.h"
/*--------------------------------------------------------------------------*/
const struct stk1160config { int reg; int set; } stk1160config[256] = {
{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},
#if defined(PREFER_NTSC)
#undef OLDMARGIN
#if defined(OLDMARGIN)
{0x110, 0x0008},
#else
{0x110, 0x0014},
#endif /*OLDMARGIN*/
{0x111, 0x0000},
{0x112, 0x0003},
{0x113, 0x0000},
#if defined(OLDMARGIN)
{0x114, 0x0508},
#else
{0x114, 0x0514},
#endif /*OLDMARGIN*/
{0x115, 0x0005},
{0x116, 0x00F3},
{0x117, 0x0000},
#else /* ! PREFER_NTSC*/
#if defined(OLDMARGIN)
{0x110, 0x0008},
#else
{0x110, 0x0014},
#endif /*OLDMARGIN*/
{0x111, 0x0000},
{0x112, 0x0020},
{0x113, 0x0000},
#if defined(OLDMARGIN)
{0x114, 0x0508},
#else
{0x114, 0x0514},
#endif /*OLDMARGIN*/
{0x115, 0x0005},
{0x116, 0x0110},
{0x117, 0x0001},
#endif /* ! PREFER_NTSC*/
{0x202, 0x000F},
{0x203, 0x004A},
{0x2FF, 0x0000},
/*---------------------------------------------------------------------------*/
{0xFFF, 0xFFFF}
};
/*--------------------------------------------------------------------------*/
const struct saa7113config { int reg; int set; } saa7113config[256] = {
{0x01, 0x08},
{0x02, 0x80},
{0x03, 0x33},
{0x04, 0x00},
{0x05, 0x00},
{0x06, 0xE9},
{0x07, 0x0D},
#if defined(PREFER_NTSC)
{0x08, 0x78},
#else
{0x08, 0x38},
#endif /* ! PREFER_NTSC*/
{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},
#if defined(PREFER_NTSC)
{0x40, 0x82},
#else
{0x40, 0x02},
#endif /* ! PREFER_NTSC*/
{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},
#if defined(PREFER_NTSC)
{0x5A, 0x0A},
#else
{0x5A, 0x07},
#endif /* ! PREFER_NTSC*/
{0x5B, 0x83},
{0xFF, 0xFF}
};
/*--------------------------------------------------------------------------*/
/****************************************************************************/
int
confirm_resolution(struct usb_device *p)
{
__u8 get0, get1, get2, get3, get4, get5, get6, get7;
GET(p, 0x0110, &get0);
GET(p, 0x0111, &get1);
GET(p, 0x0112, &get2);
GET(p, 0x0113, &get3);
GET(p, 0x0114, &get4);
GET(p, 0x0115, &get5);
GET(p, 0x0116, &get6);
GET(p, 0x0117, &get7);
JOT(8, "0x%03X, 0x%03X, " \
"0x%03X, 0x%03X, " \
"0x%03X, 0x%03X, " \
"0x%03X, 0x%03X\n", \
get0, get1, get2, get3, get4, get5, get6, get7);
JOT(8, "....cf PAL_720x526: " \
"0x%03X, 0x%03X, " \
"0x%03X, 0x%03X, " \
"0x%03X, 0x%03X, " \
"0x%03X, 0x%03X\n", \
0x000, 0x000, 0x001, 0x000, 0x5A0, 0x005, 0x121, 0x001);
JOT(8, "....cf PAL_704x526: " \
"0x%03X, 0x%03X, " \
"0x%03X, 0x%03X, " \
"0x%03X, 0x%03X, " \
"0x%03X, 0x%03X\n", \
0x004, 0x000, 0x001, 0x000, 0x584, 0x005, 0x121, 0x001);
JOT(8, "....cf VGA_640x480: " \
"0x%03X, 0x%03X, " \
"0x%03X, 0x%03X, " \
"0x%03X, 0x%03X, " \
"0x%03X, 0x%03X\n", \
0x008, 0x000, 0x020, 0x000, 0x508, 0x005, 0x110, 0x001);
return 0;
}
/****************************************************************************/
int
confirm_stream(struct usb_device *p)
{
__u16 get2;
__u8 igot;
GET(p, 0x0100, &igot); get2 = 0x80 & igot;
if (0x80 == get2)
JOT(8, "confirm_stream: OK\n");
else
JOT(8, "confirm_stream: STUCK\n");
return 0;
}
/****************************************************************************/
int
setup_stk(struct usb_device *p)
{
int i0;
i0 = 0;
while (0xFFF != stk1160config[i0].reg) {
SET(p, stk1160config[i0].reg, stk1160config[i0].set);
i0++;
}
write_300(p);
return 0;
}
/****************************************************************************/
int
setup_saa(struct usb_device *p)
{
int i0, ir;
set2to78(p);
i0 = 0;
while (0xFF != saa7113config[i0].reg) {
ir = write_saa(p, saa7113config[i0].reg, saa7113config[i0].set);
i0++;
}
return 0;
}
/****************************************************************************/
int
write_000(struct usb_device *p, __u16 set2, __u16 set0)
{
__u8 igot0, igot2;
GET(p, 0x0002, &igot2);
GET(p, 0x0000, &igot0);
SET(p, 0x0002, set2);
SET(p, 0x0000, set0);
return 0;
}
/****************************************************************************/
int
write_saa(struct usb_device *p, __u16 reg0, __u16 set0)
{
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
*/
/*--------------------------------------------------------------------------*/
int
write_vt(struct usb_device *p, __u16 reg0, __u16 set0)
{
__u8 igot;
__u16 got502, got503;
__u16 set502, set503;
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
*/
/*--------------------------------------------------------------------------*/
int
read_vt(struct usb_device *p, __u16 reg0)
{
__u8 igot;
__u16 got502, got503;
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.
*/
/*--------------------------------------------------------------------------*/
int
write_300(struct usb_device *p)
{
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;
}
/****************************************************************************/
/*--------------------------------------------------------------------------*/
/*
* NOTE: THE FOLLOWING IS NOT CHECKED:
* REGISTER 0x0F, WHICH IS INVOLVED IN CHROMINANCE AUTOMATIC GAIN CONTROL.
*/
/*--------------------------------------------------------------------------*/
int
check_saa(struct usb_device *p)
{
int i0, ir, rc;
i0 = 0;
rc = 0;
while (0xFF != saa7113config[i0].reg) {
if (0x0F == saa7113config[i0].reg) {
i0++; continue;
}
ir = read_saa(p, saa7113config[i0].reg);
if (ir != saa7113config[i0].set) {
SAY("SAA register 0x%02X has 0x%02X, expected 0x%02X\n", \
saa7113config[i0].reg, ir, saa7113config[i0].set);
rc--;
}
i0++;
}
if (-8 > rc)
return rc;
else
return 0;
}
/****************************************************************************/
int
merit_saa(struct usb_device *p)
{
int rc;
rc = read_saa(p, 0x1F);
if ((0 > rc) || (0x02 & rc))
return 1 ;
else
return 0;
}
/****************************************************************************/
int
ready_saa(struct usb_device *p)
{
int j, rc;
static int max = 10;
j = 0;
while (max > j) {
rc = read_saa(p, 0x1F);
if (0 <= rc) {
if ((1 == (0x01 & rc))&&(0 == (0x40 & rc)))
break;
}
msleep(100); j++;
}
if (max == j)
return -1;
else {
if (0x20 & rc)
JOT(8, "hardware detects 60 Hz\n");
else
JOT(8, "hardware detects 50 Hz\n");
if (0x80 & rc)
JOT(8, "hardware detects interlacing\n");
else
JOT(8, "hardware detects no interlacing\n");
}
return 0;
}
/****************************************************************************/
/*--------------------------------------------------------------------------*/
/*
* NOTE: THE FOLLOWING ARE NOT CHECKED:
* REGISTERS 0x000, 0x002: FUNCTIONALITY IS NOT KNOWN
* REGISTER 0x100: ACCEPT ALSO (0x80 | stk1160config[.].set)
*/
/*--------------------------------------------------------------------------*/
int
check_stk(struct usb_device *p)
{
int i0, ir;
i0 = 0;
while (0xFFF != stk1160config[i0].reg) {
if (0x000 == stk1160config[i0].reg) {
i0++; continue;
}
if (0x002 == stk1160config[i0].reg) {
i0++; continue;
}
ir = read_stk(p, stk1160config[i0].reg);
if (0x100 == stk1160config[i0].reg) {
if ((ir != (0xFF & stk1160config[i0].set)) && \
(ir != (0x80 | (0xFF & stk1160config[i0].set))) && \
(0xFFFF != stk1160config[i0].set)) {
SAY("STK register 0x%03X has 0x%02X, " \
"expected 0x%02X\n", \
stk1160config[i0].reg, ir, \
stk1160config[i0].set);
}
i0++; continue;
}
if ((ir != (0xFF & stk1160config[i0].set)) && \
(0xFFFF != stk1160config[i0].set)) {
SAY("STK register 0x%03X has 0x%02X, " \
"expected 0x%02X\n", \
stk1160config[i0].reg, ir, \
stk1160config[i0].set);
}
i0++;
}
return 0;
}
/****************************************************************************/
int
read_saa(struct usb_device *p, __u16 reg0)
{
__u8 igot;
SET(p, 0x208, reg0);
SET(p, 0x200, 0x20);
if (0 != wait_i2c(p))
return -1;
igot = 0;
GET(p, 0x0209, &igot);
return igot;
}
/****************************************************************************/
int
read_stk(struct usb_device *p, __u32 reg0)
{
__u8 igot;
igot = 0;
GET(p, reg0, &igot);
return igot;
}
/*****************************************************************************/
/*---------------------------------------------------------------------------*/
/*
* HARDWARE USERSPACE INPUT NUMBER PHYSICAL INPUT DRIVER input VALUE
*
* CVBS+S-VIDEO 0 or 1 CVBS 1
* FOUR-CVBS 0 or 1 CVBS1 1
* FOUR-CVBS 2 CVBS2 2
* FOUR-CVBS 3 CVBS3 3
* FOUR-CVBS 4 CVBS4 4
* CVBS+S-VIDEO 5 S-VIDEO 5
*
* WHEN 5==input THE ARGUMENT mode MUST ALSO BE SUPPLIED:
*
* mode 7 => GAIN TO BE SET EXPLICITLY USING REGISTER 0x05 (UNTESTED)
* mode 9 => USE AUTOMATIC GAIN CONTROL (DEFAULT)
*
*/
/*---------------------------------------------------------------------------*/
int
select_input(struct usb_device *p, int input, int mode)
{
stop_100(p);
msleep(20);
switch (input) {
case 0:
case 1: {
SET(p, 0x0000, 0x0098); break;
}
case 2: {
SET(p, 0x0000, 0x0090); break;
}
case 3: {
SET(p, 0x0000, 0x0088); break;
}
case 4: {
SET(p, 0x0000, 0x0080); 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);
}
break;
}
default:
{
SAY("ERROR: bad input: %i\n", input);
return -1;
}
}
msleep(20);
SET(p, 0x0002, 0x0093);
msleep(20);
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;
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 get0;
__u8 igot;
GET(p, 0x0100, &igot); get0 = igot;
msleep(0x1f4);
SET(p, 0x0100, (0x80 | get0));
msleep(0x1f4);
return 0;
}
/****************************************************************************/
int
stop_100(struct usb_device *p)
{
__u16 get0;
__u8 igot;
GET(p, 0x0100, &igot); get0 = igot;
msleep(0x1f4);
SET(p, 0x0100, (0x7F & get0));
msleep(0x1f4);
return 0;
}
/****************************************************************************/
/*--------------------------------------------------------------------------*/
/*
* FUNCTION wait_i2c() RETURNS 0 ON SUCCESS
*/
/*--------------------------------------------------------------------------*/
int
wait_i2c(struct usb_device *p)
{
__u16 get0;
__u8 igot;
const int max = 4;
int k;
for (k = 0; k < max; k++) {
GET(p, 0x0201, &igot); get0 = igot;
switch (get0) {
case 0x04:
case 0x01: {
return 0;
}
case 0x00: {
msleep(10);
continue;
}
default: {
return get0 - 1;
}
}
}
return -1;
}
/****************************************************************************/
int
regset(struct usb_device *pusb_device, __u16 index, __u16 value)
{
__u16 igot;
int rc0, rc1;
if (!pusb_device)
return -EFAULT;
rc1 = 0; igot = 0;
rc0 = usb_control_msg(pusb_device, usb_sndctrlpipe(pusb_device, 0), \
(__u8)0x01, \
(__u8)(USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE), \
(__u16)value, \
(__u16)index, \
(void *)NULL, \
(__u16)0, \
(int)500);
#if defined(NOREADBACK)
#
#else
rc1 = usb_control_msg(pusb_device, usb_rcvctrlpipe(pusb_device, 0), \
(__u8)0x00, \
(__u8)(USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE), \
(__u16)0x00, \
(__u16)index, \
(void *)&igot, \
(__u16)sizeof(__u16), \
(int)50000);
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 (0 != igot) {
JOT(8, "unexpected 0x%02X for STK register 0x%03X\n", \
igot, index);
}
break;
}
case 0x114:
case 0x116: {
if ((0xFF & value) != igot) {
JOT(8, "unexpected 0x%02X != 0x%02X " \
"for STK register 0x%03X\n", \
igot, value, index);
}
break;
}
case 0x200: {
if (0 == igot)
break;
}
default: {
if (value != igot) {
JOT(8, "unexpected 0x%02X != 0x%02X " \
"for STK register 0x%03X\n", \
igot, value, index);
}
break;
}
}
#endif /* ! NOREADBACK*/
return (0 > rc0) ? rc0 : rc1;
}
/*****************************************************************************/
int
regget(struct usb_device *pusb_device, __u16 index, void *pvoid)
{
int ir;
if (!pusb_device)
return -EFAULT;
ir = usb_control_msg(pusb_device, usb_rcvctrlpipe(pusb_device, 0), \
(__u8)0x00, \
(__u8)(USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE), \
(__u16)0x00, \
(__u16)index, \
(void *)pvoid, \
sizeof(__u8), \
(int)50000);
return 0xFF & ir;
}
/*****************************************************************************/
int
wakeup_device(struct usb_device *pusb_device)
{
return usb_control_msg(pusb_device, usb_sndctrlpipe(pusb_device, 0), \
(__u8)USB_REQ_SET_FEATURE, \
(__u8)(USB_DIR_OUT | USB_TYPE_STANDARD | USB_RECIP_DEVICE), \
USB_DEVICE_REMOTE_WAKEUP, \
(__u16)0, \
(void *) NULL, \
(__u16)0, \
(int)50000);
}
/*****************************************************************************/
/*---------------------------------------------------------------------------*/
/*
* 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.
*/
/*---------------------------------------------------------------------------*/
int
audio_setup(struct easycap *peasycap)
{
struct usb_device *pusb_device;
static __u8 request = 0x01;
static __u8 requesttype = \
(__u8)(USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE);
static __u16 value_unmute = 0x0200;
static __u16 index = 0x0301;
static unsigned char buffer[1];
static __u16 length = 1;
int rc;
if (NULL == peasycap)
return -EFAULT;
pusb_device = peasycap->pusb_device;
if (NULL == pusb_device)
return -EFAULT;
JOT(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), \
(__u8)request, \
(__u8)requesttype, \
(__u16)value_unmute, \
(__u16)index, \
(void *)&buffer[0], \
(__u16)length, \
(int)50000);
JOT(8, "0x%02X=buffer\n", *((__u8 *) &buffer[0]));
if (rc != (int)length)
SAY("ERROR: usb_control_msg returned %i\n", rc);
/*--------------------------------------------------------------------------*/
/*
* 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);
if (false == peasycap->microphone) {
/*-------------------------------------------------------------------*/
/*
* SELECT AUDIO SOURCE "LINE IN" AND SET DEFAULT GAIN TO 0dB.
*/
/*-------------------------------------------------------------------*/
write_vt(pusb_device, 0x0002, 0x8000);
write_vt(pusb_device, 0x001C, 0x8000);
write_vt(pusb_device, 0x000E, 0x0000);
write_vt(pusb_device, 0x0010, 0x0000);
write_vt(pusb_device, 0x0012, 0x8000);
write_vt(pusb_device, 0x0016, 0x0000);
write_vt(pusb_device, 0x001A, 0x0404);
write_vt(pusb_device, 0x0002, 0x0000);
write_vt(pusb_device, 0x001C, 0x0000);
} else {
/*-------------------------------------------------------------------*/
/*
* SELECT AUDIO SOURCE "MIC" AND SET DEFAULT GAIN TO 0 dB.
*
* REGISTER 0x000E CAN BE SET TO PROVIDE UP TO 34.5 dB ATTENTUATION,
* BUT THIS HAS NOT PROVED NECESSARY FOR THE FEW SIGNAL SOURCES
* TESTED HITHERTO.
*/
/*-------------------------------------------------------------------*/
write_vt(pusb_device, 0x0006, 0x8000);
write_vt(pusb_device, 0x001C, 0x8000);
write_vt(pusb_device, 0x000E, 0x0008);
write_vt(pusb_device, 0x0010, 0x0000);
write_vt(pusb_device, 0x0012, 0x8000);
write_vt(pusb_device, 0x0016, 0x0000);
write_vt(pusb_device, 0x001A, 0x0000);
write_vt(pusb_device, 0x0006, 0x0000);
write_vt(pusb_device, 0x001C, 0x0000);
}
check_vt(pusb_device);
return 0;
}
/*****************************************************************************/
int
check_vt(struct usb_device *pusb_device)
{
int igot;
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, 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, 0x001A);
if (0 > igot)
SAY("ERROR: failed to read VT1612A register 0x1A\n");
if (0x8000 & igot)
SAY("register 0x%02X muted\n", 0x1A);
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);
*
* IF 16<loud<31 VT1621A REGISTER 0x1C IS SET FOR POSITIVE GAIN.
* IF loud<=16 VT1621A REGISTER 0x1C IS SET FOR ZERO GAIN.
* THERE IS NEVER ANY (ADDITIONAL) ATTENUATION.
*/
/*---------------------------------------------------------------------------*/
int
audio_gainset(struct usb_device *pusb_device, __s8 loud)
{
int igot;
__u8 u8;
__u16 mute;
if (16 > loud)
loud = 16;
u8 = 0x000F & (__u8)(loud - 16);
write_vt(pusb_device, 0x0002, 0x8000);
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);
JOT(8, "0x%04X=(mute|u8|(u8<<8))\n", mute | u8 | (u8 << 8));
write_vt(pusb_device, 0x001C, 0x8000);
write_vt(pusb_device, 0x001C, (mute | u8 | (u8 << 8)));
write_vt(pusb_device, 0x0002, 0x0000);
return 0;
}
/*****************************************************************************/
int
audio_gainget(struct usb_device *pusb_device)
{
int igot;
igot = read_vt(pusb_device, 0x001C);
if (0 > igot)
SAY("ERROR: failed to read VT1612A register 0x1C\n");
return igot;
}
/*****************************************************************************/
int
set2to78(struct usb_device *p)
{
int ir;
msleep(20);
ir = regset(p, 0x0002, 0x0078);
if (0 > ir)
SAY("ERROR: failed to set register 0x0002 to 0x0078\n");
msleep(20);
return ir;
}
/*****************************************************************************/
int
set2to93(struct usb_device *p)
{
int ir;
msleep(20);
ir = regset(p, 0x0002, 0x0093);
if (0 > ir)
SAY("ERROR: failed to set register 0x0002 to 0x0078\n");
msleep(20);
return ir;
}
/*****************************************************************************/
This source diff could not be displayed because it is too large. You can view the blob instead.
/******************************************************************************
* *
* 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"
#include "easycap_debug.h"
/*---------------------------------------------------------------------------*/
/*
* THE LEAST SIGNIFICANT BIT OF easycap_standard.mask HAS MEANING:
* 0 => 25 fps
* 1 => 30 fps
*/
/*---------------------------------------------------------------------------*/
struct easycap_standard easycap_standard[] = {
{
.mask = 0x000F & 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 = 0x000F & 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 = 0x000F & 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 = 0x000F & 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 = 0x000F & SECAM ,
.v4l2_standard = {
.index = SECAM,
.id = V4L2_STD_SECAM,
.name = "SECAM",
.frameperiod = {1, 25},
.framelines = 625,
.reserved = {0, 0, 0, 0}
}
},
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
{
.mask = 0x000F & 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 = 0x000F & 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 = 0x000F & 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 = 0x000F & 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 = 0x000F & 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 = 0xFFFF
}
};
/*---------------------------------------------------------------------------*/
/*
* THE 16-BIT easycap_format.mask HAS MEANING:
* (least significant) BIT 0: 0 => PAL, 25 FPS; 1 => NTSC, 30 FPS
* BITS 1-3: RESERVED FOR DIFFERENTIATING STANDARDS
* BITS 4-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
* (most significant) BITS 13-15: RESERVED FOR OTHER FIELD ORDER OPTIONS
* IT FOLLOWS THAT:
* bytesperpixel IS ((0x00F0 & easycap_format.mask) >> 4)
* 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
fillin_formats(void)
{
int i, j, k, m, n;
__u32 width, height, pixelformat, bytesperline, sizeimage;
__u32 field, colorspace;
__u16 mask1, mask2, mask3, mask4;
char name1[32], name2[32], name3[32], name4[32];
for (i = 0, n = 0; i < STANDARD_MANY; i++) {
mask1 = 0x0000;
switch (i) {
case PAL_BGHIN: {
mask1 = PAL_BGHIN;
strcpy(&name1[0], "PAL_BGHIN");
colorspace = V4L2_COLORSPACE_470_SYSTEM_BG;
break;
}
case SECAM: {
mask1 = SECAM;
strcpy(&name1[0], "SECAM");
colorspace = V4L2_COLORSPACE_470_SYSTEM_BG;
break;
}
case PAL_Nc: {
mask1 = PAL_Nc;
strcpy(&name1[0], "PAL_Nc");
colorspace = V4L2_COLORSPACE_470_SYSTEM_BG;
break;
}
case PAL_60: {
mask1 = PAL_60;
strcpy(&name1[0], "PAL_60");
colorspace = V4L2_COLORSPACE_470_SYSTEM_BG;
break;
}
case PAL_M: {
mask1 = PAL_M;
strcpy(&name1[0], "PAL_M");
colorspace = V4L2_COLORSPACE_470_SYSTEM_BG;
break;
}
case NTSC_M: {
mask1 = NTSC_M;
strcpy(&name1[0], "NTSC_M");
colorspace = V4L2_COLORSPACE_470_SYSTEM_M;
break;
}
case NTSC_443: {
mask1 = NTSC_443;
strcpy(&name1[0], "NTSC_443");
colorspace = V4L2_COLORSPACE_470_SYSTEM_M;
break;
}
case NTSC_M_JP: {
mask1 = NTSC_M_JP;
strcpy(&name1[0], "NTSC_M_JP");
colorspace = V4L2_COLORSPACE_470_SYSTEM_M;
break;
}
case NTSC_N: {
mask1 = NTSC_M;
strcpy(&name1[0], "NTSC_N");
colorspace = V4L2_COLORSPACE_470_SYSTEM_M;
break;
}
case NTSC_N_443: {
mask1 = NTSC_N_443;
strcpy(&name1[0], "NTSC_N_443");
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;
strcpy(&name2[0], "_AT_720x576");
width = 720; height = 576; break;
}
case AT_704x576: {
if (0x1 & mask1)
continue;
strcpy(&name2[0], "_AT_704x576");
width = 704; height = 576; break;
}
case AT_640x480: {
strcpy(&name2[0], "_AT_640x480");
width = 640; height = 480; break;
}
case AT_720x480: {
if (!(0x1 & mask1))
continue;
strcpy(&name2[0], "_AT_720x480");
width = 720; height = 480; break;
}
case AT_360x288: {
if (0x1 & mask1)
continue;
strcpy(&name2[0], "_AT_360x288");
width = 360; height = 288; mask2 = 0x0800; break;
}
case AT_320x240: {
strcpy(&name2[0], "_AT_320x240");
width = 320; height = 240; mask2 = 0x0800; break;
}
case AT_360x240: {
if (!(0x1 & mask1))
continue;
strcpy(&name2[0], "_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: {
strcpy(&name3[0], "_" STRINGIZE(FMT_UYVY));
pixelformat = V4L2_PIX_FMT_UYVY;
mask3 |= (0x02 << 4);
break;
}
case FMT_YUY2: {
strcpy(&name3[0], "_" STRINGIZE(FMT_YUY2));
pixelformat = V4L2_PIX_FMT_YUYV;
mask3 |= (0x02 << 4);
mask3 |= 0x0100;
break;
}
case FMT_RGB24: {
strcpy(&name3[0], "_" STRINGIZE(FMT_RGB24));
pixelformat = V4L2_PIX_FMT_RGB24;
mask3 |= (0x03 << 4);
break;
}
case FMT_RGB32: {
strcpy(&name3[0], "_" STRINGIZE(FMT_RGB32));
pixelformat = V4L2_PIX_FMT_RGB32;
mask3 |= (0x04 << 4);
break;
}
case FMT_BGR24: {
strcpy(&name3[0], "_" STRINGIZE(FMT_BGR24));
pixelformat = V4L2_PIX_FMT_BGR24;
mask3 |= (0x03 << 4);
mask3 |= 0x0100;
break;
}
case FMT_BGR32: {
strcpy(&name3[0], "_" STRINGIZE(FMT_BGR32));
pixelformat = V4L2_PIX_FMT_BGR32;
mask3 |= (0x04 << 4);
mask3 |= 0x0100;
break;
}
default:
return -3;
}
bytesperline = width * ((mask3 & 0x00F0) >> 4);
sizeimage = bytesperline * height;
for (m = 0; m < INTERLACE_MANY; m++) {
mask4 = 0x0000;
switch (m) {
case FIELD_NONE: {
strcpy(&name4[0], "-n");
field = V4L2_FIELD_NONE;
break;
}
case FIELD_INTERLACED: {
strcpy(&name4[0], "-i");
field = V4L2_FIELD_INTERLACED;
break;
}
case FIELD_ALTERNATE: {
strcpy(&name4[0], "-a");
mask4 |= 0x1000;
field = V4L2_FIELD_ALTERNATE;
break;
}
default:
return -4;
}
if (SETTINGS_MANY <= n)
return -5;
strcpy(&easycap_format[n].name[0], &name1[0]);
strcat(&easycap_format[n].name[0], &name2[0]);
strcat(&easycap_format[n].name[0], &name3[0]);
strcat(&easycap_format[n].name[0], &name4[0]);
easycap_format[n].mask = \
mask1 | mask2 | mask3 | mask4;
easycap_format[n].v4l2_format\
.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
easycap_format[n].v4l2_format\
.fmt.pix.width = width;
easycap_format[n].v4l2_format\
.fmt.pix.height = height;
easycap_format[n].v4l2_format\
.fmt.pix.pixelformat = pixelformat;
easycap_format[n].v4l2_format\
.fmt.pix.field = field;
easycap_format[n].v4l2_format\
.fmt.pix.bytesperline = bytesperline;
easycap_format[n].v4l2_format\
.fmt.pix.sizeimage = sizeimage;
easycap_format[n].v4l2_format\
.fmt.pix.colorspace = colorspace;
easycap_format[n].v4l2_format\
.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
}
};
/*****************************************************************************/
/******************************************************************************
* *
* 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"
#include "easycap_debug.h"
#include "easycap_sound.h"
/*****************************************************************************/
/*---------------------------------------------------------------------------*/
/*
* ON COMPLETION OF AN AUDIO URB ITS DATA IS COPIED TO THE AUDIO BUFFERS
* PROVIDED peasycap->audio_idle IS ZER0. REGARDLESS OF THIS BEING TRUE,
* IT IS RESUBMITTED PROVIDED peasycap->audio_isoc_streaming IS NOT ZERO.
*/
/*---------------------------------------------------------------------------*/
void
easysnd_complete(struct urb *purb)
{
static int mt;
struct easycap *peasycap;
struct data_buffer *paudio_buffer;
char errbuf[16];
__u8 *p1, *p2;
__s16 s16;
int i, j, more, much, leap, rc;
JOT(16, "\n");
if (NULL == purb) {
SAY("ERROR: purb is NULL\n");
return;
}
peasycap = purb->context;
if (NULL == peasycap) {
SAY("ERROR: peasycap is NULL\n");
return;
}
much = 0;
if (peasycap->audio_idle) {
JOT(16, "%i=audio_idle %i=audio_isoc_streaming\n", \
peasycap->audio_idle, peasycap->audio_isoc_streaming);
if (peasycap->audio_isoc_streaming) {
rc = usb_submit_urb(purb, GFP_ATOMIC);
if (0 != rc) {
SAY("ERROR: while %i=audio_idle, " \
"usb_submit_urb() failed with rc:\n", \
peasycap->audio_idle);
switch (rc) {
case -ENOMEM: {
SAY("ENOMEM\n"); break;
}
case -ENODEV: {
SAY("ENODEV\n"); break;
}
case -ENXIO: {
SAY("ENXIO\n"); break;
}
case -EINVAL: {
SAY("EINVAL\n"); break;
}
case -EAGAIN: {
SAY("EAGAIN\n"); break;
}
case -EFBIG: {
SAY("EFBIG\n"); break;
}
case -EPIPE: {
SAY("EPIPE\n"); break;
}
case -EMSGSIZE: {
SAY("EMSGSIZE\n"); break;
}
default: {
SAY("0x%08X\n", rc); break;
}
}
}
}
return;
}
/*---------------------------------------------------------------------------*/
if (purb->status) {
if (-ESHUTDOWN == purb->status) {
JOT(16, "immediate return because -ESHUTDOWN=purb->status\n");
return;
}
SAY("ERROR: non-zero urb status:\n");
switch (purb->status) {
case -EINPROGRESS: {
SAY("-EINPROGRESS\n"); break;
}
case -ENOSR: {
SAY("-ENOSR\n"); break;
}
case -EPIPE: {
SAY("-EPIPE\n"); break;
}
case -EOVERFLOW: {
SAY("-EOVERFLOW\n"); break;
}
case -EPROTO: {
SAY("-EPROTO\n"); break;
}
case -EILSEQ: {
SAY("-EILSEQ\n"); break;
}
case -ETIMEDOUT: {
SAY("-ETIMEDOUT\n"); break;
}
case -EMSGSIZE: {
SAY("-EMSGSIZE\n"); break;
}
case -EOPNOTSUPP: {
SAY("-EOPNOTSUPP\n"); break;
}
case -EPFNOSUPPORT: {
SAY("-EPFNOSUPPORT\n"); break;
}
case -EAFNOSUPPORT: {
SAY("-EAFNOSUPPORT\n"); break;
}
case -EADDRINUSE: {
SAY("-EADDRINUSE\n"); break;
}
case -EADDRNOTAVAIL: {
SAY("-EADDRNOTAVAIL\n"); break;
}
case -ENOBUFS: {
SAY("-ENOBUFS\n"); break;
}
case -EISCONN: {
SAY("-EISCONN\n"); break;
}
case -ENOTCONN: {
SAY("-ENOTCONN\n"); break;
}
case -ESHUTDOWN: {
SAY("-ESHUTDOWN\n"); break;
}
case -ENOENT: {
SAY("-ENOENT\n"); break;
}
case -ECONNRESET: {
SAY("-ECONNRESET\n"); break;
}
default: {
SAY("unknown error code 0x%08X\n", purb->status); break;
}
}
/*---------------------------------------------------------------------------*/
/*
* RESUBMIT THIS URB AFTER AN ERROR
*
* (THIS IS DUPLICATE CODE TO REDUCE INDENTATION OF THE NO-ERROR PATH)
*/
/*---------------------------------------------------------------------------*/
if (peasycap->audio_isoc_streaming) {
rc = usb_submit_urb(purb, GFP_ATOMIC);
if (0 != rc) {
SAY("ERROR: while %i=audio_idle, usb_submit_urb() "
"failed with rc:\n", peasycap->audio_idle);
switch (rc) {
case -ENOMEM: {
SAY("ENOMEM\n"); break;
}
case -ENODEV: {
SAY("ENODEV\n"); break;
}
case -ENXIO: {
SAY("ENXIO\n"); break;
}
case -EINVAL: {
SAY("EINVAL\n"); break;
}
case -EAGAIN: {
SAY("EAGAIN\n"); break;
}
case -EFBIG: {
SAY("EFBIG\n"); break;
}
case -EPIPE: {
SAY("EPIPE\n"); break;
}
case -EMSGSIZE: {
SAY("EMSGSIZE\n"); break;
}
default: {
SAY("0x%08X\n", rc); break;
}
}
}
}
return;
}
/*---------------------------------------------------------------------------*/
/*
* PROCEED HERE WHEN NO ERROR
*/
/*---------------------------------------------------------------------------*/
for (i = 0; i < purb->number_of_packets; i++) {
switch (purb->iso_frame_desc[i].status) {
case 0: {
strcpy(&errbuf[0], "OK"); break;
}
case -ENOENT: {
strcpy(&errbuf[0], "-ENOENT"); break;
}
case -EINPROGRESS: {
strcpy(&errbuf[0], "-EINPROGRESS"); break;
}
case -EPROTO: {
strcpy(&errbuf[0], "-EPROTO"); break;
}
case -EILSEQ: {
strcpy(&errbuf[0], "-EILSEQ"); break;
}
case -ETIME: {
strcpy(&errbuf[0], "-ETIME"); break;
}
case -ETIMEDOUT: {
strcpy(&errbuf[0], "-ETIMEDOUT"); break;
}
case -EPIPE: {
strcpy(&errbuf[0], "-EPIPE"); break;
}
case -ECOMM: {
strcpy(&errbuf[0], "-ECOMM"); break;
}
case -ENOSR: {
strcpy(&errbuf[0], "-ENOSR"); break;
}
case -EOVERFLOW: {
strcpy(&errbuf[0], "-EOVERFLOW"); break;
}
case -EREMOTEIO: {
strcpy(&errbuf[0], "-EREMOTEIO"); break;
}
case -ENODEV: {
strcpy(&errbuf[0], "-ENODEV"); break;
}
case -EXDEV: {
strcpy(&errbuf[0], "-EXDEV"); break;
}
case -EINVAL: {
strcpy(&errbuf[0], "-EINVAL"); break;
}
case -ECONNRESET: {
strcpy(&errbuf[0], "-ECONNRESET"); break;
}
case -ESHUTDOWN: {
strcpy(&errbuf[0], "-ESHUTDOWN"); break;
}
default: {
strcpy(&errbuf[0], "UNKNOWN"); break;
}
}
if ((!purb->iso_frame_desc[i].status) && 0) {
JOT(16, "frame[%2i]: %i=status{=%16s} " \
"%5i=actual " \
"%5i=length " \
"%3i=offset\n", \
i, purb->iso_frame_desc[i].status, &errbuf[0],
purb->iso_frame_desc[i].actual_length,
purb->iso_frame_desc[i].length,
purb->iso_frame_desc[i].offset);
}
if (!purb->iso_frame_desc[i].status) {
more = purb->iso_frame_desc[i].actual_length;
#if defined(TESTTONE)
if (!more)
more = purb->iso_frame_desc[i].length;
#endif
if (!more)
mt++;
else {
if (mt) {
JOT(16, "%4i empty audio urb frames\n", mt);
mt = 0;
}
p1 = (__u8 *)(purb->transfer_buffer + \
purb->iso_frame_desc[i].offset);
leap = 0;
p1 += leap;
more -= leap;
/*---------------------------------------------------------------------------*/
/*
* COPY more BYTES FROM ISOC BUFFER TO AUDIO BUFFER,
* CONVERTING 8-BIT SAMPLES TO 16-BIT SIGNED LITTLE-ENDED SAMPLES IF NECESSARY
*/
/*---------------------------------------------------------------------------*/
while (more) {
if (0 > more) {
SAY("easysnd_complete: MISTAKE: " \
"more is negative\n");
return;
}
if (audio_buffer_page_many <= \
peasycap->audio_fill) {
SAY("ERROR: bad " \
"peasycap->audio_fill\n");
return;
}
paudio_buffer = &peasycap->audio_buffer\
[peasycap->audio_fill];
if (PAGE_SIZE < (paudio_buffer->pto - \
paudio_buffer->pgo)) {
SAY("ERROR: bad paudio_buffer->pto\n");
return;
}
if (PAGE_SIZE == (paudio_buffer->pto - \
paudio_buffer->pgo)) {
#if defined(TESTTONE)
easysnd_testtone(peasycap, \
peasycap->audio_fill);
#endif /*TESTTONE*/
paudio_buffer->pto = \
paudio_buffer->pgo;
(peasycap->audio_fill)++;
if (audio_buffer_page_many <= \
peasycap->audio_fill)
peasycap->audio_fill = 0;
JOT(12, "bumped peasycap->" \
"audio_fill to %i\n", \
peasycap->audio_fill);
paudio_buffer = &peasycap->\
audio_buffer\
[peasycap->audio_fill];
paudio_buffer->pto = \
paudio_buffer->pgo;
if (!(peasycap->audio_fill % \
audio_pages_per_fragment)) {
JOT(12, "wakeup call on wq_" \
"audio, %i=frag reading %i" \
"=fragment fill\n", \
(peasycap->audio_read / \
audio_pages_per_fragment), \
(peasycap->audio_fill / \
audio_pages_per_fragment));
wake_up_interruptible\
(&(peasycap->wq_audio));
}
}
much = PAGE_SIZE - (int)(paudio_buffer->pto -\
paudio_buffer->pgo);
if (much % 2)
JOT(8, "MISTAKE? much is odd\n");
if (false == peasycap->microphone) {
if (much > more)
much = more;
memcpy(paudio_buffer->pto, p1, much);
p1 += much;
more -= much;
} else {
if (much > (2 * more))
much = 2 * more;
p2 = (__u8 *)paudio_buffer->pto;
for (j = 0; j < (much / 2); j++) {
s16 = ((int) *p1) - 128;
*p2 = (0xFF00 & s16) >> 8;
*(p2 + 1) = (0x00FF & s16);
p1++; p2 += 2;
more--;
}
}
(paudio_buffer->pto) += much;
}
}
} else {
JOT(12, "discarding audio samples because " \
"%i=purb->iso_frame_desc[i].status\n", \
purb->iso_frame_desc[i].status);
}
}
/*---------------------------------------------------------------------------*/
/*
* RESUBMIT THIS URB AFTER NO ERROR
*/
/*---------------------------------------------------------------------------*/
if (peasycap->audio_isoc_streaming) {
rc = usb_submit_urb(purb, GFP_ATOMIC);
if (0 != rc) {
SAY("ERROR: while %i=audio_idle, usb_submit_urb() failed " \
"with rc:\n", peasycap->audio_idle);
switch (rc) {
case -ENOMEM: {
SAY("ENOMEM\n"); break;
}
case -ENODEV: {
SAY("ENODEV\n"); break;
}
case -ENXIO: {
SAY("ENXIO\n"); break;
}
case -EINVAL: {
SAY("EINVAL\n"); break;
}
case -EAGAIN: {
SAY("EAGAIN\n"); break;
}
case -EFBIG: {
SAY("EFBIG\n"); break;
}
case -EPIPE: {
SAY("EPIPE\n"); break;
}
case -EMSGSIZE: {
SAY("EMSGSIZE\n"); break;
}
default: {
SAY("0x%08X\n", rc); break;
}
}
}
}
return;
}
/*****************************************************************************/
/*---------------------------------------------------------------------------*/
/*
* THE AUDIO URBS ARE SUBMITTED AT THIS EARLY STAGE SO THAT IT IS POSSIBLE TO
* STREAM FROM /dev/easysnd1 WITH SIMPLE PROGRAMS SUCH AS cat WHICH DO NOT
* HAVE AN IOCTL INTERFACE. THE VIDEO URBS, BY CONTRAST, MUST BE SUBMITTED
* MUCH LATER: SEE COMMENTS IN FILE easycap_main.c.
*/
/*---------------------------------------------------------------------------*/
int
easysnd_open(struct inode *inode, struct file *file)
{
struct usb_interface *pusb_interface;
struct easycap *peasycap;
int subminor, rc;
JOT(4, "begins.\n");
subminor = iminor(inode);
pusb_interface = usb_find_interface(&easycap_usb_driver, subminor);
if (NULL == pusb_interface) {
SAY("ERROR: pusb_interface is NULL\n");
SAY("ending unsuccessfully\n");
return -1;
}
peasycap = usb_get_intfdata(pusb_interface);
if (NULL == peasycap) {
SAY("ERROR: peasycap is NULL\n");
SAY("ending unsuccessfully\n");
return -1;
}
file->private_data = peasycap;
/*---------------------------------------------------------------------------*/
/*
* INITIALIZATION.
*/
/*---------------------------------------------------------------------------*/
JOT(4, "starting initialization\n");
if ((struct usb_device *)NULL == peasycap->pusb_device) {
SAY("ERROR: peasycap->pusb_device is NULL\n");
return -EFAULT;
} else {
JOT(16, "0x%08lX=peasycap->pusb_device\n", \
(long int)peasycap->pusb_device);
}
rc = audio_setup(peasycap);
if (0 <= rc)
JOT(8, "audio_setup() returned %i\n", rc);
else
JOT(8, "easysnd open(): ERROR: audio_setup() returned %i\n", rc);
if ((struct usb_device *)NULL == peasycap->pusb_device) {
SAY("ERROR: peasycap->pusb_device has become NULL\n");
return -EFAULT;
}
rc = adjust_volume(peasycap, -8192);
if (0 != rc) {
SAY("ERROR: adjust_volume(default) returned %i\n", rc);
return -EFAULT;
}
/*---------------------------------------------------------------------------*/
if ((struct usb_device *)NULL == peasycap->pusb_device) {
SAY("ERROR: peasycap->pusb_device has become NULL\n");
return -EFAULT;
}
rc = usb_set_interface(peasycap->pusb_device, peasycap->audio_interface, \
peasycap->audio_altsetting_on);
JOT(8, "usb_set_interface(.,%i,%i) returned %i\n", peasycap->audio_interface, \
peasycap->audio_altsetting_on, rc);
if ((struct usb_device *)NULL == peasycap->pusb_device) {
SAY("ERROR: peasycap->pusb_device has become NULL\n");
return -EFAULT;
}
rc = wakeup_device(peasycap->pusb_device);
if (0 == rc)
JOT(8, "wakeup_device() returned %i\n", rc);
else
JOT(8, "easysnd open(): ERROR: wakeup_device() returned %i\n", rc);
if ((struct usb_device *)NULL == peasycap->pusb_device) {
SAY("ERROR: peasycap->pusb_device has become NULL\n");
return -EFAULT;
}
submit_audio_urbs(peasycap);
peasycap->audio_idle = 0;
peasycap->timeval1.tv_sec = 0;
peasycap->timeval1.tv_usec = 0;
JOT(4, "finished initialization\n");
return 0;
}
/*****************************************************************************/
int
easysnd_release(struct inode *inode, struct file *file)
{
struct easycap *peasycap;
JOT(4, "begins\n");
peasycap = (struct easycap *)file->private_data;
if (NULL == peasycap) {
SAY("ERROR: peasycap is NULL.\n");
return -EFAULT;
}
if (0 != kill_audio_urbs(peasycap)) {
SAY("ERROR: kill_audio_urbs() failed\n");
return -EFAULT;
}
JOT(4, "ending successfully\n");
return 0;
}
/*****************************************************************************/
ssize_t
easysnd_read(struct file *file, char __user *puserspacebuffer, \
size_t kount, loff_t *poff)
{
struct timeval timeval;
static struct timeval timeval1;
static long long int audio_bytes, above, below, mean;
struct signed_div_result sdr;
unsigned char *p0;
long int kount1, more, rc, l0, lm;
int fragment;
struct easycap *peasycap;
struct data_buffer *pdata_buffer;
size_t szret;
/*---------------------------------------------------------------------------*/
/*
* DO A BLOCKING READ TO TRANSFER DATA TO USER SPACE.
*
******************************************************************************
***** N.B. IF THIS FUNCTION RETURNS 0, NOTHING IS SEEN IN USER SPACE. ******
***** THIS CONDITION SIGNIFIES END-OF-FILE. ******
******************************************************************************
*/
/*---------------------------------------------------------------------------*/
JOT(8, "===== easysnd_read(): kount=%i, *poff=%i\n", (int)kount, (int)(*poff));
peasycap = (struct easycap *)(file->private_data);
if (NULL == peasycap) {
SAY("ERROR in easysnd_read(): peasycap is NULL\n");
return -EFAULT;
}
/*---------------------------------------------------------------------------*/
if ((0 > peasycap->audio_read) || \
(audio_buffer_page_many <= peasycap->audio_read)) {
SAY("ERROR: peasycap->audio_read out of range\n");
return -EFAULT;
}
pdata_buffer = &peasycap->audio_buffer[peasycap->audio_read];
if ((struct data_buffer *)NULL == pdata_buffer) {
SAY("ERROR: pdata_buffer is NULL\n");
return -EFAULT;
}
JOT(12, "before wait, %i=frag read %i=frag fill\n", \
(peasycap->audio_read / audio_pages_per_fragment), \
(peasycap->audio_fill / audio_pages_per_fragment));
fragment = (peasycap->audio_read / audio_pages_per_fragment);
while ((fragment == (peasycap->audio_fill / audio_pages_per_fragment)) || \
(0 == (PAGE_SIZE - (pdata_buffer->pto - pdata_buffer->pgo)))) {
if (file->f_flags & O_NONBLOCK) {
JOT(16, "returning -EAGAIN as instructed\n");
return -EAGAIN;
}
rc = wait_event_interruptible(peasycap->wq_audio, \
(peasycap->audio_idle || peasycap->audio_eof || \
((fragment != (peasycap->audio_fill / \
audio_pages_per_fragment)) && \
(0 < (PAGE_SIZE - (pdata_buffer->pto - pdata_buffer->pgo))))));
if (0 != rc) {
SAY("aborted by signal\n");
return -ERESTARTSYS;
}
if (peasycap->audio_eof) {
JOT(8, "returning 0 because %i=audio_eof\n", \
peasycap->audio_eof);
kill_audio_urbs(peasycap);
msleep(500);
return 0;
}
if (peasycap->audio_idle) {
JOT(16, "returning 0 because %i=audio_idle\n", \
peasycap->audio_idle);
return 0;
}
if (!peasycap->audio_isoc_streaming) {
JOT(16, "returning 0 because audio urbs not streaming\n");
return 0;
}
}
JOT(12, "after wait, %i=frag read %i=frag fill\n", \
(peasycap->audio_read / audio_pages_per_fragment), \
(peasycap->audio_fill / audio_pages_per_fragment));
szret = (size_t)0;
while (fragment == (peasycap->audio_read / audio_pages_per_fragment)) {
if (NULL == pdata_buffer->pgo) {
SAY("ERROR: pdata_buffer->pgo is NULL\n");
return -EFAULT;
}
if (NULL == pdata_buffer->pto) {
SAY("ERROR: pdata_buffer->pto is NULL\n");
return -EFAULT;
}
kount1 = PAGE_SIZE - (pdata_buffer->pto - pdata_buffer->pgo);
if (0 > kount1) {
SAY("easysnd_read: MISTAKE: kount1 is negative\n");
return -ERESTARTSYS;
}
if (!kount1) {
(peasycap->audio_read)++;
if (audio_buffer_page_many <= peasycap->audio_read)
peasycap->audio_read = 0;
JOT(12, "bumped peasycap->audio_read to %i\n", \
peasycap->audio_read);
if (fragment != (peasycap->audio_read / \
audio_pages_per_fragment))
break;
if ((0 > peasycap->audio_read) || \
(audio_buffer_page_many <= peasycap->audio_read)) {
SAY("ERROR: peasycap->audio_read out of range\n");
return -EFAULT;
}
pdata_buffer = &peasycap->audio_buffer[peasycap->audio_read];
if ((struct data_buffer *)NULL == pdata_buffer) {
SAY("ERROR: pdata_buffer is NULL\n");
return -EFAULT;
}
if (NULL == pdata_buffer->pgo) {
SAY("ERROR: pdata_buffer->pgo is NULL\n");
return -EFAULT;
}
if (NULL == pdata_buffer->pto) {
SAY("ERROR: pdata_buffer->pto is NULL\n");
return -EFAULT;
}
kount1 = PAGE_SIZE - (pdata_buffer->pto - pdata_buffer->pgo);
}
JOT(12, "ready to send %li bytes\n", (long int) kount1);
JOT(12, "still to send %li bytes\n", (long int) kount);
more = kount1;
if (more > kount)
more = kount;
JOT(12, "agreed to send %li bytes from page %i\n", \
more, peasycap->audio_read);
if (!more)
break;
/*---------------------------------------------------------------------------*/
/*
* ACCUMULATE DYNAMIC-RANGE INFORMATION
*/
/*---------------------------------------------------------------------------*/
p0 = (unsigned char *)pdata_buffer->pgo; l0 = 0; lm = more/2;
while (l0 < lm) {
SUMMER(p0, &peasycap->audio_sample, &peasycap->audio_niveau, \
&peasycap->audio_square); l0++; p0 += 2;
}
/*---------------------------------------------------------------------------*/
rc = copy_to_user(puserspacebuffer, pdata_buffer->pto, more);
if (0 != rc) {
SAY("ERROR: copy_to_user() returned %li\n", rc);
return -EFAULT;
}
*poff += (loff_t)more;
szret += (size_t)more;
pdata_buffer->pto += more;
puserspacebuffer += more;
kount -= (size_t)more;
}
JOT(12, "after read, %i=frag read %i=frag fill\n", \
(peasycap->audio_read / audio_pages_per_fragment), \
(peasycap->audio_fill / audio_pages_per_fragment));
if (kount < 0) {
SAY("MISTAKE: %li=kount %li=szret\n", \
(long int)kount, (long int)szret);
}
/*---------------------------------------------------------------------------*/
/*
* CALCULATE DYNAMIC RANGE FOR (VAPOURWARE) AUTOMATIC VOLUME CONTROL
*/
/*---------------------------------------------------------------------------*/
if (peasycap->audio_sample) {
below = peasycap->audio_sample;
above = peasycap->audio_square;
sdr = signed_div(above, below);
above = sdr.quotient;
mean = peasycap->audio_niveau;
sdr = signed_div(mean, peasycap->audio_sample);
JOT(12, "%8lli=mean %8lli=meansquare after %lli samples, =>\n", \
sdr.quotient, above, peasycap->audio_sample);
sdr = signed_div(above, 32768);
JOT(8, "audio dynamic range is roughly %lli\n", sdr.quotient);
}
/*---------------------------------------------------------------------------*/
/*
* UPDATE THE AUDIO CLOCK
*/
/*---------------------------------------------------------------------------*/
do_gettimeofday(&timeval);
if (!peasycap->timeval1.tv_sec) {
audio_bytes = 0;
timeval1 = timeval;
if (mutex_lock_interruptible(&(peasycap->mutex_timeval1)))
return -ERESTARTSYS;
peasycap->timeval1 = timeval1;
mutex_unlock(&(peasycap->mutex_timeval1));
sdr.quotient = 192000;
} else {
audio_bytes += (long long int) szret;
below = ((long long int)(1000000)) * \
((long long int)(timeval.tv_sec - timeval1.tv_sec)) + \
(long long int)(timeval.tv_usec - timeval1.tv_usec);
above = 1000000 * ((long long int) audio_bytes);
if (below)
sdr = signed_div(above, below);
else
sdr.quotient = 192000;
}
JOT(8, "audio streaming at %lli bytes/second\n", sdr.quotient);
if (mutex_lock_interruptible(&(peasycap->mutex_timeval1)))
return -ERESTARTSYS;
peasycap->dnbydt = sdr.quotient;
mutex_unlock(&(peasycap->mutex_timeval1));
JOT(8, "returning %li\n", (long int)szret);
return szret;
}
/*****************************************************************************/
/*---------------------------------------------------------------------------*/
/*
* SUBMIT ALL AUDIO URBS.
*/
/*---------------------------------------------------------------------------*/
int
submit_audio_urbs(struct easycap *peasycap)
{
struct data_urb *pdata_urb;
struct urb *purb;
struct list_head *plist_head;
int j, isbad, m, rc;
int isbuf;
if ((struct list_head *)NULL == peasycap->purb_audio_head) {
SAY("ERROR: peasycap->urb_audio_head uninitialized\n");
return -EFAULT;
}
if ((struct usb_device *)NULL == peasycap->pusb_device) {
SAY("ERROR: peasycap->pusb_device is NULL\n");
return -EFAULT;
}
if (!peasycap->audio_isoc_streaming) {
JOT(4, "initial submission of all audio urbs\n");
rc = usb_set_interface(peasycap->pusb_device,
peasycap->audio_interface, \
peasycap->audio_altsetting_on);
JOT(8, "usb_set_interface(.,%i,%i) returned %i\n", \
peasycap->audio_interface, \
peasycap->audio_altsetting_on, rc);
isbad = 0; m = 0;
list_for_each(plist_head, (peasycap->purb_audio_head)) {
pdata_urb = list_entry(plist_head, struct data_urb, list_head);
if (NULL != pdata_urb) {
purb = pdata_urb->purb;
if (NULL != 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 = easysnd_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 (0 != rc) {
isbad++;
SAY("ERROR: usb_submit_urb() failed" \
" for urb with rc:\n");
switch (rc) {
case -ENOMEM: {
SAY("ENOMEM\n"); break;
}
case -ENODEV: {
SAY("ENODEV\n"); break;
}
case -ENXIO: {
SAY("ENXIO\n"); break;
}
case -EINVAL: {
SAY("EINVAL\n"); break;
}
case -EAGAIN: {
SAY("EAGAIN\n"); break;
}
case -EFBIG: {
SAY("EFBIG\n"); break;
}
case -EPIPE: {
SAY("EPIPE\n"); break;
}
case -EMSGSIZE: {
SAY("EMSGSIZE\n"); break;
}
default: {
SAY("unknown error code %i\n",\
rc); break;
}
}
} else {
m++;
}
} else {
isbad++;
}
} else {
isbad++;
}
}
if (isbad) {
JOT(4, "attempting cleanup instead of submitting\n");
list_for_each(plist_head, (peasycap->purb_audio_head)) {
pdata_urb = list_entry(plist_head, struct data_urb, \
list_head);
if (NULL != pdata_urb) {
purb = pdata_urb->purb;
if (NULL != purb)
usb_kill_urb(purb);
}
}
peasycap->audio_isoc_streaming = 0;
} else {
peasycap->audio_isoc_streaming = 1;
JOT(4, "submitted %i audio urbs\n", m);
}
} else
JOT(4, "already streaming audio urbs\n");
return 0;
}
/*****************************************************************************/
/*---------------------------------------------------------------------------*/
/*
* KILL ALL AUDIO URBS.
*/
/*---------------------------------------------------------------------------*/
int
kill_audio_urbs(struct easycap *peasycap)
{
int m;
struct list_head *plist_head;
struct data_urb *pdata_urb;
if (peasycap->audio_isoc_streaming) {
if ((struct list_head *)NULL != peasycap->purb_audio_head) {
peasycap->audio_isoc_streaming = 0;
JOT(4, "killing audio urbs\n");
m = 0;
list_for_each(plist_head, (peasycap->purb_audio_head)) {
pdata_urb = list_entry(plist_head, struct data_urb,
list_head);
if ((struct data_urb *)NULL != pdata_urb) {
if ((struct urb *)NULL != pdata_urb->purb) {
usb_kill_urb(pdata_urb->purb);
m++;
}
}
}
JOT(4, "%i audio urbs killed\n", m);
} else {
SAY("ERROR: peasycap->purb_audio_head is NULL\n");
return -EFAULT;
}
} else {
JOT(8, "%i=audio_isoc_streaming, no audio urbs killed\n", \
peasycap->audio_isoc_streaming);
}
return 0;
}
/*****************************************************************************/
/*****************************************************************************
* *
* easycap_sound.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
*
*/
/*****************************************************************************/
extern struct easycap *peasycap;
extern struct usb_driver easycap_usb_driver;
extern unsigned int audio_buffer_page_many;
extern unsigned int audio_pages_per_fragment;
/*****************************************************************************
* *
* easycap_standard.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
*
*/
/*****************************************************************************/
extern struct easycap_standard easycap_standard[];
/******************************************************************************
* *
* 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"
#include "easycap_debug.h"
/*****************************************************************************/
#define TESTCARD_BYTESPERLINE (2 * 1440)
void
easycap_testcard(struct easycap *peasycap, int field_fill)
{
int total;
int y, u, v, r, g, b;
unsigned char uyvy[4];
int i1, line, k, m, n, more, much, barwidth;
unsigned char bfbar[TESTCARD_BYTESPERLINE / 8], *p1, *p2;
struct data_buffer *pfield_buffer;
JOT(8, "%i=field_fill\n", field_fill);
if ((TESTCARD_BYTESPERLINE / 2) < peasycap->width) {
SAY("ERROR: image is too wide\n");
return;
}
if (peasycap->width % 16) {
SAY("ERROR: indivisible image width\n");
return;
}
total = 0;
barwidth = (2 * peasycap->width) / 8;
k = field_fill;
m = 0;
n = 0;
for (line = 0; line < (peasycap->height / 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) {
SAY("ERROR: bad m reached\n");
return;
}
if (PAGE_SIZE < n) {
SAY("ERROR: bad n reached\n"); return;
}
if (0 > more) {
SAY("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;
}
}
}
}
JOT(8, "%i=total\n", total);
if (total != peasycap->width * peasycap->height)
SAY("ERROR: wrong number of bytes written: %i\n", total);
return;
}
/*****************************************************************************/
#if defined(EASYCAP_TESTTONE)
/*-----------------------------------------------------------------------------
THE tones[] ARRAY BELOW IS THE OUTPUT OF THIS PROGRAM,
COMPILED gcc -o prog -lm prog.c
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
#include <stdio.h>
#include <math.h>
int main(void);
int
main(void)
{
int i1, i2, last;
double d1, d2;
last = 1024 - 1;
d1 = 10.0*3.14159265/1024.0;
printf("int tones[2048] =\n{\n");
for (i1 = 0; i1 <= last; i1++)
{
d2 = ((double)i1) * d1;
i2 = (int)(16384.0*sin(d2));
if (last != i1)
{
printf("%6i, ", i2); printf("%6i, ", i2);
if (!((i1 + 1)%5)) printf("\n");
}
else
{
printf("%6i, ", i2); printf("%6i\n};\n", i2);
}
}
return(0);
}
-----------------------------------------------------------------------------*/
int tones[2048] = {
0, 0, 502, 502, 1004, 1004, 1505, 1505, 2005, 2005,
2503, 2503, 2998, 2998, 3491, 3491, 3980, 3980, 4466, 4466,
4948, 4948, 5424, 5424, 5896, 5896, 6362, 6362, 6822, 6822,
7276, 7276, 7723, 7723, 8162, 8162, 8594, 8594, 9018, 9018,
9434, 9434, 9840, 9840, 10237, 10237, 10625, 10625, 11002, 11002,
11370, 11370, 11726, 11726, 12072, 12072, 12406, 12406, 12728, 12728,
13038, 13038, 13337, 13337, 13622, 13622, 13895, 13895, 14155, 14155,
14401, 14401, 14634, 14634, 14853, 14853, 15058, 15058, 15249, 15249,
15426, 15426, 15588, 15588, 15735, 15735, 15868, 15868, 15985, 15985,
16088, 16088, 16175, 16175, 16248, 16248, 16305, 16305, 16346, 16346,
16372, 16372, 16383, 16383, 16379, 16379, 16359, 16359, 16323, 16323,
16272, 16272, 16206, 16206, 16125, 16125, 16028, 16028, 15917, 15917,
15790, 15790, 15649, 15649, 15492, 15492, 15322, 15322, 15136, 15136,
14937, 14937, 14723, 14723, 14496, 14496, 14255, 14255, 14001, 14001,
13733, 13733, 13452, 13452, 13159, 13159, 12854, 12854, 12536, 12536,
12207, 12207, 11866, 11866, 11513, 11513, 11150, 11150, 10777, 10777,
10393, 10393, 10000, 10000, 9597, 9597, 9185, 9185, 8765, 8765,
8336, 8336, 7900, 7900, 7456, 7456, 7005, 7005, 6547, 6547,
6083, 6083, 5614, 5614, 5139, 5139, 4659, 4659, 4175, 4175,
3687, 3687, 3196, 3196, 2701, 2701, 2204, 2204, 1705, 1705,
1205, 1205, 703, 703, 201, 201, -301, -301, -803, -803,
-1305, -1305, -1805, -1805, -2304, -2304, -2801, -2801, -3294, -3294,
-3785, -3785, -4272, -4272, -4756, -4756, -5234, -5234, -5708, -5708,
-6176, -6176, -6639, -6639, -7095, -7095, -7545, -7545, -7988, -7988,
-8423, -8423, -8850, -8850, -9268, -9268, -9679, -9679, -10079, -10079,
-10471, -10471, -10853, -10853, -11224, -11224, -11585, -11585, -11935, -11935,
-12273, -12273, -12600, -12600, -12916, -12916, -13219, -13219, -13510, -13510,
-13788, -13788, -14053, -14053, -14304, -14304, -14543, -14543, -14767, -14767,
-14978, -14978, -15175, -15175, -15357, -15357, -15525, -15525, -15678, -15678,
-15817, -15817, -15940, -15940, -16049, -16049, -16142, -16142, -16221, -16221,
-16284, -16284, -16331, -16331, -16364, -16364, -16381, -16381, -16382, -16382,
-16368, -16368, -16339, -16339, -16294, -16294, -16234, -16234, -16159, -16159,
-16069, -16069, -15963, -15963, -15842, -15842, -15707, -15707, -15557, -15557,
-15392, -15392, -15212, -15212, -15018, -15018, -14810, -14810, -14589, -14589,
-14353, -14353, -14104, -14104, -13842, -13842, -13566, -13566, -13278, -13278,
-12977, -12977, -12665, -12665, -12340, -12340, -12003, -12003, -11656, -11656,
-11297, -11297, -10928, -10928, -10548, -10548, -10159, -10159, -9759, -9759,
-9351, -9351, -8934, -8934, -8509, -8509, -8075, -8075, -7634, -7634,
-7186, -7186, -6731, -6731, -6269, -6269, -5802, -5802, -5329, -5329,
-4852, -4852, -4369, -4369, -3883, -3883, -3393, -3393, -2900, -2900,
-2404, -2404, -1905, -1905, -1405, -1405, -904, -904, -402, -402,
100, 100, 603, 603, 1105, 1105, 1605, 1605, 2105, 2105,
2602, 2602, 3097, 3097, 3589, 3589, 4078, 4078, 4563, 4563,
5043, 5043, 5519, 5519, 5990, 5990, 6455, 6455, 6914, 6914,
7366, 7366, 7811, 7811, 8249, 8249, 8680, 8680, 9102, 9102,
9516, 9516, 9920, 9920, 10315, 10315, 10701, 10701, 11077, 11077,
11442, 11442, 11796, 11796, 12139, 12139, 12471, 12471, 12791, 12791,
13099, 13099, 13395, 13395, 13678, 13678, 13948, 13948, 14205, 14205,
14449, 14449, 14679, 14679, 14895, 14895, 15098, 15098, 15286, 15286,
15459, 15459, 15618, 15618, 15763, 15763, 15892, 15892, 16007, 16007,
16107, 16107, 16191, 16191, 16260, 16260, 16314, 16314, 16353, 16353,
16376, 16376, 16384, 16384, 16376, 16376, 16353, 16353, 16314, 16314,
16260, 16260, 16191, 16191, 16107, 16107, 16007, 16007, 15892, 15892,
15763, 15763, 15618, 15618, 15459, 15459, 15286, 15286, 15098, 15098,
14895, 14895, 14679, 14679, 14449, 14449, 14205, 14205, 13948, 13948,
13678, 13678, 13395, 13395, 13099, 13099, 12791, 12791, 12471, 12471,
12139, 12139, 11796, 11796, 11442, 11442, 11077, 11077, 10701, 10701,
10315, 10315, 9920, 9920, 9516, 9516, 9102, 9102, 8680, 8680,
8249, 8249, 7811, 7811, 7366, 7366, 6914, 6914, 6455, 6455,
5990, 5990, 5519, 5519, 5043, 5043, 4563, 4563, 4078, 4078,
3589, 3589, 3097, 3097, 2602, 2602, 2105, 2105, 1605, 1605,
1105, 1105, 603, 603, 100, 100, -402, -402, -904, -904,
-1405, -1405, -1905, -1905, -2404, -2404, -2900, -2900, -3393, -3393,
-3883, -3883, -4369, -4369, -4852, -4852, -5329, -5329, -5802, -5802,
-6269, -6269, -6731, -6731, -7186, -7186, -7634, -7634, -8075, -8075,
-8509, -8509, -8934, -8934, -9351, -9351, -9759, -9759, -10159, -10159,
-10548, -10548, -10928, -10928, -11297, -11297, -11656, -11656, -12003, -12003,
-12340, -12340, -12665, -12665, -12977, -12977, -13278, -13278, -13566, -13566,
-13842, -13842, -14104, -14104, -14353, -14353, -14589, -14589, -14810, -14810,
-15018, -15018, -15212, -15212, -15392, -15392, -15557, -15557, -15707, -15707,
-15842, -15842, -15963, -15963, -16069, -16069, -16159, -16159, -16234, -16234,
-16294, -16294, -16339, -16339, -16368, -16368, -16382, -16382, -16381, -16381,
-16364, -16364, -16331, -16331, -16284, -16284, -16221, -16221, -16142, -16142,
-16049, -16049, -15940, -15940, -15817, -15817, -15678, -15678, -15525, -15525,
-15357, -15357, -15175, -15175, -14978, -14978, -14767, -14767, -14543, -14543,
-14304, -14304, -14053, -14053, -13788, -13788, -13510, -13510, -13219, -13219,
-12916, -12916, -12600, -12600, -12273, -12273, -11935, -11935, -11585, -11585,
-11224, -11224, -10853, -10853, -10471, -10471, -10079, -10079, -9679, -9679,
-9268, -9268, -8850, -8850, -8423, -8423, -7988, -7988, -7545, -7545,
-7095, -7095, -6639, -6639, -6176, -6176, -5708, -5708, -5234, -5234,
-4756, -4756, -4272, -4272, -3785, -3785, -3294, -3294, -2801, -2801,
-2304, -2304, -1805, -1805, -1305, -1305, -803, -803, -301, -301,
201, 201, 703, 703, 1205, 1205, 1705, 1705, 2204, 2204,
2701, 2701, 3196, 3196, 3687, 3687, 4175, 4175, 4659, 4659,
5139, 5139, 5614, 5614, 6083, 6083, 6547, 6547, 7005, 7005,
7456, 7456, 7900, 7900, 8336, 8336, 8765, 8765, 9185, 9185,
9597, 9597, 10000, 10000, 10393, 10393, 10777, 10777, 11150, 11150,
11513, 11513, 11866, 11866, 12207, 12207, 12536, 12536, 12854, 12854,
13159, 13159, 13452, 13452, 13733, 13733, 14001, 14001, 14255, 14255,
14496, 14496, 14723, 14723, 14937, 14937, 15136, 15136, 15322, 15322,
15492, 15492, 15649, 15649, 15790, 15790, 15917, 15917, 16028, 16028,
16125, 16125, 16206, 16206, 16272, 16272, 16323, 16323, 16359, 16359,
16379, 16379, 16383, 16383, 16372, 16372, 16346, 16346, 16305, 16305,
16248, 16248, 16175, 16175, 16088, 16088, 15985, 15985, 15868, 15868,
15735, 15735, 15588, 15588, 15426, 15426, 15249, 15249, 15058, 15058,
14853, 14853, 14634, 14634, 14401, 14401, 14155, 14155, 13895, 13895,
13622, 13622, 13337, 13337, 13038, 13038, 12728, 12728, 12406, 12406,
12072, 12072, 11726, 11726, 11370, 11370, 11002, 11002, 10625, 10625,
10237, 10237, 9840, 9840, 9434, 9434, 9018, 9018, 8594, 8594,
8162, 8162, 7723, 7723, 7276, 7276, 6822, 6822, 6362, 6362,
5896, 5896, 5424, 5424, 4948, 4948, 4466, 4466, 3980, 3980,
3491, 3491, 2998, 2998, 2503, 2503, 2005, 2005, 1505, 1505,
1004, 1004, 502, 502, 0, 0, -502, -502, -1004, -1004,
-1505, -1505, -2005, -2005, -2503, -2503, -2998, -2998, -3491, -3491,
-3980, -3980, -4466, -4466, -4948, -4948, -5424, -5424, -5896, -5896,
-6362, -6362, -6822, -6822, -7276, -7276, -7723, -7723, -8162, -8162,
-8594, -8594, -9018, -9018, -9434, -9434, -9840, -9840, -10237, -10237,
-10625, -10625, -11002, -11002, -11370, -11370, -11726, -11726, -12072, -12072,
-12406, -12406, -12728, -12728, -13038, -13038, -13337, -13337, -13622, -13622,
-13895, -13895, -14155, -14155, -14401, -14401, -14634, -14634, -14853, -14853,
-15058, -15058, -15249, -15249, -15426, -15426, -15588, -15588, -15735, -15735,
-15868, -15868, -15985, -15985, -16088, -16088, -16175, -16175, -16248, -16248,
-16305, -16305, -16346, -16346, -16372, -16372, -16383, -16383, -16379, -16379,
-16359, -16359, -16323, -16323, -16272, -16272, -16206, -16206, -16125, -16125,
-16028, -16028, -15917, -15917, -15790, -15790, -15649, -15649, -15492, -15492,
-15322, -15322, -15136, -15136, -14937, -14937, -14723, -14723, -14496, -14496,
-14255, -14255, -14001, -14001, -13733, -13733, -13452, -13452, -13159, -13159,
-12854, -12854, -12536, -12536, -12207, -12207, -11866, -11866, -11513, -11513,
-11150, -11150, -10777, -10777, -10393, -10393, -10000, -10000, -9597, -9597,
-9185, -9185, -8765, -8765, -8336, -8336, -7900, -7900, -7456, -7456,
-7005, -7005, -6547, -6547, -6083, -6083, -5614, -5614, -5139, -5139,
-4659, -4659, -4175, -4175, -3687, -3687, -3196, -3196, -2701, -2701,
-2204, -2204, -1705, -1705, -1205, -1205, -703, -703, -201, -201,
301, 301, 803, 803, 1305, 1305, 1805, 1805, 2304, 2304,
2801, 2801, 3294, 3294, 3785, 3785, 4272, 4272, 4756, 4756,
5234, 5234, 5708, 5708, 6176, 6176, 6639, 6639, 7095, 7095,
7545, 7545, 7988, 7988, 8423, 8423, 8850, 8850, 9268, 9268,
9679, 9679, 10079, 10079, 10471, 10471, 10853, 10853, 11224, 11224,
11585, 11585, 11935, 11935, 12273, 12273, 12600, 12600, 12916, 12916,
13219, 13219, 13510, 13510, 13788, 13788, 14053, 14053, 14304, 14304,
14543, 14543, 14767, 14767, 14978, 14978, 15175, 15175, 15357, 15357,
15525, 15525, 15678, 15678, 15817, 15817, 15940, 15940, 16049, 16049,
16142, 16142, 16221, 16221, 16284, 16284, 16331, 16331, 16364, 16364,
16381, 16381, 16382, 16382, 16368, 16368, 16339, 16339, 16294, 16294,
16234, 16234, 16159, 16159, 16069, 16069, 15963, 15963, 15842, 15842,
15707, 15707, 15557, 15557, 15392, 15392, 15212, 15212, 15018, 15018,
14810, 14810, 14589, 14589, 14353, 14353, 14104, 14104, 13842, 13842,
13566, 13566, 13278, 13278, 12977, 12977, 12665, 12665, 12340, 12340,
12003, 12003, 11656, 11656, 11297, 11297, 10928, 10928, 10548, 10548,
10159, 10159, 9759, 9759, 9351, 9351, 8934, 8934, 8509, 8509,
8075, 8075, 7634, 7634, 7186, 7186, 6731, 6731, 6269, 6269,
5802, 5802, 5329, 5329, 4852, 4852, 4369, 4369, 3883, 3883,
3393, 3393, 2900, 2900, 2404, 2404, 1905, 1905, 1405, 1405,
904, 904, 402, 402, -100, -100, -603, -603, -1105, -1105,
-1605, -1605, -2105, -2105, -2602, -2602, -3097, -3097, -3589, -3589,
-4078, -4078, -4563, -4563, -5043, -5043, -5519, -5519, -5990, -5990,
-6455, -6455, -6914, -6914, -7366, -7366, -7811, -7811, -8249, -8249,
-8680, -8680, -9102, -9102, -9516, -9516, -9920, -9920, -10315, -10315,
-10701, -10701, -11077, -11077, -11442, -11442, -11796, -11796, -12139, -12139,
-12471, -12471, -12791, -12791, -13099, -13099, -13395, -13395, -13678, -13678,
-13948, -13948, -14205, -14205, -14449, -14449, -14679, -14679, -14895, -14895,
-15098, -15098, -15286, -15286, -15459, -15459, -15618, -15618, -15763, -15763,
-15892, -15892, -16007, -16007, -16107, -16107, -16191, -16191, -16260, -16260,
-16314, -16314, -16353, -16353, -16376, -16376, -16383, -16383, -16376, -16376,
-16353, -16353, -16314, -16314, -16260, -16260, -16191, -16191, -16107, -16107,
-16007, -16007, -15892, -15892, -15763, -15763, -15618, -15618, -15459, -15459,
-15286, -15286, -15098, -15098, -14895, -14895, -14679, -14679, -14449, -14449,
-14205, -14205, -13948, -13948, -13678, -13678, -13395, -13395, -13099, -13099,
-12791, -12791, -12471, -12471, -12139, -12139, -11796, -11796, -11442, -11442,
-11077, -11077, -10701, -10701, -10315, -10315, -9920, -9920, -9516, -9516,
-9102, -9102, -8680, -8680, -8249, -8249, -7811, -7811, -7366, -7366,
-6914, -6914, -6455, -6455, -5990, -5990, -5519, -5519, -5043, -5043,
-4563, -4563, -4078, -4078, -3589, -3589, -3097, -3097, -2602, -2602,
-2105, -2105, -1605, -1605, -1105, -1105, -603, -603, -100, -100,
402, 402, 904, 904, 1405, 1405, 1905, 1905, 2404, 2404,
2900, 2900, 3393, 3393, 3883, 3883, 4369, 4369, 4852, 4852,
5329, 5329, 5802, 5802, 6269, 6269, 6731, 6731, 7186, 7186,
7634, 7634, 8075, 8075, 8509, 8509, 8934, 8934, 9351, 9351,
9759, 9759, 10159, 10159, 10548, 10548, 10928, 10928, 11297, 11297,
11656, 11656, 12003, 12003, 12340, 12340, 12665, 12665, 12977, 12977,
13278, 13278, 13566, 13566, 13842, 13842, 14104, 14104, 14353, 14353,
14589, 14589, 14810, 14810, 15018, 15018, 15212, 15212, 15392, 15392,
15557, 15557, 15707, 15707, 15842, 15842, 15963, 15963, 16069, 16069,
16159, 16159, 16234, 16234, 16294, 16294, 16339, 16339, 16368, 16368,
16382, 16382, 16381, 16381, 16364, 16364, 16331, 16331, 16284, 16284,
16221, 16221, 16142, 16142, 16049, 16049, 15940, 15940, 15817, 15817,
15678, 15678, 15525, 15525, 15357, 15357, 15175, 15175, 14978, 14978,
14767, 14767, 14543, 14543, 14304, 14304, 14053, 14053, 13788, 13788,
13510, 13510, 13219, 13219, 12916, 12916, 12600, 12600, 12273, 12273,
11935, 11935, 11585, 11585, 11224, 11224, 10853, 10853, 10471, 10471,
10079, 10079, 9679, 9679, 9268, 9268, 8850, 8850, 8423, 8423,
7988, 7988, 7545, 7545, 7095, 7095, 6639, 6639, 6176, 6176,
5708, 5708, 5234, 5234, 4756, 4756, 4272, 4272, 3785, 3785,
3294, 3294, 2801, 2801, 2304, 2304, 1805, 1805, 1305, 1305,
803, 803, 301, 301, -201, -201, -703, -703, -1205, -1205,
-1705, -1705, -2204, -2204, -2701, -2701, -3196, -3196, -3687, -3687,
-4175, -4175, -4659, -4659, -5139, -5139, -5614, -5614, -6083, -6083,
-6547, -6547, -7005, -7005, -7456, -7456, -7900, -7900, -8336, -8336,
-8765, -8765, -9185, -9185, -9597, -9597, -10000, -10000, -10393, -10393,
-10777, -10777, -11150, -11150, -11513, -11513, -11866, -11866, -12207, -12207,
-12536, -12536, -12854, -12854, -13159, -13159, -13452, -13452, -13733, -13733,
-14001, -14001, -14255, -14255, -14496, -14496, -14723, -14723, -14937, -14937,
-15136, -15136, -15322, -15322, -15492, -15492, -15649, -15649, -15790, -15790,
-15917, -15917, -16028, -16028, -16125, -16125, -16206, -16206, -16272, -16272,
-16323, -16323, -16359, -16359, -16379, -16379, -16383, -16383, -16372, -16372,
-16346, -16346, -16305, -16305, -16248, -16248, -16175, -16175, -16088, -16088,
-15985, -15985, -15868, -15868, -15735, -15735, -15588, -15588, -15426, -15426,
-15249, -15249, -15058, -15058, -14853, -14853, -14634, -14634, -14401, -14401,
-14155, -14155, -13895, -13895, -13622, -13622, -13337, -13337, -13038, -13038,
-12728, -12728, -12406, -12406, -12072, -12072, -11726, -11726, -11370, -11370,
-11002, -11002, -10625, -10625, -10237, -10237, -9840, -9840, -9434, -9434,
-9018, -9018, -8594, -8594, -8162, -8162, -7723, -7723, -7276, -7276,
-6822, -6822, -6362, -6362, -5896, -5896, -5424, -5424, -4948, -4948,
-4466, -4466, -3980, -3980, -3491, -3491, -2998, -2998, -2503, -2503,
-2005, -2005, -1505, -1505, -1004, -1004, -502, -502
};
/*****************************************************************************/
void
easysnd_testtone(struct easycap *peasycap, int audio_fill)
{
int i1;
unsigned char *p2;
struct data_buffer *paudio_buffer;
JOT(8, "%i=audio_fill\n", audio_fill);
paudio_buffer = &peasycap->audio_buffer[audio_fill];
p2 = (unsigned char *)(paudio_buffer->pgo);
for (i1 = 0; i1 < PAGE_SIZE; i1 += 4, p2 += 4) {
*p2 = (unsigned char) (0x00FF & tones[i1/2]);
*(p2 + 1) = (unsigned char)((0xFF00 & tones[i1/2]) >> 8);
*(p2 + 2) = (unsigned char) (0x00FF & tones[i1/2 + 1]);
*(p2 + 3) = (unsigned char)((0xFF00 & tones[i1/2 + 1]) >> 8);
}
return;
}
#endif /*EASYCAP_TESTTONE*/
/*****************************************************************************/
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment