···11+config EASYCAP22+ tristate "EasyCAP USB ID 05e1:0408 support"33+44+ ---help---55+ This is an integrated audio/video driver for EasyCAP cards with66+ USB ID 05e1:0408. It supports two hardware variants:77+88+ * EasyCAP USB 2.0 Video Adapter with Audio, Model DC60,99+ having input cables labelled CVBS, S-VIDEO, AUDIO(L), AUDIO(R)1010+1111+ * EasyCAP002 4-Channel USB 2.0 DVR, having input cables labelled1212+ 1, 2, 3, 4 and an unlabelled input cable for a microphone.1313+1414+ To compile this driver as a module, choose M here: the1515+ module will be called easycap1616+
+13
drivers/staging/easycap/Makefile
···11+22+obj-$(CONFIG_EASYCAP) += easycap.o33+44+easycap-objs := easycap_main.o easycap_low.o easycap_sound.o55+easycap-objs += easycap_ioctl.o easycap_settings.o66+easycap-objs += easycap_testcard.o77+88+EXTRA_CFLAGS += -Wall99+# Impose all or none of the following:1010+EXTRA_CFLAGS += -DEASYCAP_IS_VIDEODEV_CLIENT1111+EXTRA_CFLAGS += -DEASYCAP_NEEDS_V4L2_DEVICE_H1212+EXTRA_CFLAGS += -DEASYCAP_NEEDS_V4L2_FOPS1313+
+130
drivers/staging/easycap/README
···11+22+ ***********************************************************33+ * EasyCAP USB 2.0 Video Adapter with Audio, Model DC60 *44+ * and *55+ * EasyCAP002 4-Channel USB 2.0 DVR *66+ ***********************************************************77+ Mike Thomas <rmthomas@sciolus.org>88+99+1010+1111+SUPPORTED HARDWARE1212+------------------1313+1414+This driver is intended for use with hardware having USB ID 05e1:0408.1515+Two kinds of EasyCAP have this USB ID, namely:1616+1717+ * EasyCAP USB 2.0 Video Adapter with Audio, Model DC60,1818+ having input cables labelled CVBS, S-VIDEO, AUDIO(L), AUDIO(R)1919+2020+ * EasyCAP002 4-Channel USB 2.0 DVR, having input cables labelled2121+ 1, 2, 3, 4 and an unlabelled input cable for a microphone.2222+2323+2424+BUILD OPTIONS AND DEPENDENCIES2525+------------------------------2626+2727+If the parameter EASYCAP_IS_VIDEODEV_CLIENT is undefined during compilation2828+the built module is entirely independent of the videodev module, and when2929+the EasyCAP is physically plugged into a USB port the special files3030+/dev/easycap0 and /dev/easysnd1 are created as video and sound sources3131+respectively.3232+3333+If the parameter EASYCAP_IS_VIDEODEV_CLIENT is defined during compilation3434+the built easycap module is configured to register with the videodev module,3535+in which case the special files created when the EasyCAP is plugged in are3636+/dev/video0 and /dev/easysnd0. Use of the easycap module as a client of3737+the videodev module has received very little testing as of June 2010.3838+3939+4040+KNOWN BUILD PROBLEMS4141+--------------------4242+4343+(1) Recent gcc versions may generate the message:4444+4545+ warning: the frame size of .... bytes is larger than 1024 bytes4646+4747+This warning can be suppressed by specifying in the Makefile:4848+4949+ EXTRA_CFLAGS += -Wframe-larger-than=81925050+5151+but it would be preferable to remove the cause of the warning.5252+5353+5454+KNOWN RUNTIME ISSUES5555+--------------------5656+5757+(1) Randomly (maybe 5 to 10% of occasions) the driver fails to produce any5858+output at start-up. Closing mplayer (or whatever the user program is) and5959+restarting it restores normal performance without any other remedial action6060+being necessary. The reason for this is not known.6161+6262+(2) Intentionally, this driver will not stream material which is unambiguously6363+identified by the hardware as copy-protected. The video output will freeze6464+within about a minute when this situation arises.6565+6666+(3) The controls for luminance, contrast, saturation, hue and volume may not6767+always work properly.6868+6969+(4) Reduced-resolution S-Video seems to suffer from moire artefacts. No7070+attempt has yet been made to rememdy this.7171+7272+7373+SUPPORTED TV STANDARDS AND RESOLUTIONS7474+--------------------------------------7575+7676+The following TV standards are natively supported by the hardware and are7777+usable as (for example) the "norm=" parameter in the mplayer command:7878+7979+ PAL_BGHIN, NTSC_N_443,8080+ PAL_Nc, NTSC_N,8181+ SECAM, NTSC_M, NTSC_M_JP,8282+ PAL_60, NTSC_443,8383+ PAL_M.8484+8585+The available picture sizes are:8686+8787+ at 25 frames per second: 720x576, 704x576, 640x480, 360x288, 320x240;8888+ at 30 frames per second: 720x480, 640x480, 360x240, 320x240;8989+9090+9191+WHAT'S TESTED AND WHAT'S NOT9292+----------------------------9393+9494+This driver is known to work with mplayer, mencoder, tvtime and sufficiently9595+recent versions of vlc. An interface to ffmpeg is implemented, but serious9696+audio-video synchronization problems remain.9797+9898+The driver is designed to support all the TV standards accepted by the9999+hardware, but as yet it has actually been tested on only a few of these.100100+101101+I have been unable to test and calibrate the S-video input myself because I102102+do not possess any equipment with S-video output.103103+104104+This driver does not understand the V4L1 IOCTL commands, so programs such105105+as camorama are not compatible. There are reports that the driver does106106+work with sufficiently recent (V4L2) versions of zoneminder, but I have not107107+attempted to confirm this myself.108108+109109+110110+UDEV RULES111111+----------112112+113113+In order that the special files /dev/easycap0 and /dev/easysnd1 are created114114+with conveniently relaxed permissions when the EasyCAP is plugged in, a file115115+is preferably to be provided in directory /etc/udev/rules.d with content:116116+117117+ACTION!="add|change", GOTO="easycap_rules_end"118118+ATTRS{idVendor}=="05e1", ATTRS{idProduct}=="0408", \119119+ MODE="0666", OWNER="root", GROUP="root"120120+LABEL="easycap_rules_end"121121+122122+123123+ACKNOWLEGEMENTS AND REFERENCES124124+------------------------------125125+This driver makes use of information contained in the Syntek Semicon DC-1125126126+Driver, presently maintained at http://sourceforge.net/projects/syntekdriver/127127+by Nicolas Vivien. Particularly useful has been a patch to the latter driver128128+provided by Ivor Hewitt in January 2009. The NTSC implementation is taken129129+from the work of Ben Trask.130130+
+632
drivers/staging/easycap/easycap.h
···11+/*****************************************************************************22+* *33+* easycap.h *44+* *55+*****************************************************************************/66+/*77+ *88+ * Copyright (C) 2010 R.M. Thomas <rmthomas@sciolus.org>99+ *1010+ *1111+ * This is free software; you can redistribute it and/or modify1212+ * it under the terms of the GNU General Public License as published by1313+ * the Free Software Foundation; either version 2 of the License, or1414+ * (at your option) any later version.1515+ *1616+ * The software is distributed in the hope that it will be useful,1717+ * but WITHOUT ANY WARRANTY; without even the implied warranty of1818+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the1919+ * GNU General Public License for more details.2020+ *2121+ * You should have received a copy of the GNU General Public License2222+ * along with this software; if not, write to the Free Software2323+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA2424+ *2525+*/2626+/*****************************************************************************/2727+/*---------------------------------------------------------------------------*/2828+/*2929+ * THE FOLLOWING PARAMETERS ARE UNDEFINED:3030+ *3131+ * EASYCAP_DEBUG3232+ * EASYCAP_IS_VIDEODEV_CLIENT3333+ * EASYCAP_NEEDS_USBVIDEO_H3434+ * EASYCAP_NEEDS_V4L2_DEVICE_H3535+ * EASYCAP_NEEDS_V4L2_FOPS3636+ *3737+ * IF REQUIRED THEY MUST BE EXTERNALLY DEFINED, FOR EXAMPLE AS COMPILER3838+ * OPTIONS.3939+ */4040+/*---------------------------------------------------------------------------*/4141+4242+#if (!defined(EASYCAP_H))4343+#define EASYCAP_H4444+4545+#if defined(EASYCAP_DEBUG)4646+#if (9 < EASYCAP_DEBUG)4747+#error Debug levels 0 to 9 are okay.\4848+ To achieve higher levels, remove this trap manually from easycap.h4949+#endif5050+#endif /*EASYCAP_DEBUG*/5151+/*---------------------------------------------------------------------------*/5252+/*5353+ * THESE ARE FOR MAINTENANCE ONLY - NORMALLY UNDEFINED:5454+ */5555+/*---------------------------------------------------------------------------*/5656+#undef PREFER_NTSC5757+#undef EASYCAP_TESTCARD5858+#undef EASYCAP_TESTTONE5959+#undef LOCKFRAME6060+#undef NOREADBACK6161+#undef AUDIOTIME6262+/*---------------------------------------------------------------------------*/6363+/*6464+ *6565+ * DEFINE BRIDGER TO ACTIVATE THE ROUTINE FOR BRIDGING VIDEOTAPE DROPOUTS.6666+ *6767+ * *** UNDER DEVELOPMENT/TESTING - NOT READY YET!***6868+ *6969+ */7070+/*---------------------------------------------------------------------------*/7171+#undef BRIDGER7272+/*---------------------------------------------------------------------------*/7373+7474+#include <linux/kernel.h>7575+#include <linux/errno.h>7676+#include <linux/init.h>7777+#include <linux/slab.h>7878+#include <linux/module.h>7979+#include <linux/kref.h>8080+#include <linux/smp_lock.h>8181+#include <linux/usb.h>8282+#include <linux/uaccess.h>8383+8484+#include <linux/i2c.h>8585+#include <linux/version.h>8686+#include <linux/workqueue.h>8787+#include <linux/poll.h>8888+#include <linux/mm.h>8989+#include <linux/fs.h>9090+#include <linux/delay.h>9191+#include <linux/types.h>9292+9393+/*vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv*/9494+#if defined(EASYCAP_IS_VIDEODEV_CLIENT)9595+#if (!defined(__OLD_VIDIOC_))9696+#define __OLD_VIDIOC_9797+#endif /* !defined(__OLD_VIDIOC_) */9898+9999+#include <media/v4l2-dev.h>100100+101101+#if defined(EASYCAP_NEEDS_V4L2_DEVICE_H)102102+#include <media/v4l2-device.h>103103+#endif /*EASYCAP_NEEDS_V4L2_DEVICE_H*/104104+#endif /*EASYCAP_IS_VIDEODEV_CLIENT*/105105+/*^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^*/106106+107107+#if (!defined(__OLD_VIDIOC_))108108+#define __OLD_VIDIOC_109109+#endif /* !defined(__OLD_VIDIOC_) */110110+#include <linux/videodev2.h>111111+112112+#include <linux/soundcard.h>113113+114114+#if defined(EASYCAP_NEEDS_USBVIDEO_H)115115+#include <config/video/usbvideo.h>116116+#endif /*EASYCAP_NEEDS_USBVIDEO_H*/117117+118118+#if (!defined(PAGE_SIZE))119119+#error "PAGE_SIZE not defined"120120+#endif121121+122122+#define STRINGIZE_AGAIN(x) #x123123+#define STRINGIZE(x) STRINGIZE_AGAIN(x)124124+125125+/*---------------------------------------------------------------------------*/126126+/* VENDOR, PRODUCT: Syntek Semiconductor Co., Ltd127127+ *128128+ * EITHER EasyCAP USB 2.0 Video Adapter with Audio, Model No. DC60129129+ * with input cabling: AUDIO(L), AUDIO(R), CVBS, S-VIDEO.130130+ *131131+ * OR EasyCAP 4CHANNEL USB 2.0 DVR, Model No. EasyCAP002132132+ * with input cabling: MICROPHONE, CVBS1, CVBS2, CVBS3, CVBS4.133133+ */134134+/*---------------------------------------------------------------------------*/135135+#define USB_EASYCAP_VENDOR_ID 0x05e1136136+#define USB_EASYCAP_PRODUCT_ID 0x0408137137+138138+#define EASYCAP_DRIVER_VERSION "0.8"139139+#define EASYCAP_DRIVER_DESCRIPTION "easycapdc60"140140+141141+#define USB_SKEL_MINOR_BASE 192142142+#define VIDEO_DEVICE_MANY 8143143+144144+/*---------------------------------------------------------------------------*/145145+/*146146+ * DEFAULT LUMINANCE, CONTRAST, SATURATION AND HUE147147+ */148148+/*---------------------------------------------------------------------------*/149149+#define SAA_0A_DEFAULT 0x7F150150+#define SAA_0B_DEFAULT 0x3F151151+#define SAA_0C_DEFAULT 0x2F152152+#define SAA_0D_DEFAULT 0x00153153+/*---------------------------------------------------------------------------*/154154+/*155155+ * VIDEO STREAMING PARAMETERS:156156+ * USB 2.0 PROVIDES FOR HIGH-BANDWIDTH ENDPOINTS WITH AN UPPER LIMIT157157+ * OF 3072 BYTES PER MICROFRAME for wMaxPacketSize.158158+ */159159+/*---------------------------------------------------------------------------*/160160+#define VIDEO_ISOC_BUFFER_MANY 16161161+#define VIDEO_ISOC_ORDER 3162162+#define VIDEO_ISOC_FRAMESPERDESC ((unsigned int) 1 << VIDEO_ISOC_ORDER)163163+#define USB_2_0_MAXPACKETSIZE 3072164164+#if (USB_2_0_MAXPACKETSIZE > PAGE_SIZE)165165+#error video_isoc_buffer[.] will not be big enough166166+#endif167167+/*---------------------------------------------------------------------------*/168168+/*169169+ * VIDEO BUFFERS170170+ */171171+/*---------------------------------------------------------------------------*/172172+#define FIELD_BUFFER_SIZE (203 * PAGE_SIZE)173173+#define FRAME_BUFFER_SIZE (405 * PAGE_SIZE)174174+#define FIELD_BUFFER_MANY 4175175+#define FRAME_BUFFER_MANY 6176176+/*---------------------------------------------------------------------------*/177177+/*178178+ * AUDIO STREAMING PARAMETERS179179+ */180180+/*---------------------------------------------------------------------------*/181181+#define AUDIO_ISOC_BUFFER_MANY 16182182+#define AUDIO_ISOC_ORDER 3183183+#define AUDIO_ISOC_BUFFER_SIZE (PAGE_SIZE << AUDIO_ISOC_ORDER)184184+/*---------------------------------------------------------------------------*/185185+/*186186+ * AUDIO BUFFERS187187+ */188188+/*---------------------------------------------------------------------------*/189189+#define AUDIO_FRAGMENT_MANY 32190190+/*---------------------------------------------------------------------------*/191191+/*192192+ * STRUCTURE DEFINITIONS193193+ */194194+/*---------------------------------------------------------------------------*/195195+struct data_buffer {196196+struct list_head list_head;197197+void *pgo;198198+void *pto;199199+__u16 kount;200200+};201201+/*---------------------------------------------------------------------------*/202202+struct data_urb {203203+struct list_head list_head;204204+struct urb *purb;205205+int isbuf;206206+int length;207207+};208208+/*---------------------------------------------------------------------------*/209209+/*210210+ * easycap.ilk == 0 => CVBS+S-VIDEO HARDWARE, AUDIO wMaxPacketSize=256211211+ * easycap.ilk == 2 => CVBS+S-VIDEO HARDWARE, AUDIO wMaxPacketSize=9212212+ * easycap.ilk == 3 => FOUR-CVBS HARDWARE, AUDIO wMaxPacketSize=9213213+ */214214+/*---------------------------------------------------------------------------*/215215+struct easycap {216216+217217+int ilk;218218+bool microphone;219219+220220+/*vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv*/221221+#if defined(EASYCAP_IS_VIDEODEV_CLIENT)222222+struct video_device *pvideo_device;223223+#endif /*EASYCAP_IS_VIDEODEV_CLIENT*/224224+/*^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^*/225225+226226+struct usb_device *pusb_device;227227+struct usb_interface *pusb_interface;228228+229229+struct kref kref;230230+231231+struct mutex mutex_mmap_video[FRAME_BUFFER_MANY];232232+struct mutex mutex_timeval0;233233+struct mutex mutex_timeval1;234234+235235+int queued[FRAME_BUFFER_MANY];236236+int done[FRAME_BUFFER_MANY];237237+238238+wait_queue_head_t wq_video;239239+wait_queue_head_t wq_audio;240240+241241+int input;242242+int polled;243243+int standard_offset;244244+int format_offset;245245+246246+int fps;247247+int usec;248248+int tolerate;249249+int merit[180];250250+251251+struct timeval timeval0;252252+struct timeval timeval1;253253+struct timeval timeval2;254254+struct timeval timeval7;255255+long long int dnbydt;256256+257257+int video_interface;258258+int video_altsetting_on;259259+int video_altsetting_off;260260+int video_endpointnumber;261261+int video_isoc_maxframesize;262262+int video_isoc_buffer_size;263263+int video_isoc_framesperdesc;264264+265265+int video_isoc_streaming;266266+int video_isoc_sequence;267267+int video_idle;268268+int video_eof;269269+int video_junk;270270+271271+int fudge;272272+273273+struct data_buffer video_isoc_buffer[VIDEO_ISOC_BUFFER_MANY];274274+struct data_buffer \275275+ field_buffer[FIELD_BUFFER_MANY][(FIELD_BUFFER_SIZE/PAGE_SIZE)];276276+struct data_buffer \277277+ frame_buffer[FRAME_BUFFER_MANY][(FRAME_BUFFER_SIZE/PAGE_SIZE)];278278+279279+struct list_head urb_video_head;280280+struct list_head *purb_video_head;281281+282282+int vma_many;283283+284284+/*---------------------------------------------------------------------------*/285285+/*286286+ * BUFFER INDICATORS287287+ */288288+/*---------------------------------------------------------------------------*/289289+int field_fill; /* Field buffer being filled by easycap_complete(). */290290+ /* Bumped only by easycap_complete(). */291291+int field_page; /* Page of field buffer page being filled by */292292+ /* easycap_complete(). */293293+int field_read; /* Field buffer to be read by field2frame(). */294294+ /* Bumped only by easycap_complete(). */295295+int frame_fill; /* Frame buffer being filled by field2frame(). */296296+ /* Bumped only by easycap_dqbuf() when */297297+ /* field2frame() has created a complete frame. */298298+int frame_read; /* Frame buffer offered to user by DQBUF. */299299+ /* Set only by easycap_dqbuf() to trail frame_fill.*/300300+int frame_lock; /* Flag set to 1 by DQBUF and cleared by QBUF */301301+/*---------------------------------------------------------------------------*/302302+/*303303+ * IMAGE PROPERTIES304304+ */305305+/*---------------------------------------------------------------------------*/306306+__u32 pixelformat;307307+__u32 field;308308+int width;309309+int height;310310+int bytesperpixel;311311+bool byteswaporder;312312+bool decimatepixel;313313+bool offerfields;314314+int frame_buffer_used;315315+int frame_buffer_many;316316+int videofieldamount;317317+318318+int brightness;319319+int contrast;320320+int saturation;321321+int hue;322322+323323+int allocation_video_urb;324324+int allocation_video_page;325325+int allocation_video_struct;326326+int registered_video;327327+/*---------------------------------------------------------------------------*/328328+/*329329+ * SOUND PROPERTIES330330+ */331331+/*---------------------------------------------------------------------------*/332332+int audio_interface;333333+int audio_altsetting_on;334334+int audio_altsetting_off;335335+int audio_endpointnumber;336336+int audio_isoc_maxframesize;337337+int audio_isoc_buffer_size;338338+int audio_isoc_framesperdesc;339339+340340+int audio_isoc_streaming;341341+int audio_idle;342342+int audio_eof;343343+int volume;344344+int mute;345345+346346+struct data_buffer audio_isoc_buffer[AUDIO_ISOC_BUFFER_MANY];347347+348348+struct list_head urb_audio_head;349349+struct list_head *purb_audio_head;350350+/*---------------------------------------------------------------------------*/351351+/*352352+ * BUFFER INDICATORS353353+ */354354+/*---------------------------------------------------------------------------*/355355+int audio_fill; /* Audio buffer being filled by easysnd_complete(). */356356+ /* Bumped only by easysnd_complete(). */357357+int audio_read; /* Audio buffer page being read by easysnd_read(). */358358+ /* Set by easysnd_read() to trail audio_fill by */359359+ /* one fragment. */360360+/*---------------------------------------------------------------------------*/361361+/*362362+ * SOUND PROPERTIES363363+ */364364+/*---------------------------------------------------------------------------*/365365+366366+int audio_buffer_many;367367+368368+int allocation_audio_urb;369369+int allocation_audio_page;370370+int allocation_audio_struct;371371+int registered_audio;372372+373373+long long int audio_sample;374374+long long int audio_niveau;375375+long long int audio_square;376376+377377+struct data_buffer audio_buffer[];378378+};379379+/*---------------------------------------------------------------------------*/380380+struct easycap_standard {381381+__u16 mask;382382+struct v4l2_standard v4l2_standard;383383+};384384+struct easycap_format {385385+__u16 mask;386386+char name[128];387387+struct v4l2_format v4l2_format;388388+};389389+/*---------------------------------------------------------------------------*/390390+/*391391+ * VIDEO FUNCTION PROTOTYPES392392+ */393393+/*---------------------------------------------------------------------------*/394394+void easycap_complete(struct urb *);395395+int easycap_open(struct inode *, struct file *);396396+int easycap_release(struct inode *, struct file *);397397+int easycap_ioctl(struct inode *, struct file *, \398398+ unsigned int, unsigned long);399399+400400+/*vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv*/401401+#if defined(EASYCAP_IS_VIDEODEV_CLIENT)402402+int easycap_open_noinode(struct file *);403403+int easycap_release_noinode(struct file *);404404+long easycap_ioctl_noinode(struct file *, \405405+ unsigned int, unsigned long);406406+int videodev_release(struct video_device *);407407+#endif /*EASYCAP_IS_VIDEODEV_CLIENT*/408408+/*^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^*/409409+410410+unsigned int easycap_poll(struct file *, poll_table *);411411+int easycap_mmap(struct file *, struct vm_area_struct *);412412+int easycap_usb_probe(struct usb_interface *, \413413+ const struct usb_device_id *);414414+void easycap_usb_disconnect(struct usb_interface *);415415+void easycap_delete(struct kref *);416416+417417+void easycap_vma_open(struct vm_area_struct *);418418+void easycap_vma_close(struct vm_area_struct *);419419+int easycap_vma_fault(struct vm_area_struct *, struct vm_fault *);420420+int easycap_dqbuf(struct easycap *, int);421421+int submit_video_urbs(struct easycap *);422422+int kill_video_urbs(struct easycap *);423423+int field2frame(struct easycap *);424424+int redaub(struct easycap *, void *, void *, \425425+ int, int, __u8, __u8, bool);426426+void debrief(struct easycap *);427427+void sayreadonly(struct easycap *);428428+void easycap_testcard(struct easycap *, int);429429+int explain_ioctl(__u32);430430+int explain_cid(__u32);431431+int fillin_formats(void);432432+int adjust_standard(struct easycap *, v4l2_std_id);433433+int adjust_format(struct easycap *, __u32, __u32, __u32, \434434+ int, bool);435435+int adjust_brightness(struct easycap *, int);436436+int adjust_contrast(struct easycap *, int);437437+int adjust_saturation(struct easycap *, int);438438+int adjust_hue(struct easycap *, int);439439+int adjust_volume(struct easycap *, int);440440+/*---------------------------------------------------------------------------*/441441+/*442442+ * AUDIO FUNCTION PROTOTYPES443443+ */444444+/*---------------------------------------------------------------------------*/445445+void easysnd_complete(struct urb *);446446+ssize_t easysnd_read(struct file *, char __user *, size_t, loff_t *);447447+int easysnd_open(struct inode *, struct file *);448448+int easysnd_release(struct inode *, struct file *);449449+int easysnd_ioctl(struct inode *, struct file *, \450450+ unsigned int, unsigned long);451451+unsigned int easysnd_poll(struct file *, poll_table *);452452+void easysnd_delete(struct kref *);453453+int submit_audio_urbs(struct easycap *);454454+int kill_audio_urbs(struct easycap *);455455+void easysnd_testtone(struct easycap *, int);456456+int audio_setup(struct easycap *);457457+/*---------------------------------------------------------------------------*/458458+/*459459+ * LOW-LEVEL FUNCTION PROTOTYPES460460+ */461461+/*---------------------------------------------------------------------------*/462462+int audio_gainget(struct usb_device *);463463+int audio_gainset(struct usb_device *, __s8);464464+465465+int set_interface(struct usb_device *, __u16);466466+int wakeup_device(struct usb_device *);467467+int confirm_resolution(struct usb_device *);468468+int confirm_stream(struct usb_device *);469469+470470+int setup_stk(struct usb_device *);471471+int setup_saa(struct usb_device *);472472+int setup_vt(struct usb_device *);473473+int check_stk(struct usb_device *);474474+int check_saa(struct usb_device *);475475+int ready_saa(struct usb_device *);476476+int merit_saa(struct usb_device *);477477+int check_vt(struct usb_device *);478478+int select_input(struct usb_device *, int, int);479479+int set_resolution(struct usb_device *, \480480+ __u16, __u16, __u16, __u16);481481+482482+int read_saa(struct usb_device *, __u16);483483+int read_stk(struct usb_device *, __u32);484484+int write_saa(struct usb_device *, __u16, __u16);485485+int wait_i2c(struct usb_device *);486486+int write_000(struct usb_device *, __u16, __u16);487487+int start_100(struct usb_device *);488488+int stop_100(struct usb_device *);489489+int write_300(struct usb_device *);490490+int read_vt(struct usb_device *, __u16);491491+int write_vt(struct usb_device *, __u16, __u16);492492+493493+int set2to78(struct usb_device *);494494+int set2to93(struct usb_device *);495495+496496+int regset(struct usb_device *, __u16, __u16);497497+int regget(struct usb_device *, __u16, void *);498498+/*---------------------------------------------------------------------------*/499499+struct signed_div_result {500500+long long int quotient;501501+unsigned long long int remainder;502502+} signed_div(long long int, long long int);503503+/*---------------------------------------------------------------------------*/504504+/*505505+ * IT IS ESSENTIAL THAT EVEN-NUMBERED STANDARDS ARE 25 FRAMES PER SECOND,506506+ * ODD-NUMBERED STANDARDS ARE 30 FRAMES PER SECOND.507507+ * THE NUMBERING OF STANDARDS MUST NOT BE CHANGED WITHOUT DUE CARE. NOT508508+ * ONLY MUST THE PARAMETER509509+ * STANDARD_MANY510510+ * BE CHANGED TO CORRESPOND TO THE NEW NUMBER OF STANDARDS, BUT ALSO THE511511+ * NUMBERING MUST REMAIN AN UNBROKEN ASCENDING SEQUENCE: DUMMY STANDARDS512512+ * MAY NEED TO BE ADDED. APPROPRIATE CHANGES WILL ALWAYS BE REQUIRED IN513513+ * ROUTINE fillin_formats() AND POSSIBLY ELSEWHERE. BEWARE.514514+ */515515+/*---------------------------------------------------------------------------*/516516+#define PAL_BGHIN 0517517+#define PAL_Nc 2518518+#define SECAM 4519519+#define NTSC_N 6520520+#define NTSC_N_443 8521521+#define NTSC_M 1522522+#define NTSC_443 3523523+#define NTSC_M_JP 5524524+#define PAL_60 7525525+#define PAL_M 9526526+#define STANDARD_MANY 10527527+/*---------------------------------------------------------------------------*/528528+/*529529+ * ENUMS530530+ */531531+/*---------------------------------------------------------------------------*/532532+enum {533533+AT_720x576,534534+AT_704x576,535535+AT_640x480,536536+AT_720x480,537537+AT_360x288,538538+AT_320x240,539539+AT_360x240,540540+RESOLUTION_MANY541541+};542542+enum {543543+FMT_UYVY,544544+FMT_YUY2,545545+FMT_RGB24,546546+FMT_RGB32,547547+FMT_BGR24,548548+FMT_BGR32,549549+PIXELFORMAT_MANY550550+};551551+enum {552552+FIELD_NONE,553553+FIELD_INTERLACED,554554+FIELD_ALTERNATE,555555+INTERLACE_MANY556556+};557557+#define SETTINGS_MANY (STANDARD_MANY * \558558+ RESOLUTION_MANY * \559559+ 2 * \560560+ PIXELFORMAT_MANY * \561561+ INTERLACE_MANY)562562+/*---------------------------------------------------------------------------*/563563+/*564564+ * MACROS565565+ */566566+/*---------------------------------------------------------------------------*/567567+#define GET(X, Y, Z) do { \568568+ int rc; \569569+ *(Z) = (__u16)0; \570570+ rc = regget(X, Y, Z); \571571+ if (0 > rc) { \572572+ JOT(8, ":-(%i\n", __LINE__); return(rc); \573573+ } \574574+} while (0)575575+576576+#define SET(X, Y, Z) do { \577577+ int rc; \578578+ rc = regset(X, Y, Z); \579579+ if (0 > rc) { \580580+ JOT(8, ":-(%i\n", __LINE__); return(rc); \581581+ } \582582+} while (0)583583+/*---------------------------------------------------------------------------*/584584+585585+#define SAY(format, args...) do { \586586+ printk(KERN_DEBUG "easycap: %s: " format, __func__, ##args); \587587+} while (0)588588+589589+590590+#if defined(EASYCAP_DEBUG)591591+#define JOT(n, format, args...) do { \592592+ if (n <= easycap_debug) { \593593+ printk(KERN_DEBUG "easycap: %s: " format, __func__, ##args); \594594+ } \595595+} while (0)596596+#else597597+#define JOT(n, format, args...) do {} while (0)598598+#endif /*EASYCAP_DEBUG*/599599+600600+#define POUT JOT(8, ":-(in file %s line %4i\n", __FILE__, __LINE__)601601+602602+#define MICROSECONDS(X, Y) \603603+ ((1000000*((long long int)(X.tv_sec - Y.tv_sec))) + \604604+ (long long int)(X.tv_usec - Y.tv_usec))605605+606606+/*---------------------------------------------------------------------------*/607607+/*608608+ * (unsigned char *)P pointer to next byte pair609609+ * (long int *)X pointer to accumulating count610610+ * (long int *)Y pointer to accumulating sum611611+ * (long long int *)Z pointer to accumulating sum of squares612612+ */613613+/*---------------------------------------------------------------------------*/614614+#define SUMMER(P, X, Y, Z) do { \615615+ unsigned char *p; \616616+ unsigned int u0, u1, u2; \617617+ long int s; \618618+ p = (unsigned char *)(P); \619619+ u0 = (unsigned int) (*p); \620620+ u1 = (unsigned int) (*(p + 1)); \621621+ u2 = (unsigned int) ((u1 << 8) | u0); \622622+ if (0x8000 & u2) \623623+ s = -(long int)(0x7FFF & (~u2)); \624624+ else \625625+ s = (long int)(0x7FFF & u2); \626626+ *((X)) += (long int) 1; \627627+ *((Y)) += (long int) s; \628628+ *((Z)) += ((long long int)(s) * (long long int)(s)); \629629+} while (0)630630+/*---------------------------------------------------------------------------*/631631+632632+#endif /*EASYCAP_H*/
+27
drivers/staging/easycap/easycap_debug.h
···11+/*****************************************************************************22+* *33+* easycap_debug.h *44+* *55+*****************************************************************************/66+/*77+ *88+ * Copyright (C) 2010 R.M. Thomas <rmthomas@sciolus.org>99+ *1010+ *1111+ * This is free software; you can redistribute it and/or modify1212+ * it under the terms of the GNU General Public License as published by1313+ * the Free Software Foundation; either version 2 of the License, or1414+ * (at your option) any later version.1515+ *1616+ * The software is distributed in the hope that it will be useful,1717+ * but WITHOUT ANY WARRANTY; without even the implied warranty of1818+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the1919+ * GNU General Public License for more details.2020+ *2121+ * You should have received a copy of the GNU General Public License2222+ * along with this software; if not, write to the Free Software2323+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA2424+ *2525+*/2626+/*****************************************************************************/2727+extern int easycap_debug;
···11+/*****************************************************************************22+* *33+* easycap_ioctl.h *44+* *55+*****************************************************************************/66+/*77+ *88+ * Copyright (C) 2010 R.M. Thomas <rmthomas@sciolus.org>99+ *1010+ *1111+ * This is free software; you can redistribute it and/or modify1212+ * it under the terms of the GNU General Public License as published by1313+ * the Free Software Foundation; either version 2 of the License, or1414+ * (at your option) any later version.1515+ *1616+ * The software is distributed in the hope that it will be useful,1717+ * but WITHOUT ANY WARRANTY; without even the implied warranty of1818+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the1919+ * GNU General Public License for more details.2020+ *2121+ * You should have received a copy of the GNU General Public License2222+ * along with this software; if not, write to the Free Software2323+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA2424+ *2525+*/2626+/*****************************************************************************/2727+extern struct easycap_format easycap_format[];2828+extern struct v4l2_queryctrl easycap_control[];2929+extern unsigned int audio_bytes_per_fragment;
+1057
drivers/staging/easycap/easycap_low.c
···11+/*****************************************************************************22+* *33+* *44+* easycap_low.c *55+* *66+* *77+*****************************************************************************/88+/*99+ *1010+ * Copyright (C) 2010 R.M. Thomas <rmthomas@sciolus.org>1111+ *1212+ *1313+ * This is free software; you can redistribute it and/or modify1414+ * it under the terms of the GNU General Public License as published by1515+ * the Free Software Foundation; either version 2 of the License, or1616+ * (at your option) any later version.1717+ *1818+ * The software is distributed in the hope that it will be useful,1919+ * but WITHOUT ANY WARRANTY; without even the implied warranty of2020+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the2121+ * GNU General Public License for more details.2222+ *2323+ * You should have received a copy of the GNU General Public License2424+ * along with this software; if not, write to the Free Software2525+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA2626+ *2727+*/2828+/*****************************************************************************/2929+/*3030+ * ACKNOWLEGEMENTS AND REFERENCES3131+ * ------------------------------3232+ * This driver makes use of register information contained in the Syntek3333+ * Semicon DC-1125 driver hosted at3434+ * http://sourceforge.net/projects/syntekdriver/.3535+ * Particularly useful has been a patch to the latter driver provided by3636+ * Ivor Hewitt in January 2009. The NTSC implementation is taken from the3737+ * work of Ben Trask.3838+*/3939+/****************************************************************************/4040+4141+#include "easycap_debug.h"4242+#include "easycap.h"4343+4444+/*--------------------------------------------------------------------------*/4545+const struct stk1160config { int reg; int set; } stk1160config[256] = {4646+ {0x000, 0x0098},4747+ {0x002, 0x0093},4848+4949+ {0x001, 0x0003},5050+ {0x003, 0x0080},5151+ {0x00D, 0x0000},5252+ {0x00F, 0x0002},5353+ {0x018, 0x0010},5454+ {0x019, 0x0000},5555+ {0x01A, 0x0014},5656+ {0x01B, 0x000E},5757+ {0x01C, 0x0046},5858+5959+ {0x100, 0x0033},6060+ {0x103, 0x0000},6161+ {0x104, 0x0000},6262+ {0x105, 0x0000},6363+ {0x106, 0x0000},6464+6565+#if defined(PREFER_NTSC)6666+6767+#undef OLDMARGIN6868+#if defined(OLDMARGIN)6969+ {0x110, 0x0008},7070+#else7171+ {0x110, 0x0014},7272+#endif /*OLDMARGIN*/7373+7474+ {0x111, 0x0000},7575+ {0x112, 0x0003},7676+ {0x113, 0x0000},7777+7878+#if defined(OLDMARGIN)7979+ {0x114, 0x0508},8080+#else8181+ {0x114, 0x0514},8282+#endif /*OLDMARGIN*/8383+8484+ {0x115, 0x0005},8585+ {0x116, 0x00F3},8686+ {0x117, 0x0000},8787+8888+#else /* ! PREFER_NTSC*/8989+9090+#if defined(OLDMARGIN)9191+ {0x110, 0x0008},9292+#else9393+ {0x110, 0x0014},9494+#endif /*OLDMARGIN*/9595+9696+ {0x111, 0x0000},9797+ {0x112, 0x0020},9898+ {0x113, 0x0000},9999+100100+#if defined(OLDMARGIN)101101+ {0x114, 0x0508},102102+#else103103+ {0x114, 0x0514},104104+#endif /*OLDMARGIN*/105105+106106+ {0x115, 0x0005},107107+ {0x116, 0x0110},108108+ {0x117, 0x0001},109109+110110+#endif /* ! PREFER_NTSC*/111111+112112+ {0x202, 0x000F},113113+ {0x203, 0x004A},114114+ {0x2FF, 0x0000},115115+/*---------------------------------------------------------------------------*/116116+ {0xFFF, 0xFFFF}117117+ };118118+/*--------------------------------------------------------------------------*/119119+const struct saa7113config { int reg; int set; } saa7113config[256] = {120120+ {0x01, 0x08},121121+ {0x02, 0x80},122122+ {0x03, 0x33},123123+ {0x04, 0x00},124124+ {0x05, 0x00},125125+ {0x06, 0xE9},126126+ {0x07, 0x0D},127127+#if defined(PREFER_NTSC)128128+ {0x08, 0x78},129129+#else130130+ {0x08, 0x38},131131+#endif /* ! PREFER_NTSC*/132132+ {0x09, 0x00},133133+ {0x0A, SAA_0A_DEFAULT},134134+ {0x0B, SAA_0B_DEFAULT},135135+ {0x0C, SAA_0C_DEFAULT},136136+ {0x0D, SAA_0D_DEFAULT},137137+ {0x0E, 0x01},138138+ {0x0F, 0x36},139139+ {0x10, 0x00},140140+ {0x11, 0x0C},141141+ {0x12, 0xE7},142142+ {0x13, 0x00},143143+ {0x15, 0x00},144144+ {0x16, 0x00},145145+#if defined(PREFER_NTSC)146146+ {0x40, 0x82},147147+#else148148+ {0x40, 0x02},149149+#endif /* ! PREFER_NTSC*/150150+ {0x41, 0xFF},151151+ {0x42, 0xFF},152152+ {0x43, 0xFF},153153+ {0x44, 0xFF},154154+ {0x45, 0xFF},155155+ {0x46, 0xFF},156156+ {0x47, 0xFF},157157+ {0x48, 0xFF},158158+ {0x49, 0xFF},159159+ {0x4A, 0xFF},160160+ {0x4B, 0xFF},161161+ {0x4C, 0xFF},162162+ {0x4D, 0xFF},163163+ {0x4E, 0xFF},164164+ {0x4F, 0xFF},165165+ {0x50, 0xFF},166166+ {0x51, 0xFF},167167+ {0x52, 0xFF},168168+ {0x53, 0xFF},169169+ {0x54, 0xFF},170170+ {0x55, 0xFF},171171+ {0x56, 0xFF},172172+ {0x57, 0xFF},173173+ {0x58, 0x40},174174+ {0x59, 0x54},175175+#if defined(PREFER_NTSC)176176+ {0x5A, 0x0A},177177+#else178178+ {0x5A, 0x07},179179+#endif /* ! PREFER_NTSC*/180180+ {0x5B, 0x83},181181+ {0xFF, 0xFF}182182+ };183183+/*--------------------------------------------------------------------------*/184184+185185+/****************************************************************************/186186+int187187+confirm_resolution(struct usb_device *p)188188+{189189+__u8 get0, get1, get2, get3, get4, get5, get6, get7;190190+GET(p, 0x0110, &get0);191191+GET(p, 0x0111, &get1);192192+GET(p, 0x0112, &get2);193193+GET(p, 0x0113, &get3);194194+GET(p, 0x0114, &get4);195195+GET(p, 0x0115, &get5);196196+GET(p, 0x0116, &get6);197197+GET(p, 0x0117, &get7);198198+JOT(8, "0x%03X, 0x%03X, " \199199+ "0x%03X, 0x%03X, " \200200+ "0x%03X, 0x%03X, " \201201+ "0x%03X, 0x%03X\n", \202202+ get0, get1, get2, get3, get4, get5, get6, get7);203203+JOT(8, "....cf PAL_720x526: " \204204+ "0x%03X, 0x%03X, " \205205+ "0x%03X, 0x%03X, " \206206+ "0x%03X, 0x%03X, " \207207+ "0x%03X, 0x%03X\n", \208208+ 0x000, 0x000, 0x001, 0x000, 0x5A0, 0x005, 0x121, 0x001);209209+JOT(8, "....cf PAL_704x526: " \210210+ "0x%03X, 0x%03X, " \211211+ "0x%03X, 0x%03X, " \212212+ "0x%03X, 0x%03X, " \213213+ "0x%03X, 0x%03X\n", \214214+ 0x004, 0x000, 0x001, 0x000, 0x584, 0x005, 0x121, 0x001);215215+JOT(8, "....cf VGA_640x480: " \216216+ "0x%03X, 0x%03X, " \217217+ "0x%03X, 0x%03X, " \218218+ "0x%03X, 0x%03X, " \219219+ "0x%03X, 0x%03X\n", \220220+ 0x008, 0x000, 0x020, 0x000, 0x508, 0x005, 0x110, 0x001);221221+return 0;222222+}223223+/****************************************************************************/224224+int225225+confirm_stream(struct usb_device *p)226226+{227227+__u16 get2;228228+__u8 igot;229229+230230+GET(p, 0x0100, &igot); get2 = 0x80 & igot;231231+if (0x80 == get2)232232+ JOT(8, "confirm_stream: OK\n");233233+else234234+ JOT(8, "confirm_stream: STUCK\n");235235+return 0;236236+}237237+/****************************************************************************/238238+int239239+setup_stk(struct usb_device *p)240240+{241241+int i0;242242+243243+i0 = 0;244244+while (0xFFF != stk1160config[i0].reg) {245245+ SET(p, stk1160config[i0].reg, stk1160config[i0].set);246246+ i0++;247247+ }248248+249249+write_300(p);250250+251251+return 0;252252+}253253+/****************************************************************************/254254+int255255+setup_saa(struct usb_device *p)256256+{257257+int i0, ir;258258+259259+260260+set2to78(p);261261+262262+263263+i0 = 0;264264+while (0xFF != saa7113config[i0].reg) {265265+ ir = write_saa(p, saa7113config[i0].reg, saa7113config[i0].set);266266+ i0++;267267+ }268268+return 0;269269+}270270+/****************************************************************************/271271+int272272+write_000(struct usb_device *p, __u16 set2, __u16 set0)273273+{274274+__u8 igot0, igot2;275275+276276+GET(p, 0x0002, &igot2);277277+GET(p, 0x0000, &igot0);278278+SET(p, 0x0002, set2);279279+SET(p, 0x0000, set0);280280+return 0;281281+}282282+/****************************************************************************/283283+int284284+write_saa(struct usb_device *p, __u16 reg0, __u16 set0)285285+{286286+SET(p, 0x200, 0x00);287287+SET(p, 0x204, reg0);288288+SET(p, 0x205, set0);289289+SET(p, 0x200, 0x01);290290+return wait_i2c(p);291291+}292292+/****************************************************************************/293293+/*--------------------------------------------------------------------------*/294294+/*295295+ * REGISTER 500: SETTING VALUE TO 0x008B READS FROM VT1612A (?)296296+ * REGISTER 500: SETTING VALUE TO 0x008C WRITES TO VT1612A297297+ * REGISTER 502: LEAST SIGNIFICANT BYTE OF VALUE TO SET298298+ * REGISTER 503: MOST SIGNIFICANT BYTE OF VALUE TO SET299299+ * REGISTER 504: TARGET ADDRESS ON VT1612A300300+ */301301+/*--------------------------------------------------------------------------*/302302+int303303+write_vt(struct usb_device *p, __u16 reg0, __u16 set0)304304+{305305+__u8 igot;306306+__u16 got502, got503;307307+__u16 set502, set503;308308+309309+SET(p, 0x0504, reg0);310310+SET(p, 0x0500, 0x008B);311311+312312+GET(p, 0x0502, &igot); got502 = (0xFF & igot);313313+GET(p, 0x0503, &igot); got503 = (0xFF & igot);314314+315315+JOT(16, "write_vt(., 0x%04X, 0x%04X): was 0x%04X\n", \316316+ reg0, set0, ((got503 << 8) | got502));317317+318318+set502 = (0x00FF & set0);319319+set503 = ((0xFF00 & set0) >> 8);320320+321321+SET(p, 0x0504, reg0);322322+SET(p, 0x0502, set502);323323+SET(p, 0x0503, set503);324324+SET(p, 0x0500, 0x008C);325325+326326+return 0;327327+}328328+/****************************************************************************/329329+/*--------------------------------------------------------------------------*/330330+/*331331+ * REGISTER 500: SETTING VALUE TO 0x008B READS FROM VT1612A (?)332332+ * REGISTER 500: SETTING VALUE TO 0x008C WRITES TO VT1612A333333+ * REGISTER 502: LEAST SIGNIFICANT BYTE OF VALUE TO GET334334+ * REGISTER 503: MOST SIGNIFICANT BYTE OF VALUE TO GET335335+ * REGISTER 504: TARGET ADDRESS ON VT1612A336336+ */337337+/*--------------------------------------------------------------------------*/338338+int339339+read_vt(struct usb_device *p, __u16 reg0)340340+{341341+__u8 igot;342342+__u16 got502, got503;343343+344344+SET(p, 0x0504, reg0);345345+SET(p, 0x0500, 0x008B);346346+347347+GET(p, 0x0502, &igot); got502 = (0xFF & igot);348348+GET(p, 0x0503, &igot); got503 = (0xFF & igot);349349+350350+JOT(16, "read_vt(., 0x%04X): has 0x%04X\n", reg0, ((got503 << 8) | got502));351351+352352+return (got503 << 8) | got502;353353+}354354+/****************************************************************************/355355+/*--------------------------------------------------------------------------*/356356+/*357357+ * THESE APPEAR TO HAVE NO EFFECT ON EITHER VIDEO OR AUDIO.358358+ */359359+/*--------------------------------------------------------------------------*/360360+int361361+write_300(struct usb_device *p)362362+{363363+SET(p, 0x300, 0x0012);364364+SET(p, 0x350, 0x002D);365365+SET(p, 0x351, 0x0001);366366+SET(p, 0x352, 0x0000);367367+SET(p, 0x353, 0x0000);368368+SET(p, 0x300, 0x0080);369369+return 0;370370+}371371+/****************************************************************************/372372+/*--------------------------------------------------------------------------*/373373+/*374374+ * NOTE: THE FOLLOWING IS NOT CHECKED:375375+ * REGISTER 0x0F, WHICH IS INVOLVED IN CHROMINANCE AUTOMATIC GAIN CONTROL.376376+ */377377+/*--------------------------------------------------------------------------*/378378+int379379+check_saa(struct usb_device *p)380380+{381381+int i0, ir, rc;382382+i0 = 0;383383+384384+rc = 0;385385+while (0xFF != saa7113config[i0].reg) {386386+ if (0x0F == saa7113config[i0].reg) {387387+ i0++; continue;388388+ }389389+390390+ ir = read_saa(p, saa7113config[i0].reg);391391+ if (ir != saa7113config[i0].set) {392392+ SAY("SAA register 0x%02X has 0x%02X, expected 0x%02X\n", \393393+ saa7113config[i0].reg, ir, saa7113config[i0].set);394394+ rc--;395395+ }396396+ i0++;397397+}398398+if (-8 > rc)399399+ return rc;400400+else401401+ return 0;402402+}403403+/****************************************************************************/404404+int405405+merit_saa(struct usb_device *p)406406+{407407+int rc;408408+409409+rc = read_saa(p, 0x1F);410410+if ((0 > rc) || (0x02 & rc))411411+ return 1 ;412412+else413413+ return 0;414414+}415415+/****************************************************************************/416416+int417417+ready_saa(struct usb_device *p)418418+{419419+int j, rc;420420+static int max = 10;421421+422422+j = 0;423423+while (max > j) {424424+ rc = read_saa(p, 0x1F);425425+ if (0 <= rc) {426426+ if ((1 == (0x01 & rc))&&(0 == (0x40 & rc)))427427+ break;428428+ }429429+ msleep(100); j++;430430+}431431+if (max == j)432432+ return -1;433433+else {434434+ if (0x20 & rc)435435+ JOT(8, "hardware detects 60 Hz\n");436436+ else437437+ JOT(8, "hardware detects 50 Hz\n");438438+ if (0x80 & rc)439439+ JOT(8, "hardware detects interlacing\n");440440+ else441441+ JOT(8, "hardware detects no interlacing\n");442442+}443443+return 0;444444+}445445+/****************************************************************************/446446+/*--------------------------------------------------------------------------*/447447+/*448448+ * NOTE: THE FOLLOWING ARE NOT CHECKED:449449+ * REGISTERS 0x000, 0x002: FUNCTIONALITY IS NOT KNOWN450450+ * REGISTER 0x100: ACCEPT ALSO (0x80 | stk1160config[.].set)451451+ */452452+/*--------------------------------------------------------------------------*/453453+int454454+check_stk(struct usb_device *p)455455+{456456+int i0, ir;457457+i0 = 0;458458+while (0xFFF != stk1160config[i0].reg) {459459+ if (0x000 == stk1160config[i0].reg) {460460+ i0++; continue;461461+ }462462+ if (0x002 == stk1160config[i0].reg) {463463+ i0++; continue;464464+ }465465+466466+ ir = read_stk(p, stk1160config[i0].reg);467467+468468+ if (0x100 == stk1160config[i0].reg) {469469+ if ((ir != (0xFF & stk1160config[i0].set)) && \470470+ (ir != (0x80 | (0xFF & stk1160config[i0].set))) && \471471+ (0xFFFF != stk1160config[i0].set)) {472472+ SAY("STK register 0x%03X has 0x%02X, " \473473+ "expected 0x%02X\n", \474474+ stk1160config[i0].reg, ir, \475475+ stk1160config[i0].set);476476+ }477477+ i0++; continue;478478+ }479479+480480+ if ((ir != (0xFF & stk1160config[i0].set)) && \481481+ (0xFFFF != stk1160config[i0].set)) {482482+ SAY("STK register 0x%03X has 0x%02X, " \483483+ "expected 0x%02X\n", \484484+ stk1160config[i0].reg, ir, \485485+ stk1160config[i0].set);486486+ }487487+ i0++;488488+ }489489+return 0;490490+}491491+/****************************************************************************/492492+int493493+read_saa(struct usb_device *p, __u16 reg0)494494+{495495+__u8 igot;496496+497497+SET(p, 0x208, reg0);498498+SET(p, 0x200, 0x20);499499+if (0 != wait_i2c(p))500500+ return -1;501501+igot = 0;502502+GET(p, 0x0209, &igot);503503+return igot;504504+}505505+/****************************************************************************/506506+int507507+read_stk(struct usb_device *p, __u32 reg0)508508+{509509+__u8 igot;510510+511511+igot = 0;512512+GET(p, reg0, &igot);513513+return igot;514514+}515515+/*****************************************************************************/516516+/*---------------------------------------------------------------------------*/517517+/*518518+ * HARDWARE USERSPACE INPUT NUMBER PHYSICAL INPUT DRIVER input VALUE519519+ *520520+ * CVBS+S-VIDEO 0 or 1 CVBS 1521521+ * FOUR-CVBS 0 or 1 CVBS1 1522522+ * FOUR-CVBS 2 CVBS2 2523523+ * FOUR-CVBS 3 CVBS3 3524524+ * FOUR-CVBS 4 CVBS4 4525525+ * CVBS+S-VIDEO 5 S-VIDEO 5526526+ *527527+ * WHEN 5==input THE ARGUMENT mode MUST ALSO BE SUPPLIED:528528+ *529529+ * mode 7 => GAIN TO BE SET EXPLICITLY USING REGISTER 0x05 (UNTESTED)530530+ * mode 9 => USE AUTOMATIC GAIN CONTROL (DEFAULT)531531+ *532532+*/533533+/*---------------------------------------------------------------------------*/534534+int535535+select_input(struct usb_device *p, int input, int mode)536536+{537537+538538+stop_100(p);539539+540540+msleep(20);541541+switch (input) {542542+case 0:543543+case 1: {544544+ SET(p, 0x0000, 0x0098); break;545545+}546546+case 2: {547547+ SET(p, 0x0000, 0x0090); break;548548+}549549+case 3: {550550+ SET(p, 0x0000, 0x0088); break;551551+}552552+case 4: {553553+ SET(p, 0x0000, 0x0080); break;554554+}555555+case 5: {556556+ if (9 != mode)557557+ mode = 7;558558+ switch (mode) {559559+ case 7:560560+ {561561+ if (0 != write_saa(p, 0x02, 0x87)) {562562+ SAY("ERROR: failed to set SAA " \563563+ "register 0x02 for input " \564564+ "%i\n", input);565565+ }566566+ if (0 != write_saa(p, 0x05, 0xFF)) {567567+ SAY("ERROR: failed to set SAA " \568568+ "register 0x05 for input " \569569+ "%i\n", input);570570+ }571571+ break;572572+ }573573+ case 9:574574+ {575575+ if (0 != write_saa(p, 0x02, 0x89)) {576576+ SAY("ERROR: failed to set SAA " \577577+ "register 0x02 for input " \578578+ "%i\n", input);579579+ }580580+ if (0 != write_saa(p, 0x05, 0x00)) {581581+ SAY("ERROR: failed to set SAA " \582582+ "register 0x05 for input " \583583+ "%i\n", input);584584+ }585585+ break;586586+ }587587+ default:588588+ {589589+ SAY("MISTAKE: bad mode: %i\n", mode);590590+ return -1;591591+ }592592+ }593593+ if (0 != write_saa(p, 0x04, 0x00)) {594594+ SAY("ERROR: failed to set SAA register 0x04 " \595595+ "for input %i\n", input);596596+ }597597+ if (0 != write_saa(p, 0x09, 0x80)) {598598+ SAY("ERROR: failed to set SAA register 0x09 " \599599+ "for input %i\n", input);600600+ }601601+ break;602602+}603603+default:604604+ {605605+ SAY("ERROR: bad input: %i\n", input);606606+ return -1;607607+}608608+}609609+msleep(20);610610+SET(p, 0x0002, 0x0093);611611+msleep(20);612612+613613+start_100(p);614614+615615+return 0;616616+}617617+/****************************************************************************/618618+int619619+set_resolution(struct usb_device *p, \620620+ __u16 set0, __u16 set1, __u16 set2, __u16 set3)621621+{622622+__u16 u0x0111, u0x0113, u0x0115, u0x0117;623623+624624+u0x0111 = ((0xFF00 & set0) >> 8);625625+u0x0113 = ((0xFF00 & set1) >> 8);626626+u0x0115 = ((0xFF00 & set2) >> 8);627627+u0x0117 = ((0xFF00 & set3) >> 8);628628+629629+SET(p, 0x0110, (0x00FF & set0));630630+SET(p, 0x0111, u0x0111);631631+SET(p, 0x0112, (0x00FF & set1));632632+SET(p, 0x0113, u0x0113);633633+SET(p, 0x0114, (0x00FF & set2));634634+SET(p, 0x0115, u0x0115);635635+SET(p, 0x0116, (0x00FF & set3));636636+SET(p, 0x0117, u0x0117);637637+638638+return 0;639639+}640640+/****************************************************************************/641641+int642642+start_100(struct usb_device *p)643643+{644644+__u16 get0;645645+__u8 igot;646646+647647+GET(p, 0x0100, &igot); get0 = igot;648648+msleep(0x1f4);649649+SET(p, 0x0100, (0x80 | get0));650650+msleep(0x1f4);651651+return 0;652652+}653653+/****************************************************************************/654654+int655655+stop_100(struct usb_device *p)656656+{657657+__u16 get0;658658+__u8 igot;659659+660660+GET(p, 0x0100, &igot); get0 = igot;661661+msleep(0x1f4);662662+SET(p, 0x0100, (0x7F & get0));663663+msleep(0x1f4);664664+return 0;665665+}666666+/****************************************************************************/667667+/*--------------------------------------------------------------------------*/668668+/*669669+ * FUNCTION wait_i2c() RETURNS 0 ON SUCCESS670670+*/671671+/*--------------------------------------------------------------------------*/672672+int673673+wait_i2c(struct usb_device *p)674674+{675675+__u16 get0;676676+__u8 igot;677677+const int max = 4;678678+int k;679679+680680+for (k = 0; k < max; k++) {681681+ GET(p, 0x0201, &igot); get0 = igot;682682+ switch (get0) {683683+ case 0x04:684684+ case 0x01: {685685+ return 0;686686+ }687687+ case 0x00: {688688+ msleep(10);689689+ continue;690690+ }691691+ default: {692692+ return get0 - 1;693693+ }694694+ }695695+}696696+return -1;697697+}698698+/****************************************************************************/699699+int700700+regset(struct usb_device *pusb_device, __u16 index, __u16 value)701701+{702702+__u16 igot;703703+int rc0, rc1;704704+705705+if (!pusb_device)706706+ return -EFAULT;707707+708708+rc1 = 0; igot = 0;709709+rc0 = usb_control_msg(pusb_device, usb_sndctrlpipe(pusb_device, 0), \710710+ (__u8)0x01, \711711+ (__u8)(USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE), \712712+ (__u16)value, \713713+ (__u16)index, \714714+ (void *)NULL, \715715+ (__u16)0, \716716+ (int)500);717717+718718+#if defined(NOREADBACK)719719+#720720+#else721721+rc1 = usb_control_msg(pusb_device, usb_rcvctrlpipe(pusb_device, 0), \722722+ (__u8)0x00, \723723+ (__u8)(USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE), \724724+ (__u16)0x00, \725725+ (__u16)index, \726726+ (void *)&igot, \727727+ (__u16)sizeof(__u16), \728728+ (int)50000);729729+igot = 0xFF & igot;730730+switch (index) {731731+case 0x000:732732+case 0x500:733733+case 0x502:734734+case 0x503:735735+case 0x504:736736+case 0x506:737737+case 0x507: {738738+ break;739739+}740740+case 0x204:741741+case 0x205:742742+case 0x350:743743+case 0x351: {744744+ if (0 != igot) {745745+ JOT(8, "unexpected 0x%02X for STK register 0x%03X\n", \746746+ igot, index);747747+ }748748+break;749749+}750750+case 0x114:751751+case 0x116: {752752+ if ((0xFF & value) != igot) {753753+ JOT(8, "unexpected 0x%02X != 0x%02X " \754754+ "for STK register 0x%03X\n", \755755+ igot, value, index);756756+ }757757+break;758758+}759759+case 0x200: {760760+ if (0 == igot)761761+ break;762762+}763763+default: {764764+ if (value != igot) {765765+ JOT(8, "unexpected 0x%02X != 0x%02X " \766766+ "for STK register 0x%03X\n", \767767+ igot, value, index);768768+ }769769+break;770770+}771771+}772772+#endif /* ! NOREADBACK*/773773+774774+return (0 > rc0) ? rc0 : rc1;775775+}776776+/*****************************************************************************/777777+int778778+regget(struct usb_device *pusb_device, __u16 index, void *pvoid)779779+{780780+int ir;781781+782782+if (!pusb_device)783783+ return -EFAULT;784784+785785+ir = usb_control_msg(pusb_device, usb_rcvctrlpipe(pusb_device, 0), \786786+ (__u8)0x00, \787787+ (__u8)(USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE), \788788+ (__u16)0x00, \789789+ (__u16)index, \790790+ (void *)pvoid, \791791+ sizeof(__u8), \792792+ (int)50000);793793+return 0xFF & ir;794794+}795795+/*****************************************************************************/796796+int797797+wakeup_device(struct usb_device *pusb_device)798798+{799799+return usb_control_msg(pusb_device, usb_sndctrlpipe(pusb_device, 0), \800800+ (__u8)USB_REQ_SET_FEATURE, \801801+ (__u8)(USB_DIR_OUT | USB_TYPE_STANDARD | USB_RECIP_DEVICE), \802802+ USB_DEVICE_REMOTE_WAKEUP, \803803+ (__u16)0, \804804+ (void *) NULL, \805805+ (__u16)0, \806806+ (int)50000);807807+}808808+/*****************************************************************************/809809+/*---------------------------------------------------------------------------*/810810+/*811811+ * IMPORTANT:812812+ * THE MESSAGE OF TYPE (USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE)813813+ * CAUSES MUTING IF THE VALUE 0x0100 IS SENT.814814+ * TO ENABLE AUDIO THE VALUE 0x0200 MUST BE SENT.815815+ */816816+/*---------------------------------------------------------------------------*/817817+int818818+audio_setup(struct easycap *peasycap)819819+{820820+struct usb_device *pusb_device;821821+static __u8 request = 0x01;822822+static __u8 requesttype = \823823+ (__u8)(USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE);824824+825825+static __u16 value_unmute = 0x0200;826826+static __u16 index = 0x0301;827827+828828+static unsigned char buffer[1];829829+static __u16 length = 1;830830+int rc;831831+832832+if (NULL == peasycap)833833+ return -EFAULT;834834+835835+pusb_device = peasycap->pusb_device;836836+if (NULL == pusb_device)837837+ return -EFAULT;838838+839839+JOT(8, "%02X %02X %02X %02X %02X %02X %02X %02X\n", \840840+ requesttype, request, \841841+ (0x00FF & value_unmute), \842842+ (0xFF00 & value_unmute) >> 8, \843843+ (0x00FF & index), \844844+ (0xFF00 & index) >> 8, \845845+ (0x00FF & length), \846846+ (0xFF00 & length) >> 8);847847+848848+buffer[0] = 0x01;849849+850850+rc = usb_control_msg(pusb_device, usb_sndctrlpipe(pusb_device, 0), \851851+ (__u8)request, \852852+ (__u8)requesttype, \853853+ (__u16)value_unmute, \854854+ (__u16)index, \855855+ (void *)&buffer[0], \856856+ (__u16)length, \857857+ (int)50000);858858+859859+JOT(8, "0x%02X=buffer\n", *((__u8 *) &buffer[0]));860860+if (rc != (int)length)861861+ SAY("ERROR: usb_control_msg returned %i\n", rc);862862+863863+/*--------------------------------------------------------------------------*/864864+/*865865+ * REGISTER 500: SETTING VALUE TO 0x0094 RESETS AUDIO CONFIGURATION ???866866+ * REGISTER 506: ANALOGUE AUDIO ATTENTUATOR ???867867+ * FOR THE CVBS+S-VIDEO HARDWARE:868868+ * SETTING VALUE TO 0x0000 GIVES QUIET SOUND.869869+ * THE UPPER BYTE SEEMS TO HAVE NO EFFECT.870870+ * FOR THE FOUR-CVBS HARDWARE:871871+ * SETTING VALUE TO 0x0000 SEEMS TO HAVE NO EFFECT.872872+ * REGISTER 507: ANALOGUE AUDIO PREAMPLIFIER ON/OFF ???873873+ * FOR THE CVBS-S-VIDEO HARDWARE:874874+ * SETTING VALUE TO 0x0001 GIVES VERY LOUD, DISTORTED SOUND.875875+ * THE UPPER BYTE SEEMS TO HAVE NO EFFECT.876876+ */877877+/*--------------------------------------------------------------------------*/878878+879879+SET(pusb_device, 0x0500, 0x0094);880880+881881+SET(pusb_device, 0x0500, 0x008C);882882+883883+SET(pusb_device, 0x0506, 0x0001);884884+SET(pusb_device, 0x0507, 0x0000);885885+886886+if (false == peasycap->microphone) {887887+ /*-------------------------------------------------------------------*/888888+ /*889889+ * SELECT AUDIO SOURCE "LINE IN" AND SET DEFAULT GAIN TO 0dB.890890+ */891891+ /*-------------------------------------------------------------------*/892892+ write_vt(pusb_device, 0x0002, 0x8000);893893+ write_vt(pusb_device, 0x001C, 0x8000);894894+895895+ write_vt(pusb_device, 0x000E, 0x0000);896896+ write_vt(pusb_device, 0x0010, 0x0000);897897+ write_vt(pusb_device, 0x0012, 0x8000);898898+ write_vt(pusb_device, 0x0016, 0x0000);899899+900900+ write_vt(pusb_device, 0x001A, 0x0404);901901+ write_vt(pusb_device, 0x0002, 0x0000);902902+ write_vt(pusb_device, 0x001C, 0x0000);903903+} else {904904+ /*-------------------------------------------------------------------*/905905+ /*906906+ * SELECT AUDIO SOURCE "MIC" AND SET DEFAULT GAIN TO 0 dB.907907+ *908908+ * REGISTER 0x000E CAN BE SET TO PROVIDE UP TO 34.5 dB ATTENTUATION,909909+ * BUT THIS HAS NOT PROVED NECESSARY FOR THE FEW SIGNAL SOURCES910910+ * TESTED HITHERTO.911911+ */912912+ /*-------------------------------------------------------------------*/913913+ write_vt(pusb_device, 0x0006, 0x8000);914914+ write_vt(pusb_device, 0x001C, 0x8000);915915+916916+ write_vt(pusb_device, 0x000E, 0x0008);917917+918918+ write_vt(pusb_device, 0x0010, 0x0000);919919+ write_vt(pusb_device, 0x0012, 0x8000);920920+ write_vt(pusb_device, 0x0016, 0x0000);921921+922922+ write_vt(pusb_device, 0x001A, 0x0000);923923+ write_vt(pusb_device, 0x0006, 0x0000);924924+ write_vt(pusb_device, 0x001C, 0x0000);925925+}926926+927927+check_vt(pusb_device);928928+929929+return 0;930930+}931931+/*****************************************************************************/932932+int933933+check_vt(struct usb_device *pusb_device)934934+{935935+int igot;936936+937937+igot = read_vt(pusb_device, 0x0002);938938+if (0 > igot)939939+ SAY("ERROR: failed to read VT1612A register 0x02\n");940940+if (0x8000 & igot)941941+ SAY("register 0x%02X muted\n", 0x02);942942+943943+igot = read_vt(pusb_device, 0x000E);944944+if (0 > igot)945945+ SAY("ERROR: failed to read VT1612A register 0x0E\n");946946+if (0x8000 & igot)947947+ SAY("register 0x%02X muted\n", 0x0E);948948+949949+igot = read_vt(pusb_device, 0x0010);950950+if (0 > igot)951951+ SAY("ERROR: failed to read VT1612A register 0x10\n");952952+if (0x8000 & igot)953953+ SAY("register 0x%02X muted\n", 0x10);954954+955955+igot = read_vt(pusb_device, 0x0012);956956+if (0 > igot)957957+ SAY("ERROR: failed to read VT1612A register 0x12\n");958958+if (0x8000 & igot)959959+ SAY("register 0x%02X muted\n", 0x12);960960+961961+igot = read_vt(pusb_device, 0x0016);962962+if (0 > igot)963963+ SAY("ERROR: failed to read VT1612A register 0x16\n");964964+if (0x8000 & igot)965965+ SAY("register 0x%02X muted\n", 0x16);966966+967967+igot = read_vt(pusb_device, 0x001A);968968+if (0 > igot)969969+ SAY("ERROR: failed to read VT1612A register 0x1A\n");970970+if (0x8000 & igot)971971+ SAY("register 0x%02X muted\n", 0x1A);972972+973973+igot = read_vt(pusb_device, 0x001C);974974+if (0 > igot)975975+ SAY("ERROR: failed to read VT1612A register 0x1C\n");976976+if (0x8000 & igot)977977+ SAY("register 0x%02X muted\n", 0x1C);978978+979979+return 0;980980+}981981+/*****************************************************************************/982982+/*---------------------------------------------------------------------------*/983983+/*984984+ * NOTE: THIS DOES INCREASE THE VOLUME DRAMATICALLY:985985+ * audio_gainset(pusb_device, 0x000F);986986+ *987987+ * IF 16<loud<31 VT1621A REGISTER 0x1C IS SET FOR POSITIVE GAIN.988988+ * IF loud<=16 VT1621A REGISTER 0x1C IS SET FOR ZERO GAIN.989989+ * THERE IS NEVER ANY (ADDITIONAL) ATTENUATION.990990+ */991991+/*---------------------------------------------------------------------------*/992992+int993993+audio_gainset(struct usb_device *pusb_device, __s8 loud)994994+{995995+int igot;996996+__u8 u8;997997+__u16 mute;998998+999999+if (16 > loud)10001000+ loud = 16;10011001+u8 = 0x000F & (__u8)(loud - 16);10021002+10031003+write_vt(pusb_device, 0x0002, 0x8000);10041004+10051005+igot = read_vt(pusb_device, 0x001C);10061006+if (0 > igot) {10071007+ SAY("ERROR: failed to read VT1612A register 0x1C\n");10081008+ mute = 0x0000;10091009+} else10101010+ mute = 0x8000 & ((unsigned int)igot);10111011+10121012+JOT(8, "0x%04X=(mute|u8|(u8<<8))\n", mute | u8 | (u8 << 8));10131013+10141014+write_vt(pusb_device, 0x001C, 0x8000);10151015+write_vt(pusb_device, 0x001C, (mute | u8 | (u8 << 8)));10161016+write_vt(pusb_device, 0x0002, 0x0000);10171017+10181018+return 0;10191019+}10201020+/*****************************************************************************/10211021+int10221022+audio_gainget(struct usb_device *pusb_device)10231023+{10241024+int igot;10251025+10261026+igot = read_vt(pusb_device, 0x001C);10271027+if (0 > igot)10281028+ SAY("ERROR: failed to read VT1612A register 0x1C\n");10291029+return igot;10301030+}10311031+/*****************************************************************************/10321032+int10331033+set2to78(struct usb_device *p)10341034+{10351035+int ir;10361036+10371037+msleep(20);10381038+ir = regset(p, 0x0002, 0x0078);10391039+if (0 > ir)10401040+ SAY("ERROR: failed to set register 0x0002 to 0x0078\n");10411041+msleep(20);10421042+return ir;10431043+}10441044+/*****************************************************************************/10451045+int10461046+set2to93(struct usb_device *p)10471047+{10481048+int ir;10491049+10501050+msleep(20);10511051+ir = regset(p, 0x0002, 0x0093);10521052+if (0 > ir)10531053+ SAY("ERROR: failed to set register 0x0002 to 0x0078\n");10541054+msleep(20);10551055+return ir;10561056+}10571057+/*****************************************************************************/
+4342
drivers/staging/easycap/easycap_main.c
···11+/******************************************************************************22+* *33+* easycap_main.c *44+* *55+* Video driver for EasyCAP USB2.0 Video Capture Device DC60 *66+* *77+* *88+******************************************************************************/99+/*1010+ *1111+ * Copyright (C) 2010 R.M. Thomas <rmthomas@sciolus.org>1212+ *1313+ *1414+ * This is free software; you can redistribute it and/or modify1515+ * it under the terms of the GNU General Public License as published by1616+ * the Free Software Foundation; either version 2 of the License, or1717+ * (at your option) any later version.1818+ *1919+ * The software is distributed in the hope that it will be useful,2020+ * but WITHOUT ANY WARRANTY; without even the implied warranty of2121+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the2222+ * GNU General Public License for more details.2323+ *2424+ * You should have received a copy of the GNU General Public License2525+ * along with this software; if not, write to the Free Software2626+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA2727+ *2828+*/2929+/*****************************************************************************/3030+3131+#include "easycap.h"3232+#include "easycap_standard.h"3333+3434+int easycap_debug;3535+module_param(easycap_debug, int, S_IRUGO | S_IWUSR);3636+3737+unsigned int audio_pages_per_fragment;3838+unsigned int audio_bytes_per_fragment;3939+unsigned int audio_buffer_page_many;4040+4141+/*---------------------------------------------------------------------------*/4242+/*4343+ * PARAMETERS APPLICABLE TO ENTIRE DRIVER, I.E. BOTH VIDEO AND AUDIO4444+ */4545+/*---------------------------------------------------------------------------*/4646+struct usb_device_id easycap_usb_device_id_table[] = {4747+{ USB_DEVICE(USB_EASYCAP_VENDOR_ID, USB_EASYCAP_PRODUCT_ID) },4848+{ }4949+};5050+MODULE_DEVICE_TABLE(usb, easycap_usb_device_id_table);5151+struct usb_driver easycap_usb_driver = {5252+.name = "easycap",5353+.id_table = easycap_usb_device_id_table,5454+.probe = easycap_usb_probe,5555+.disconnect = easycap_usb_disconnect,5656+};5757+/*---------------------------------------------------------------------------*/5858+/*5959+ * PARAMETERS USED WHEN REGISTERING THE VIDEO INTERFACE6060+ *6161+ * NOTE: SOME KERNELS IGNORE usb_class_driver.minor_base, AS MENTIONED BY6262+ * CORBET ET AL. "LINUX DEVICE DRIVERS", 3rd EDITION, PAGE 253.6363+ * THIS IS THE CASE FOR OpenSUSE.6464+ */6565+/*---------------------------------------------------------------------------*/6666+const struct file_operations easycap_fops = {6767+.owner = THIS_MODULE,6868+.open = easycap_open,6969+.release = easycap_release,7070+.ioctl = easycap_ioctl,7171+.poll = easycap_poll,7272+.mmap = easycap_mmap,7373+.llseek = no_llseek,7474+};7575+struct vm_operations_struct easycap_vm_ops = {7676+.open = easycap_vma_open,7777+.close = easycap_vma_close,7878+.fault = easycap_vma_fault,7979+};8080+struct usb_class_driver easycap_class = {8181+.name = "usb/easycap%d",8282+.fops = &easycap_fops,8383+.minor_base = USB_SKEL_MINOR_BASE,8484+};8585+8686+/*vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv*/8787+#if defined(EASYCAP_IS_VIDEODEV_CLIENT)8888+#if defined(EASYCAP_NEEDS_V4L2_FOPS)8989+struct v4l2_file_operations v4l2_fops = {9090+.owner = THIS_MODULE,9191+.open = easycap_open_noinode,9292+.release = easycap_release_noinode,9393+.ioctl = easycap_ioctl_noinode,9494+.poll = easycap_poll,9595+.mmap = easycap_mmap,9696+};9797+#endif /*EASYCAP_NEEDS_V4L2_FOPS*/9898+int video_device_many /*=0*/;9999+struct video_device *pvideo_array[VIDEO_DEVICE_MANY], *pvideo_device;100100+#endif /*EASYCAP_IS_VIDEODEV_CLIENT*/101101+/*^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^*/102102+103103+/*--------------------------------------------------------------------------*/104104+/*105105+ * PARAMETERS USED WHEN REGISTERING THE AUDIO INTERFACE106106+ */107107+/*--------------------------------------------------------------------------*/108108+const struct file_operations easysnd_fops = {109109+.owner = THIS_MODULE,110110+.open = easysnd_open,111111+.release = easysnd_release,112112+.ioctl = easysnd_ioctl,113113+.read = easysnd_read,114114+.llseek = no_llseek,115115+};116116+struct usb_class_driver easysnd_class = {117117+.name = "usb/easysnd%d",118118+.fops = &easysnd_fops,119119+.minor_base = USB_SKEL_MINOR_BASE,120120+};121121+/****************************************************************************/122122+/*--------------------------------------------------------------------------*/123123+/*124124+ * IT IS NOT APPROPRIATE FOR easycap_open() TO SUBMIT THE VIDEO URBS HERE,125125+ * BECAUSE THERE WILL ALWAYS BE SUBSEQUENT NEGOTIATION OF TV STANDARD AND126126+ * FORMAT BY IOCTL AND IT IS INADVISABLE TO HAVE THE URBS RUNNING WHILE127127+ * REGISTERS OF THE SA7113H ARE BEING MANIPULATED.128128+ *129129+ * THE SUBMISSION OF VIDEO URBS IS THEREFORE DELAYED UNTIL THE IOCTL COMMAND130130+ * STREAMON IS RECEIVED.131131+ */132132+/*--------------------------------------------------------------------------*/133133+/*vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv*/134134+#if defined(EASYCAP_IS_VIDEODEV_CLIENT)135135+int136136+easycap_open_noinode(struct file *file)137137+{138138+return easycap_open((struct inode *)NULL, file);139139+}140140+#endif /*EASYCAP_IS_VIDEODEV_CLIENT*/141141+/*^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^*/142142+int143143+easycap_open(struct inode *inode, struct file *file)144144+{145145+#if (!defined(EASYCAP_IS_VIDEODEV_CLIENT))146146+struct usb_interface *pusb_interface;147147+#endif /*EASYCAP_IS_VIDEODEV_CLIENT*/148148+struct usb_device *p;149149+struct easycap *peasycap;150150+int i, k, m, rc;151151+152152+JOT(4, "\n");153153+SAY("==========OPEN=========\n");154154+155155+peasycap = (struct easycap *)NULL;156156+#if (!defined(EASYCAP_IS_VIDEODEV_CLIENT))157157+if ((struct inode *)NULL == inode) {158158+ SAY("ERROR: inode is NULL.\n");159159+ return -EFAULT;160160+}161161+pusb_interface = usb_find_interface(&easycap_usb_driver, iminor(inode));162162+if (!pusb_interface) {163163+ SAY("ERROR: pusb_interface is NULL.\n");164164+ return -EFAULT;165165+}166166+peasycap = usb_get_intfdata(pusb_interface);167167+/*vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv*/168168+#else169169+for (i = 0; i < video_device_many; i++) {170170+ pvideo_device = pvideo_array[i];171171+ if ((struct video_device *)NULL != pvideo_device) {172172+ peasycap = (struct easycap *)video_get_drvdata(pvideo_device);173173+ break;174174+ }175175+}176176+/*^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^*/177177+#endif /*EASYCAP_IS_VIDEODEV_CLIENT*/178178+if ((struct easycap *)NULL == peasycap) {179179+ SAY("MISTAKE: peasycap is NULL\n");180180+ return -EFAULT;181181+}182182+file->private_data = peasycap;183183+/*---------------------------------------------------------------------------*/184184+/*185185+ * INITIALIZATION186186+ */187187+/*---------------------------------------------------------------------------*/188188+JOT(4, "starting initialization\n");189189+190190+for (k = 0; k < FRAME_BUFFER_MANY; k++) {191191+ for (m = 0; m < FRAME_BUFFER_SIZE/PAGE_SIZE; m++)192192+ memset(peasycap->frame_buffer[k][m].pgo, 0, PAGE_SIZE);193193+}194194+p = peasycap->pusb_device;195195+if ((struct usb_device *)NULL == p) {196196+ SAY("ERROR: peasycap->pusb_device is NULL\n");197197+ return -EFAULT;198198+} else {199199+ JOT(16, "0x%08lX=peasycap->pusb_device\n", \200200+ (long int)peasycap->pusb_device);201201+}202202+rc = wakeup_device(peasycap->pusb_device);203203+if (0 == rc)204204+ JOT(8, "wakeup_device() OK\n");205205+else {206206+ SAY("ERROR: wakeup_device() returned %i\n", rc);207207+ return -EFAULT;208208+}209209+rc = setup_stk(p); peasycap->input = 0;210210+if (0 == rc)211211+ JOT(8, "setup_stk() OK\n");212212+else {213213+ SAY("ERROR: setup_stk() returned %i\n", rc);214214+ return -EFAULT;215215+}216216+rc = setup_saa(p);217217+if (0 == rc)218218+ JOT(8, "setup_saa() OK\n");219219+else {220220+ SAY("ERROR: setup_saa() returned %i\n", rc);221221+ return -EFAULT;222222+}223223+rc = check_saa(p);224224+if (0 == rc)225225+ JOT(8, "check_saa() OK\n");226226+else if (-8 < rc)227227+ SAY("check_saa() returned %i\n", rc);228228+else {229229+ SAY("ERROR: check_saa() returned %i\n", rc);230230+ return -EFAULT;231231+}232232+peasycap->standard_offset = -1;233233+/*---------------------------------------------------------------------------*/234234+#if defined(PREFER_NTSC)235235+236236+rc = adjust_standard(peasycap, V4L2_STD_NTSC_M);237237+if (0 == rc)238238+ JOT(8, "adjust_standard(.,NTSC_M) OK\n");239239+else {240240+ SAY("ERROR: adjust_standard(.,NTSC_M) returned %i\n", rc);241241+ return -EFAULT;242242+}243243+rc = adjust_format(peasycap, 640, 480, V4L2_PIX_FMT_UYVY, V4L2_FIELD_NONE, \244244+ false);245245+if (0 <= rc)246246+ JOT(8, "adjust_format(.,640,480,UYVY) OK\n");247247+else {248248+ SAY("ERROR: adjust_format(.,640,480,UYVY) returned %i\n", rc);249249+ return -EFAULT;250250+}251251+252252+#else253253+254254+rc = adjust_standard(peasycap, \255255+ (V4L2_STD_PAL_B | V4L2_STD_PAL_G | V4L2_STD_PAL_H | \256256+ V4L2_STD_PAL_I | V4L2_STD_PAL_N));257257+if (0 == rc)258258+ JOT(8, "adjust_standard(.,PAL_BGHIN) OK\n");259259+else {260260+ SAY("ERROR: adjust_standard(.,PAL_BGHIN) returned %i\n", rc);261261+ return -EFAULT;262262+}263263+rc = adjust_format(peasycap, 640, 480, V4L2_PIX_FMT_UYVY, V4L2_FIELD_NONE, \264264+ false);265265+if (0 <= rc)266266+ JOT(8, "adjust_format(.,640,480,uyvy,false) OK\n");267267+else {268268+ SAY("ERROR: adjust_format(.,640,480,uyvy,false) returned %i\n", rc);269269+ return -EFAULT;270270+}271271+272272+#endif /* !PREFER_NTSC*/273273+/*---------------------------------------------------------------------------*/274274+rc = adjust_brightness(peasycap, -8192);275275+if (0 != rc) {276276+ SAY("ERROR: adjust_brightness(default) returned %i\n", rc);277277+ return -EFAULT;278278+}279279+rc = adjust_contrast(peasycap, -8192);280280+if (0 != rc) {281281+ SAY("ERROR: adjust_contrast(default) returned %i\n", rc);282282+ return -EFAULT;283283+}284284+rc = adjust_saturation(peasycap, -8192);285285+if (0 != rc) {286286+ SAY("ERROR: adjust_saturation(default) returned %i\n", rc);287287+ return -EFAULT;288288+}289289+rc = adjust_hue(peasycap, -8192);290290+if (0 != rc) {291291+ SAY("ERROR: adjust_hue(default) returned %i\n", rc);292292+ return -EFAULT;293293+}294294+/*---------------------------------------------------------------------------*/295295+rc = usb_set_interface(peasycap->pusb_device, peasycap->video_interface, \296296+ peasycap->video_altsetting_on);297297+if (0 == rc)298298+ JOT(8, "usb_set_interface(.,%i,%i) OK\n", peasycap->video_interface, \299299+ peasycap->video_altsetting_on);300300+else {301301+ SAY("ERROR: usb_set_interface() returned %i\n", rc);302302+ return -EFAULT;303303+}304304+rc = start_100(p);305305+if (0 == rc)306306+ JOT(8, "start_100() OK\n");307307+else {308308+ SAY("ERROR: start_100() returned %i\n", rc);309309+ return -EFAULT;310310+}311311+peasycap->video_isoc_sequence = VIDEO_ISOC_BUFFER_MANY - 1;312312+peasycap->video_idle = 0;313313+peasycap->video_junk = 0;314314+for (i = 0; i < 180; i++)315315+ peasycap->merit[i] = 0;316316+peasycap->video_eof = 0;317317+peasycap->audio_eof = 0;318318+319319+do_gettimeofday(&peasycap->timeval7);320320+321321+peasycap->fudge = 0;322322+323323+JOT(4, "finished initialization\n");324324+return 0;325325+}326326+/*****************************************************************************/327327+int328328+submit_video_urbs(struct easycap *peasycap)329329+{330330+struct data_urb *pdata_urb;331331+struct urb *purb;332332+struct list_head *plist_head;333333+int j, isbad, m, rc;334334+int isbuf;335335+336336+if ((struct list_head *)NULL == peasycap->purb_video_head) {337337+ SAY("ERROR: peasycap->urb_video_head uninitialized\n");338338+ return -EFAULT;339339+}340340+if ((struct usb_device *)NULL == peasycap->pusb_device) {341341+ SAY("ERROR: peasycap->pusb_device is NULL\n");342342+ return -EFAULT;343343+}344344+if (!peasycap->video_isoc_streaming) {345345+346346+347347+348348+349349+350350+351351+352352+353353+ JOT(4, "submission of all video urbs\n");354354+ if (0 != ready_saa(peasycap->pusb_device)) {355355+ SAY("ERROR: not ready to capture after waiting " \356356+ "one second\n");357357+ SAY("..... continuing anyway\n");358358+ }359359+ isbad = 0; m = 0;360360+ list_for_each(plist_head, (peasycap->purb_video_head)) {361361+ pdata_urb = list_entry(plist_head, struct data_urb, list_head);362362+ if (NULL != pdata_urb) {363363+ purb = pdata_urb->purb;364364+ if (NULL != purb) {365365+ isbuf = pdata_urb->isbuf;366366+ purb->interval = 1;367367+ purb->dev = peasycap->pusb_device;368368+ purb->pipe = \369369+ usb_rcvisocpipe(peasycap->pusb_device,\370370+ peasycap->video_endpointnumber);371371+ purb->transfer_flags = URB_ISO_ASAP;372372+ purb->transfer_buffer = \373373+ peasycap->video_isoc_buffer[isbuf].pgo;374374+ purb->transfer_buffer_length = \375375+ peasycap->video_isoc_buffer_size;376376+ purb->complete = easycap_complete;377377+ purb->context = peasycap;378378+ purb->start_frame = 0;379379+ purb->number_of_packets = \380380+ peasycap->video_isoc_framesperdesc;381381+382382+ for (j = 0; j < peasycap->\383383+ video_isoc_framesperdesc; j++) {384384+ purb->iso_frame_desc[j].\385385+ offset = j * \386386+ peasycap->\387387+ video_isoc_maxframesize;388388+ purb->iso_frame_desc[j].\389389+ length = peasycap->\390390+ video_isoc_maxframesize;391391+ }392392+393393+ rc = usb_submit_urb(purb, GFP_KERNEL);394394+ if (0 != rc) {395395+ isbad++;396396+ SAY("ERROR: usb_submit_urb() failed " \397397+ "for urb with rc:\n");398398+ switch (rc) {399399+ case -ENOMEM: {400400+ SAY("ENOMEM\n");401401+ break;402402+ }403403+ case -ENODEV: {404404+ SAY("ENODEV\n");405405+ break;406406+ }407407+ case -ENXIO: {408408+ SAY("ENXIO\n");409409+ break;410410+ }411411+ case -EINVAL: {412412+ SAY("EINVAL\n");413413+ break;414414+ }415415+ case -EAGAIN: {416416+ SAY("EAGAIN\n");417417+ break;418418+ }419419+ case -EFBIG: {420420+ SAY("EFBIG\n");421421+ break;422422+ }423423+ case -EPIPE: {424424+ SAY("EPIPE\n");425425+ break;426426+ }427427+ case -EMSGSIZE: {428428+ SAY("EMSGSIZE\n");429429+ break;430430+ }431431+ default: {432432+ SAY("unknown error code %i\n",\433433+ rc);434434+ break;435435+ }436436+ }437437+ } else {438438+ m++;439439+ }440440+ } else {441441+ isbad++;442442+ }443443+ } else {444444+ isbad++;445445+ }446446+ }447447+ if (isbad) {448448+ JOT(4, "attempting cleanup instead of submitting\n");449449+ list_for_each(plist_head, (peasycap->purb_video_head)) {450450+ pdata_urb = list_entry(plist_head, struct data_urb, \451451+ list_head);452452+ if (NULL != pdata_urb) {453453+ purb = pdata_urb->purb;454454+ if (NULL != purb)455455+ usb_kill_urb(purb);456456+ }457457+ }458458+ peasycap->video_isoc_streaming = 0;459459+ } else {460460+ peasycap->video_isoc_streaming = 1;461461+ JOT(4, "submitted %i video urbs\n", m);462462+ }463463+464464+465465+466466+467467+468468+469469+} else {470470+ JOT(4, "already streaming video urbs\n");471471+}472472+return 0;473473+}474474+/*****************************************************************************/475475+int476476+kill_video_urbs(struct easycap *peasycap)477477+{478478+int m;479479+struct list_head *plist_head;480480+struct data_urb *pdata_urb;481481+482482+if ((struct easycap *)NULL == peasycap) {483483+ SAY("ERROR: peasycap is NULL\n");484484+ return -EFAULT;485485+}486486+if (peasycap->video_isoc_streaming) {487487+488488+489489+490490+ if ((struct list_head *)NULL != peasycap->purb_video_head) {491491+ peasycap->video_isoc_streaming = 0;492492+ JOT(4, "killing video urbs\n");493493+ m = 0;494494+ list_for_each(plist_head, (peasycap->purb_video_head)) {495495+ pdata_urb = list_entry(plist_head, struct data_urb, \496496+ list_head);497497+ if ((struct data_urb *)NULL != pdata_urb) {498498+ if ((struct urb *)NULL != pdata_urb->purb) {499499+ usb_kill_urb(pdata_urb->purb);500500+ m++;501501+ }502502+ }503503+ }504504+ JOT(4, "%i video urbs killed\n", m);505505+ } else {506506+ SAY("ERROR: peasycap->purb_video_head is NULL\n");507507+ return -EFAULT;508508+ }509509+} else {510510+ JOT(8, "%i=video_isoc_streaming, no video urbs killed\n", \511511+ peasycap->video_isoc_streaming);512512+}513513+return 0;514514+}515515+/****************************************************************************/516516+/*vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv*/517517+#if defined(EASYCAP_IS_VIDEODEV_CLIENT)518518+int519519+easycap_release_noinode(struct file *file)520520+{521521+return easycap_release((struct inode *)NULL, file);522522+}523523+#endif /*EASYCAP_IS_VIDEODEV_CLIENT*/524524+/*^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^*/525525+/*--------------------------------------------------------------------------*/526526+int527527+easycap_release(struct inode *inode, struct file *file)528528+{529529+#if (!defined(EASYCAP_IS_VIDEODEV_CLIENT))530530+struct easycap *peasycap;531531+532532+JOT(4, "\n");533533+534534+peasycap = (struct easycap *)file->private_data;535535+if (NULL == peasycap) {536536+ SAY("ERROR: peasycap is NULL.\n");537537+ SAY("ending unsuccessfully\n");538538+ return -EFAULT;539539+}540540+if (0 != kill_video_urbs(peasycap)) {541541+ SAY("ERROR: kill_video_urbs() failed\n");542542+ return -EFAULT;543543+}544544+JOT(4, "ending successfully\n");545545+/*vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv*/546546+#else547547+#548548+/*^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^*/549549+#endif /*EASYCAP_IS_VIDEODEV_CLIENT*/550550+551551+return 0;552552+}553553+/****************************************************************************/554554+/*vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv*/555555+#if defined(EASYCAP_IS_VIDEODEV_CLIENT)556556+int557557+videodev_release(struct video_device *pvd)558558+{559559+struct easycap *peasycap;560560+int i, j, k;561561+562562+JOT(4, "\n");563563+564564+k = 0;565565+for (i = 0; i < video_device_many; i++) {566566+ pvideo_device = pvideo_array[i];567567+ if ((struct video_device *)NULL != pvideo_device) {568568+ if (pvd->minor == pvideo_device->minor) {569569+ peasycap = (struct easycap *)\570570+ video_get_drvdata(pvideo_device);571571+ if ((struct easycap *)NULL == peasycap) {572572+ SAY("ERROR: peasycap is NULL\n");573573+ SAY("ending unsuccessfully\n");574574+ return -EFAULT;575575+ }576576+ if (0 != kill_video_urbs(peasycap)) {577577+ SAY("ERROR: kill_video_urbs() failed\n");578578+ return -EFAULT;579579+ }580580+ JOT(4, "freeing video_device structure: " \581581+ "/dev/video%i\n", i);582582+ kfree((void *)pvideo_device);583583+ for (j = i; j < (VIDEO_DEVICE_MANY - 1); j++)584584+ pvideo_array[j] = pvideo_array[j + 1];585585+ video_device_many--; k++;586586+ break;587587+ }588588+ }589589+}590590+if (!k) {591591+ SAY("ERROR: lost video_device structure for %i=minor\n", pvd->minor);592592+ SAY("cannot free: may cause memory leak\n");593593+ SAY("ending unsuccessfully\n");594594+ return -EFAULT;595595+}596596+597597+JOT(4, "ending successfully\n");598598+return 0;599599+}600600+#endif /*EASYCAP_IS_VIDEODEV_CLIENT*/601601+/*^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^*/602602+/****************************************************************************/603603+/*--------------------------------------------------------------------------*/604604+/*605605+ * THIS FUNCTION IS CALLED FROM WITHIN easycap_usb_disconnect().606606+ * BY THIS STAGE THE DEVICE HAS ALREADY BEEN PHYSICALLY UNPLUGGED.607607+ * peasycap->pusb_device IS NO LONGER VALID AND SHOULD HAVE BEEN SET TO NULL.608608+ */609609+/*---------------------------------------------------------------------------*/610610+void611611+easycap_delete(struct kref *pkref)612612+{613613+int k, m, lost;614614+int allocation_video_urb, allocation_video_page, allocation_video_struct;615615+int allocation_audio_urb, allocation_audio_page, allocation_audio_struct;616616+int registered_video, registered_audio;617617+struct easycap *peasycap;618618+struct data_urb *pdata_urb;619619+struct list_head *plist_head, *plist_next;620620+621621+JOT(4, "\n");622622+623623+peasycap = container_of(pkref, struct easycap, kref);624624+if ((struct easycap *)NULL == peasycap) {625625+ SAY("ERROR: peasycap is NULL: cannot perform deletions\n");626626+ return;627627+}628628+/*---------------------------------------------------------------------------*/629629+/*630630+ * FREE VIDEO.631631+ */632632+/*---------------------------------------------------------------------------*/633633+if ((struct list_head *)NULL != peasycap->purb_video_head) {634634+ JOT(4, "freeing video urbs\n");635635+ m = 0;636636+ list_for_each(plist_head, (peasycap->purb_video_head)) {637637+ pdata_urb = list_entry(plist_head, struct data_urb, list_head);638638+ if (NULL == pdata_urb)639639+ JOT(4, "ERROR: pdata_urb is NULL\n");640640+ else {641641+ if ((struct urb *)NULL != pdata_urb->purb) {642642+ usb_free_urb(pdata_urb->purb);643643+ pdata_urb->purb = (struct urb *)NULL;644644+ peasycap->allocation_video_urb -= 1;645645+ m++;646646+ }647647+ }648648+ }649649+650650+ JOT(4, "%i video urbs freed\n", m);651651+/*---------------------------------------------------------------------------*/652652+ JOT(4, "freeing video data_urb structures.\n");653653+ m = 0;654654+ list_for_each_safe(plist_head, plist_next, peasycap->purb_video_head) {655655+ pdata_urb = list_entry(plist_head, struct data_urb, list_head);656656+ if ((struct data_urb *)NULL != pdata_urb) {657657+ kfree(pdata_urb); pdata_urb = (struct data_urb *)NULL;658658+ peasycap->allocation_video_struct -= \659659+ sizeof(struct data_urb);660660+ m++;661661+ }662662+ }663663+ JOT(4, "%i video data_urb structures freed\n", m);664664+ JOT(4, "setting peasycap->purb_video_head=NULL\n");665665+ peasycap->purb_video_head = (struct list_head *)NULL;666666+ } else {667667+JOT(4, "peasycap->purb_video_head is NULL\n");668668+}669669+/*---------------------------------------------------------------------------*/670670+JOT(4, "freeing video isoc buffers.\n");671671+m = 0;672672+for (k = 0; k < VIDEO_ISOC_BUFFER_MANY; k++) {673673+ if ((void *)NULL != peasycap->video_isoc_buffer[k].pgo) {674674+ free_pages((unsigned long)\675675+ (peasycap->video_isoc_buffer[k].pgo), \676676+ VIDEO_ISOC_ORDER);677677+ peasycap->video_isoc_buffer[k].pgo = (void *)NULL;678678+ peasycap->allocation_video_page -= \679679+ ((unsigned int)(0x01 << VIDEO_ISOC_ORDER));680680+ m++;681681+ }682682+}683683+JOT(4, "isoc video buffers freed: %i pages\n", m * (0x01 << VIDEO_ISOC_ORDER));684684+/*---------------------------------------------------------------------------*/685685+JOT(4, "freeing video field buffers.\n");686686+lost = 0;687687+for (k = 0; k < FIELD_BUFFER_MANY; k++) {688688+ for (m = 0; m < FIELD_BUFFER_SIZE/PAGE_SIZE; m++) {689689+ if ((void *)NULL != peasycap->field_buffer[k][m].pgo) {690690+ free_page((unsigned long)\691691+ (peasycap->field_buffer[k][m].pgo));692692+ peasycap->field_buffer[k][m].pgo = (void *)NULL;693693+ peasycap->allocation_video_page -= 1;694694+ lost++;695695+ }696696+ }697697+}698698+JOT(4, "video field buffers freed: %i pages\n", lost);699699+/*---------------------------------------------------------------------------*/700700+JOT(4, "freeing video frame buffers.\n");701701+lost = 0;702702+for (k = 0; k < FRAME_BUFFER_MANY; k++) {703703+ for (m = 0; m < FRAME_BUFFER_SIZE/PAGE_SIZE; m++) {704704+ if ((void *)NULL != peasycap->frame_buffer[k][m].pgo) {705705+ free_page((unsigned long)\706706+ (peasycap->frame_buffer[k][m].pgo));707707+ peasycap->frame_buffer[k][m].pgo = (void *)NULL;708708+ peasycap->allocation_video_page -= 1;709709+ lost++;710710+ }711711+ }712712+}713713+JOT(4, "video frame buffers freed: %i pages\n", lost);714714+/*---------------------------------------------------------------------------*/715715+/*716716+ * FREE AUDIO.717717+ */718718+/*---------------------------------------------------------------------------*/719719+if ((struct list_head *)NULL != peasycap->purb_audio_head) {720720+ JOT(4, "freeing audio urbs\n");721721+ m = 0;722722+ list_for_each(plist_head, (peasycap->purb_audio_head)) {723723+ pdata_urb = list_entry(plist_head, struct data_urb, list_head);724724+ if (NULL == pdata_urb)725725+ JOT(4, "ERROR: pdata_urb is NULL\n");726726+ else {727727+ if ((struct urb *)NULL != pdata_urb->purb) {728728+ usb_free_urb(pdata_urb->purb);729729+ pdata_urb->purb = (struct urb *)NULL;730730+ peasycap->allocation_audio_urb -= 1;731731+ m++;732732+ }733733+ }734734+ }735735+ JOT(4, "%i audio urbs freed\n", m);736736+/*---------------------------------------------------------------------------*/737737+ JOT(4, "freeing audio data_urb structures.\n");738738+ m = 0;739739+ list_for_each_safe(plist_head, plist_next, peasycap->purb_audio_head) {740740+ pdata_urb = list_entry(plist_head, struct data_urb, list_head);741741+ if ((struct data_urb *)NULL != pdata_urb) {742742+ kfree(pdata_urb); pdata_urb = (struct data_urb *)NULL;743743+ peasycap->allocation_audio_struct -= \744744+ sizeof(struct data_urb);745745+ m++;746746+ }747747+ }748748+JOT(4, "%i audio data_urb structures freed\n", m);749749+JOT(4, "setting peasycap->purb_audio_head=NULL\n");750750+peasycap->purb_audio_head = (struct list_head *)NULL;751751+} else {752752+JOT(4, "peasycap->purb_audio_head is NULL\n");753753+}754754+/*---------------------------------------------------------------------------*/755755+JOT(4, "freeing audio isoc buffers.\n");756756+m = 0;757757+for (k = 0; k < AUDIO_ISOC_BUFFER_MANY; k++) {758758+ if ((void *)NULL != peasycap->audio_isoc_buffer[k].pgo) {759759+ free_pages((unsigned long)\760760+ (peasycap->audio_isoc_buffer[k].pgo), \761761+ AUDIO_ISOC_ORDER);762762+ peasycap->audio_isoc_buffer[k].pgo = (void *)NULL;763763+ peasycap->allocation_audio_page -= \764764+ ((unsigned int)(0x01 << AUDIO_ISOC_ORDER));765765+ m++;766766+ }767767+}768768+JOT(4, "easysnd_delete(): isoc audio buffers freed: %i pages\n", \769769+ m * (0x01 << AUDIO_ISOC_ORDER));770770+/*---------------------------------------------------------------------------*/771771+JOT(4, "freeing audio buffers.\n");772772+lost = 0;773773+for (k = 0; k < audio_buffer_page_many; k++) {774774+ if ((void *)NULL != peasycap->audio_buffer[k].pgo) {775775+ free_page((unsigned long)(peasycap->audio_buffer[k].pgo));776776+ peasycap->audio_buffer[k].pgo = (void *)NULL;777777+ peasycap->allocation_audio_page -= 1;778778+ lost++;779779+ }780780+}781781+JOT(4, "easysnd_delete(): audio buffers freed: %i pages\n", lost);782782+/*---------------------------------------------------------------------------*/783783+JOT(4, "freeing easycap structure.\n");784784+allocation_video_urb = peasycap->allocation_video_urb;785785+allocation_video_page = peasycap->allocation_video_page;786786+allocation_video_struct = peasycap->allocation_video_struct;787787+registered_video = peasycap->registered_video;788788+allocation_audio_urb = peasycap->allocation_audio_urb;789789+allocation_audio_page = peasycap->allocation_audio_page;790790+allocation_audio_struct = peasycap->allocation_audio_struct;791791+registered_audio = peasycap->registered_audio;792792+m = 0;793793+if ((struct easycap *)NULL != peasycap) {794794+ kfree(peasycap); peasycap = (struct easycap *)NULL;795795+ allocation_video_struct -= sizeof(struct easycap);796796+ m++;797797+}798798+JOT(4, "%i easycap structure freed\n", m);799799+/*---------------------------------------------------------------------------*/800800+801801+SAY("%8i= video urbs after all deletions\n", allocation_video_urb);802802+SAY("%8i= video pages after all deletions\n", allocation_video_page);803803+SAY("%8i= video structs after all deletions\n", allocation_video_struct);804804+SAY("%8i= video devices after all deletions\n", registered_video);805805+SAY("%8i= audio urbs after all deletions\n", allocation_audio_urb);806806+SAY("%8i= audio pages after all deletions\n", allocation_audio_page);807807+SAY("%8i= audio structs after all deletions\n", allocation_audio_struct);808808+SAY("%8i= audio devices after all deletions\n", registered_audio);809809+810810+JOT(4, "ending.\n");811811+return;812812+}813813+/*****************************************************************************/814814+unsigned int easycap_poll(struct file *file, poll_table *wait)815815+{816816+struct easycap *peasycap;817817+818818+JOT(8, "\n");819819+820820+if (NULL == ((poll_table *)wait))821821+ JOT(8, "WARNING: poll table pointer is NULL ... continuing\n");822822+if (NULL == ((struct file *)file)) {823823+ SAY("ERROR: file pointer is NULL\n");824824+ return -EFAULT;825825+}826826+peasycap = (struct easycap *)file->private_data;827827+if (NULL == peasycap) {828828+ SAY("ERROR: peasycap is NULL\n");829829+ return -EFAULT;830830+}831831+peasycap->polled = 1;832832+833833+if (0 == easycap_dqbuf(peasycap, 0))834834+ return POLLIN | POLLRDNORM;835835+else836836+ return POLLERR;837837+838838+}839839+/*****************************************************************************/840840+/*---------------------------------------------------------------------------*/841841+/*842842+ * IF mode IS NONZERO THIS ROUTINE RETURNS -EAGAIN RATHER THAN BLOCKING.843843+ */844844+/*---------------------------------------------------------------------------*/845845+int846846+easycap_dqbuf(struct easycap *peasycap, int mode)847847+{848848+int miss, rc;849849+850850+JOT(8, "\n");851851+852852+if (NULL == peasycap) {853853+ SAY("ERROR: peasycap is NULL\n");854854+ return -EFAULT;855855+}856856+/*---------------------------------------------------------------------------*/857857+/*858858+ * WAIT FOR FIELD 0859859+ */860860+/*---------------------------------------------------------------------------*/861861+miss = 0;862862+if (mutex_lock_interruptible(&(peasycap->mutex_mmap_video[0])))863863+ return -ERESTARTSYS;864864+while ((peasycap->field_read == peasycap->field_fill) || \865865+ (0 != (0xFF00 & peasycap->field_buffer\866866+ [peasycap->field_read][0].kount)) || \867867+ (0 != (0x00FF & peasycap->field_buffer\868868+ [peasycap->field_read][0].kount))) {869869+ mutex_unlock(&(peasycap->mutex_mmap_video[0]));870870+871871+ if (mode)872872+ return -EAGAIN;873873+874874+ JOT(8, "first wait on wq_video, " \875875+ "%i=field_read %i=field_fill\n", \876876+ peasycap->field_read, peasycap->field_fill);877877+878878+ msleep(1);879879+ if (0 != (wait_event_interruptible(peasycap->wq_video, \880880+ (peasycap->video_idle || peasycap->video_eof || \881881+ ((peasycap->field_read != peasycap->field_fill) && \882882+ (0 == (0xFF00 & peasycap->field_buffer\883883+ [peasycap->field_read][0].kount)) && \884884+ (0 == (0x00FF & peasycap->field_buffer\885885+ [peasycap->field_read][0].kount))))))){886886+ SAY("aborted by signal\n");887887+ return -EIO;888888+ }889889+ if (peasycap->video_idle) {890890+ JOT(8, "%i=peasycap->video_idle\n", peasycap->video_idle);891891+ return -EIO;892892+ }893893+ if (peasycap->video_eof) {894894+ JOT(8, "%i=peasycap->video_eof\n", peasycap->video_eof);895895+ debrief(peasycap);896896+ kill_video_urbs(peasycap);897897+ return -EIO;898898+ }899899+miss++;900900+if (mutex_lock_interruptible(&(peasycap->mutex_mmap_video[0])))901901+ return -ERESTARTSYS;902902+}903903+mutex_unlock(&(peasycap->mutex_mmap_video[0]));904904+JOT(8, "first awakening on wq_video after %i waits\n", miss);905905+906906+rc = field2frame(peasycap);907907+if (0 != rc)908908+ SAY("ERROR: field2frame() returned %i\n", rc);909909+910910+if (true == peasycap->offerfields) {911911+ peasycap->frame_read = peasycap->frame_fill;912912+ (peasycap->frame_fill)++;913913+ if (peasycap->frame_buffer_many <= peasycap->frame_fill)914914+ peasycap->frame_fill = 0;915915+916916+ if (0x01 & easycap_standard[peasycap->standard_offset].mask) {917917+ peasycap->frame_buffer[peasycap->frame_read][0].kount = \918918+ V4L2_FIELD_BOTTOM;919919+ } else {920920+ peasycap->frame_buffer[peasycap->frame_read][0].kount = \921921+ V4L2_FIELD_TOP;922922+ }923923+JOT(8, "setting: %i=peasycap->frame_read\n", peasycap->frame_read);924924+JOT(8, "bumped to: %i=peasycap->frame_fill\n", peasycap->frame_fill);925925+}926926+/*---------------------------------------------------------------------------*/927927+/*928928+ * WAIT FOR FIELD 1929929+ */930930+/*---------------------------------------------------------------------------*/931931+miss = 0;932932+if (mutex_lock_interruptible(&(peasycap->mutex_mmap_video[0])))933933+ return -ERESTARTSYS;934934+while ((peasycap->field_read == peasycap->field_fill) || \935935+ (0 != (0xFF00 & peasycap->field_buffer\936936+ [peasycap->field_read][0].kount)) || \937937+ (0 == (0x00FF & peasycap->field_buffer\938938+ [peasycap->field_read][0].kount))) {939939+ mutex_unlock(&(peasycap->mutex_mmap_video[0]));940940+941941+ if (mode)942942+ return -EAGAIN;943943+944944+ JOT(8, "second wait on wq_video, " \945945+ "%i=field_read %i=field_fill\n", \946946+ peasycap->field_read, peasycap->field_fill);947947+ msleep(1);948948+ if (0 != (wait_event_interruptible(peasycap->wq_video, \949949+ (peasycap->video_idle || peasycap->video_eof || \950950+ ((peasycap->field_read != peasycap->field_fill) && \951951+ (0 == (0xFF00 & peasycap->field_buffer\952952+ [peasycap->field_read][0].kount)) && \953953+ (0 != (0x00FF & peasycap->field_buffer\954954+ [peasycap->field_read][0].kount))))))){955955+ SAY("aborted by signal\n");956956+ return -EIO;957957+ }958958+ if (peasycap->video_idle) {959959+ JOT(8, "%i=peasycap->video_idle\n", peasycap->video_idle);960960+ return -EIO;961961+ }962962+ if (peasycap->video_eof) {963963+ JOT(8, "%i=peasycap->video_eof\n", peasycap->video_eof);964964+ debrief(peasycap);965965+ kill_video_urbs(peasycap);966966+ return -EIO;967967+ }968968+miss++;969969+if (mutex_lock_interruptible(&(peasycap->mutex_mmap_video[0])))970970+ return -ERESTARTSYS;971971+}972972+mutex_unlock(&(peasycap->mutex_mmap_video[0]));973973+JOT(8, "second awakening on wq_video after %i waits\n", miss);974974+975975+rc = field2frame(peasycap);976976+if (0 != rc)977977+ SAY("ERROR: field2frame() returned %i\n", rc);978978+979979+peasycap->frame_read = peasycap->frame_fill;980980+peasycap->queued[peasycap->frame_read] = 0;981981+peasycap->done[peasycap->frame_read] = V4L2_BUF_FLAG_DONE;982982+983983+(peasycap->frame_fill)++;984984+if (peasycap->frame_buffer_many <= peasycap->frame_fill)985985+ peasycap->frame_fill = 0;986986+987987+if (0x01 & easycap_standard[peasycap->standard_offset].mask) {988988+ peasycap->frame_buffer[peasycap->frame_read][0].kount = \989989+ V4L2_FIELD_TOP;990990+} else {991991+ peasycap->frame_buffer[peasycap->frame_read][0].kount = \992992+ V4L2_FIELD_BOTTOM;993993+}994994+995995+JOT(8, "setting: %i=peasycap->frame_read\n", peasycap->frame_read);996996+JOT(8, "bumped to: %i=peasycap->frame_fill\n", peasycap->frame_fill);997997+998998+return 0;999999+}10001000+/*****************************************************************************/10011001+/*---------------------------------------------------------------------------*/10021002+/*10031003+ * BY DEFINITION, odd IS true FOR THE FIELD OCCUPYING LINES 1,3,5,...,47910041004+ * odd IS false FOR THE FIELD OCCUPYING LINES 0,2,4,...,47810051005+ *10061006+ * WHEN BOOLEAN PARAMETER decimatepixel IS true, ONLY THE FIELD FOR WHICH10071007+ * odd==false IS TRANSFERRED TO THE FRAME BUFFER.10081008+ *10091009+ * THE BOOLEAN PARAMETER offerfields IS true ONLY WHEN THE USER PROGRAM10101010+ * CHOOSES THE OPTION V4L2_FIELD_ALTERNATE. NO USERSPACE PROGRAM TESTED10111011+ * TO DATE HAS DONE THIS. BUGS ARE LIKELY.10121012+ */10131013+/*---------------------------------------------------------------------------*/10141014+int10151015+field2frame(struct easycap *peasycap)10161016+{10171017+static struct timeval timeval0;10181018+struct timeval timeval;10191019+long long int above, below;10201020+__u32 remainder;10211021+struct signed_div_result sdr;10221022+10231023+void *pex, *pad;10241024+int kex, kad, mex, mad, rex, rad, rad2;10251025+int c2, c3, w2, w3, cz, wz;10261026+int rc, bytesperpixel, multiplier, much, more, over, rump, caches;10271027+__u8 mask, margin;10281028+bool odd, isuy, decimatepixel, offerfields;10291029+10301030+JOT(8, "===== parity %i, field buffer %i --> frame buffer %i\n", \10311031+ peasycap->field_buffer[peasycap->field_read][0].kount,\10321032+ peasycap->field_read, peasycap->frame_fill);10331033+JOT(8, "===== %i=bytesperpixel\n", peasycap->bytesperpixel);10341034+if (true == peasycap->offerfields)10351035+ JOT(8, "===== offerfields\n");10361036+10371037+/*---------------------------------------------------------------------------*/10381038+/*10391039+ * REJECT OR CLEAN BAD FIELDS10401040+ */10411041+/*---------------------------------------------------------------------------*/10421042+if (peasycap->field_read == peasycap->field_fill) {10431043+ SAY("ERROR: on entry, still filling field buffer %i\n", \10441044+ peasycap->field_read);10451045+ return 0;10461046+}10471047+#if defined(EASYCAP_TESTCARD)10481048+easycap_testcard(peasycap, peasycap->field_read);10491049+#else10501050+if (0 != (0x0400 & peasycap->field_buffer[peasycap->field_read][0].kount))10511051+ easycap_testcard(peasycap, peasycap->field_read);10521052+#endif /*EASYCAP_TESTCARD*/10531053+/*---------------------------------------------------------------------------*/10541054+10551055+offerfields = peasycap->offerfields;10561056+bytesperpixel = peasycap->bytesperpixel;10571057+decimatepixel = peasycap->decimatepixel;10581058+10591059+if ((2 != bytesperpixel) && \10601060+ (3 != bytesperpixel) && \10611061+ (4 != bytesperpixel)) {10621062+ SAY("MISTAKE: %i=bytesperpixel\n", bytesperpixel);10631063+ return -EFAULT;10641064+}10651065+if (true == decimatepixel)10661066+ multiplier = 2;10671067+else10681068+ multiplier = 1;10691069+10701070+w2 = 2 * multiplier * (peasycap->width);10711071+w3 = bytesperpixel * \10721072+ multiplier * \10731073+ (peasycap->width);10741074+wz = multiplier * \10751075+ (peasycap->height) * \10761076+ multiplier * \10771077+ (peasycap->width);10781078+10791079+kex = peasycap->field_read; mex = 0;10801080+kad = peasycap->frame_fill; mad = 0;10811081+10821082+pex = peasycap->field_buffer[kex][0].pgo; rex = PAGE_SIZE;10831083+pad = peasycap->frame_buffer[kad][0].pgo; rad = PAGE_SIZE;10841084+if (peasycap->field_buffer[kex][0].kount)10851085+ odd = true;10861086+else10871087+ odd = false;10881088+10891089+if ((true == odd) && (false == offerfields) &&(false == decimatepixel)) {10901090+ JOT(8, " initial skipping %4i bytes p.%4i\n", \10911091+ w3/multiplier, mad);10921092+ pad += (w3 / multiplier); rad -= (w3 / multiplier);10931093+}10941094+isuy = true;10951095+mask = 0; rump = 0; caches = 0;10961096+10971097+cz = 0;10981098+while (cz < wz) {10991099+ /*-------------------------------------------------------------------*/11001100+ /*11011101+ ** PROCESS ONE LINE OF FRAME AT FULL RESOLUTION:11021102+ ** READ w2 BYTES FROM FIELD BUFFER,11031103+ ** WRITE w3 BYTES TO FRAME BUFFER11041104+ **/11051105+ /*-------------------------------------------------------------------*/11061106+ if (false == decimatepixel) {11071107+ over = w2;11081108+ do {11091109+ much = over; more = 0; margin = 0; mask = 0x00;11101110+ if (rex < much)11111111+ much = rex;11121112+ rump = 0;11131113+11141114+ if (much % 2) {11151115+ SAY("MISTAKE: much is odd\n");11161116+ return -EFAULT;11171117+ }11181118+11191119+ more = (bytesperpixel * \11201120+ much) / 2;11211121+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */11221122+ if (1 < bytesperpixel) {11231123+ if ((rad * \11241124+ 2) < (much * \11251125+ bytesperpixel)) {11261126+ /*11271127+ ** INJUDICIOUS ALTERATION OF THIS11281128+ ** BLOCK WILL CAUSE BREAKAGE.11291129+ ** BEWARE.11301130+ **/11311131+ rad2 = rad + bytesperpixel - 1;11321132+ much = ((((2 * \11331133+ rad2)/bytesperpixel)/2) * 2);11341134+ rump = ((bytesperpixel * \11351135+ much) / 2) - rad;11361136+ more = rad;11371137+ }11381138+ mask = (__u8)rump;11391139+ margin = 0;11401140+ if (much == rex) {11411141+ mask |= 0x04;11421142+ if ((mex + 1) < FIELD_BUFFER_SIZE/ \11431143+ PAGE_SIZE) {11441144+ margin = *((__u8 *)(peasycap->\11451145+ field_buffer\11461146+ [kex][mex + 1].pgo));11471147+ } else11481148+ mask |= 0x08;11491149+ }11501150+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */11511151+ } else {11521152+ SAY("MISTAKE: %i=bytesperpixel\n", \11531153+ bytesperpixel);11541154+ return -EFAULT;11551155+ }11561156+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */11571157+ if (rump)11581158+ caches++;11591159+11601160+ rc = redaub(peasycap, pad, pex, much, more, \11611161+ mask, margin, isuy);11621162+ if (0 > rc) {11631163+ SAY("ERROR: redaub() failed\n");11641164+ return -EFAULT;11651165+ }11661166+ if (much % 4) {11671167+ if (isuy)11681168+ isuy = false;11691169+ else11701170+ isuy = true;11711171+ }11721172+ over -= much; cz += much;11731173+ pex += much; rex -= much;11741174+ if (!rex) {11751175+ mex++;11761176+ pex = peasycap->field_buffer[kex][mex].pgo;11771177+ rex = PAGE_SIZE;11781178+ }11791179+ pad += more;11801180+ rad -= more;11811181+ if (!rad) {11821182+ mad++;11831183+ pad = peasycap->frame_buffer[kad][mad].pgo;11841184+ rad = PAGE_SIZE;11851185+ if (rump) {11861186+ pad += rump;11871187+ rad -= rump;11881188+ }11891189+ }11901190+ } while (over);11911191+/*---------------------------------------------------------------------------*/11921192+/*11931193+ * SKIP w3 BYTES IN TARGET FRAME BUFFER,11941194+ * UNLESS IT IS THE LAST LINE OF AN ODD FRAME11951195+ */11961196+/*---------------------------------------------------------------------------*/11971197+ if (((false == odd) || (cz != wz))&&(false == offerfields)) {11981198+ over = w3;11991199+ do {12001200+ if (!rad) {12011201+ mad++;12021202+ pad = peasycap->frame_buffer\12031203+ [kad][mad].pgo;12041204+ rad = PAGE_SIZE;12051205+ }12061206+ more = over;12071207+ if (rad < more)12081208+ more = rad;12091209+ over -= more;12101210+ pad += more;12111211+ rad -= more;12121212+ } while (over);12131213+ }12141214+/*---------------------------------------------------------------------------*/12151215+/*12161216+ * PROCESS ONE LINE OF FRAME AT REDUCED RESOLUTION:12171217+ * ONLY IF false==odd,12181218+ * READ w2 BYTES FROM FIELD BUFFER,12191219+ * WRITE w3 / 2 BYTES TO FRAME BUFFER12201220+ */12211221+/*---------------------------------------------------------------------------*/12221222+ } else if (false == odd) {12231223+ over = w2;12241224+ do {12251225+ much = over; more = 0; margin = 0; mask = 0x00;12261226+ if (rex < much)12271227+ much = rex;12281228+ rump = 0;12291229+12301230+ if (much % 2) {12311231+ SAY("MISTAKE: much is odd\n");12321232+ return -EFAULT;12331233+ }12341234+12351235+ more = (bytesperpixel * \12361236+ much) / 4;12371237+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */12381238+ if (1 < bytesperpixel) {12391239+ if ((rad * 4) < (much * \12401240+ bytesperpixel)) {12411241+ /*12421242+ ** INJUDICIOUS ALTERATION OF THIS12431243+ ** BLOCK WILL CAUSE BREAKAGE.12441244+ ** BEWARE.12451245+ **/12461246+ rad2 = rad + bytesperpixel - 1;12471247+ much = ((((2 * rad2)/bytesperpixel)/2)\12481248+ * 4);12491249+ rump = ((bytesperpixel * \12501250+ much) / 4) - rad;12511251+ more = rad;12521252+ }12531253+ mask = (__u8)rump;12541254+ margin = 0;12551255+ if (much == rex) {12561256+ mask |= 0x04;12571257+ if ((mex + 1) < FIELD_BUFFER_SIZE/ \12581258+ PAGE_SIZE) {12591259+ margin = *((__u8 *)(peasycap->\12601260+ field_buffer\12611261+ [kex][mex + 1].pgo));12621262+ }12631263+ else12641264+ mask |= 0x08;12651265+ }12661266+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */12671267+ } else {12681268+ SAY("MISTAKE: %i=bytesperpixel\n", \12691269+ bytesperpixel);12701270+ return -EFAULT;12711271+ }12721272+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */12731273+ if (rump)12741274+ caches++;12751275+12761276+ rc = redaub(peasycap, pad, pex, much, more, \12771277+ mask, margin, isuy);12781278+ if (0 > rc) {12791279+ SAY("ERROR: redaub() failed\n");12801280+ return -EFAULT;12811281+ }12821282+ over -= much; cz += much;12831283+ pex += much; rex -= much;12841284+ if (!rex) {12851285+ mex++;12861286+ pex = peasycap->field_buffer[kex][mex].pgo;12871287+ rex = PAGE_SIZE;12881288+ }12891289+ pad += more;12901290+ rad -= more;12911291+ if (!rad) {12921292+ mad++;12931293+ pad = peasycap->frame_buffer[kad][mad].pgo;12941294+ rad = PAGE_SIZE;12951295+ if (rump) {12961296+ pad += rump;12971297+ rad -= rump;12981298+ }12991299+ }13001300+ } while (over);13011301+/*---------------------------------------------------------------------------*/13021302+/*13031303+ * OTHERWISE JUST13041304+ * READ w2 BYTES FROM FIELD BUFFER AND DISCARD THEM13051305+ */13061306+/*---------------------------------------------------------------------------*/13071307+ } else {13081308+ over = w2;13091309+ do {13101310+ if (!rex) {13111311+ mex++;13121312+ pex = peasycap->field_buffer[kex][mex].pgo;13131313+ rex = PAGE_SIZE;13141314+ }13151315+ much = over;13161316+ if (rex < much)13171317+ much = rex;13181318+ over -= much;13191319+ cz += much;13201320+ pex += much;13211321+ rex -= much;13221322+ } while (over);13231323+ }13241324+}13251325+/*---------------------------------------------------------------------------*/13261326+/*13271327+ * SANITY CHECKS13281328+ */13291329+/*---------------------------------------------------------------------------*/13301330+c2 = (mex + 1)*PAGE_SIZE - rex;13311331+if (cz != c2)13321332+ SAY("ERROR: discrepancy %i in bytes read\n", c2 - cz);13331333+c3 = (mad + 1)*PAGE_SIZE - rad;13341334+13351335+if (false == decimatepixel) {13361336+ if (bytesperpixel * \13371337+ cz != c3) \13381338+ SAY("ERROR: discrepancy %i in bytes written\n", \13391339+ c3 - (bytesperpixel * \13401340+ cz));13411341+} else {13421342+ if (false == odd) {13431343+ if (bytesperpixel * \13441344+ cz != (4 * c3))13451345+ SAY("ERROR: discrepancy %i in bytes written\n", \13461346+ (2*c3)-(bytesperpixel * \13471347+ cz));13481348+ } else {13491349+ if (0 != c3)13501350+ SAY("ERROR: discrepancy %i " \13511351+ "in bytes written\n", c3);13521352+ }13531353+}13541354+if (rump)13551355+ SAY("ERROR: undischarged cache at end of line in frame buffer\n");13561356+13571357+JOT(8, "===== field2frame(): %i bytes --> %i bytes (incl skip)\n", c2, c3);13581358+JOT(8, "===== field2frame(): %i=mad %i=rad\n", mad, rad);13591359+13601360+if (true == odd)13611361+ JOT(8, "+++++ field2frame(): frame buffer %i is full\n", kad);13621362+13631363+if (peasycap->field_read == peasycap->field_fill)13641364+ SAY("WARNING: on exit, filling field buffer %i\n", \13651365+ peasycap->field_read);13661366+/*---------------------------------------------------------------------------*/13671367+/*13681368+ * CALCULATE VIDEO STREAMING RATE13691369+ */13701370+/*---------------------------------------------------------------------------*/13711371+do_gettimeofday(&timeval);13721372+if (timeval0.tv_sec) {13731373+ below = ((long long int)(1000000)) * \13741374+ ((long long int)(timeval.tv_sec - timeval0.tv_sec)) + \13751375+ (long long int)(timeval.tv_usec - timeval0.tv_usec);13761376+ above = (long long int)1000000;13771377+13781378+ sdr = signed_div(above, below);13791379+ above = sdr.quotient;13801380+ remainder = (__u32)sdr.remainder;13811381+13821382+ JOT(8, "video streaming at %3lli.%03i fields per second\n", above, \13831383+ (remainder/1000));13841384+}13851385+timeval0 = timeval;13861386+13871387+if (caches)13881388+ JOT(8, "%i=caches\n", caches);13891389+return 0;13901390+}13911391+/*****************************************************************************/13921392+struct signed_div_result13931393+signed_div(long long int above, long long int below)13941394+{13951395+struct signed_div_result sdr;13961396+13971397+if (((0 <= above) && (0 <= below)) || ((0 > above) && (0 > below))) {13981398+ sdr.remainder = (unsigned long long int) do_div(above, below);13991399+ sdr.quotient = (long long int) above;14001400+} else {14011401+ if (0 > above)14021402+ above = -above;14031403+ if (0 > below)14041404+ below = -below;14051405+ sdr.remainder = (unsigned long long int) do_div(above, below);14061406+ sdr.quotient = -((long long int) above);14071407+}14081408+return sdr;14091409+}14101410+/*****************************************************************************/14111411+/*---------------------------------------------------------------------------*/14121412+/*14131413+ * DECIMATION AND COLOURSPACE CONVERSION.14141414+ *14151415+ * THIS ROUTINE REQUIRES THAT ALL THE DATA TO BE READ RESIDES ON ONE PAGE14161416+ * AND THAT ALL THE DATA TO BE WRITTEN RESIDES ON ONE (DIFFERENT) PAGE.14171417+ * THE CALLING ROUTINE MUST ENSURE THAT THIS REQUIREMENT IS MET, AND MUST14181418+ * ALSO ENSURE THAT much IS EVEN.14191419+ *14201420+ * much BYTES ARE READ, AT LEAST (bytesperpixel * much)/2 BYTES ARE WRITTEN14211421+ * IF THERE IS NO DECIMATION, HALF THIS AMOUNT IF THERE IS DECIMATION.14221422+ *14231423+ * mask IS ZERO WHEN NO SPECIAL BEHAVIOUR REQUIRED. OTHERWISE IT IS SET THUS:14241424+ * 0x03 & mask = number of bytes to be written to cache instead of to14251425+ * frame buffer14261426+ * 0x04 & mask => use argument margin to set the chrominance for last pixel14271427+ * 0x08 & mask => do not set the chrominance for last pixel14281428+ *14291429+ * YUV to RGB CONVERSION IS (OR SHOULD BE) ITU-R BT 601.14301430+ *14311431+ * THERE IS A LOT OF CODE REPETITION IN THIS ROUTINE IN ORDER TO AVOID14321432+ * INEFFICIENT SWITCHING INSIDE INNER LOOPS. REARRANGING THE LOGIC TO14331433+ * REDUCE CODE LENGTH WILL GENERALLY IMPAIR RUNTIME PERFORMANCE. BEWARE.14341434+ */14351435+/*---------------------------------------------------------------------------*/14361436+int14371437+redaub(struct easycap *peasycap, void *pad, void *pex, int much, int more, \14381438+ __u8 mask, __u8 margin, bool isuy)14391439+{14401440+static __s32 ay[256], bu[256], rv[256], gu[256], gv[256];14411441+static __u8 cache[8], *pcache;14421442+__u8 r, g, b, y, u, v, c, *p2, *p3, *pz, *pr;14431443+int bytesperpixel;14441444+bool byteswaporder, decimatepixel, last;14451445+int j, rump;14461446+__s32 s32;14471447+14481448+if (much % 2) {14491449+ SAY("MISTAKE: much is odd\n");14501450+ return -EFAULT;14511451+}14521452+bytesperpixel = peasycap->bytesperpixel;14531453+byteswaporder = peasycap->byteswaporder;14541454+decimatepixel = peasycap->decimatepixel;14551455+14561456+/*---------------------------------------------------------------------------*/14571457+if (!bu[255]) {14581458+ for (j = 0; j < 112; j++) {14591459+ s32 = (0xFF00 & (453 * j)) >> 8;14601460+ bu[j + 128] = s32; bu[127 - j] = -s32;14611461+ s32 = (0xFF00 & (359 * j)) >> 8;14621462+ rv[j + 128] = s32; rv[127 - j] = -s32;14631463+ s32 = (0xFF00 & (88 * j)) >> 8;14641464+ gu[j + 128] = s32; gu[127 - j] = -s32;14651465+ s32 = (0xFF00 & (183 * j)) >> 8;14661466+ gv[j + 128] = s32; gv[127 - j] = -s32;14671467+ }14681468+ for (j = 0; j < 16; j++) {14691469+ bu[j] = bu[16]; rv[j] = rv[16];14701470+ gu[j] = gu[16]; gv[j] = gv[16];14711471+ }14721472+ for (j = 240; j < 256; j++) {14731473+ bu[j] = bu[239]; rv[j] = rv[239];14741474+ gu[j] = gu[239]; gv[j] = gv[239];14751475+ }14761476+ for (j = 16; j < 236; j++)14771477+ ay[j] = j;14781478+ for (j = 0; j < 16; j++)14791479+ ay[j] = ay[16];14801480+ for (j = 236; j < 256; j++)14811481+ ay[j] = ay[235];14821482+ JOT(8, "lookup tables are prepared\n");14831483+}14841484+if ((__u8 *)NULL == pcache)14851485+ pcache = &cache[0];14861486+/*---------------------------------------------------------------------------*/14871487+/*14881488+ * TRANSFER CONTENTS OF CACHE TO THE FRAME BUFFER14891489+ */14901490+/*---------------------------------------------------------------------------*/14911491+if (!pcache) {14921492+ SAY("MISTAKE: pcache is NULL\n");14931493+ return -EFAULT;14941494+}14951495+14961496+if (pcache != &cache[0])14971497+ JOT(16, "cache has %i bytes\n", (int)(pcache - &cache[0]));14981498+p2 = &cache[0];14991499+p3 = (__u8 *)pad - (int)(pcache - &cache[0]);15001500+while (p2 < pcache) {15011501+ *p3++ = *p2; p2++;15021502+}15031503+pcache = &cache[0];15041504+if (p3 != pad) {15051505+ SAY("MISTAKE: pointer misalignment\n");15061506+ return -EFAULT;15071507+}15081508+/*---------------------------------------------------------------------------*/15091509+rump = (int)(0x03 & mask);15101510+u = 0; v = 0;15111511+p2 = (__u8 *)pex; pz = p2 + much; pr = p3 + more; last = false;15121512+p2++;15131513+15141514+if (true == isuy)15151515+ u = *(p2 - 1);15161516+else15171517+ v = *(p2 - 1);15181518+15191519+if (rump)15201520+ JOT(16, "%4i=much %4i=more %i=rump\n", much, more, rump);15211521+15221522+/*---------------------------------------------------------------------------*/15231523+switch (bytesperpixel) {15241524+case 2: {15251525+ if (false == decimatepixel) {15261526+ memcpy(pad, pex, (size_t)much);15271527+ if (false == byteswaporder)15281528+ /*---------------------------------------------------*/15291529+ /*15301530+ ** UYVY15311531+ */15321532+ /*---------------------------------------------------*/15331533+ return 0;15341534+ else {15351535+ /*---------------------------------------------------*/15361536+ /*15371537+ ** YUYV15381538+ */15391539+ /*---------------------------------------------------*/15401540+ p3 = (__u8 *)pad; pz = p3 + much;15411541+ while (pz > p3) {15421542+ c = *p3;15431543+ *p3 = *(p3 + 1);15441544+ *(p3 + 1) = c;15451545+ p3 += 2;15461546+ }15471547+ return 0;15481548+ }15491549+ } else {15501550+ if (false == byteswaporder) {15511551+ /*---------------------------------------------------*/15521552+ /*15531553+ ** UYVY DECIMATED15541554+ */15551555+ /*---------------------------------------------------*/15561556+ p2 = (__u8 *)pex; p3 = (__u8 *)pad; pz = p2 + much;15571557+ while (pz > p2) {15581558+ *p3 = *p2;15591559+ *(p3 + 1) = *(p2 + 1);15601560+ *(p3 + 2) = *(p2 + 2);15611561+ *(p3 + 3) = *(p2 + 3);15621562+ p3 += 4; p2 += 8;15631563+ }15641564+ return 0;15651565+ } else {15661566+ /*---------------------------------------------------*/15671567+ /*15681568+ ** YUYV DECIMATED15691569+ **/15701570+ /*---------------------------------------------------*/15711571+ p2 = (__u8 *)pex; p3 = (__u8 *)pad; pz = p2 + much;15721572+ while (pz > p2) {15731573+ *p3 = *(p2 + 1);15741574+ *(p3 + 1) = *p2;15751575+ *(p3 + 2) = *(p2 + 3);15761576+ *(p3 + 3) = *(p2 + 2);15771577+ p3 += 4; p2 += 8;15781578+ }15791579+ return 0;15801580+ }15811581+ }15821582+ break;15831583+ }15841584+case 3:15851585+ {15861586+ if (false == decimatepixel) {15871587+ if (false == byteswaporder) {15881588+ /*---------------------------------------------------*/15891589+ /*15901590+ ** RGB15911591+ **/15921592+ /*---------------------------------------------------*/15931593+ while (pz > p2) {15941594+ if (pr <= (p3 + bytesperpixel))15951595+ last = true;15961596+ else15971597+ last = false;15981598+ y = *p2;15991599+ if ((true == last) && (0x0C & mask)) {16001600+ if (0x04 & mask) {16011601+ if (true == isuy)16021602+ v = margin;16031603+ else16041604+ u = margin;16051605+ } else16061606+ if (0x08 & mask)16071607+ ;16081608+ } else {16091609+ if (true == isuy)16101610+ v = *(p2 + 1);16111611+ else16121612+ u = *(p2 + 1);16131613+ }16141614+16151615+ s32 = ay[(int)y] + rv[(int)v];16161616+ r = (255 < s32) ? 255 : ((0 > s32) ? \16171617+ 0 : (__u8)s32);16181618+ s32 = ay[(int)y] - gu[(int)u] - gv[(int)v];16191619+ g = (255 < s32) ? 255 : ((0 > s32) ? \16201620+ 0 : (__u8)s32);16211621+ s32 = ay[(int)y] + bu[(int)u];16221622+ b = (255 < s32) ? 255 : ((0 > s32) ? \16231623+ 0 : (__u8)s32);16241624+16251625+ if ((true == last) && rump) {16261626+ pcache = &cache[0];16271627+ switch (bytesperpixel - rump) {16281628+ case 1: {16291629+ *p3 = r;16301630+ *pcache++ = g;16311631+ *pcache++ = b;16321632+ break;16331633+ }16341634+ case 2: {16351635+ *p3 = r;16361636+ *(p3 + 1) = g;16371637+ *pcache++ = b;16381638+ break;16391639+ }16401640+ default: {16411641+ SAY("MISTAKE: %i=rump\n", \16421642+ bytesperpixel - rump);16431643+ return -EFAULT;16441644+ }16451645+ }16461646+ } else {16471647+ *p3 = r;16481648+ *(p3 + 1) = g;16491649+ *(p3 + 2) = b;16501650+ }16511651+ p2 += 2;16521652+ if (true == isuy)16531653+ isuy = false;16541654+ else16551655+ isuy = true;16561656+ p3 += bytesperpixel;16571657+ }16581658+ return 0;16591659+ } else {16601660+ /*---------------------------------------------------*/16611661+ /*16621662+ ** BGR16631663+ */16641664+ /*---------------------------------------------------*/16651665+ while (pz > p2) {16661666+ if (pr <= (p3 + bytesperpixel))16671667+ last = true;16681668+ else16691669+ last = false;16701670+ y = *p2;16711671+ if ((true == last) && (0x0C & mask)) {16721672+ if (0x04 & mask) {16731673+ if (true == isuy)16741674+ v = margin;16751675+ else16761676+ u = margin;16771677+ }16781678+ else16791679+ if (0x08 & mask)16801680+ ;16811681+ } else {16821682+ if (true == isuy)16831683+ v = *(p2 + 1);16841684+ else16851685+ u = *(p2 + 1);16861686+ }16871687+16881688+ s32 = ay[(int)y] + rv[(int)v];16891689+ r = (255 < s32) ? 255 : ((0 > s32) ? \16901690+ 0 : (__u8)s32);16911691+ s32 = ay[(int)y] - gu[(int)u] - gv[(int)v];16921692+ g = (255 < s32) ? 255 : ((0 > s32) ? \16931693+ 0 : (__u8)s32);16941694+ s32 = ay[(int)y] + bu[(int)u];16951695+ b = (255 < s32) ? 255 : ((0 > s32) ? \16961696+ 0 : (__u8)s32);16971697+16981698+ if ((true == last) && rump) {16991699+ pcache = &cache[0];17001700+ switch (bytesperpixel - rump) {17011701+ case 1: {17021702+ *p3 = b;17031703+ *pcache++ = g;17041704+ *pcache++ = r;17051705+ break;17061706+ }17071707+ case 2: {17081708+ *p3 = b;17091709+ *(p3 + 1) = g;17101710+ *pcache++ = r;17111711+ break;17121712+ }17131713+ default: {17141714+ SAY("MISTAKE: %i=rump\n", \17151715+ bytesperpixel - rump);17161716+ return -EFAULT;17171717+ }17181718+ }17191719+ } else {17201720+ *p3 = b;17211721+ *(p3 + 1) = g;17221722+ *(p3 + 2) = r;17231723+ }17241724+ p2 += 2;17251725+ if (true == isuy)17261726+ isuy = false;17271727+ else17281728+ isuy = true;17291729+ p3 += bytesperpixel;17301730+ }17311731+ }17321732+ return 0;17331733+ } else {17341734+ if (false == byteswaporder) {17351735+ /*---------------------------------------------------*/17361736+ /*17371737+ ** RGB DECIMATED17381738+ */17391739+ /*---------------------------------------------------*/17401740+ while (pz > p2) {17411741+ if (pr <= (p3 + bytesperpixel))17421742+ last = true;17431743+ else17441744+ last = false;17451745+ y = *p2;17461746+ if ((true == last) && (0x0C & mask)) {17471747+ if (0x04 & mask) {17481748+ if (true == isuy)17491749+ v = margin;17501750+ else17511751+ u = margin;17521752+ } else17531753+ if (0x08 & mask)17541754+ ;17551755+ } else {17561756+ if (true == isuy)17571757+ v = *(p2 + 1);17581758+ else17591759+ u = *(p2 + 1);17601760+ }17611761+17621762+ if (true == isuy) {17631763+ s32 = ay[(int)y] + rv[(int)v];17641764+ r = (255 < s32) ? 255 : ((0 > s32) ? \17651765+ 0 : (__u8)s32);17661766+ s32 = ay[(int)y] - gu[(int)u] - \17671767+ gv[(int)v];17681768+ g = (255 < s32) ? 255 : ((0 > s32) ? \17691769+ 0 : (__u8)s32);17701770+ s32 = ay[(int)y] + bu[(int)u];17711771+ b = (255 < s32) ? 255 : ((0 > s32) ? \17721772+ 0 : (__u8)s32);17731773+17741774+ if ((true == last) && rump) {17751775+ pcache = &cache[0];17761776+ switch (bytesperpixel - rump) {17771777+ case 1: {17781778+ *p3 = r;17791779+ *pcache++ = g;17801780+ *pcache++ = b;17811781+ break;17821782+ }17831783+ case 2: {17841784+ *p3 = r;17851785+ *(p3 + 1) = g;17861786+ *pcache++ = b;17871787+ break;17881788+ }17891789+ default: {17901790+ SAY("MISTAKE: " \17911791+ "%i=rump\n", \17921792+ bytesperpixel - rump);17931793+ return -EFAULT;17941794+ }17951795+ }17961796+ } else {17971797+ *p3 = r;17981798+ *(p3 + 1) = g;17991799+ *(p3 + 2) = b;18001800+ }18011801+ isuy = false;18021802+ p3 += bytesperpixel;18031803+ } else {18041804+ isuy = true;18051805+ }18061806+ p2 += 2;18071807+ }18081808+ return 0;18091809+ } else {18101810+ /*---------------------------------------------------*/18111811+ /*18121812+ * BGR DECIMATED18131813+ */18141814+ /*---------------------------------------------------*/18151815+ while (pz > p2) {18161816+ if (pr <= (p3 + bytesperpixel))18171817+ last = true;18181818+ else18191819+ last = false;18201820+ y = *p2;18211821+ if ((true == last) && (0x0C & mask)) {18221822+ if (0x04 & mask) {18231823+ if (true == isuy)18241824+ v = margin;18251825+ else18261826+ u = margin;18271827+ } else18281828+ if (0x08 & mask)18291829+ ;18301830+ } else {18311831+ if (true == isuy)18321832+ v = *(p2 + 1);18331833+ else18341834+ u = *(p2 + 1);18351835+ }18361836+18371837+ if (true == isuy) {18381838+18391839+ s32 = ay[(int)y] + rv[(int)v];18401840+ r = (255 < s32) ? 255 : ((0 > s32) ? \18411841+ 0 : (__u8)s32);18421842+ s32 = ay[(int)y] - gu[(int)u] - \18431843+ gv[(int)v];18441844+ g = (255 < s32) ? 255 : ((0 > s32) ? \18451845+ 0 : (__u8)s32);18461846+ s32 = ay[(int)y] + bu[(int)u];18471847+ b = (255 < s32) ? 255 : ((0 > s32) ? \18481848+ 0 : (__u8)s32);18491849+18501850+ if ((true == last) && rump) {18511851+ pcache = &cache[0];18521852+ switch (bytesperpixel - rump) {18531853+ case 1: {18541854+ *p3 = b;18551855+ *pcache++ = g;18561856+ *pcache++ = r;18571857+ break;18581858+ }18591859+ case 2: {18601860+ *p3 = b;18611861+ *(p3 + 1) = g;18621862+ *pcache++ = r;18631863+ break;18641864+ }18651865+ default: {18661866+ SAY("MISTAKE: " \18671867+ "%i=rump\n", \18681868+ bytesperpixel - rump);18691869+ return -EFAULT;18701870+ }18711871+ }18721872+ } else {18731873+ *p3 = b;18741874+ *(p3 + 1) = g;18751875+ *(p3 + 2) = r;18761876+ }18771877+ isuy = false;18781878+ p3 += bytesperpixel;18791879+ }18801880+ else18811881+ isuy = true;18821882+ p2 += 2;18831883+ }18841884+ return 0;18851885+ }18861886+ }18871887+ break;18881888+ }18891889+case 4:18901890+ {18911891+ if (false == decimatepixel) {18921892+ if (false == byteswaporder) {18931893+ /*---------------------------------------------------*/18941894+ /*18951895+ ** RGBA18961896+ */18971897+ /*---------------------------------------------------*/18981898+ while (pz > p2) {18991899+ if (pr <= (p3 + bytesperpixel))19001900+ last = true;19011901+ else19021902+ last = false;19031903+ y = *p2;19041904+ if ((true == last) && (0x0C & mask)) {19051905+ if (0x04 & mask) {19061906+ if (true == isuy)19071907+ v = margin;19081908+ else19091909+ u = margin;19101910+ } else19111911+ if (0x08 & mask)19121912+ ;19131913+ } else {19141914+ if (true == isuy)19151915+ v = *(p2 + 1);19161916+ else19171917+ u = *(p2 + 1);19181918+ }19191919+19201920+ s32 = ay[(int)y] + rv[(int)v];19211921+ r = (255 < s32) ? 255 : ((0 > s32) ? \19221922+ 0 : (__u8)s32);19231923+ s32 = ay[(int)y] - gu[(int)u] - gv[(int)v];19241924+ g = (255 < s32) ? 255 : ((0 > s32) ? \19251925+ 0 : (__u8)s32);19261926+ s32 = ay[(int)y] + bu[(int)u];19271927+ b = (255 < s32) ? 255 : ((0 > s32) ? \19281928+ 0 : (__u8)s32);19291929+19301930+ if ((true == last) && rump) {19311931+ pcache = &cache[0];19321932+ switch (bytesperpixel - rump) {19331933+ case 1: {19341934+ *p3 = r;19351935+ *pcache++ = g;19361936+ *pcache++ = b;19371937+ *pcache++ = 0;19381938+ break;19391939+ }19401940+ case 2: {19411941+ *p3 = r;19421942+ *(p3 + 1) = g;19431943+ *pcache++ = b;19441944+ *pcache++ = 0;19451945+ break;19461946+ }19471947+ case 3: {19481948+ *p3 = r;19491949+ *(p3 + 1) = g;19501950+ *(p3 + 2) = b;19511951+ *pcache++ = 0;19521952+ break;19531953+ }19541954+ default: {19551955+ SAY("MISTAKE: %i=rump\n", \19561956+ bytesperpixel - rump);19571957+ return -EFAULT;19581958+ }19591959+ }19601960+ } else {19611961+ *p3 = r;19621962+ *(p3 + 1) = g;19631963+ *(p3 + 2) = b;19641964+ *(p3 + 3) = 0;19651965+ }19661966+ p2 += 2;19671967+ if (true == isuy)19681968+ isuy = false;19691969+ else19701970+ isuy = true;19711971+ p3 += bytesperpixel;19721972+ }19731973+ return 0;19741974+ } else {19751975+ /*---------------------------------------------------*/19761976+ /*19771977+ ** BGRA19781978+ */19791979+ /*---------------------------------------------------*/19801980+ while (pz > p2) {19811981+ if (pr <= (p3 + bytesperpixel))19821982+ last = true;19831983+ else19841984+ last = false;19851985+ y = *p2;19861986+ if ((true == last) && (0x0C & mask)) {19871987+ if (0x04 & mask) {19881988+ if (true == isuy)19891989+ v = margin;19901990+ else19911991+ u = margin;19921992+ } else19931993+ if (0x08 & mask)19941994+ ;19951995+ } else {19961996+ if (true == isuy)19971997+ v = *(p2 + 1);19981998+ else19991999+ u = *(p2 + 1);20002000+ }20012001+20022002+ s32 = ay[(int)y] + rv[(int)v];20032003+ r = (255 < s32) ? 255 : ((0 > s32) ? \20042004+ 0 : (__u8)s32);20052005+ s32 = ay[(int)y] - gu[(int)u] - gv[(int)v];20062006+ g = (255 < s32) ? 255 : ((0 > s32) ? \20072007+ 0 : (__u8)s32);20082008+ s32 = ay[(int)y] + bu[(int)u];20092009+ b = (255 < s32) ? 255 : ((0 > s32) ? \20102010+ 0 : (__u8)s32);20112011+20122012+ if ((true == last) && rump) {20132013+ pcache = &cache[0];20142014+ switch (bytesperpixel - rump) {20152015+ case 1: {20162016+ *p3 = b;20172017+ *pcache++ = g;20182018+ *pcache++ = r;20192019+ *pcache++ = 0;20202020+ break;20212021+ }20222022+ case 2: {20232023+ *p3 = b;20242024+ *(p3 + 1) = g;20252025+ *pcache++ = r;20262026+ *pcache++ = 0;20272027+ break;20282028+ }20292029+ case 3: {20302030+ *p3 = b;20312031+ *(p3 + 1) = g;20322032+ *(p3 + 2) = r;20332033+ *pcache++ = 0;20342034+ break;20352035+ }20362036+ default: {20372037+ SAY("MISTAKE: %i=rump\n", \20382038+ bytesperpixel - rump);20392039+ return -EFAULT;20402040+ }20412041+ }20422042+ } else {20432043+ *p3 = b;20442044+ *(p3 + 1) = g;20452045+ *(p3 + 2) = r;20462046+ *(p3 + 3) = 0;20472047+ }20482048+ p2 += 2;20492049+ if (true == isuy)20502050+ isuy = false;20512051+ else20522052+ isuy = true;20532053+ p3 += bytesperpixel;20542054+ }20552055+ }20562056+ return 0;20572057+ } else {20582058+ if (false == byteswaporder) {20592059+ /*---------------------------------------------------*/20602060+ /*20612061+ ** RGBA DECIMATED20622062+ */20632063+ /*---------------------------------------------------*/20642064+ while (pz > p2) {20652065+ if (pr <= (p3 + bytesperpixel))20662066+ last = true;20672067+ else20682068+ last = false;20692069+ y = *p2;20702070+ if ((true == last) && (0x0C & mask)) {20712071+ if (0x04 & mask) {20722072+ if (true == isuy)20732073+ v = margin;20742074+ else20752075+ u = margin;20762076+ } else20772077+ if (0x08 & mask)20782078+ ;20792079+ } else {20802080+ if (true == isuy)20812081+ v = *(p2 + 1);20822082+ else20832083+ u = *(p2 + 1);20842084+ }20852085+20862086+ if (true == isuy) {20872087+20882088+ s32 = ay[(int)y] + rv[(int)v];20892089+ r = (255 < s32) ? 255 : ((0 > s32) ? \20902090+ 0 : (__u8)s32);20912091+ s32 = ay[(int)y] - gu[(int)u] - \20922092+ gv[(int)v];20932093+ g = (255 < s32) ? 255 : ((0 > s32) ? \20942094+ 0 : (__u8)s32);20952095+ s32 = ay[(int)y] + bu[(int)u];20962096+ b = (255 < s32) ? 255 : ((0 > s32) ? \20972097+ 0 : (__u8)s32);20982098+20992099+ if ((true == last) && rump) {21002100+ pcache = &cache[0];21012101+ switch (bytesperpixel - rump) {21022102+ case 1: {21032103+ *p3 = r;21042104+ *pcache++ = g;21052105+ *pcache++ = b;21062106+ *pcache++ = 0;21072107+ break;21082108+ }21092109+ case 2: {21102110+ *p3 = r;21112111+ *(p3 + 1) = g;21122112+ *pcache++ = b;21132113+ *pcache++ = 0;21142114+ break;21152115+ }21162116+ case 3: {21172117+ *p3 = r;21182118+ *(p3 + 1) = g;21192119+ *(p3 + 2) = b;21202120+ *pcache++ = 0;21212121+ break;21222122+ }21232123+ default: {21242124+ SAY("MISTAKE: " \21252125+ "%i=rump\n", \21262126+ bytesperpixel - \21272127+ rump);21282128+ return -EFAULT;21292129+ }21302130+ }21312131+ } else {21322132+ *p3 = r;21332133+ *(p3 + 1) = g;21342134+ *(p3 + 2) = b;21352135+ *(p3 + 3) = 0;21362136+ }21372137+ isuy = false;21382138+ p3 += bytesperpixel;21392139+ } else21402140+ isuy = true;21412141+ p2 += 2;21422142+ }21432143+ return 0;21442144+ } else {21452145+ /*---------------------------------------------------*/21462146+ /*21472147+ ** BGRA DECIMATED21482148+ */21492149+ /*---------------------------------------------------*/21502150+ while (pz > p2) {21512151+ if (pr <= (p3 + bytesperpixel))21522152+ last = true;21532153+ else21542154+ last = false;21552155+ y = *p2;21562156+ if ((true == last) && (0x0C & mask)) {21572157+ if (0x04 & mask) {21582158+ if (true == isuy)21592159+ v = margin;21602160+ else21612161+ u = margin;21622162+ } else21632163+ if (0x08 & mask)21642164+ ;21652165+ } else {21662166+ if (true == isuy)21672167+ v = *(p2 + 1);21682168+ else21692169+ u = *(p2 + 1);21702170+ }21712171+21722172+ if (true == isuy) {21732173+ s32 = ay[(int)y] + rv[(int)v];21742174+ r = (255 < s32) ? 255 : ((0 > s32) ? \21752175+ 0 : (__u8)s32);21762176+ s32 = ay[(int)y] - gu[(int)u] - \21772177+ gv[(int)v];21782178+ g = (255 < s32) ? 255 : ((0 > s32) ? \21792179+ 0 : (__u8)s32);21802180+ s32 = ay[(int)y] + bu[(int)u];21812181+ b = (255 < s32) ? 255 : ((0 > s32) ? \21822182+ 0 : (__u8)s32);21832183+21842184+ if ((true == last) && rump) {21852185+ pcache = &cache[0];21862186+ switch (bytesperpixel - rump) {21872187+ case 1: {21882188+ *p3 = b;21892189+ *pcache++ = g;21902190+ *pcache++ = r;21912191+ *pcache++ = 0;21922192+ break;21932193+ }21942194+ case 2: {21952195+ *p3 = b;21962196+ *(p3 + 1) = g;21972197+ *pcache++ = r;21982198+ *pcache++ = 0;21992199+ break;22002200+ }22012201+ case 3: {22022202+ *p3 = b;22032203+ *(p3 + 1) = g;22042204+ *(p3 + 2) = r;22052205+ *pcache++ = 0;22062206+ break;22072207+ }22082208+ default: {22092209+ SAY("MISTAKE: " \22102210+ "%i=rump\n", \22112211+ bytesperpixel - rump);22122212+ return -EFAULT;22132213+ }22142214+ }22152215+ } else {22162216+ *p3 = b;22172217+ *(p3 + 1) = g;22182218+ *(p3 + 2) = r;22192219+ *(p3 + 3) = 0;22202220+ }22212221+ isuy = false;22222222+ p3 += bytesperpixel;22232223+ } else22242224+ isuy = true;22252225+ p2 += 2;22262226+ }22272227+ return 0;22282228+ }22292229+ }22302230+ break;22312231+ }22322232+default: {22332233+ SAY("MISTAKE: %i=bytesperpixel\n", bytesperpixel);22342234+ return -EFAULT;22352235+ }22362236+}22372237+return 0;22382238+}22392239+/*****************************************************************************/22402240+void22412241+debrief(struct easycap *peasycap)22422242+{22432243+if ((struct usb_device *)NULL != peasycap->pusb_device) {22442244+ check_stk(peasycap->pusb_device);22452245+ check_saa(peasycap->pusb_device);22462246+ sayreadonly(peasycap);22472247+ SAY("%i=peasycap->field_fill\n", peasycap->field_fill);22482248+ SAY("%i=peasycap->field_read\n", peasycap->field_read);22492249+ SAY("%i=peasycap->frame_fill\n", peasycap->frame_fill);22502250+ SAY("%i=peasycap->frame_read\n", peasycap->frame_read);22512251+}22522252+return;22532253+}22542254+/*****************************************************************************/22552255+void22562256+sayreadonly(struct easycap *peasycap)22572257+{22582258+static int done;22592259+int got00, got1F, got60, got61, got62;22602260+22612261+if ((!done) && ((struct usb_device *)NULL != peasycap->pusb_device)) {22622262+ done = 1;22632263+ got00 = read_saa(peasycap->pusb_device, 0x00);22642264+ got1F = read_saa(peasycap->pusb_device, 0x1F);22652265+ got60 = read_saa(peasycap->pusb_device, 0x60);22662266+ got61 = read_saa(peasycap->pusb_device, 0x61);22672267+ got62 = read_saa(peasycap->pusb_device, 0x62);22682268+ SAY("0x%02X=reg0x00 0x%02X=reg0x1F\n", got00, got1F);22692269+ SAY("0x%02X=reg0x60 0x%02X=reg0x61 0x%02X=reg0x62\n", \22702270+ got60, got61, got62);22712271+}22722272+return;22732273+}22742274+/*****************************************************************************/22752275+/*---------------------------------------------------------------------------*/22762276+/*22772277+ * SEE CORBET ET AL. "LINUX DEVICE DRIVERS", 3rd EDITION, PAGES 430-43422782278+ */22792279+/*---------------------------------------------------------------------------*/22802280+int easycap_mmap(struct file *file, struct vm_area_struct *pvma)22812281+{22822282+22832283+JOT(8, "\n");22842284+22852285+pvma->vm_ops = &easycap_vm_ops;22862286+pvma->vm_flags |= VM_RESERVED;22872287+if (NULL != file)22882288+ pvma->vm_private_data = file->private_data;22892289+easycap_vma_open(pvma);22902290+return 0;22912291+}22922292+/*****************************************************************************/22932293+void22942294+easycap_vma_open(struct vm_area_struct *pvma)22952295+{22962296+struct easycap *peasycap;22972297+22982298+peasycap = pvma->vm_private_data;22992299+if (NULL != peasycap)23002300+ peasycap->vma_many++;23012301+23022302+JOT(8, "%i=peasycap->vma_many\n", peasycap->vma_many);23032303+23042304+return;23052305+}23062306+/*****************************************************************************/23072307+void23082308+easycap_vma_close(struct vm_area_struct *pvma)23092309+{23102310+struct easycap *peasycap;23112311+23122312+peasycap = pvma->vm_private_data;23132313+if (NULL != peasycap) {23142314+ peasycap->vma_many--;23152315+ JOT(8, "%i=peasycap->vma_many\n", peasycap->vma_many);23162316+}23172317+return;23182318+}23192319+/*****************************************************************************/23202320+int23212321+easycap_vma_fault(struct vm_area_struct *pvma, struct vm_fault *pvmf)23222322+{23232323+int k, m, retcode;23242324+void *pbuf;23252325+struct page *page;23262326+struct easycap *peasycap;23272327+23282328+retcode = VM_FAULT_NOPAGE;23292329+pbuf = (void *)NULL;23302330+page = (struct page *)NULL;23312331+23322332+if (NULL == pvma) {23332333+ SAY("pvma is NULL\n");23342334+ return retcode;23352335+}23362336+if (NULL == pvmf) {23372337+ SAY("pvmf is NULL\n");23382338+ return retcode;23392339+}23402340+23412341+k = (pvmf->pgoff) / (FRAME_BUFFER_SIZE/PAGE_SIZE);23422342+m = (pvmf->pgoff) % (FRAME_BUFFER_SIZE/PAGE_SIZE);23432343+23442344+if (!m)23452345+ JOT(4, "%4i=k, %4i=m\n", k, m);23462346+else23472347+ JOT(16, "%4i=k, %4i=m\n", k, m);23482348+23492349+if ((0 > k) || (FRAME_BUFFER_MANY <= k)) {23502350+ SAY("ERROR: buffer index %i out of range\n", k);23512351+ return retcode;23522352+}23532353+if ((0 > m) || (FRAME_BUFFER_SIZE/PAGE_SIZE <= m)) {23542354+ SAY("ERROR: page number %i out of range\n", m);23552355+ return retcode;23562356+}23572357+peasycap = pvma->vm_private_data;23582358+if (NULL == peasycap) {23592359+ SAY("ERROR: peasycap is NULL\n");23602360+ return retcode;23612361+}23622362+mutex_lock(&(peasycap->mutex_mmap_video[0]));23632363+/*---------------------------------------------------------------------------*/23642364+pbuf = peasycap->frame_buffer[k][m].pgo;23652365+if (NULL == pbuf) {23662366+ SAY("ERROR: pbuf is NULL\n");23672367+ goto finish;23682368+}23692369+page = virt_to_page(pbuf);23702370+if (NULL == page) {23712371+ SAY("ERROR: page is NULL\n");23722372+ goto finish;23732373+}23742374+get_page(page);23752375+/*---------------------------------------------------------------------------*/23762376+finish:23772377+mutex_unlock(&(peasycap->mutex_mmap_video[0]));23782378+if (NULL == page) {23792379+ SAY("ERROR: page is NULL after get_page(page)\n");23802380+} else {23812381+ pvmf->page = page;23822382+ retcode = VM_FAULT_MINOR;23832383+}23842384+return retcode;23852385+}23862386+/*****************************************************************************/23872387+/*---------------------------------------------------------------------------*/23882388+/*23892389+ * ON COMPLETION OF A VIDEO URB ITS DATA IS COPIED TO THE FIELD BUFFERS23902390+ * PROVIDED peasycap->video_idle IS ZER0. REGARDLESS OF THIS BEING TRUE,23912391+ * IT IS RESUBMITTED PROVIDED peasycap->video_isoc_streaming IS NOT ZERO.23922392+ *23932393+ * THIS FUNCTION IS AN INTERRUPT SERVICE ROUTINE AND MUST NOT SLEEP.23942394+ *23952395+ * INFORMATION ABOUT THE VALIDITY OF THE CONTENTS OF THE FIELD BUFFER ARE23962396+ * STORED IN THE TWO-BYTE STATUS PARAMETER23972397+ * peasycap->field_buffer[peasycap->field_fill][0].kount23982398+ * NOTICE THAT THE INFORMATION IS STORED ONLY WITH PAGE 0 OF THE FIELD BUFFER.23992399+ *24002400+ * THE LOWER BYTE CONTAINS THE FIELD PARITY BYTE FURNISHED BY THE SAA7113H24012401+ * CHIP.24022402+ *24032403+ * THE UPPER BYTE IS ZERO IF NO PROBLEMS, OTHERWISE:24042404+ * 0 != (kount & 0x8000) => AT LEAST ONE URB COMPLETED WITH ERRORS24052405+ * 0 != (kount & 0x4000) => BUFFER HAS TOO MUCH DATA24062406+ * 0 != (kount & 0x2000) => BUFFER HAS NOT ENOUGH DATA24072407+ * 0 != (kount & 0x0400) => FIELD WAS SUBMITTED BY BRIDGER ROUTINE24082408+ * 0 != (kount & 0x0200) => FIELD BUFFER NOT YET CHECKED24092409+ * 0 != (kount & 0x0100) => BUFFER HAS TWO EXTRA BYTES - WHY?24102410+ */24112411+/*---------------------------------------------------------------------------*/24122412+void24132413+easycap_complete(struct urb *purb)24142414+{24152415+static int mt;24162416+struct easycap *peasycap;24172417+struct data_buffer *pfield_buffer;24182418+char errbuf[16];24192419+int i, more, much, leap, rc, last;24202420+int videofieldamount;24212421+unsigned int override;24222422+int framestatus, framelength, frameactual, frameoffset;24232423+__u8 *pu;24242424+#if defined(BRIDGER)24252425+struct timeval timeval;24262426+long long usec;24272427+#endif /*BRIDGER*/24282428+24292429+if (NULL == purb) {24302430+ SAY("ERROR: easycap_complete(): purb is NULL\n");24312431+ return;24322432+}24332433+peasycap = purb->context;24342434+if (NULL == peasycap) {24352435+ SAY("ERROR: easycap_complete(): peasycap is NULL\n");24362436+ return;24372437+}24382438+24392439+if (peasycap->video_eof)24402440+ return;24412441+24422442+for (i = 0; i < VIDEO_ISOC_BUFFER_MANY; i++)24432443+ if (purb->transfer_buffer == peasycap->video_isoc_buffer[i].pgo)24442444+ break;24452445+JOT(16, "%2i=urb\n", i);24462446+last = peasycap->video_isoc_sequence;24472447+if ((((VIDEO_ISOC_BUFFER_MANY - 1) == last) && \24482448+ (0 != i)) || \24492449+ (((VIDEO_ISOC_BUFFER_MANY - 1) != last) && \24502450+ ((last + 1) != i))) {24512451+ SAY("ERROR: out-of-order urbs %i,%i ... continuing\n", last, i);24522452+}24532453+peasycap->video_isoc_sequence = i;24542454+24552455+if (peasycap->video_idle) {24562456+ JOT(16, "%i=video_idle %i=video_isoc_streaming\n", \24572457+ peasycap->video_idle, peasycap->video_isoc_streaming);24582458+ if (peasycap->video_isoc_streaming) {24592459+ rc = usb_submit_urb(purb, GFP_ATOMIC);24602460+ if (0 != rc) {24612461+ SAY("ERROR: while %i=video_idle, " \24622462+ "usb_submit_urb() failed with rc:\n", \24632463+ peasycap->video_idle);24642464+ switch (rc) {24652465+ case -ENOMEM: {24662466+ SAY("ENOMEM\n");24672467+ break;24682468+ }24692469+ case -ENODEV: {24702470+ SAY("ENODEV\n");24712471+ break;24722472+ }24732473+ case -ENXIO: {24742474+ SAY("ENXIO\n");24752475+ break;24762476+ }24772477+ case -EINVAL: {24782478+ SAY("EINVAL\n");24792479+ break;24802480+ }24812481+ case -EAGAIN: {24822482+ SAY("EAGAIN\n");24832483+ break;24842484+ }24852485+ case -EFBIG: {24862486+ SAY("EFBIG\n");24872487+ break;24882488+ }24892489+ case -EPIPE: {24902490+ SAY("EPIPE\n");24912491+ break;24922492+ }24932493+ case -EMSGSIZE: {24942494+ SAY("EMSGSIZE\n");24952495+ break;24962496+ }24972497+ default: {24982498+ SAY("0x%08X\n", rc);24992499+ break;25002500+ }25012501+ }25022502+ }25032503+ }25042504+return;25052505+}25062506+override = 0;25072507+/*---------------------------------------------------------------------------*/25082508+if (FIELD_BUFFER_MANY <= peasycap->field_fill) {25092509+ SAY("ERROR: bad peasycap->field_fill\n");25102510+ return;25112511+}25122512+if (purb->status) {25132513+ if ((-ESHUTDOWN == purb->status) || (-ENOENT == purb->status)) {25142514+ JOT(8, "urb status -ESHUTDOWN or -ENOENT\n");25152515+ return;25162516+ }25172517+25182518+ (peasycap->field_buffer[peasycap->field_fill][0].kount) |= 0x8000 ;25192519+ SAY("ERROR: bad urb status:\n");25202520+ switch (purb->status) {25212521+ case -EINPROGRESS: {25222522+ SAY("-EINPROGRESS\n"); break;25232523+ }25242524+ case -ENOSR: {25252525+ SAY("-ENOSR\n"); break;25262526+ }25272527+ case -EPIPE: {25282528+ SAY("-EPIPE\n"); break;25292529+ }25302530+ case -EOVERFLOW: {25312531+ SAY("-EOVERFLOW\n"); break;25322532+ }25332533+ case -EPROTO: {25342534+ SAY("-EPROTO\n"); break;25352535+ }25362536+ case -EILSEQ: {25372537+ SAY("-EILSEQ\n"); break;25382538+ }25392539+ case -ETIMEDOUT: {25402540+ SAY("-ETIMEDOUT\n"); break;25412541+ }25422542+ case -EMSGSIZE: {25432543+ SAY("-EMSGSIZE\n"); break;25442544+ }25452545+ case -EOPNOTSUPP: {25462546+ SAY("-EOPNOTSUPP\n"); break;25472547+ }25482548+ case -EPFNOSUPPORT: {25492549+ SAY("-EPFNOSUPPORT\n"); break;25502550+ }25512551+ case -EAFNOSUPPORT: {25522552+ SAY("-EAFNOSUPPORT\n"); break;25532553+ }25542554+ case -EADDRINUSE: {25552555+ SAY("-EADDRINUSE\n"); break;25562556+ }25572557+ case -EADDRNOTAVAIL: {25582558+ SAY("-EADDRNOTAVAIL\n"); break;25592559+ }25602560+ case -ENOBUFS: {25612561+ SAY("-ENOBUFS\n"); break;25622562+ }25632563+ case -EISCONN: {25642564+ SAY("-EISCONN\n"); break;25652565+ }25662566+ case -ENOTCONN: {25672567+ SAY("-ENOTCONN\n"); break;25682568+ }25692569+ case -ESHUTDOWN: {25702570+ SAY("-ESHUTDOWN\n"); break;25712571+ }25722572+ case -ENOENT: {25732573+ SAY("-ENOENT\n"); break;25742574+ }25752575+ case -ECONNRESET: {25762576+ SAY("-ECONNRESET\n"); break;25772577+ }25782578+ default: {25792579+ SAY("unknown error code 0x%08X\n", purb->status); break;25802580+ }25812581+ }25822582+/*---------------------------------------------------------------------------*/25832583+} else {25842584+ for (i = 0; i < purb->number_of_packets; i++) {25852585+ if (0 != purb->iso_frame_desc[i].status) {25862586+ (peasycap->field_buffer\25872587+ [peasycap->field_fill][0].kount) |= 0x8000 ;25882588+ switch (purb->iso_frame_desc[i].status) {25892589+ case 0: {25902590+ strcpy(&errbuf[0], "OK"); break;25912591+ }25922592+ case -ENOENT: {25932593+ strcpy(&errbuf[0], "-ENOENT"); break;25942594+ }25952595+ case -EINPROGRESS: {25962596+ strcpy(&errbuf[0], "-EINPROGRESS"); break;25972597+ }25982598+ case -EPROTO: {25992599+ strcpy(&errbuf[0], "-EPROTO"); break;26002600+ }26012601+ case -EILSEQ: {26022602+ strcpy(&errbuf[0], "-EILSEQ"); break;26032603+ }26042604+ case -ETIME: {26052605+ strcpy(&errbuf[0], "-ETIME"); break;26062606+ }26072607+ case -ETIMEDOUT: {26082608+ strcpy(&errbuf[0], "-ETIMEDOUT"); break;26092609+ }26102610+ case -EPIPE: {26112611+ strcpy(&errbuf[0], "-EPIPE"); break;26122612+ }26132613+ case -ECOMM: {26142614+ strcpy(&errbuf[0], "-ECOMM"); break;26152615+ }26162616+ case -ENOSR: {26172617+ strcpy(&errbuf[0], "-ENOSR"); break;26182618+ }26192619+ case -EOVERFLOW: {26202620+ strcpy(&errbuf[0], "-EOVERFLOW"); break;26212621+ }26222622+ case -EREMOTEIO: {26232623+ strcpy(&errbuf[0], "-EREMOTEIO"); break;26242624+ }26252625+ case -ENODEV: {26262626+ strcpy(&errbuf[0], "-ENODEV"); break;26272627+ }26282628+ case -EXDEV: {26292629+ strcpy(&errbuf[0], "-EXDEV"); break;26302630+ }26312631+ case -EINVAL: {26322632+ strcpy(&errbuf[0], "-EINVAL"); break;26332633+ }26342634+ case -ECONNRESET: {26352635+ strcpy(&errbuf[0], "-ECONNRESET"); break;26362636+ }26372637+ case -ESHUTDOWN: {26382638+ strcpy(&errbuf[0], "-ESHUTDOWN"); break;26392639+ }26402640+ default: {26412641+ strcpy(&errbuf[0], "unknown error"); break;26422642+ }26432643+ }26442644+ }26452645+ framestatus = purb->iso_frame_desc[i].status;26462646+ framelength = purb->iso_frame_desc[i].length;26472647+ frameactual = purb->iso_frame_desc[i].actual_length;26482648+ frameoffset = purb->iso_frame_desc[i].offset;26492649+26502650+ JOT(16, "frame[%2i]:" \26512651+ "%4i=status " \26522652+ "%4i=actual " \26532653+ "%4i=length " \26542654+ "%5i=offset\n", \26552655+ i, framestatus, frameactual, framelength, frameoffset);26562656+ if (!purb->iso_frame_desc[i].status) {26572657+ more = purb->iso_frame_desc[i].actual_length;26582658+ pfield_buffer = &peasycap->field_buffer\26592659+ [peasycap->field_fill][peasycap->field_page];26602660+ videofieldamount = (peasycap->field_page * \26612661+ PAGE_SIZE) + \26622662+ (int)(pfield_buffer->pto - pfield_buffer->pgo);26632663+ if (4 == more)26642664+ mt++;26652665+ if (4 < more) {26662666+ if (mt) {26672667+ JOT(8, "%4i empty video urb frames\n", mt);26682668+ mt = 0;26692669+ }26702670+ if (FIELD_BUFFER_MANY <= peasycap->field_fill) {26712671+ SAY("ERROR: bad peasycap->field_fill\n");26722672+ return;26732673+ }26742674+ if (FIELD_BUFFER_SIZE/PAGE_SIZE <= \26752675+ peasycap->field_page) {26762676+ SAY("ERROR: bad peasycap->field_page\n");26772677+ return;26782678+ }26792679+ pfield_buffer = &peasycap->field_buffer\26802680+ [peasycap->field_fill][peasycap->field_page];26812681+ pu = (__u8 *)(purb->transfer_buffer + \26822682+ purb->iso_frame_desc[i].offset);26832683+ if (0x80 & *pu)26842684+ leap = 8;26852685+ else26862686+ leap = 4;26872687+/*--------------------------------------------------------------------------*/26882688+/*26892689+ * EIGHT-BYTE END-OF-VIDEOFIELD MARKER.26902690+ * NOTE: A SUCCESSION OF URB FRAMES FOLLOWING THIS ARE EMPTY,26912691+ * CORRESPONDING TO THE FIELD FLYBACK (VERTICAL BLANKING) PERIOD.26922692+ *26932693+ * PROVIDED THE FIELD BUFFER CONTAINS GOOD DATA AS INDICATED BY A ZERO UPPER26942694+ * BYTE OF26952695+ * peasycap->field_buffer[peasycap->field_fill][0].kount26962696+ * THE CONTENTS OF THE FIELD BUFFER ARE OFFERED TO dqbuf(), field_read IS26972697+ * UPDATED AND field_fill IS BUMPED. IF THE FIELD BUFFER CONTAINS BAD DATA26982698+ * NOTHING IS OFFERED TO dqbuf().26992699+ *27002700+ * THE DECISION ON WHETHER THE PARITY OF THE OFFERED FIELD BUFFER IS RIGHT27012701+ * RESTS WITH dqbuf().27022702+ */27032703+/*---------------------------------------------------------------------------*/27042704+ if ((8 == more) || override) {27052705+ if (videofieldamount > \27062706+ peasycap->videofieldamount) {27072707+ if (2 == videofieldamount - \27082708+ peasycap->\27092709+ videofieldamount)27102710+ (peasycap->field_buffer\27112711+ [peasycap->field_fill]\27122712+ [0].kount) |= 0x0100;27132713+ else27142714+ (peasycap->field_buffer\27152715+ [peasycap->field_fill]\27162716+ [0].kount) |= 0x4000;27172717+ } else if (videofieldamount < \27182718+ peasycap->\27192719+ videofieldamount) {27202720+ (peasycap->field_buffer\27212721+ [peasycap->field_fill]\27222722+ [0].kount) |= 0x2000;27232723+ }27242724+ if (!(0xFF00 & peasycap->field_buffer\27252725+ [peasycap->field_fill]\27262726+ [0].kount)) {27272727+ (peasycap->video_junk)--;27282728+ if (-16 > peasycap->video_junk)27292729+ peasycap->video_junk = -16;27302730+ peasycap->field_read = \27312731+ (peasycap->\27322732+ field_fill)++;27332733+27342734+ if (FIELD_BUFFER_MANY <= \27352735+ peasycap->field_fill)27362736+ peasycap->field_fill = 0;27372737+ peasycap->field_page = 0;27382738+ pfield_buffer = &peasycap->\27392739+ field_buffer\27402740+ [peasycap->field_fill]\27412741+ [peasycap->field_page];27422742+ pfield_buffer->pto = \27432743+ pfield_buffer->pgo;27442744+27452745+ JOT(8, "bumped to: %i=peasycap->" \27462746+ "field_fill %i=parity\n", \27472747+ peasycap->field_fill, \27482748+ 0x00FF & pfield_buffer->kount);27492749+ JOT(8, "field buffer %i has %i " \27502750+ "bytes fit to be read\n", \27512751+ peasycap->field_read, \27522752+ videofieldamount);27532753+ JOT(8, "wakeup call to wq_video, " \27542754+ "%i=field_read %i=field_fill "\27552755+ "%i=parity\n", \27562756+ peasycap->field_read, \27572757+ peasycap->field_fill, \27582758+ 0x00FF & peasycap->\27592759+ field_buffer[peasycap->\27602760+ field_read][0].kount);27612761+ wake_up_interruptible(&(peasycap->\27622762+ wq_video));27632763+ do_gettimeofday(&peasycap->timeval7);27642764+ } else {27652765+ peasycap->video_junk++;27662766+ JOT(8, "field buffer %i had %i " \27672767+ "bytes, now discarded\n", \27682768+ peasycap->field_fill, \27692769+ videofieldamount);27702770+27712771+ (peasycap->field_fill)++;27722772+27732773+ if (FIELD_BUFFER_MANY <= \27742774+ peasycap->field_fill)27752775+ peasycap->field_fill = 0;27762776+ peasycap->field_page = 0;27772777+ pfield_buffer = \27782778+ &peasycap->field_buffer\27792779+ [peasycap->field_fill]\27802780+ [peasycap->field_page];27812781+ pfield_buffer->pto = \27822782+ pfield_buffer->pgo;27832783+27842784+ JOT(8, "bumped to: %i=peasycap->" \27852785+ "field_fill %i=parity\n", \27862786+ peasycap->field_fill, \27872787+ 0x00FF & pfield_buffer->kount);27882788+ }27892789+ if (8 == more) {27902790+ JOT(8, "end-of-field: received " \27912791+ "parity byte 0x%02X\n", \27922792+ (0xFF & *pu));27932793+ if (0x40 & *pu)27942794+ pfield_buffer->kount = 0x0000;27952795+ else27962796+ pfield_buffer->kount = 0x0001;27972797+ JOT(8, "end-of-field: 0x%02X=kount\n",\27982798+ 0xFF & pfield_buffer->kount);27992799+ }28002800+ }28012801+/*---------------------------------------------------------------------------*/28022802+/*28032803+ * COPY more BYTES FROM ISOC BUFFER TO FIELD BUFFER28042804+ */28052805+/*---------------------------------------------------------------------------*/28062806+ pu += leap;28072807+ more -= leap;28082808+28092809+ if (FIELD_BUFFER_MANY <= peasycap->field_fill) {28102810+ SAY("ERROR: bad peasycap->field_fill\n");28112811+ return;28122812+ }28132813+ if (FIELD_BUFFER_SIZE/PAGE_SIZE <= \28142814+ peasycap->field_page) {28152815+ SAY("ERROR: bad peasycap->field_page\n");28162816+ return;28172817+ }28182818+ pfield_buffer = &peasycap->field_buffer\28192819+ [peasycap->field_fill][peasycap->field_page];28202820+ while (more) {28212821+ pfield_buffer = &peasycap->field_buffer\28222822+ [peasycap->field_fill]\28232823+ [peasycap->field_page];28242824+ if (PAGE_SIZE < (pfield_buffer->pto - \28252825+ pfield_buffer->pgo)) {28262826+ SAY("ERROR: bad pfield_buffer->pto\n");28272827+ return;28282828+ }28292829+ if (PAGE_SIZE == (pfield_buffer->pto - \28302830+ pfield_buffer->pgo)) {28312831+ (peasycap->field_page)++;28322832+ if (FIELD_BUFFER_SIZE/PAGE_SIZE <= \28332833+ peasycap->field_page) {28342834+ JOT(16, "wrapping peasycap->" \28352835+ "field_page\n");28362836+ peasycap->field_page = 0;28372837+ }28382838+ pfield_buffer = &peasycap->\28392839+ field_buffer\28402840+ [peasycap->field_fill]\28412841+ [peasycap->field_page];28422842+ pfield_buffer->pto = \28432843+ pfield_buffer->pgo;28442844+ }28452845+28462846+ much = PAGE_SIZE - (int)(pfield_buffer->pto - \28472847+ pfield_buffer->pgo);28482848+28492849+ if (much > more)28502850+ much = more;28512851+ memcpy(pfield_buffer->pto, pu, much);28522852+ pu += much;28532853+ (pfield_buffer->pto) += much;28542854+ more -= much;28552855+ }28562856+ }28572857+ }28582858+ }28592859+}28602860+/*---------------------------------------------------------------------------*/28612861+/*28622862+ *28632863+ *28642864+ * *** UNDER DEVELOPMENT/TESTING - NOT READY YET! ***28652865+ *28662866+ *28672867+ *28682868+ * VIDEOTAPES MAY HAVE BEEN MANUALLY PAUSED AND RESTARTED DURING RECORDING.28692869+ * THIS CAUSES LOSS OF SYNC, CONFUSING DOWNSTREAM USERSPACE PROGRAMS WHICH28702870+ * MAY INTERPRET THE INTERRUPTION AS A SYMPTOM OF LATENCY. TO OVERCOME THIS28712871+ * THE DRIVER BRIDGES THE HIATUS BY SENDING DUMMY VIDEO FRAMES AT ROUGHLY28722872+ * THE RIGHT TIME INTERVALS IN THE HOPE OF PERSUADING THE DOWNSTREAM USERSPACE28732873+ * PROGRAM TO RESUME NORMAL SERVICE WHEN THE INTERRUPTION IS OVER.28742874+ */28752875+/*---------------------------------------------------------------------------*/28762876+#if defined(BRIDGER)28772877+do_gettimeofday(&timeval);28782878+if (peasycap->timeval7.tv_sec) {28792879+ usec = 1000000*(timeval.tv_sec - peasycap->timeval7.tv_sec) + \28802880+ (timeval.tv_usec - peasycap->timeval7.tv_usec);28812881+ if (usec > (peasycap->usec + peasycap->tolerate)) {28822882+ JOT(8, "bridging hiatus\n");28832883+ peasycap->video_junk = 0;28842884+ peasycap->field_buffer[peasycap->field_fill][0].kount |= 0x0400;28852885+28862886+ peasycap->field_read = (peasycap->field_fill)++;28872887+28882888+ if (FIELD_BUFFER_MANY <= peasycap->field_fill) \28892889+ peasycap->field_fill = 0;28902890+ peasycap->field_page = 0;28912891+ pfield_buffer = &peasycap->field_buffer\28922892+ [peasycap->field_fill][peasycap->field_page];28932893+ pfield_buffer->pto = pfield_buffer->pgo;28942894+28952895+ JOT(8, "bumped to: %i=peasycap->field_fill %i=parity\n", \28962896+ peasycap->field_fill, 0x00FF & pfield_buffer->kount);28972897+ JOT(8, "field buffer %i has %i bytes to be overwritten\n", \28982898+ peasycap->field_read, videofieldamount);28992899+ JOT(8, "wakeup call to wq_video, " \29002900+ "%i=field_read %i=field_fill %i=parity\n", \29012901+ peasycap->field_read, peasycap->field_fill, \29022902+ 0x00FF & \29032903+ peasycap->field_buffer[peasycap->field_read][0].kount);29042904+ wake_up_interruptible(&(peasycap->wq_video));29052905+ do_gettimeofday(&peasycap->timeval7);29062906+ }29072907+}29082908+#endif /*BRIDGER*/29092909+/*---------------------------------------------------------------------------*/29102910+/*29112911+ * RESUBMIT THIS URB, UNLESS A SEVERE PERSISTENT ERROR CONDITION EXISTS.29122912+ *29132913+ * IF THE WAIT QUEUES ARE NOT CLEARED IN RESPONSE TO AN ERROR CONDITION29142914+ * THE USERSPACE PROGRAM, E.G. mplayer, MAY HANG ON EXIT. BEWARE.29152915+ */29162916+/*---------------------------------------------------------------------------*/29172917+if (VIDEO_ISOC_BUFFER_MANY <= peasycap->video_junk) {29182918+ SAY("easycap driver shutting down on condition green\n");29192919+ peasycap->video_eof = 1;29202920+ peasycap->audio_eof = 1;29212921+ peasycap->video_junk = -VIDEO_ISOC_BUFFER_MANY;29222922+ wake_up_interruptible(&(peasycap->wq_video));29232923+ wake_up_interruptible(&(peasycap->wq_audio));29242924+ return;29252925+}29262926+if (peasycap->video_isoc_streaming) {29272927+ rc = usb_submit_urb(purb, GFP_ATOMIC);29282928+ if (0 != rc) {29292929+ SAY("ERROR: while %i=video_idle, usb_submit_urb() failed " \29302930+ "with rc:\n", peasycap->video_idle);29312931+ switch (rc) {29322932+ case -ENOMEM: {29332933+ SAY("ENOMEM\n"); break;29342934+ }29352935+ case -ENODEV: {29362936+ SAY("ENODEV\n"); break;29372937+ }29382938+ case -ENXIO: {29392939+ SAY("ENXIO\n"); break;29402940+ }29412941+ case -EINVAL: {29422942+ SAY("EINVAL\n"); break;29432943+ }29442944+ case -EAGAIN: {29452945+ SAY("EAGAIN\n"); break;29462946+ }29472947+ case -EFBIG: {29482948+ SAY("EFBIG\n"); break;29492949+ }29502950+ case -EPIPE: {29512951+ SAY("EPIPE\n"); break;29522952+ }29532953+ case -EMSGSIZE: {29542954+ SAY("EMSGSIZE\n"); break;29552955+ }29562956+ default: {29572957+ SAY("0x%08X\n", rc); break;29582958+ }29592959+ }29602960+ }29612961+}29622962+return;29632963+}29642964+/*****************************************************************************/29652965+/*---------------------------------------------------------------------------*/29662966+/*29672967+ *29682968+ * FIXME29692969+ *29702970+ *29712971+ * THIS FUNCTION ASSUMES THAT, ON EACH AND EVERY OCCASION THAT THE DEVICE IS29722972+ * PHYSICALLY PLUGGED IN, INTERFACE 0 IS PROBED FIRST.29732973+ * IF THIS IS NOT TRUE, THERE IS THE POSSIBILITY OF AN Oops.29742974+ *29752975+ * THIS HAS NEVER BEEN A PROBLEM IN PRACTICE, BUT SOMETHING SEEMS WRONG HERE.29762976+ */29772977+/*---------------------------------------------------------------------------*/29782978+int29792979+easycap_usb_probe(struct usb_interface *pusb_interface, \29802980+ const struct usb_device_id *id)29812981+{29822982+struct usb_device *pusb_device, *pusb_device1;29832983+struct usb_host_interface *pusb_host_interface;29842984+struct usb_endpoint_descriptor *pepd;29852985+struct usb_interface_descriptor *pusb_interface_descriptor;29862986+struct usb_interface_assoc_descriptor *pusb_interface_assoc_descriptor;29872987+struct urb *purb;29882988+static struct easycap *peasycap /*=NULL*/;29892989+struct data_urb *pdata_urb;29902990+size_t wMaxPacketSize;29912991+int ISOCwMaxPacketSize;29922992+int BULKwMaxPacketSize;29932993+int INTwMaxPacketSize;29942994+int CTRLwMaxPacketSize;29952995+__u8 bEndpointAddress;29962996+__u8 ISOCbEndpointAddress;29972997+__u8 INTbEndpointAddress;29982998+int isin, i, j, k, m;29992999+__u8 bInterfaceNumber;30003000+__u8 bInterfaceClass;30013001+__u8 bInterfaceSubClass;30023002+void *pbuf;30033003+int okalt[8], isokalt;30043004+int okepn[8], isokepn;30053005+int okmps[8], isokmps;30063006+int maxpacketsize;30073007+int rc;30083008+30093009+JOT(4, "\n");30103010+30113011+if ((struct usb_interface *)NULL == pusb_interface) {30123012+ SAY("ERROR: pusb_interface is NULL\n");30133013+ return -EFAULT;30143014+}30153015+/*---------------------------------------------------------------------------*/30163016+/*30173017+ * GET POINTER TO STRUCTURE usb_device30183018+ */30193019+/*---------------------------------------------------------------------------*/30203020+pusb_device1 = container_of(pusb_interface->dev.parent, \30213021+ struct usb_device, dev);30223022+if ((struct usb_device *)NULL == pusb_device1) {30233023+ SAY("ERROR: pusb_device1 is NULL\n");30243024+ return -EFAULT;30253025+}30263026+pusb_device = usb_get_dev(pusb_device1);30273027+if ((struct usb_device *)NULL == pusb_device) {30283028+ SAY("ERROR: pusb_device is NULL\n");30293029+ return -EFAULT;30303030+}30313031+if ((unsigned long int)pusb_device1 != (unsigned long int)pusb_device) {30323032+ JOT(4, "ERROR: pusb_device1 != pusb_device\n");30333033+ return -EFAULT;30343034+}30353035+30363036+JOT(4, "bNumConfigurations=%i\n", pusb_device->descriptor.bNumConfigurations);30373037+30383038+/*---------------------------------------------------------------------------*/30393039+pusb_host_interface = pusb_interface->cur_altsetting;30403040+if (NULL == pusb_host_interface) {30413041+ SAY("ERROR: pusb_host_interface is NULL\n");30423042+ return -EFAULT;30433043+}30443044+pusb_interface_descriptor = &(pusb_host_interface->desc);30453045+if (NULL == pusb_interface_descriptor) {30463046+ SAY("ERROR: pusb_interface_descriptor is NULL\n");30473047+ return -EFAULT;30483048+}30493049+/*---------------------------------------------------------------------------*/30503050+/*30513051+ * GET PROPERTIES OF PROBED INTERFACE30523052+ */30533053+/*---------------------------------------------------------------------------*/30543054+bInterfaceNumber = pusb_interface_descriptor->bInterfaceNumber;30553055+bInterfaceClass = pusb_interface_descriptor->bInterfaceClass;30563056+bInterfaceSubClass = pusb_interface_descriptor->bInterfaceSubClass;30573057+30583058+JOT(4, "intf[%i]: pusb_interface->num_altsetting=%i\n", \30593059+ bInterfaceNumber, pusb_interface->num_altsetting);30603060+JOT(4, "intf[%i]: pusb_interface->cur_altsetting - " \30613061+ "pusb_interface->altsetting=%li\n", bInterfaceNumber, \30623062+ (long int)(pusb_interface->cur_altsetting - \30633063+ pusb_interface->altsetting));30643064+switch (bInterfaceClass) {30653065+case USB_CLASS_AUDIO: {30663066+ JOT(4, "intf[%i]: bInterfaceClass=0x%02X=USB_CLASS_AUDIO\n", \30673067+ bInterfaceNumber, bInterfaceClass); break;30683068+ }30693069+case USB_CLASS_VIDEO: {30703070+ JOT(4, "intf[%i]: bInterfaceClass=0x%02X=USB_CLASS_VIDEO\n", \30713071+ bInterfaceNumber, bInterfaceClass); break;30723072+ }30733073+case USB_CLASS_VENDOR_SPEC: {30743074+ JOT(4, "intf[%i]: bInterfaceClass=0x%02X=USB_CLASS_VENDOR_SPEC\n", \30753075+ bInterfaceNumber, bInterfaceClass); break;30763076+ }30773077+default:30783078+ break;30793079+}30803080+switch (bInterfaceSubClass) {30813081+case 0x01: {30823082+ JOT(4, "intf[%i]: bInterfaceSubClass=0x%02X=AUDIOCONTROL\n", \30833083+ bInterfaceNumber, bInterfaceSubClass); break;30843084+}30853085+case 0x02: {30863086+ JOT(4, "intf[%i]: bInterfaceSubClass=0x%02X=AUDIOSTREAMING\n", \30873087+ bInterfaceNumber, bInterfaceSubClass); break;30883088+}30893089+case 0x03: {30903090+ JOT(4, "intf[%i]: bInterfaceSubClass=0x%02X=MIDISTREAMING\n", \30913091+ bInterfaceNumber, bInterfaceSubClass); break;30923092+}30933093+default:30943094+ break;30953095+}30963096+/*---------------------------------------------------------------------------*/30973097+pusb_interface_assoc_descriptor = pusb_interface->intf_assoc;30983098+if (NULL != pusb_interface_assoc_descriptor) {30993099+ JOT(4, "intf[%i]: bFirstInterface=0x%02X bInterfaceCount=0x%02X\n", \31003100+ bInterfaceNumber, \31013101+ pusb_interface_assoc_descriptor->bFirstInterface, \31023102+ pusb_interface_assoc_descriptor->bInterfaceCount);31033103+} else {31043104+JOT(4, "intf[%i]: pusb_interface_assoc_descriptor is NULL\n", \31053105+ bInterfaceNumber);31063106+}31073107+/*---------------------------------------------------------------------------*/31083108+/*31093109+ * A NEW struct easycap IS ALWAYS ALLOCATED WHEN INTERFACE 0 IS PROBED.31103110+ * IT IS NOT POSSIBLE HERE TO FREE ANY EXISTING struct easycap. THIS31113111+ * SHOULD HAVE BEEN DONE BY easycap_delete() WHEN THE DEVICE WAS PHYSICALLY31123112+ * UNPLUGGED.31133113+ */31143114+/*---------------------------------------------------------------------------*/31153115+if (0 == bInterfaceNumber) {31163116+ peasycap = kzalloc(sizeof(struct easycap), GFP_KERNEL);31173117+ if (NULL == peasycap) {31183118+ SAY("ERROR: Could not allocate peasycap\n");31193119+ return -ENOMEM;31203120+ } else {31213121+ peasycap->allocation_video_struct = sizeof(struct easycap);31223122+ peasycap->allocation_video_page = 0;31233123+ peasycap->allocation_video_urb = 0;31243124+ peasycap->allocation_audio_struct = 0;31253125+ peasycap->allocation_audio_page = 0;31263126+ peasycap->allocation_audio_urb = 0;31273127+ }31283128+/*---------------------------------------------------------------------------*/31293129+/*31303130+ * INITIALIZE THE NEW easycap STRUCTURE.31313131+ * NO PARAMETERS ARE SPECIFIED HERE REQUIRING THE SETTING OF REGISTERS.31323132+ * THAT IS DONE FIRST BY easycap_open() AND LATER BY easycap_ioctl().31333133+ */31343134+/*---------------------------------------------------------------------------*/31353135+ peasycap->pusb_device = pusb_device;31363136+ peasycap->pusb_interface = pusb_interface;31373137+31383138+ kref_init(&peasycap->kref);31393139+ JOT(8, "intf[%i]: after kref_init(..._video) " \31403140+ "%i=peasycap->kref.refcount.counter\n", \31413141+ bInterfaceNumber, peasycap->kref.refcount.counter);31423142+31433143+ init_waitqueue_head(&(peasycap->wq_video));31443144+ init_waitqueue_head(&(peasycap->wq_audio));31453145+31463146+ mutex_init(&(peasycap->mutex_timeval0));31473147+ mutex_init(&(peasycap->mutex_timeval1));31483148+31493149+ for (k = 0; k < FRAME_BUFFER_MANY; k++)31503150+ mutex_init(&(peasycap->mutex_mmap_video[k]));31513151+31523152+ peasycap->ilk = 0;31533153+ peasycap->microphone = false;31543154+31553155+ peasycap->video_interface = -1;31563156+ peasycap->video_altsetting_on = -1;31573157+ peasycap->video_altsetting_off = -1;31583158+ peasycap->video_endpointnumber = -1;31593159+ peasycap->video_isoc_maxframesize = -1;31603160+ peasycap->video_isoc_buffer_size = -1;31613161+31623162+ peasycap->audio_interface = -1;31633163+ peasycap->audio_altsetting_on = -1;31643164+ peasycap->audio_altsetting_off = -1;31653165+ peasycap->audio_endpointnumber = -1;31663166+ peasycap->audio_isoc_maxframesize = -1;31673167+ peasycap->audio_isoc_buffer_size = -1;31683168+31693169+ peasycap->frame_buffer_many = FRAME_BUFFER_MANY;31703170+31713171+ if ((struct mutex *)NULL == &(peasycap->mutex_mmap_video[0])) {31723172+ SAY("ERROR: &(peasycap->mutex_mmap_video[%i]) is NULL\n", 0);31733173+ return -EFAULT;31743174+ }31753175+/*---------------------------------------------------------------------------*/31763176+/*31773177+ * DYNAMICALLY FILL IN THE AVAILABLE FORMATS.31783178+ */31793179+/*---------------------------------------------------------------------------*/31803180+ rc = fillin_formats();31813181+ if (0 > rc) {31823182+ SAY("ERROR: fillin_formats() returned %i\n", rc);31833183+ return -EFAULT;31843184+ }31853185+ JOT(4, "%i formats available\n", rc);31863186+ } else {31873187+/*---------------------------------------------------------------------------*/31883188+ if ((struct easycap *)NULL == peasycap) {31893189+ SAY("ERROR: peasycap is NULL " \31903190+ "when probing interface %i\n", \31913191+ bInterfaceNumber);31923192+ return -EFAULT;31933193+ }31943194+31953195+ JOT(8, "kref_get() with %i=peasycap->kref.refcount.counter\n", \31963196+ (int)peasycap->kref.refcount.counter);31973197+ kref_get(&peasycap->kref);31983198+}31993199+/*---------------------------------------------------------------------------*/32003200+if ((USB_CLASS_VIDEO == bInterfaceClass) || \32013201+ (USB_CLASS_VENDOR_SPEC == bInterfaceClass)) {32023202+ if (-1 == peasycap->video_interface) {32033203+ peasycap->video_interface = bInterfaceNumber;32043204+ JOT(4, "setting peasycap->video_interface=%i\n", \32053205+ peasycap->video_interface);32063206+ } else {32073207+ if (peasycap->video_interface != bInterfaceNumber) {32083208+ SAY("ERROR: attempting to reset " \32093209+ "peasycap->video_interface\n");32103210+ SAY("...... continuing with " \32113211+ "%i=peasycap->video_interface\n", \32123212+ peasycap->video_interface);32133213+ }32143214+ }32153215+} else if ((USB_CLASS_AUDIO == bInterfaceClass) && \32163216+ (0x02 == bInterfaceSubClass)) {32173217+ if (-1 == peasycap->audio_interface) {32183218+ peasycap->audio_interface = bInterfaceNumber;32193219+ JOT(4, "setting peasycap->audio_interface=%i\n", \32203220+ peasycap->audio_interface);32213221+ } else {32223222+ if (peasycap->audio_interface != bInterfaceNumber) {32233223+ SAY("ERROR: attempting to reset " \32243224+ "peasycap->audio_interface\n");32253225+ SAY("...... continuing with " \32263226+ "%i=peasycap->audio_interface\n", \32273227+ peasycap->audio_interface);32283228+ }32293229+ }32303230+}32313231+/*---------------------------------------------------------------------------*/32323232+/*32333233+ * INVESTIGATE ALL ALTSETTINGS.32343234+ * DONE IN DETAIL BECAUSE USB DEVICE 05e1:0408 HAS DISPARATE INCARNATIONS.32353235+ */32363236+/*---------------------------------------------------------------------------*/32373237+isokalt = 0;32383238+isokepn = 0;32393239+isokmps = 0;32403240+32413241+for (i = 0; i < pusb_interface->num_altsetting; i++) {32423242+ pusb_host_interface = &(pusb_interface->altsetting[i]);32433243+ if ((struct usb_host_interface *)NULL == pusb_host_interface) {32443244+ SAY("ERROR: pusb_host_interface is NULL\n");32453245+ return -EFAULT;32463246+ }32473247+ pusb_interface_descriptor = &(pusb_host_interface->desc);32483248+ if ((struct usb_interface_descriptor *)NULL == \32493249+ pusb_interface_descriptor) {32503250+ SAY("ERROR: pusb_interface_descriptor is NULL\n");32513251+ return -EFAULT;32523252+ }32533253+32543254+ JOT(4, "intf[%i]alt[%i]: desc.bDescriptorType=0x%02X\n", \32553255+ bInterfaceNumber, i, pusb_interface_descriptor->bDescriptorType);32563256+ JOT(4, "intf[%i]alt[%i]: desc.bInterfaceNumber=0x%02X\n", \32573257+ bInterfaceNumber, i, pusb_interface_descriptor->bInterfaceNumber);32583258+ JOT(4, "intf[%i]alt[%i]: desc.bAlternateSetting=0x%02X\n", \32593259+ bInterfaceNumber, i, pusb_interface_descriptor->bAlternateSetting);32603260+ JOT(4, "intf[%i]alt[%i]: desc.bNumEndpoints=0x%02X\n", \32613261+ bInterfaceNumber, i, pusb_interface_descriptor->bNumEndpoints);32623262+ JOT(4, "intf[%i]alt[%i]: desc.bInterfaceClass=0x%02X\n", \32633263+ bInterfaceNumber, i, pusb_interface_descriptor->bInterfaceClass);32643264+ JOT(4, "intf[%i]alt[%i]: desc.bInterfaceSubClass=0x%02X\n", \32653265+ bInterfaceNumber, i, pusb_interface_descriptor->bInterfaceSubClass);32663266+ JOT(4, "intf[%i]alt[%i]: desc.bInterfaceProtocol=0x%02X\n", \32673267+ bInterfaceNumber, i, pusb_interface_descriptor->bInterfaceProtocol);32683268+ JOT(4, "intf[%i]alt[%i]: desc.iInterface=0x%02X\n", \32693269+ bInterfaceNumber, i, pusb_interface_descriptor->iInterface);32703270+32713271+ ISOCwMaxPacketSize = -1;32723272+ BULKwMaxPacketSize = -1;32733273+ INTwMaxPacketSize = -1;32743274+ CTRLwMaxPacketSize = -1;32753275+ ISOCbEndpointAddress = 0;32763276+ INTbEndpointAddress = 0;32773277+32783278+ if (0 == pusb_interface_descriptor->bNumEndpoints)32793279+ JOT(4, "intf[%i]alt[%i] has no endpoints\n", \32803280+ bInterfaceNumber, i);32813281+/*---------------------------------------------------------------------------*/32823282+ for (j = 0; j < pusb_interface_descriptor->bNumEndpoints; j++) {32833283+ pepd = &(pusb_host_interface->endpoint[j].desc);32843284+ if ((struct usb_endpoint_descriptor *)NULL == pepd) {32853285+ SAY("ERROR: pepd is NULL.\n");32863286+ SAY("...... skipping\n");32873287+ continue;32883288+ }32893289+ wMaxPacketSize = le16_to_cpu(pepd->wMaxPacketSize);32903290+ bEndpointAddress = pepd->bEndpointAddress;32913291+32923292+ JOT(4, "intf[%i]alt[%i]end[%i]: bEndpointAddress=0x%X\n", \32933293+ bInterfaceNumber, i, j, \32943294+ pepd->bEndpointAddress);32953295+ JOT(4, "intf[%i]alt[%i]end[%i]: bmAttributes=0x%X\n", \32963296+ bInterfaceNumber, i, j, \32973297+ pepd->bmAttributes);32983298+ JOT(4, "intf[%i]alt[%i]end[%i]: wMaxPacketSize=%i\n", \32993299+ bInterfaceNumber, i, j, \33003300+ pepd->wMaxPacketSize);33013301+ JOT(4, "intf[%i]alt[%i]end[%i]: bInterval=%i\n",33023302+ bInterfaceNumber, i, j, \33033303+ pepd->bInterval);33043304+33053305+ if (pepd->bEndpointAddress & USB_DIR_IN) {33063306+ JOT(4, "intf[%i]alt[%i]end[%i] is an IN endpoint\n",\33073307+ bInterfaceNumber, i, j);33083308+ isin = 1;33093309+ } else {33103310+ JOT(4, "intf[%i]alt[%i]end[%i] is an OUT endpoint\n",\33113311+ bInterfaceNumber, i, j);33123312+ SAY("ERROR: OUT endpoint unexpected\n");33133313+ SAY("...... continuing\n");33143314+ isin = 0;33153315+ }33163316+ if ((pepd->bmAttributes & \33173317+ USB_ENDPOINT_XFERTYPE_MASK) == \33183318+ USB_ENDPOINT_XFER_ISOC) {33193319+ JOT(4, "intf[%i]alt[%i]end[%i] is an ISOC endpoint\n",\33203320+ bInterfaceNumber, i, j);33213321+ if (isin) {33223322+ switch (bInterfaceClass) {33233323+ case USB_CLASS_VIDEO:33243324+ case USB_CLASS_VENDOR_SPEC: {33253325+ if (!peasycap) {33263326+ SAY("MISTAKE: " \33273327+ "peasycap is NULL\n");33283328+ return -EFAULT;33293329+ }33303330+ if (pepd->wMaxPacketSize) {33313331+ if (8 > isokalt) {33323332+ okalt[isokalt] = i;33333333+ JOT(4,\33343334+ "%i=okalt[%i]\n", \33353335+ okalt[isokalt], \33363336+ isokalt);33373337+ isokalt++;33383338+ }33393339+ if (8 > isokepn) {33403340+ okepn[isokepn] = \33413341+ pepd->\33423342+ bEndpointAddress & \33433343+ 0x0F;33443344+ JOT(4,\33453345+ "%i=okepn[%i]\n", \33463346+ okepn[isokepn], \33473347+ isokepn);33483348+ isokepn++;33493349+ }33503350+ if (8 > isokmps) {33513351+ okmps[isokmps] = \33523352+ le16_to_cpu(pepd->\33533353+ wMaxPacketSize);33543354+ JOT(4,\33553355+ "%i=okmps[%i]\n", \33563356+ okmps[isokmps], \33573357+ isokmps);33583358+ isokmps++;33593359+ }33603360+ } else {33613361+ if (-1 == peasycap->\33623362+ video_altsetting_off) {33633363+ peasycap->\33643364+ video_altsetting_off =\33653365+ i;33663366+ JOT(4, "%i=video_" \33673367+ "altsetting_off " \33683368+ "<====\n", \33693369+ peasycap->\33703370+ video_altsetting_off);33713371+ } else {33723372+ SAY("ERROR: peasycap" \33733373+ "->video_altsetting_" \33743374+ "off already set\n");33753375+ SAY("...... " \33763376+ "continuing with " \33773377+ "%i=peasycap->video_" \33783378+ "altsetting_off\n", \33793379+ peasycap->\33803380+ video_altsetting_off);33813381+ }33823382+ }33833383+ break;33843384+ }33853385+ case USB_CLASS_AUDIO: {33863386+ if (0x02 != bInterfaceSubClass)33873387+ break;33883388+ if (!peasycap) {33893389+ SAY("MISTAKE: " \33903390+ "peasycap is NULL\n");33913391+ return -EFAULT;33923392+ }33933393+ if (pepd->wMaxPacketSize) {33943394+ if (8 > isokalt) {33953395+ okalt[isokalt] = i ;33963396+ JOT(4,\33973397+ "%i=okalt[%i]\n", \33983398+ okalt[isokalt], \33993399+ isokalt);34003400+ isokalt++;34013401+ }34023402+ if (8 > isokepn) {34033403+ okepn[isokepn] = \34043404+ pepd->\34053405+ bEndpointAddress & \34063406+ 0x0F;34073407+ JOT(4,\34083408+ "%i=okepn[%i]\n", \34093409+ okepn[isokepn], \34103410+ isokepn);34113411+ isokepn++;34123412+ }34133413+ if (8 > isokmps) {34143414+ okmps[isokmps] = \34153415+ le16_to_cpu(pepd->\34163416+ wMaxPacketSize);34173417+ JOT(4,\34183418+ "%i=okmps[%i]\n",\34193419+ okmps[isokmps], \34203420+ isokmps);34213421+ isokmps++;34223422+ }34233423+ } else {34243424+ if (-1 == peasycap->\34253425+ audio_altsetting_off) {34263426+ peasycap->\34273427+ audio_altsetting_off =\34283428+ i;34293429+ JOT(4, "%i=audio_" \34303430+ "altsetting_off " \34313431+ "<====\n", \34323432+ peasycap->\34333433+ audio_altsetting_off);34343434+ } else {34353435+ SAY("ERROR: peasycap" \34363436+ "->audio_altsetting_" \34373437+ "off already set\n");34383438+ SAY("...... " \34393439+ "continuing with " \34403440+ "%i=peasycap->\34413441+ audio_altsetting_" \34423442+ "off\n",34433443+ peasycap->\34443444+ audio_altsetting_off);34453445+ }34463446+ }34473447+ break;34483448+ }34493449+ default:34503450+ break;34513451+ }34523452+ }34533453+ } else if ((pepd->bmAttributes & \34543454+ USB_ENDPOINT_XFERTYPE_MASK) ==\34553455+ USB_ENDPOINT_XFER_BULK) {34563456+ JOT(4, "intf[%i]alt[%i]end[%i] is a BULK endpoint\n",\34573457+ bInterfaceNumber, i, j);34583458+ } else if ((pepd->bmAttributes & \34593459+ USB_ENDPOINT_XFERTYPE_MASK) ==\34603460+ USB_ENDPOINT_XFER_INT) {34613461+ JOT(4, "intf[%i]alt[%i]end[%i] is an INT endpoint\n",\34623462+ bInterfaceNumber, i, j);34633463+ } else {34643464+ JOT(4, "intf[%i]alt[%i]end[%i] is a CTRL endpoint\n",\34653465+ bInterfaceNumber, i, j);34663466+ }34673467+ if (0 == pepd->wMaxPacketSize) {34683468+ JOT(4, "intf[%i]alt[%i]end[%i] " \34693469+ "has zero packet size\n", \34703470+ bInterfaceNumber, i, j);34713471+ }34723472+ }34733473+}34743474+/*---------------------------------------------------------------------------*/34753475+/*34763476+ * PERFORM INITIALIZATION OF THE PROBED INTERFACE34773477+ */34783478+/*---------------------------------------------------------------------------*/34793479+JOT(4, "initialization begins for interface %i\n", \34803480+ pusb_interface_descriptor->bInterfaceNumber);34813481+switch (bInterfaceNumber) {34823482+/*---------------------------------------------------------------------------*/34833483+/*34843484+ * INTERFACE 0 IS THE VIDEO INTERFACE34853485+ */34863486+/*---------------------------------------------------------------------------*/34873487+case 0: {34883488+ if (!peasycap) {34893489+ SAY("MISTAKE: peasycap is NULL\n");34903490+ return -EFAULT;34913491+ }34923492+ if (!isokalt) {34933493+ SAY("ERROR: no viable video_altsetting_on\n");34943494+ return -ENOENT;34953495+ } else {34963496+ peasycap->video_altsetting_on = okalt[isokalt - 1];34973497+ JOT(4, "%i=video_altsetting_on <====\n", \34983498+ peasycap->video_altsetting_on);34993499+ }35003500+ if (!isokepn) {35013501+ SAY("ERROR: no viable video_endpointnumber\n");35023502+ return -ENOENT;35033503+ } else {35043504+ peasycap->video_endpointnumber = okepn[isokepn - 1];35053505+ JOT(4, "%i=video_endpointnumber\n", \35063506+ peasycap->video_endpointnumber);35073507+ }35083508+ if (!isokmps) {35093509+ SAY("ERROR: no viable video_maxpacketsize\n");35103510+ return -ENOENT;35113511+/*---------------------------------------------------------------------------*/35123512+/*35133513+ * DECIDE THE VIDEO STREAMING PARAMETERS35143514+ */35153515+/*---------------------------------------------------------------------------*/35163516+ } else {35173517+ maxpacketsize = okmps[isokmps - 1] - 1024;35183518+ if (USB_2_0_MAXPACKETSIZE > maxpacketsize) {35193519+ peasycap->video_isoc_maxframesize = maxpacketsize;35203520+ } else {35213521+ peasycap->video_isoc_maxframesize = \35223522+ USB_2_0_MAXPACKETSIZE;35233523+ }35243524+ JOT(4, "%i=video_isoc_maxframesize\n", \35253525+ peasycap->video_isoc_maxframesize);35263526+ if (0 >= peasycap->video_isoc_maxframesize) {35273527+ SAY("ERROR: bad video_isoc_maxframesize\n");35283528+ return -ENOENT;35293529+ }35303530+ peasycap->video_isoc_framesperdesc = VIDEO_ISOC_FRAMESPERDESC;35313531+ JOT(4, "%i=video_isoc_framesperdesc\n", \35323532+ peasycap->video_isoc_framesperdesc);35333533+ if (0 >= peasycap->video_isoc_framesperdesc) {35343534+ SAY("ERROR: bad video_isoc_framesperdesc\n");35353535+ return -ENOENT;35363536+ }35373537+ peasycap->video_isoc_buffer_size = \35383538+ peasycap->video_isoc_maxframesize * \35393539+ peasycap->video_isoc_framesperdesc;35403540+ JOT(4, "%i=video_isoc_buffer_size\n", \35413541+ peasycap->video_isoc_buffer_size);35423542+ if ((PAGE_SIZE << VIDEO_ISOC_ORDER) < \35433543+ peasycap->video_isoc_buffer_size) {35443544+ SAY("MISTAKE: " \35453545+ "peasycap->video_isoc_buffer_size too big\n");35463546+ return -EFAULT;35473547+ }35483548+ }35493549+/*---------------------------------------------------------------------------*/35503550+ if (-1 == peasycap->video_interface) {35513551+ SAY("MISTAKE: video_interface is unset\n");35523552+ return -EFAULT;35533553+ }35543554+ if (-1 == peasycap->video_altsetting_on) {35553555+ SAY("MISTAKE: video_altsetting_on is unset\n");35563556+ return -EFAULT;35573557+ }35583558+ if (-1 == peasycap->video_altsetting_off) {35593559+ SAY("MISTAKE: video_interface_off is unset\n");35603560+ return -EFAULT;35613561+ }35623562+ if (-1 == peasycap->video_endpointnumber) {35633563+ SAY("MISTAKE: video_endpointnumber is unset\n");35643564+ return -EFAULT;35653565+ }35663566+ if (-1 == peasycap->video_isoc_maxframesize) {35673567+ SAY("MISTAKE: video_isoc_maxframesize is unset\n");35683568+ return -EFAULT;35693569+ }35703570+ if (-1 == peasycap->video_isoc_buffer_size) {35713571+ SAY("MISTAKE: video_isoc_buffer_size is unset\n");35723572+ return -EFAULT;35733573+ }35743574+/*---------------------------------------------------------------------------*/35753575+/*35763576+ * ALLOCATE MEMORY FOR VIDEO BUFFERS. LISTS MUST BE INITIALIZED FIRST.35773577+ */35783578+/*---------------------------------------------------------------------------*/35793579+ INIT_LIST_HEAD(&(peasycap->urb_video_head));35803580+ peasycap->purb_video_head = &(peasycap->urb_video_head);35813581+/*---------------------------------------------------------------------------*/35823582+ JOT(4, "allocating %i frame buffers of size %li\n", \35833583+ FRAME_BUFFER_MANY, (long int)FRAME_BUFFER_SIZE);35843584+ JOT(4, ".... each scattered over %li pages\n", \35853585+ FRAME_BUFFER_SIZE/PAGE_SIZE);35863586+35873587+ for (k = 0; k < FRAME_BUFFER_MANY; k++) {35883588+ for (m = 0; m < FRAME_BUFFER_SIZE/PAGE_SIZE; m++) {35893589+ if ((void *)NULL != peasycap->frame_buffer[k][m].pgo)35903590+ SAY("attempting to reallocate frame " \35913591+ " buffers\n");35923592+ else {35933593+ pbuf = (void *)__get_free_page(GFP_KERNEL);35943594+ if ((void *)NULL == pbuf) {35953595+ SAY("ERROR: Could not allocate frame "\35963596+ "buffer %i page %i\n", k, m);35973597+ return -ENOMEM;35983598+ } else35993599+ peasycap->allocation_video_page += 1;36003600+ peasycap->frame_buffer[k][m].pgo = pbuf;36013601+ }36023602+ peasycap->frame_buffer[k][m].pto = \36033603+ peasycap->frame_buffer[k][m].pgo;36043604+ }36053605+ }36063606+36073607+ peasycap->frame_fill = 0;36083608+ peasycap->frame_read = 0;36093609+ JOT(4, "allocation of frame buffers done: %i pages\n", k * \36103610+ m);36113611+/*---------------------------------------------------------------------------*/36123612+ JOT(4, "allocating %i field buffers of size %li\n", \36133613+ FIELD_BUFFER_MANY, (long int)FIELD_BUFFER_SIZE);36143614+ JOT(4, ".... each scattered over %li pages\n", \36153615+ FIELD_BUFFER_SIZE/PAGE_SIZE);36163616+36173617+ for (k = 0; k < FIELD_BUFFER_MANY; k++) {36183618+ for (m = 0; m < FIELD_BUFFER_SIZE/PAGE_SIZE; m++) {36193619+ if ((void *)NULL != peasycap->field_buffer[k][m].pgo) {36203620+ SAY("ERROR: attempting to reallocate " \36213621+ "field buffers\n");36223622+ } else {36233623+ pbuf = (void *) __get_free_page(GFP_KERNEL);36243624+ if ((void *)NULL == pbuf) {36253625+ SAY("ERROR: Could not allocate field" \36263626+ " buffer %i page %i\n", k, m);36273627+ return -ENOMEM;36283628+ }36293629+ else36303630+ peasycap->allocation_video_page += 1;36313631+ peasycap->field_buffer[k][m].pgo = pbuf;36323632+ }36333633+ peasycap->field_buffer[k][m].pto = \36343634+ peasycap->field_buffer[k][m].pgo;36353635+ }36363636+ peasycap->field_buffer[k][0].kount = 0x0200;36373637+ }36383638+ peasycap->field_fill = 0;36393639+ peasycap->field_page = 0;36403640+ peasycap->field_read = 0;36413641+ JOT(4, "allocation of field buffers done: %i pages\n", k * \36423642+ m);36433643+/*---------------------------------------------------------------------------*/36443644+ JOT(4, "allocating %i isoc video buffers of size %i\n", \36453645+ VIDEO_ISOC_BUFFER_MANY, \36463646+ peasycap->video_isoc_buffer_size);36473647+ JOT(4, ".... each occupying contiguous memory pages\n");36483648+36493649+ for (k = 0; k < VIDEO_ISOC_BUFFER_MANY; k++) {36503650+ pbuf = (void *)__get_free_pages(GFP_KERNEL, VIDEO_ISOC_ORDER);36513651+ if (NULL == pbuf) {36523652+ SAY("ERROR: Could not allocate isoc video buffer " \36533653+ "%i\n", k);36543654+ return -ENOMEM;36553655+ } else36563656+ peasycap->allocation_video_page += \36573657+ ((unsigned int)(0x01 << VIDEO_ISOC_ORDER));36583658+36593659+ peasycap->video_isoc_buffer[k].pgo = pbuf;36603660+ peasycap->video_isoc_buffer[k].pto = pbuf + \36613661+ peasycap->video_isoc_buffer_size;36623662+ peasycap->video_isoc_buffer[k].kount = k;36633663+ }36643664+ JOT(4, "allocation of isoc video buffers done: %i pages\n", \36653665+ k * (0x01 << VIDEO_ISOC_ORDER));36663666+/*---------------------------------------------------------------------------*/36673667+/*36683668+ * ALLOCATE AND INITIALIZE MULTIPLE struct urb ...36693669+ */36703670+/*---------------------------------------------------------------------------*/36713671+ JOT(4, "allocating %i struct urb.\n", VIDEO_ISOC_BUFFER_MANY);36723672+ JOT(4, "using %i=peasycap->video_isoc_framesperdesc\n", \36733673+ peasycap->video_isoc_framesperdesc);36743674+ JOT(4, "using %i=peasycap->video_isoc_maxframesize\n", \36753675+ peasycap->video_isoc_maxframesize);36763676+ JOT(4, "using %i=peasycap->video_isoc_buffer_sizen", \36773677+ peasycap->video_isoc_buffer_size);36783678+36793679+ for (k = 0; k < VIDEO_ISOC_BUFFER_MANY; k++) {36803680+ purb = usb_alloc_urb(peasycap->video_isoc_framesperdesc, \36813681+ GFP_KERNEL);36823682+ if (NULL == purb) {36833683+ SAY("ERROR: usb_alloc_urb returned NULL for buffer " \36843684+ "%i\n", k);36853685+ return -ENOMEM;36863686+ } else36873687+ peasycap->allocation_video_urb += 1;36883688+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */36893689+ pdata_urb = kzalloc(sizeof(struct data_urb), GFP_KERNEL);36903690+ if (NULL == pdata_urb) {36913691+ SAY("ERROR: Could not allocate struct data_urb.\n");36923692+ return -ENOMEM;36933693+ } else36943694+ peasycap->allocation_video_struct += \36953695+ sizeof(struct data_urb);36963696+36973697+ pdata_urb->purb = purb;36983698+ pdata_urb->isbuf = k;36993699+ pdata_urb->length = 0;37003700+ list_add_tail(&(pdata_urb->list_head), \37013701+ peasycap->purb_video_head);37023702+/*---------------------------------------------------------------------------*/37033703+/*37043704+ * ... AND INITIALIZE THEM37053705+ */37063706+/*---------------------------------------------------------------------------*/37073707+ if (!k) {37083708+ JOT(4, "initializing video urbs thus:\n");37093709+ JOT(4, " purb->interval = 1;\n");37103710+ JOT(4, " purb->dev = peasycap->pusb_device;\n");37113711+ JOT(4, " purb->pipe = usb_rcvisocpipe" \37123712+ "(peasycap->pusb_device,%i);\n", \37133713+ peasycap->video_endpointnumber);37143714+ JOT(4, " purb->transfer_flags = URB_ISO_ASAP;\n");37153715+ JOT(4, " purb->transfer_buffer = peasycap->" \37163716+ "video_isoc_buffer[.].pgo;\n");37173717+ JOT(4, " purb->transfer_buffer_length = %i;\n", \37183718+ peasycap->video_isoc_buffer_size);37193719+ JOT(4, " purb->complete = easycap_complete;\n");37203720+ JOT(4, " purb->context = peasycap;\n");37213721+ JOT(4, " purb->start_frame = 0;\n");37223722+ JOT(4, " purb->number_of_packets = %i;\n", \37233723+ peasycap->video_isoc_framesperdesc);37243724+ JOT(4, " for (j = 0; j < %i; j++)\n", \37253725+ peasycap->video_isoc_framesperdesc);37263726+ JOT(4, " {\n");37273727+ JOT(4, " purb->iso_frame_desc[j].offset = j*%i;\n",\37283728+ peasycap->video_isoc_maxframesize);37293729+ JOT(4, " purb->iso_frame_desc[j].length = %i;\n", \37303730+ peasycap->video_isoc_maxframesize);37313731+ JOT(4, " }\n");37323732+ }37333733+37343734+ purb->interval = 1;37353735+ purb->dev = peasycap->pusb_device;37363736+ purb->pipe = usb_rcvisocpipe(peasycap->pusb_device, \37373737+ peasycap->video_endpointnumber);37383738+ purb->transfer_flags = URB_ISO_ASAP;37393739+ purb->transfer_buffer = peasycap->video_isoc_buffer[k].pgo;37403740+ purb->transfer_buffer_length = \37413741+ peasycap->video_isoc_buffer_size;37423742+ purb->complete = easycap_complete;37433743+ purb->context = peasycap;37443744+ purb->start_frame = 0;37453745+ purb->number_of_packets = peasycap->video_isoc_framesperdesc;37463746+ for (j = 0; j < peasycap->video_isoc_framesperdesc; j++) {37473747+ purb->iso_frame_desc[j].offset = j * \37483748+ peasycap->video_isoc_maxframesize;37493749+ purb->iso_frame_desc[j].length = \37503750+ peasycap->video_isoc_maxframesize;37513751+ }37523752+ }37533753+ JOT(4, "allocation of %i struct urb done.\n", k);37543754+/*--------------------------------------------------------------------------*/37553755+/*37563756+ * SAVE POINTER peasycap IN THIS INTERFACE.37573757+ */37583758+/*--------------------------------------------------------------------------*/37593759+ usb_set_intfdata(pusb_interface, peasycap);37603760+/*--------------------------------------------------------------------------*/37613761+/*37623762+ * THE VIDEO DEVICE CAN BE REGISTERED NOW, AS IT IS READY.37633763+ */37643764+/*--------------------------------------------------------------------------*/37653765+#if (!defined(EASYCAP_IS_VIDEODEV_CLIENT))37663766+ if (0 != (usb_register_dev(pusb_interface, &easycap_class))) {37673767+ err("Not able to get a minor for this device");37683768+ usb_set_intfdata(pusb_interface, NULL);37693769+ return -ENODEV;37703770+ } else37713771+ (peasycap->registered_video)++;37723772+ SAY("easycap attached to minor #%d\n", pusb_interface->minor);37733773+ break;37743774+/*vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv*/37753775+#else37763776+ pvideo_device = (struct video_device *)\37773777+ kzalloc(sizeof(struct video_device), GFP_KERNEL);37783778+ if ((struct video_device *)NULL == pvideo_device) {37793779+ SAY("ERROR: Could not allocate structure video_device\n");37803780+ return -ENOMEM;37813781+ }37823782+ if (VIDEO_DEVICE_MANY <= video_device_many) {37833783+ SAY("ERROR: Too many /dev/videos\n");37843784+ return -ENOMEM;37853785+ }37863786+ pvideo_array[video_device_many] = pvideo_device; video_device_many++;37873787+37883788+ strcpy(&pvideo_device->name[0], "easycapdc60");37893789+#if defined(EASYCAP_NEEDS_V4L2_FOPS)37903790+ pvideo_device->fops = &v4l2_fops;37913791+#else37923792+ pvideo_device->fops = &easycap_fops;37933793+#endif /*EASYCAP_NEEDS_V4L2_FOPS*/37943794+ pvideo_device->minor = -1;37953795+ pvideo_device->release = (void *)(&videodev_release);37963796+37973797+ video_set_drvdata(pvideo_device, (void *)peasycap);37983798+37993799+ rc = video_register_device(pvideo_device, VFL_TYPE_GRABBER, -1);38003800+ if (0 != rc) {38013801+ err("Not able to register with videodev");38023802+ videodev_release(pvideo_device);38033803+ return -ENODEV;38043804+ } else {38053805+ peasycap->pvideo_device = pvideo_device;38063806+ (peasycap->registered_video)++;38073807+ JOT(4, "registered with videodev: %i=minor\n", \38083808+ pvideo_device->minor);38093809+ }38103810+/*^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^*/38113811+#endif /*EASYCAP_IS_VIDEODEV_CLIENT*/38123812+ break;38133813+}38143814+/*--------------------------------------------------------------------------*/38153815+/*38163816+ * INTERFACE 1 IS THE AUDIO CONTROL INTERFACE38173817+ * INTERFACE 2 IS THE AUDIO STREAMING INTERFACE38183818+ */38193819+/*--------------------------------------------------------------------------*/38203820+case 1: {38213821+/*--------------------------------------------------------------------------*/38223822+/*38233823+ * SAVE POINTER peasycap IN INTERFACE 138243824+ */38253825+/*--------------------------------------------------------------------------*/38263826+ usb_set_intfdata(pusb_interface, peasycap);38273827+ JOT(4, "no initialization required for interface %i\n", \38283828+ pusb_interface_descriptor->bInterfaceNumber);38293829+ break;38303830+}38313831+/*--------------------------------------------------------------------------*/38323832+case 2: {38333833+ if (!peasycap) {38343834+ SAY("MISTAKE: peasycap is NULL\n");38353835+ return -EFAULT;38363836+ }38373837+ if (!isokalt) {38383838+ SAY("ERROR: no viable audio_altsetting_on\n");38393839+ return -ENOENT;38403840+ } else {38413841+ peasycap->audio_altsetting_on = okalt[isokalt - 1];38423842+ JOT(4, "%i=audio_altsetting_on <====\n", \38433843+ peasycap->audio_altsetting_on);38443844+ }38453845+ if (!isokepn) {38463846+ SAY("ERROR: no viable audio_endpointnumber\n");38473847+ return -ENOENT;38483848+ } else {38493849+ peasycap->audio_endpointnumber = okepn[isokepn - 1];38503850+ JOT(4, "%i=audio_endpointnumber\n", \38513851+ peasycap->audio_endpointnumber);38523852+ }38533853+ if (!isokmps) {38543854+ SAY("ERROR: no viable audio_maxpacketsize\n");38553855+ return -ENOENT;38563856+ } else {38573857+ peasycap->audio_isoc_maxframesize = okmps[isokmps - 1];38583858+ JOT(4, "%i=audio_isoc_maxframesize\n", \38593859+ peasycap->audio_isoc_maxframesize);38603860+ if (0 >= peasycap->audio_isoc_maxframesize) {38613861+ SAY("ERROR: bad audio_isoc_maxframesize\n");38623862+ return -ENOENT;38633863+ }38643864+ if (9 == peasycap->audio_isoc_maxframesize) {38653865+ peasycap->ilk |= 0x02;38663866+ SAY("hardware is FOUR-CVBS\n");38673867+ peasycap->microphone = true;38683868+ audio_pages_per_fragment = 2;38693869+ } else if (256 == peasycap->audio_isoc_maxframesize) {38703870+ peasycap->ilk &= ~0x02;38713871+ SAY("hardware is CVBS+S-VIDEO\n");38723872+ peasycap->microphone = false;38733873+ audio_pages_per_fragment = 4;38743874+ } else {38753875+ SAY("hardware is unidentified:\n");38763876+ SAY("%i=audio_isoc_maxframesize\n", \38773877+ peasycap->audio_isoc_maxframesize);38783878+ return -ENOENT;38793879+ }38803880+38813881+ audio_bytes_per_fragment = audio_pages_per_fragment * \38823882+ PAGE_SIZE ;38833883+ audio_buffer_page_many = (AUDIO_FRAGMENT_MANY * \38843884+ audio_pages_per_fragment);38853885+38863886+ JOT(4, "%6i=AUDIO_FRAGMENT_MANY\n", AUDIO_FRAGMENT_MANY);38873887+ JOT(4, "%6i=audio_pages_per_fragment\n", \38883888+ audio_pages_per_fragment);38893889+ JOT(4, "%6i=audio_bytes_per_fragment\n", \38903890+ audio_bytes_per_fragment);38913891+ JOT(4, "%6i=audio_buffer_page_many\n", audio_buffer_page_many);38923892+38933893+ peasycap->audio_isoc_framesperdesc = 128;38943894+38953895+ JOT(4, "%i=audio_isoc_framesperdesc\n", \38963896+ peasycap->audio_isoc_framesperdesc);38973897+ if (0 >= peasycap->audio_isoc_framesperdesc) {38983898+ SAY("ERROR: bad audio_isoc_framesperdesc\n");38993899+ return -ENOENT;39003900+ }39013901+39023902+ peasycap->audio_isoc_buffer_size = \39033903+ peasycap->audio_isoc_maxframesize * \39043904+ peasycap->audio_isoc_framesperdesc;39053905+ JOT(4, "%i=audio_isoc_buffer_size\n", \39063906+ peasycap->audio_isoc_buffer_size);39073907+ if (AUDIO_ISOC_BUFFER_SIZE < \39083908+ peasycap->audio_isoc_buffer_size) {39093909+ SAY("MISTAKE: audio_isoc_buffer_size bigger "39103910+ "than %li=AUDIO_ISOC_BUFFER_SIZE\n", \39113911+ AUDIO_ISOC_BUFFER_SIZE);39123912+ return -EFAULT;39133913+ }39143914+ }39153915+39163916+ if (-1 == peasycap->audio_interface) {39173917+ SAY("MISTAKE: audio_interface is unset\n");39183918+ return -EFAULT;39193919+ }39203920+ if (-1 == peasycap->audio_altsetting_on) {39213921+ SAY("MISTAKE: audio_altsetting_on is unset\n");39223922+ return -EFAULT;39233923+ }39243924+ if (-1 == peasycap->audio_altsetting_off) {39253925+ SAY("MISTAKE: audio_interface_off is unset\n");39263926+ return -EFAULT;39273927+ }39283928+ if (-1 == peasycap->audio_endpointnumber) {39293929+ SAY("MISTAKE: audio_endpointnumber is unset\n");39303930+ return -EFAULT;39313931+ }39323932+ if (-1 == peasycap->audio_isoc_maxframesize) {39333933+ SAY("MISTAKE: audio_isoc_maxframesize is unset\n");39343934+ return -EFAULT;39353935+ }39363936+ if (-1 == peasycap->audio_isoc_buffer_size) {39373937+ SAY("MISTAKE: audio_isoc_buffer_size is unset\n");39383938+ return -EFAULT;39393939+ }39403940+/*---------------------------------------------------------------------------*/39413941+/*39423942+ * ALLOCATE MEMORY FOR AUDIO BUFFERS. LISTS MUST BE INITIALIZED FIRST.39433943+ */39443944+/*---------------------------------------------------------------------------*/39453945+ INIT_LIST_HEAD(&(peasycap->urb_audio_head));39463946+ peasycap->purb_audio_head = &(peasycap->urb_audio_head);39473947+39483948+ JOT(4, "allocating an audio buffer\n");39493949+ JOT(4, ".... scattered over %i pages\n", audio_buffer_page_many);39503950+39513951+ for (k = 0; k < audio_buffer_page_many; k++) {39523952+ if ((void *)NULL != peasycap->audio_buffer[k].pgo) {39533953+ SAY("ERROR: attempting to reallocate audio buffers\n");39543954+ } else {39553955+ pbuf = (void *) __get_free_page(GFP_KERNEL);39563956+ if ((void *)NULL == pbuf) {39573957+ SAY("ERROR: Could not allocate audio " \39583958+ "buffer page %i\n", k);39593959+ return -ENOMEM;39603960+ } else39613961+ peasycap->allocation_audio_page += 1;39623962+39633963+ peasycap->audio_buffer[k].pgo = pbuf;39643964+ }39653965+ peasycap->audio_buffer[k].pto = peasycap->audio_buffer[k].pgo;39663966+ }39673967+39683968+ peasycap->audio_fill = 0;39693969+ peasycap->audio_read = 0;39703970+ JOT(4, "allocation of audio buffer done: %i pages\n", k);39713971+/*---------------------------------------------------------------------------*/39723972+ JOT(4, "allocating %i isoc audio buffers of size %i\n", \39733973+ AUDIO_ISOC_BUFFER_MANY, peasycap->audio_isoc_buffer_size);39743974+ JOT(4, ".... each occupying contiguous memory pages\n");39753975+39763976+ for (k = 0; k < AUDIO_ISOC_BUFFER_MANY; k++) {39773977+ pbuf = (void *)__get_free_pages(GFP_KERNEL, AUDIO_ISOC_ORDER);39783978+ if (NULL == pbuf) {39793979+ SAY("ERROR: Could not allocate isoc audio buffer " \39803980+ "%i\n", k);39813981+ return -ENOMEM;39823982+ } else39833983+ peasycap->allocation_audio_page += \39843984+ ((unsigned int)(0x01 << AUDIO_ISOC_ORDER));39853985+39863986+ peasycap->audio_isoc_buffer[k].pgo = pbuf;39873987+ peasycap->audio_isoc_buffer[k].pto = pbuf + \39883988+ peasycap->audio_isoc_buffer_size;39893989+ peasycap->audio_isoc_buffer[k].kount = k;39903990+ }39913991+ JOT(4, "allocation of isoc audio buffers done.\n");39923992+/*---------------------------------------------------------------------------*/39933993+/*39943994+ * ALLOCATE AND INITIALIZE MULTIPLE struct urb ...39953995+ */39963996+/*---------------------------------------------------------------------------*/39973997+ JOT(4, "allocating %i struct urb.\n", AUDIO_ISOC_BUFFER_MANY);39983998+ JOT(4, "using %i=peasycap->audio_isoc_framesperdesc\n", \39993999+ peasycap->audio_isoc_framesperdesc);40004000+ JOT(4, "using %i=peasycap->audio_isoc_maxframesize\n", \40014001+ peasycap->audio_isoc_maxframesize);40024002+ JOT(4, "using %i=peasycap->audio_isoc_buffer_size\n", \40034003+ peasycap->audio_isoc_buffer_size);40044004+40054005+ for (k = 0; k < AUDIO_ISOC_BUFFER_MANY; k++) {40064006+ purb = usb_alloc_urb(peasycap->audio_isoc_framesperdesc, \40074007+ GFP_KERNEL);40084008+ if (NULL == purb) {40094009+ SAY("ERROR: usb_alloc_urb returned NULL for buffer " \40104010+ "%i\n", k);40114011+ return -ENOMEM;40124012+ } else40134013+ peasycap->allocation_audio_urb += 1 ;40144014+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */40154015+ pdata_urb = kzalloc(sizeof(struct data_urb), GFP_KERNEL);40164016+ if (NULL == pdata_urb) {40174017+ SAY("ERROR: Could not allocate struct data_urb.\n");40184018+ return -ENOMEM;40194019+ } else40204020+ peasycap->allocation_audio_struct += \40214021+ sizeof(struct data_urb);40224022+40234023+ pdata_urb->purb = purb;40244024+ pdata_urb->isbuf = k;40254025+ pdata_urb->length = 0;40264026+ list_add_tail(&(pdata_urb->list_head), \40274027+ peasycap->purb_audio_head);40284028+/*---------------------------------------------------------------------------*/40294029+/*40304030+ * ... AND INITIALIZE THEM40314031+ */40324032+/*---------------------------------------------------------------------------*/40334033+ if (!k) {40344034+ JOT(4, "initializing audio urbs thus:\n");40354035+ JOT(4, " purb->interval = 1;\n");40364036+ JOT(4, " purb->dev = peasycap->pusb_device;\n");40374037+ JOT(4, " purb->pipe = usb_rcvisocpipe(peasycap->" \40384038+ "pusb_device,%i);\n", \40394039+ peasycap->audio_endpointnumber);40404040+ JOT(4, " purb->transfer_flags = URB_ISO_ASAP;\n");40414041+ JOT(4, " purb->transfer_buffer = " \40424042+ "peasycap->audio_isoc_buffer[.].pgo;\n");40434043+ JOT(4, " purb->transfer_buffer_length = %i;\n", \40444044+ peasycap->audio_isoc_buffer_size);40454045+ JOT(4, " purb->complete = easysnd_complete;\n");40464046+ JOT(4, " purb->context = peasycap;\n");40474047+ JOT(4, " purb->start_frame = 0;\n");40484048+ JOT(4, " purb->number_of_packets = %i;\n", \40494049+ peasycap->audio_isoc_framesperdesc);40504050+ JOT(4, " for (j = 0; j < %i; j++)\n", \40514051+ peasycap->audio_isoc_framesperdesc);40524052+ JOT(4, " {\n");40534053+ JOT(4, " purb->iso_frame_desc[j].offset = j*%i;\n",\40544054+ peasycap->audio_isoc_maxframesize);40554055+ JOT(4, " purb->iso_frame_desc[j].length = %i;\n", \40564056+ peasycap->audio_isoc_maxframesize);40574057+ JOT(4, " }\n");40584058+ }40594059+40604060+ purb->interval = 1;40614061+ purb->dev = peasycap->pusb_device;40624062+ purb->pipe = usb_rcvisocpipe(peasycap->pusb_device, \40634063+ peasycap->audio_endpointnumber);40644064+ purb->transfer_flags = URB_ISO_ASAP;40654065+ purb->transfer_buffer = peasycap->audio_isoc_buffer[k].pgo;40664066+ purb->transfer_buffer_length = \40674067+ peasycap->audio_isoc_buffer_size;40684068+ purb->complete = easysnd_complete;40694069+ purb->context = peasycap;40704070+ purb->start_frame = 0;40714071+ purb->number_of_packets = peasycap->audio_isoc_framesperdesc;40724072+ for (j = 0; j < peasycap->audio_isoc_framesperdesc; j++) {40734073+ purb->iso_frame_desc[j].offset = j * \40744074+ peasycap->audio_isoc_maxframesize;40754075+ purb->iso_frame_desc[j].length = \40764076+ peasycap->audio_isoc_maxframesize;40774077+ }40784078+ }40794079+ JOT(4, "allocation of %i struct urb done.\n", k);40804080+/*---------------------------------------------------------------------------*/40814081+/*40824082+ * SAVE POINTER peasycap IN THIS INTERFACE.40834083+ */40844084+/*---------------------------------------------------------------------------*/40854085+ usb_set_intfdata(pusb_interface, peasycap);40864086+/*---------------------------------------------------------------------------*/40874087+/*40884088+ * THE AUDIO DEVICE CAN BE REGISTERED NOW, AS IT IS READY.40894089+ */40904090+/*---------------------------------------------------------------------------*/40914091+ rc = usb_register_dev(pusb_interface, &easysnd_class);40924092+ if (0 != rc) {40934093+ err("Not able to get a minor for this device.");40944094+ usb_set_intfdata(pusb_interface, NULL);40954095+ return -ENODEV;40964096+ } else40974097+ (peasycap->registered_audio)++;40984098+/*---------------------------------------------------------------------------*/40994099+/*41004100+ * LET THE USER KNOW WHAT NODE THE AUDIO DEVICE IS ATTACHED TO.41014101+ */41024102+/*---------------------------------------------------------------------------*/41034103+ SAY("easysnd attached to minor #%d\n", pusb_interface->minor);41044104+ break;41054105+}41064106+/*---------------------------------------------------------------------------*/41074107+/*41084108+ * INTERFACES OTHER THAN 0, 1 AND 2 ARE UNEXPECTED41094109+ */41104110+/*---------------------------------------------------------------------------*/41114111+default: {41124112+ JOT(4, "ERROR: unexpected interface %i\n", bInterfaceNumber);41134113+ return -EINVAL;41144114+}41154115+}41164116+JOT(4, "ends successfully for interface %i\n", \41174117+ pusb_interface_descriptor->bInterfaceNumber);41184118+return 0;41194119+}41204120+/*****************************************************************************/41214121+/*---------------------------------------------------------------------------*/41224122+/*41234123+ * WHEN THIS FUNCTION IS CALLED THE DEVICE HAS ALREADY BEEN PHYSICALLY41244124+ * UNPLUGGED.41254125+ * HENCE peasycap->pusb_device IS NO LONGER VALID AND MUST BE SET TO NULL.41264126+ */41274127+/*---------------------------------------------------------------------------*/41284128+void41294129+easycap_usb_disconnect(struct usb_interface *pusb_interface)41304130+{41314131+struct usb_host_interface *pusb_host_interface;41324132+struct usb_interface_descriptor *pusb_interface_descriptor;41334133+__u8 bInterfaceNumber;41344134+struct easycap *peasycap;41354135+41364136+struct list_head *plist_head;41374137+struct data_urb *pdata_urb;41384138+int minor, m;41394139+41404140+JOT(4, "\n");41414141+41424142+if ((struct usb_interface *)NULL == pusb_interface) {41434143+ JOT(4, "ERROR: pusb_interface is NULL\n");41444144+ return;41454145+}41464146+pusb_host_interface = pusb_interface->cur_altsetting;41474147+if ((struct usb_host_interface *)NULL == pusb_host_interface) {41484148+ JOT(4, "ERROR: pusb_host_interface is NULL\n");41494149+ return;41504150+}41514151+pusb_interface_descriptor = &(pusb_host_interface->desc);41524152+if ((struct usb_interface_descriptor *)NULL == pusb_interface_descriptor) {41534153+ JOT(4, "ERROR: pusb_interface_descriptor is NULL\n");41544154+ return;41554155+}41564156+bInterfaceNumber = pusb_interface_descriptor->bInterfaceNumber;41574157+minor = pusb_interface->minor;41584158+JOT(4, "intf[%i]: minor=%i\n", bInterfaceNumber, minor);41594159+41604160+peasycap = usb_get_intfdata(pusb_interface);41614161+if ((struct easycap *)NULL == peasycap)41624162+ SAY("ERROR: peasycap is NULL\n");41634163+else {41644164+ peasycap->pusb_device = (struct usb_device *)NULL;41654165+ switch (bInterfaceNumber) {41664166+/*---------------------------------------------------------------------------*/41674167+ case 0: {41684168+ if ((struct list_head *)NULL != peasycap->purb_video_head) {41694169+ JOT(4, "killing video urbs\n");41704170+ m = 0;41714171+ list_for_each(plist_head, (peasycap->purb_video_head))41724172+ {41734173+ pdata_urb = list_entry(plist_head, \41744174+ struct data_urb, list_head);41754175+ if ((struct data_urb *)NULL != pdata_urb) {41764176+ if ((struct urb *)NULL != \41774177+ pdata_urb->purb) {41784178+ usb_kill_urb(pdata_urb->purb);41794179+ m++;41804180+ }41814181+ }41824182+ }41834183+ JOT(4, "%i video urbs killed\n", m);41844184+ } else41854185+ SAY("ERROR: peasycap->purb_video_head is NULL\n");41864186+ break;41874187+ }41884188+/*---------------------------------------------------------------------------*/41894189+ case 2: {41904190+ if ((struct list_head *)NULL != peasycap->purb_audio_head) {41914191+ JOT(4, "killing audio urbs\n");41924192+ m = 0;41934193+ list_for_each(plist_head, \41944194+ (peasycap->purb_audio_head)) {41954195+ pdata_urb = list_entry(plist_head, \41964196+ struct data_urb, list_head);41974197+ if ((struct data_urb *)NULL != pdata_urb) {41984198+ if ((struct urb *)NULL != \41994199+ pdata_urb->purb) {42004200+ usb_kill_urb(pdata_urb->purb);42014201+ m++;42024202+ }42034203+ }42044204+ }42054205+ JOT(4, "%i audio urbs killed\n", m);42064206+ } else42074207+ SAY("ERROR: peasycap->purb_audio_head is NULL\n");42084208+ break;42094209+ }42104210+/*---------------------------------------------------------------------------*/42114211+ default:42124212+ break;42134213+ }42144214+}42154215+/*--------------------------------------------------------------------------*/42164216+/*42174217+ * DEREGISTER42184218+ */42194219+/*--------------------------------------------------------------------------*/42204220+switch (bInterfaceNumber) {42214221+case 0: {42224222+#if (!defined(EASYCAP_IS_VIDEODEV_CLIENT))42234223+ if ((struct easycap *)NULL == peasycap) {42244224+ SAY("ERROR: peasycap has become NULL\n");42254225+ } else {42264226+ lock_kernel();42274227+ usb_deregister_dev(pusb_interface, &easycap_class);42284228+ (peasycap->registered_video)--;42294229+42304230+ JOT(4, "intf[%i]: usb_deregister_dev()\n", bInterfaceNumber);42314231+ unlock_kernel();42324232+ SAY("easycap detached from minor #%d\n", minor);42334233+ }42344234+/*vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv*/42354235+#else42364236+ if ((struct easycap *)NULL == peasycap)42374237+ SAY("ERROR: peasycap has become NULL\n");42384238+ else {42394239+ lock_kernel();42404240+ video_unregister_device(peasycap->pvideo_device);42414241+ (peasycap->registered_video)--;42424242+ unlock_kernel();42434243+ JOT(4, "unregistered with videodev: %i=minor\n", \42444244+ pvideo_device->minor);42454245+ }42464246+/*^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^*/42474247+#endif /*EASYCAP_IS_VIDEODEV_CLIENT*/42484248+ break;42494249+}42504250+case 2: {42514251+ lock_kernel();42524252+42534253+ usb_deregister_dev(pusb_interface, &easysnd_class);42544254+ if ((struct easycap *)NULL != peasycap)42554255+ (peasycap->registered_audio)--;42564256+42574257+ JOT(4, "intf[%i]: usb_deregister_dev()\n", bInterfaceNumber);42584258+ unlock_kernel();42594259+42604260+ SAY("easysnd detached from minor #%d\n", minor);42614261+ break;42624262+}42634263+default:42644264+ break;42654265+}42664266+/*---------------------------------------------------------------------------*/42674267+/*42684268+ * CALL easycap_delete() IF NO REMAINING REFERENCES TO peasycap42694269+ */42704270+/*---------------------------------------------------------------------------*/42714271+if ((struct easycap *)NULL == peasycap) {42724272+ SAY("ERROR: peasycap has become NULL\n");42734273+ SAY("cannot call kref_put()\n");42744274+ SAY("ending unsuccessfully: may cause memory leak\n");42754275+ return;42764276+}42774277+if (!peasycap->kref.refcount.counter) {42784278+ SAY("ERROR: peasycap->kref.refcount.counter is zero " \42794279+ "so cannot call kref_put()\n");42804280+ SAY("ending unsuccessfully: may cause memory leak\n");42814281+ return;42824282+}42834283+JOT(4, "intf[%i]: kref_put() with %i=peasycap->kref.refcount.counter\n", \42844284+ bInterfaceNumber, (int)peasycap->kref.refcount.counter);42854285+kref_put(&peasycap->kref, easycap_delete);42864286+JOT(4, "intf[%i]: kref_put() done.\n", bInterfaceNumber);42874287+/*---------------------------------------------------------------------------*/42884288+42894289+JOT(4, "ends\n");42904290+return;42914291+}42924292+/*****************************************************************************/42934293+int __init42944294+easycap_module_init(void)42954295+{42964296+int result;42974297+42984298+SAY("========easycap=======\n");42994299+JOT(4, "begins. %i=debug\n", easycap_debug);43004300+SAY("version: " EASYCAP_DRIVER_VERSION "\n");43014301+/*---------------------------------------------------------------------------*/43024302+/*43034303+ * REGISTER THIS DRIVER WITH THE USB SUBSYTEM.43044304+ */43054305+/*---------------------------------------------------------------------------*/43064306+JOT(4, "registering driver easycap\n");43074307+43084308+result = usb_register(&easycap_usb_driver);43094309+if (0 != result)43104310+ SAY("ERROR: usb_register returned %i\n", result);43114311+43124312+JOT(4, "ends\n");43134313+return result;43144314+}43154315+/*****************************************************************************/43164316+void __exit43174317+easycap_module_exit(void)43184318+{43194319+JOT(4, "begins\n");43204320+43214321+/*---------------------------------------------------------------------------*/43224322+/*43234323+ * DEREGISTER THIS DRIVER WITH THE USB SUBSYTEM.43244324+ */43254325+/*---------------------------------------------------------------------------*/43264326+usb_deregister(&easycap_usb_driver);43274327+43284328+JOT(4, "ends\n");43294329+}43304330+/*****************************************************************************/43314331+43324332+module_init(easycap_module_init);43334333+module_exit(easycap_module_exit);43344334+43354335+MODULE_LICENSE("GPL");43364336+MODULE_AUTHOR("R.M. Thomas <rmthomas@sciolus.org>");43374337+MODULE_DESCRIPTION(EASYCAP_DRIVER_DESCRIPTION);43384338+MODULE_VERSION(EASYCAP_DRIVER_VERSION);43394339+#if defined(EASYCAP_DEBUG)43404340+MODULE_PARM_DESC(easycap_debug, "debug: 0 (default), 1, 2,...");43414341+#endif /*EASYCAP_DEBUG*/43424342+/*****************************************************************************/
···11+/******************************************************************************22+* *33+* easycap_sound.c *44+* *55+* Audio driver for EasyCAP USB2.0 Video Capture Device DC60 *66+* *77+* *88+******************************************************************************/99+/*1010+ *1111+ * Copyright (C) 2010 R.M. Thomas <rmthomas@sciolus.org>1212+ *1313+ *1414+ * This is free software; you can redistribute it and/or modify1515+ * it under the terms of the GNU General Public License as published by1616+ * the Free Software Foundation; either version 2 of the License, or1717+ * (at your option) any later version.1818+ *1919+ * The software is distributed in the hope that it will be useful,2020+ * but WITHOUT ANY WARRANTY; without even the implied warranty of2121+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the2222+ * GNU General Public License for more details.2323+ *2424+ * You should have received a copy of the GNU General Public License2525+ * along with this software; if not, write to the Free Software2626+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA2727+ *2828+*/2929+/*****************************************************************************/3030+3131+#include "easycap.h"3232+#include "easycap_debug.h"3333+#include "easycap_sound.h"3434+3535+/*****************************************************************************/3636+/*---------------------------------------------------------------------------*/3737+/*3838+ * ON COMPLETION OF AN AUDIO URB ITS DATA IS COPIED TO THE AUDIO BUFFERS3939+ * PROVIDED peasycap->audio_idle IS ZER0. REGARDLESS OF THIS BEING TRUE,4040+ * IT IS RESUBMITTED PROVIDED peasycap->audio_isoc_streaming IS NOT ZERO.4141+ */4242+/*---------------------------------------------------------------------------*/4343+void4444+easysnd_complete(struct urb *purb)4545+{4646+static int mt;4747+struct easycap *peasycap;4848+struct data_buffer *paudio_buffer;4949+char errbuf[16];5050+__u8 *p1, *p2;5151+__s16 s16;5252+int i, j, more, much, leap, rc;5353+5454+JOT(16, "\n");5555+5656+if (NULL == purb) {5757+ SAY("ERROR: purb is NULL\n");5858+ return;5959+}6060+peasycap = purb->context;6161+if (NULL == peasycap) {6262+ SAY("ERROR: peasycap is NULL\n");6363+ return;6464+}6565+much = 0;6666+6767+6868+if (peasycap->audio_idle) {6969+ JOT(16, "%i=audio_idle %i=audio_isoc_streaming\n", \7070+ peasycap->audio_idle, peasycap->audio_isoc_streaming);7171+ if (peasycap->audio_isoc_streaming) {7272+ rc = usb_submit_urb(purb, GFP_ATOMIC);7373+ if (0 != rc) {7474+ SAY("ERROR: while %i=audio_idle, " \7575+ "usb_submit_urb() failed with rc:\n", \7676+ peasycap->audio_idle);7777+ switch (rc) {7878+ case -ENOMEM: {7979+ SAY("ENOMEM\n"); break;8080+ }8181+ case -ENODEV: {8282+ SAY("ENODEV\n"); break;8383+ }8484+ case -ENXIO: {8585+ SAY("ENXIO\n"); break;8686+ }8787+ case -EINVAL: {8888+ SAY("EINVAL\n"); break;8989+ }9090+ case -EAGAIN: {9191+ SAY("EAGAIN\n"); break;9292+ }9393+ case -EFBIG: {9494+ SAY("EFBIG\n"); break;9595+ }9696+ case -EPIPE: {9797+ SAY("EPIPE\n"); break;9898+ }9999+ case -EMSGSIZE: {100100+ SAY("EMSGSIZE\n"); break;101101+ }102102+ default: {103103+ SAY("0x%08X\n", rc); break;104104+ }105105+ }106106+ }107107+ }108108+return;109109+}110110+/*---------------------------------------------------------------------------*/111111+if (purb->status) {112112+ if (-ESHUTDOWN == purb->status) {113113+ JOT(16, "immediate return because -ESHUTDOWN=purb->status\n");114114+ return;115115+ }116116+ SAY("ERROR: non-zero urb status:\n");117117+ switch (purb->status) {118118+ case -EINPROGRESS: {119119+ SAY("-EINPROGRESS\n"); break;120120+ }121121+ case -ENOSR: {122122+ SAY("-ENOSR\n"); break;123123+ }124124+ case -EPIPE: {125125+ SAY("-EPIPE\n"); break;126126+ }127127+ case -EOVERFLOW: {128128+ SAY("-EOVERFLOW\n"); break;129129+ }130130+ case -EPROTO: {131131+ SAY("-EPROTO\n"); break;132132+ }133133+ case -EILSEQ: {134134+ SAY("-EILSEQ\n"); break;135135+ }136136+ case -ETIMEDOUT: {137137+ SAY("-ETIMEDOUT\n"); break;138138+ }139139+ case -EMSGSIZE: {140140+ SAY("-EMSGSIZE\n"); break;141141+ }142142+ case -EOPNOTSUPP: {143143+ SAY("-EOPNOTSUPP\n"); break;144144+ }145145+ case -EPFNOSUPPORT: {146146+ SAY("-EPFNOSUPPORT\n"); break;147147+ }148148+ case -EAFNOSUPPORT: {149149+ SAY("-EAFNOSUPPORT\n"); break;150150+ }151151+ case -EADDRINUSE: {152152+ SAY("-EADDRINUSE\n"); break;153153+ }154154+ case -EADDRNOTAVAIL: {155155+ SAY("-EADDRNOTAVAIL\n"); break;156156+ }157157+ case -ENOBUFS: {158158+ SAY("-ENOBUFS\n"); break;159159+ }160160+ case -EISCONN: {161161+ SAY("-EISCONN\n"); break;162162+ }163163+ case -ENOTCONN: {164164+ SAY("-ENOTCONN\n"); break;165165+ }166166+ case -ESHUTDOWN: {167167+ SAY("-ESHUTDOWN\n"); break;168168+ }169169+ case -ENOENT: {170170+ SAY("-ENOENT\n"); break;171171+ }172172+ case -ECONNRESET: {173173+ SAY("-ECONNRESET\n"); break;174174+ }175175+ default: {176176+ SAY("unknown error code 0x%08X\n", purb->status); break;177177+ }178178+ }179179+/*---------------------------------------------------------------------------*/180180+/*181181+ * RESUBMIT THIS URB AFTER AN ERROR182182+ *183183+ * (THIS IS DUPLICATE CODE TO REDUCE INDENTATION OF THE NO-ERROR PATH)184184+ */185185+/*---------------------------------------------------------------------------*/186186+ if (peasycap->audio_isoc_streaming) {187187+ rc = usb_submit_urb(purb, GFP_ATOMIC);188188+ if (0 != rc) {189189+ SAY("ERROR: while %i=audio_idle, usb_submit_urb() "190190+ "failed with rc:\n", peasycap->audio_idle);191191+ switch (rc) {192192+ case -ENOMEM: {193193+ SAY("ENOMEM\n"); break;194194+ }195195+ case -ENODEV: {196196+ SAY("ENODEV\n"); break;197197+ }198198+ case -ENXIO: {199199+ SAY("ENXIO\n"); break;200200+ }201201+ case -EINVAL: {202202+ SAY("EINVAL\n"); break;203203+ }204204+ case -EAGAIN: {205205+ SAY("EAGAIN\n"); break;206206+ }207207+ case -EFBIG: {208208+ SAY("EFBIG\n"); break;209209+ }210210+ case -EPIPE: {211211+ SAY("EPIPE\n"); break;212212+ }213213+ case -EMSGSIZE: {214214+ SAY("EMSGSIZE\n"); break;215215+ }216216+ default: {217217+ SAY("0x%08X\n", rc); break;218218+ }219219+ }220220+ }221221+ }222222+ return;223223+}224224+/*---------------------------------------------------------------------------*/225225+/*226226+ * PROCEED HERE WHEN NO ERROR227227+ */228228+/*---------------------------------------------------------------------------*/229229+for (i = 0; i < purb->number_of_packets; i++) {230230+ switch (purb->iso_frame_desc[i].status) {231231+ case 0: {232232+ strcpy(&errbuf[0], "OK"); break;233233+ }234234+ case -ENOENT: {235235+ strcpy(&errbuf[0], "-ENOENT"); break;236236+ }237237+ case -EINPROGRESS: {238238+ strcpy(&errbuf[0], "-EINPROGRESS"); break;239239+ }240240+ case -EPROTO: {241241+ strcpy(&errbuf[0], "-EPROTO"); break;242242+ }243243+ case -EILSEQ: {244244+ strcpy(&errbuf[0], "-EILSEQ"); break;245245+ }246246+ case -ETIME: {247247+ strcpy(&errbuf[0], "-ETIME"); break;248248+ }249249+ case -ETIMEDOUT: {250250+ strcpy(&errbuf[0], "-ETIMEDOUT"); break;251251+ }252252+ case -EPIPE: {253253+ strcpy(&errbuf[0], "-EPIPE"); break;254254+ }255255+ case -ECOMM: {256256+ strcpy(&errbuf[0], "-ECOMM"); break;257257+ }258258+ case -ENOSR: {259259+ strcpy(&errbuf[0], "-ENOSR"); break;260260+ }261261+ case -EOVERFLOW: {262262+ strcpy(&errbuf[0], "-EOVERFLOW"); break;263263+ }264264+ case -EREMOTEIO: {265265+ strcpy(&errbuf[0], "-EREMOTEIO"); break;266266+ }267267+ case -ENODEV: {268268+ strcpy(&errbuf[0], "-ENODEV"); break;269269+ }270270+ case -EXDEV: {271271+ strcpy(&errbuf[0], "-EXDEV"); break;272272+ }273273+ case -EINVAL: {274274+ strcpy(&errbuf[0], "-EINVAL"); break;275275+ }276276+ case -ECONNRESET: {277277+ strcpy(&errbuf[0], "-ECONNRESET"); break;278278+ }279279+ case -ESHUTDOWN: {280280+ strcpy(&errbuf[0], "-ESHUTDOWN"); break;281281+ }282282+ default: {283283+ strcpy(&errbuf[0], "UNKNOWN"); break;284284+ }285285+ }286286+ if ((!purb->iso_frame_desc[i].status) && 0) {287287+ JOT(16, "frame[%2i]: %i=status{=%16s} " \288288+ "%5i=actual " \289289+ "%5i=length " \290290+ "%3i=offset\n", \291291+ i, purb->iso_frame_desc[i].status, &errbuf[0],292292+ purb->iso_frame_desc[i].actual_length,293293+ purb->iso_frame_desc[i].length,294294+ purb->iso_frame_desc[i].offset);295295+ }296296+ if (!purb->iso_frame_desc[i].status) {297297+ more = purb->iso_frame_desc[i].actual_length;298298+299299+#if defined(TESTTONE)300300+ if (!more)301301+ more = purb->iso_frame_desc[i].length;302302+#endif303303+304304+ if (!more)305305+ mt++;306306+ else {307307+ if (mt) {308308+ JOT(16, "%4i empty audio urb frames\n", mt);309309+ mt = 0;310310+ }311311+312312+ p1 = (__u8 *)(purb->transfer_buffer + \313313+ purb->iso_frame_desc[i].offset);314314+315315+ leap = 0;316316+ p1 += leap;317317+ more -= leap;318318+/*---------------------------------------------------------------------------*/319319+/*320320+ * COPY more BYTES FROM ISOC BUFFER TO AUDIO BUFFER,321321+ * CONVERTING 8-BIT SAMPLES TO 16-BIT SIGNED LITTLE-ENDED SAMPLES IF NECESSARY322322+ */323323+/*---------------------------------------------------------------------------*/324324+ while (more) {325325+ if (0 > more) {326326+ SAY("easysnd_complete: MISTAKE: " \327327+ "more is negative\n");328328+ return;329329+ }330330+ if (audio_buffer_page_many <= \331331+ peasycap->audio_fill) {332332+ SAY("ERROR: bad " \333333+ "peasycap->audio_fill\n");334334+ return;335335+ }336336+337337+ paudio_buffer = &peasycap->audio_buffer\338338+ [peasycap->audio_fill];339339+ if (PAGE_SIZE < (paudio_buffer->pto - \340340+ paudio_buffer->pgo)) {341341+ SAY("ERROR: bad paudio_buffer->pto\n");342342+ return;343343+ }344344+ if (PAGE_SIZE == (paudio_buffer->pto - \345345+ paudio_buffer->pgo)) {346346+347347+#if defined(TESTTONE)348348+ easysnd_testtone(peasycap, \349349+ peasycap->audio_fill);350350+#endif /*TESTTONE*/351351+352352+ paudio_buffer->pto = \353353+ paudio_buffer->pgo;354354+ (peasycap->audio_fill)++;355355+ if (audio_buffer_page_many <= \356356+ peasycap->audio_fill)357357+ peasycap->audio_fill = 0;358358+359359+ JOT(12, "bumped peasycap->" \360360+ "audio_fill to %i\n", \361361+ peasycap->audio_fill);362362+363363+ paudio_buffer = &peasycap->\364364+ audio_buffer\365365+ [peasycap->audio_fill];366366+ paudio_buffer->pto = \367367+ paudio_buffer->pgo;368368+369369+ if (!(peasycap->audio_fill % \370370+ audio_pages_per_fragment)) {371371+ JOT(12, "wakeup call on wq_" \372372+ "audio, %i=frag reading %i" \373373+ "=fragment fill\n", \374374+ (peasycap->audio_read / \375375+ audio_pages_per_fragment), \376376+ (peasycap->audio_fill / \377377+ audio_pages_per_fragment));378378+ wake_up_interruptible\379379+ (&(peasycap->wq_audio));380380+ }381381+ }382382+383383+ much = PAGE_SIZE - (int)(paudio_buffer->pto -\384384+ paudio_buffer->pgo);385385+ if (much % 2)386386+ JOT(8, "MISTAKE? much is odd\n");387387+388388+ if (false == peasycap->microphone) {389389+ if (much > more)390390+ much = more;391391+392392+ memcpy(paudio_buffer->pto, p1, much);393393+ p1 += much;394394+ more -= much;395395+ } else {396396+ if (much > (2 * more))397397+ much = 2 * more;398398+ p2 = (__u8 *)paudio_buffer->pto;399399+400400+ for (j = 0; j < (much / 2); j++) {401401+ s16 = ((int) *p1) - 128;402402+ *p2 = (0xFF00 & s16) >> 8;403403+ *(p2 + 1) = (0x00FF & s16);404404+ p1++; p2 += 2;405405+ more--;406406+ }407407+ }408408+ (paudio_buffer->pto) += much;409409+ }410410+ }411411+ } else {412412+ JOT(12, "discarding audio samples because " \413413+ "%i=purb->iso_frame_desc[i].status\n", \414414+ purb->iso_frame_desc[i].status);415415+ }416416+}417417+/*---------------------------------------------------------------------------*/418418+/*419419+ * RESUBMIT THIS URB AFTER NO ERROR420420+ */421421+/*---------------------------------------------------------------------------*/422422+if (peasycap->audio_isoc_streaming) {423423+ rc = usb_submit_urb(purb, GFP_ATOMIC);424424+ if (0 != rc) {425425+ SAY("ERROR: while %i=audio_idle, usb_submit_urb() failed " \426426+ "with rc:\n", peasycap->audio_idle);427427+ switch (rc) {428428+ case -ENOMEM: {429429+ SAY("ENOMEM\n"); break;430430+ }431431+ case -ENODEV: {432432+ SAY("ENODEV\n"); break;433433+ }434434+ case -ENXIO: {435435+ SAY("ENXIO\n"); break;436436+ }437437+ case -EINVAL: {438438+ SAY("EINVAL\n"); break;439439+ }440440+ case -EAGAIN: {441441+ SAY("EAGAIN\n"); break;442442+ }443443+ case -EFBIG: {444444+ SAY("EFBIG\n"); break;445445+ }446446+ case -EPIPE: {447447+ SAY("EPIPE\n"); break;448448+ }449449+ case -EMSGSIZE: {450450+ SAY("EMSGSIZE\n"); break;451451+ }452452+ default: {453453+ SAY("0x%08X\n", rc); break;454454+ }455455+ }456456+ }457457+}458458+return;459459+}460460+/*****************************************************************************/461461+/*---------------------------------------------------------------------------*/462462+/*463463+ * THE AUDIO URBS ARE SUBMITTED AT THIS EARLY STAGE SO THAT IT IS POSSIBLE TO464464+ * STREAM FROM /dev/easysnd1 WITH SIMPLE PROGRAMS SUCH AS cat WHICH DO NOT465465+ * HAVE AN IOCTL INTERFACE. THE VIDEO URBS, BY CONTRAST, MUST BE SUBMITTED466466+ * MUCH LATER: SEE COMMENTS IN FILE easycap_main.c.467467+ */468468+/*---------------------------------------------------------------------------*/469469+int470470+easysnd_open(struct inode *inode, struct file *file)471471+{472472+struct usb_interface *pusb_interface;473473+struct easycap *peasycap;474474+int subminor, rc;475475+476476+JOT(4, "begins.\n");477477+478478+subminor = iminor(inode);479479+480480+pusb_interface = usb_find_interface(&easycap_usb_driver, subminor);481481+if (NULL == pusb_interface) {482482+ SAY("ERROR: pusb_interface is NULL\n");483483+ SAY("ending unsuccessfully\n");484484+ return -1;485485+}486486+peasycap = usb_get_intfdata(pusb_interface);487487+if (NULL == peasycap) {488488+ SAY("ERROR: peasycap is NULL\n");489489+ SAY("ending unsuccessfully\n");490490+ return -1;491491+}492492+493493+file->private_data = peasycap;494494+495495+/*---------------------------------------------------------------------------*/496496+/*497497+ * INITIALIZATION.498498+ */499499+/*---------------------------------------------------------------------------*/500500+JOT(4, "starting initialization\n");501501+502502+if ((struct usb_device *)NULL == peasycap->pusb_device) {503503+ SAY("ERROR: peasycap->pusb_device is NULL\n");504504+ return -EFAULT;505505+} else {506506+ JOT(16, "0x%08lX=peasycap->pusb_device\n", \507507+ (long int)peasycap->pusb_device);508508+}509509+510510+rc = audio_setup(peasycap);511511+if (0 <= rc)512512+ JOT(8, "audio_setup() returned %i\n", rc);513513+else514514+ JOT(8, "easysnd open(): ERROR: audio_setup() returned %i\n", rc);515515+516516+if ((struct usb_device *)NULL == peasycap->pusb_device) {517517+ SAY("ERROR: peasycap->pusb_device has become NULL\n");518518+ return -EFAULT;519519+}520520+rc = adjust_volume(peasycap, -8192);521521+if (0 != rc) {522522+ SAY("ERROR: adjust_volume(default) returned %i\n", rc);523523+ return -EFAULT;524524+}525525+/*---------------------------------------------------------------------------*/526526+if ((struct usb_device *)NULL == peasycap->pusb_device) {527527+ SAY("ERROR: peasycap->pusb_device has become NULL\n");528528+ return -EFAULT;529529+}530530+rc = usb_set_interface(peasycap->pusb_device, peasycap->audio_interface, \531531+ peasycap->audio_altsetting_on);532532+JOT(8, "usb_set_interface(.,%i,%i) returned %i\n", peasycap->audio_interface, \533533+ peasycap->audio_altsetting_on, rc);534534+535535+if ((struct usb_device *)NULL == peasycap->pusb_device) {536536+ SAY("ERROR: peasycap->pusb_device has become NULL\n");537537+ return -EFAULT;538538+}539539+rc = wakeup_device(peasycap->pusb_device);540540+if (0 == rc)541541+ JOT(8, "wakeup_device() returned %i\n", rc);542542+else543543+ JOT(8, "easysnd open(): ERROR: wakeup_device() returned %i\n", rc);544544+545545+if ((struct usb_device *)NULL == peasycap->pusb_device) {546546+ SAY("ERROR: peasycap->pusb_device has become NULL\n");547547+ return -EFAULT;548548+}549549+submit_audio_urbs(peasycap);550550+peasycap->audio_idle = 0;551551+552552+peasycap->timeval1.tv_sec = 0;553553+peasycap->timeval1.tv_usec = 0;554554+555555+JOT(4, "finished initialization\n");556556+return 0;557557+}558558+/*****************************************************************************/559559+int560560+easysnd_release(struct inode *inode, struct file *file)561561+{562562+struct easycap *peasycap;563563+564564+JOT(4, "begins\n");565565+566566+peasycap = (struct easycap *)file->private_data;567567+if (NULL == peasycap) {568568+ SAY("ERROR: peasycap is NULL.\n");569569+ return -EFAULT;570570+}571571+if (0 != kill_audio_urbs(peasycap)) {572572+ SAY("ERROR: kill_audio_urbs() failed\n");573573+ return -EFAULT;574574+}575575+JOT(4, "ending successfully\n");576576+return 0;577577+}578578+/*****************************************************************************/579579+ssize_t580580+easysnd_read(struct file *file, char __user *puserspacebuffer, \581581+ size_t kount, loff_t *poff)582582+{583583+struct timeval timeval;584584+static struct timeval timeval1;585585+static long long int audio_bytes, above, below, mean;586586+struct signed_div_result sdr;587587+unsigned char *p0;588588+long int kount1, more, rc, l0, lm;589589+int fragment;590590+struct easycap *peasycap;591591+struct data_buffer *pdata_buffer;592592+size_t szret;593593+594594+/*---------------------------------------------------------------------------*/595595+/*596596+ * DO A BLOCKING READ TO TRANSFER DATA TO USER SPACE.597597+ *598598+ ******************************************************************************599599+ ***** N.B. IF THIS FUNCTION RETURNS 0, NOTHING IS SEEN IN USER SPACE. ******600600+ ***** THIS CONDITION SIGNIFIES END-OF-FILE. ******601601+ ******************************************************************************602602+ */603603+/*---------------------------------------------------------------------------*/604604+605605+JOT(8, "===== easysnd_read(): kount=%i, *poff=%i\n", (int)kount, (int)(*poff));606606+607607+peasycap = (struct easycap *)(file->private_data);608608+if (NULL == peasycap) {609609+ SAY("ERROR in easysnd_read(): peasycap is NULL\n");610610+ return -EFAULT;611611+}612612+/*---------------------------------------------------------------------------*/613613+if ((0 > peasycap->audio_read) || \614614+ (audio_buffer_page_many <= peasycap->audio_read)) {615615+ SAY("ERROR: peasycap->audio_read out of range\n");616616+ return -EFAULT;617617+}618618+pdata_buffer = &peasycap->audio_buffer[peasycap->audio_read];619619+if ((struct data_buffer *)NULL == pdata_buffer) {620620+ SAY("ERROR: pdata_buffer is NULL\n");621621+ return -EFAULT;622622+}623623+JOT(12, "before wait, %i=frag read %i=frag fill\n", \624624+ (peasycap->audio_read / audio_pages_per_fragment), \625625+ (peasycap->audio_fill / audio_pages_per_fragment));626626+fragment = (peasycap->audio_read / audio_pages_per_fragment);627627+while ((fragment == (peasycap->audio_fill / audio_pages_per_fragment)) || \628628+ (0 == (PAGE_SIZE - (pdata_buffer->pto - pdata_buffer->pgo)))) {629629+ if (file->f_flags & O_NONBLOCK) {630630+ JOT(16, "returning -EAGAIN as instructed\n");631631+ return -EAGAIN;632632+ }633633+ rc = wait_event_interruptible(peasycap->wq_audio, \634634+ (peasycap->audio_idle || peasycap->audio_eof || \635635+ ((fragment != (peasycap->audio_fill / \636636+ audio_pages_per_fragment)) && \637637+ (0 < (PAGE_SIZE - (pdata_buffer->pto - pdata_buffer->pgo))))));638638+ if (0 != rc) {639639+ SAY("aborted by signal\n");640640+ return -ERESTARTSYS;641641+ }642642+ if (peasycap->audio_eof) {643643+ JOT(8, "returning 0 because %i=audio_eof\n", \644644+ peasycap->audio_eof);645645+ kill_audio_urbs(peasycap);646646+ msleep(500);647647+ return 0;648648+ }649649+ if (peasycap->audio_idle) {650650+ JOT(16, "returning 0 because %i=audio_idle\n", \651651+ peasycap->audio_idle);652652+ return 0;653653+ }654654+ if (!peasycap->audio_isoc_streaming) {655655+ JOT(16, "returning 0 because audio urbs not streaming\n");656656+ return 0;657657+ }658658+}659659+JOT(12, "after wait, %i=frag read %i=frag fill\n", \660660+ (peasycap->audio_read / audio_pages_per_fragment), \661661+ (peasycap->audio_fill / audio_pages_per_fragment));662662+szret = (size_t)0;663663+while (fragment == (peasycap->audio_read / audio_pages_per_fragment)) {664664+ if (NULL == pdata_buffer->pgo) {665665+ SAY("ERROR: pdata_buffer->pgo is NULL\n");666666+ return -EFAULT;667667+ }668668+ if (NULL == pdata_buffer->pto) {669669+ SAY("ERROR: pdata_buffer->pto is NULL\n");670670+ return -EFAULT;671671+ }672672+ kount1 = PAGE_SIZE - (pdata_buffer->pto - pdata_buffer->pgo);673673+ if (0 > kount1) {674674+ SAY("easysnd_read: MISTAKE: kount1 is negative\n");675675+ return -ERESTARTSYS;676676+ }677677+ if (!kount1) {678678+ (peasycap->audio_read)++;679679+ if (audio_buffer_page_many <= peasycap->audio_read)680680+ peasycap->audio_read = 0;681681+ JOT(12, "bumped peasycap->audio_read to %i\n", \682682+ peasycap->audio_read);683683+684684+ if (fragment != (peasycap->audio_read / \685685+ audio_pages_per_fragment))686686+ break;687687+688688+ if ((0 > peasycap->audio_read) || \689689+ (audio_buffer_page_many <= peasycap->audio_read)) {690690+ SAY("ERROR: peasycap->audio_read out of range\n");691691+ return -EFAULT;692692+ }693693+ pdata_buffer = &peasycap->audio_buffer[peasycap->audio_read];694694+ if ((struct data_buffer *)NULL == pdata_buffer) {695695+ SAY("ERROR: pdata_buffer is NULL\n");696696+ return -EFAULT;697697+ }698698+ if (NULL == pdata_buffer->pgo) {699699+ SAY("ERROR: pdata_buffer->pgo is NULL\n");700700+ return -EFAULT;701701+ }702702+ if (NULL == pdata_buffer->pto) {703703+ SAY("ERROR: pdata_buffer->pto is NULL\n");704704+ return -EFAULT;705705+ }706706+ kount1 = PAGE_SIZE - (pdata_buffer->pto - pdata_buffer->pgo);707707+ }708708+ JOT(12, "ready to send %li bytes\n", (long int) kount1);709709+ JOT(12, "still to send %li bytes\n", (long int) kount);710710+ more = kount1;711711+ if (more > kount)712712+ more = kount;713713+ JOT(12, "agreed to send %li bytes from page %i\n", \714714+ more, peasycap->audio_read);715715+ if (!more)716716+ break;717717+718718+/*---------------------------------------------------------------------------*/719719+/*720720+ * ACCUMULATE DYNAMIC-RANGE INFORMATION721721+ */722722+/*---------------------------------------------------------------------------*/723723+ p0 = (unsigned char *)pdata_buffer->pgo; l0 = 0; lm = more/2;724724+ while (l0 < lm) {725725+ SUMMER(p0, &peasycap->audio_sample, &peasycap->audio_niveau, \726726+ &peasycap->audio_square); l0++; p0 += 2;727727+ }728728+/*---------------------------------------------------------------------------*/729729+ rc = copy_to_user(puserspacebuffer, pdata_buffer->pto, more);730730+ if (0 != rc) {731731+ SAY("ERROR: copy_to_user() returned %li\n", rc);732732+ return -EFAULT;733733+ }734734+ *poff += (loff_t)more;735735+ szret += (size_t)more;736736+ pdata_buffer->pto += more;737737+ puserspacebuffer += more;738738+ kount -= (size_t)more;739739+}740740+JOT(12, "after read, %i=frag read %i=frag fill\n", \741741+ (peasycap->audio_read / audio_pages_per_fragment), \742742+ (peasycap->audio_fill / audio_pages_per_fragment));743743+if (kount < 0) {744744+ SAY("MISTAKE: %li=kount %li=szret\n", \745745+ (long int)kount, (long int)szret);746746+}747747+/*---------------------------------------------------------------------------*/748748+/*749749+ * CALCULATE DYNAMIC RANGE FOR (VAPOURWARE) AUTOMATIC VOLUME CONTROL750750+ */751751+/*---------------------------------------------------------------------------*/752752+if (peasycap->audio_sample) {753753+ below = peasycap->audio_sample;754754+ above = peasycap->audio_square;755755+ sdr = signed_div(above, below);756756+ above = sdr.quotient;757757+ mean = peasycap->audio_niveau;758758+ sdr = signed_div(mean, peasycap->audio_sample);759759+760760+ JOT(12, "%8lli=mean %8lli=meansquare after %lli samples, =>\n", \761761+ sdr.quotient, above, peasycap->audio_sample);762762+763763+ sdr = signed_div(above, 32768);764764+ JOT(8, "audio dynamic range is roughly %lli\n", sdr.quotient);765765+}766766+/*---------------------------------------------------------------------------*/767767+/*768768+ * UPDATE THE AUDIO CLOCK769769+ */770770+/*---------------------------------------------------------------------------*/771771+do_gettimeofday(&timeval);772772+if (!peasycap->timeval1.tv_sec) {773773+ audio_bytes = 0;774774+ timeval1 = timeval;775775+776776+ if (mutex_lock_interruptible(&(peasycap->mutex_timeval1)))777777+ return -ERESTARTSYS;778778+ peasycap->timeval1 = timeval1;779779+ mutex_unlock(&(peasycap->mutex_timeval1));780780+ sdr.quotient = 192000;781781+} else {782782+ audio_bytes += (long long int) szret;783783+ below = ((long long int)(1000000)) * \784784+ ((long long int)(timeval.tv_sec - timeval1.tv_sec)) + \785785+ (long long int)(timeval.tv_usec - timeval1.tv_usec);786786+ above = 1000000 * ((long long int) audio_bytes);787787+788788+ if (below)789789+ sdr = signed_div(above, below);790790+ else791791+ sdr.quotient = 192000;792792+}793793+JOT(8, "audio streaming at %lli bytes/second\n", sdr.quotient);794794+if (mutex_lock_interruptible(&(peasycap->mutex_timeval1)))795795+ return -ERESTARTSYS;796796+peasycap->dnbydt = sdr.quotient;797797+mutex_unlock(&(peasycap->mutex_timeval1));798798+799799+JOT(8, "returning %li\n", (long int)szret);800800+return szret;801801+}802802+/*****************************************************************************/803803+/*---------------------------------------------------------------------------*/804804+/*805805+ * SUBMIT ALL AUDIO URBS.806806+ */807807+/*---------------------------------------------------------------------------*/808808+int809809+submit_audio_urbs(struct easycap *peasycap)810810+{811811+struct data_urb *pdata_urb;812812+struct urb *purb;813813+struct list_head *plist_head;814814+int j, isbad, m, rc;815815+int isbuf;816816+817817+if ((struct list_head *)NULL == peasycap->purb_audio_head) {818818+ SAY("ERROR: peasycap->urb_audio_head uninitialized\n");819819+ return -EFAULT;820820+}821821+if ((struct usb_device *)NULL == peasycap->pusb_device) {822822+ SAY("ERROR: peasycap->pusb_device is NULL\n");823823+ return -EFAULT;824824+}825825+if (!peasycap->audio_isoc_streaming) {826826+ JOT(4, "initial submission of all audio urbs\n");827827+ rc = usb_set_interface(peasycap->pusb_device,828828+ peasycap->audio_interface, \829829+ peasycap->audio_altsetting_on);830830+ JOT(8, "usb_set_interface(.,%i,%i) returned %i\n", \831831+ peasycap->audio_interface, \832832+ peasycap->audio_altsetting_on, rc);833833+834834+ isbad = 0; m = 0;835835+ list_for_each(plist_head, (peasycap->purb_audio_head)) {836836+ pdata_urb = list_entry(plist_head, struct data_urb, list_head);837837+ if (NULL != pdata_urb) {838838+ purb = pdata_urb->purb;839839+ if (NULL != purb) {840840+ isbuf = pdata_urb->isbuf;841841+842842+ purb->interval = 1;843843+ purb->dev = peasycap->pusb_device;844844+ purb->pipe = \845845+ usb_rcvisocpipe(peasycap->pusb_device,\846846+ peasycap->audio_endpointnumber);847847+ purb->transfer_flags = URB_ISO_ASAP;848848+ purb->transfer_buffer = \849849+ peasycap->audio_isoc_buffer[isbuf].pgo;850850+ purb->transfer_buffer_length = \851851+ peasycap->audio_isoc_buffer_size;852852+ purb->complete = easysnd_complete;853853+ purb->context = peasycap;854854+ purb->start_frame = 0;855855+ purb->number_of_packets = \856856+ peasycap->audio_isoc_framesperdesc;857857+ for (j = 0; j < peasycap->\858858+ audio_isoc_framesperdesc; \859859+ j++) {860860+ purb->iso_frame_desc[j].offset = j * \861861+ peasycap->\862862+ audio_isoc_maxframesize;863863+ purb->iso_frame_desc[j].length = \864864+ peasycap->\865865+ audio_isoc_maxframesize;866866+ }867867+868868+ rc = usb_submit_urb(purb, GFP_KERNEL);869869+ if (0 != rc) {870870+ isbad++;871871+ SAY("ERROR: usb_submit_urb() failed" \872872+ " for urb with rc:\n");873873+ switch (rc) {874874+ case -ENOMEM: {875875+ SAY("ENOMEM\n"); break;876876+ }877877+ case -ENODEV: {878878+ SAY("ENODEV\n"); break;879879+ }880880+ case -ENXIO: {881881+ SAY("ENXIO\n"); break;882882+ }883883+ case -EINVAL: {884884+ SAY("EINVAL\n"); break;885885+ }886886+ case -EAGAIN: {887887+ SAY("EAGAIN\n"); break;888888+ }889889+ case -EFBIG: {890890+ SAY("EFBIG\n"); break;891891+ }892892+ case -EPIPE: {893893+ SAY("EPIPE\n"); break;894894+ }895895+ case -EMSGSIZE: {896896+ SAY("EMSGSIZE\n"); break;897897+ }898898+ default: {899899+ SAY("unknown error code %i\n",\900900+ rc); break;901901+ }902902+ }903903+ } else {904904+ m++;905905+ }906906+ } else {907907+ isbad++;908908+ }909909+ } else {910910+ isbad++;911911+ }912912+ }913913+ if (isbad) {914914+ JOT(4, "attempting cleanup instead of submitting\n");915915+ list_for_each(plist_head, (peasycap->purb_audio_head)) {916916+ pdata_urb = list_entry(plist_head, struct data_urb, \917917+ list_head);918918+ if (NULL != pdata_urb) {919919+ purb = pdata_urb->purb;920920+ if (NULL != purb)921921+ usb_kill_urb(purb);922922+ }923923+ }924924+ peasycap->audio_isoc_streaming = 0;925925+ } else {926926+ peasycap->audio_isoc_streaming = 1;927927+ JOT(4, "submitted %i audio urbs\n", m);928928+ }929929+} else930930+ JOT(4, "already streaming audio urbs\n");931931+932932+return 0;933933+}934934+/*****************************************************************************/935935+/*---------------------------------------------------------------------------*/936936+/*937937+ * KILL ALL AUDIO URBS.938938+ */939939+/*---------------------------------------------------------------------------*/940940+int941941+kill_audio_urbs(struct easycap *peasycap)942942+{943943+int m;944944+struct list_head *plist_head;945945+struct data_urb *pdata_urb;946946+947947+if (peasycap->audio_isoc_streaming) {948948+ if ((struct list_head *)NULL != peasycap->purb_audio_head) {949949+ peasycap->audio_isoc_streaming = 0;950950+ JOT(4, "killing audio urbs\n");951951+ m = 0;952952+ list_for_each(plist_head, (peasycap->purb_audio_head)) {953953+ pdata_urb = list_entry(plist_head, struct data_urb,954954+ list_head);955955+ if ((struct data_urb *)NULL != pdata_urb) {956956+ if ((struct urb *)NULL != pdata_urb->purb) {957957+ usb_kill_urb(pdata_urb->purb);958958+ m++;959959+ }960960+ }961961+ }962962+ JOT(4, "%i audio urbs killed\n", m);963963+ } else {964964+ SAY("ERROR: peasycap->purb_audio_head is NULL\n");965965+ return -EFAULT;966966+ }967967+} else {968968+ JOT(8, "%i=audio_isoc_streaming, no audio urbs killed\n", \969969+ peasycap->audio_isoc_streaming);970970+}971971+return 0;972972+}973973+/*****************************************************************************/
+30
drivers/staging/easycap/easycap_sound.h
···11+/*****************************************************************************22+* *33+* easycap_sound.h *44+* *55+*****************************************************************************/66+/*77+ *88+ * Copyright (C) 2010 R.M. Thomas <rmthomas@sciolus.org>99+ *1010+ *1111+ * This is free software; you can redistribute it and/or modify1212+ * it under the terms of the GNU General Public License as published by1313+ * the Free Software Foundation; either version 2 of the License, or1414+ * (at your option) any later version.1515+ *1616+ * The software is distributed in the hope that it will be useful,1717+ * but WITHOUT ANY WARRANTY; without even the implied warranty of1818+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the1919+ * GNU General Public License for more details.2020+ *2121+ * You should have received a copy of the GNU General Public License2222+ * along with this software; if not, write to the Free Software2323+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA2424+ *2525+*/2626+/*****************************************************************************/2727+extern struct easycap *peasycap;2828+extern struct usb_driver easycap_usb_driver;2929+extern unsigned int audio_buffer_page_many;3030+extern unsigned int audio_pages_per_fragment;
+27
drivers/staging/easycap/easycap_standard.h
···11+/*****************************************************************************22+* *33+* easycap_standard.h *44+* *55+*****************************************************************************/66+/*77+ *88+ * Copyright (C) 2010 R.M. Thomas <rmthomas@sciolus.org>99+ *1010+ *1111+ * This is free software; you can redistribute it and/or modify1212+ * it under the terms of the GNU General Public License as published by1313+ * the Free Software Foundation; either version 2 of the License, or1414+ * (at your option) any later version.1515+ *1616+ * The software is distributed in the hope that it will be useful,1717+ * but WITHOUT ANY WARRANTY; without even the implied warranty of1818+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the1919+ * GNU General Public License for more details.2020+ *2121+ * You should have received a copy of the GNU General Public License2222+ * along with this software; if not, write to the Free Software2323+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA2424+ *2525+*/2626+/*****************************************************************************/2727+extern struct easycap_standard easycap_standard[];