| /****************************************************************************** |
| * * |
| * easycap_ioctl.c * |
| * * |
| ******************************************************************************/ |
| /* |
| * |
| * Copyright (C) 2010 R.M. Thomas <rmthomas@sciolus.org> |
| * |
| * |
| * This is free software; you can redistribute it and/or modify |
| * it under the terms of the GNU General Public License as published by |
| * the Free Software Foundation; either version 2 of the License, or |
| * (at your option) any later version. |
| * |
| * The software is distributed in the hope that it will be useful, |
| * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| * GNU General Public License for more details. |
| * |
| * You should have received a copy of the GNU General Public License |
| * along with this software; if not, write to the Free Software |
| * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
| * |
| */ |
| /*****************************************************************************/ |
| |
| #include <linux/smp_lock.h> |
| #include "easycap.h" |
| #include "easycap_debug.h" |
| #include "easycap_standard.h" |
| #include "easycap_ioctl.h" |
| |
| /*--------------------------------------------------------------------------*/ |
| /* |
| * UNLESS THERE IS A PREMATURE ERROR RETURN THIS ROUTINE UPDATES THE |
| * FOLLOWING: |
| * peasycap->standard_offset |
| * peasycap->fps |
| * peasycap->usec |
| * peasycap->tolerate |
| */ |
| /*---------------------------------------------------------------------------*/ |
| int adjust_standard(struct easycap *peasycap, v4l2_std_id std_id) |
| { |
| struct easycap_standard const *peasycap_standard; |
| __u16 reg, set; |
| int ir, rc, need; |
| unsigned int itwas, isnow; |
| |
| if ((struct usb_device *)NULL == peasycap->pusb_device) { |
| SAY("ERROR: peasycap->pusb_device is NULL\n"); |
| return -EFAULT; |
| } |
| peasycap_standard = &easycap_standard[0]; |
| while (0xFFFF != peasycap_standard->mask) { |
| if (std_id & peasycap_standard->v4l2_standard.id) |
| break; |
| peasycap_standard++; |
| } |
| if (0xFFFF == peasycap_standard->mask) { |
| SAY("ERROR: 0x%08X=std_id: standard not found\n", \ |
| (unsigned int)std_id); |
| return -EINVAL; |
| } |
| SAY("user requests standard: %s\n", \ |
| &(peasycap_standard->v4l2_standard.name[0])); |
| if (peasycap->standard_offset == \ |
| (int)(peasycap_standard - &easycap_standard[0])) { |
| SAY("requested standard already in effect\n"); |
| return 0; |
| } |
| peasycap->standard_offset = (int)(peasycap_standard - &easycap_standard[0]); |
| peasycap->fps = peasycap_standard->v4l2_standard.frameperiod.denominator / \ |
| peasycap_standard->v4l2_standard.frameperiod.numerator; |
| if (!peasycap->fps) { |
| SAY("MISTAKE: frames-per-second is zero\n"); |
| return -EFAULT; |
| } |
| JOT(8, "%i frames-per-second\n", peasycap->fps); |
| peasycap->usec = 1000000 / (2 * peasycap->fps); |
| peasycap->tolerate = 1000 * (25 / peasycap->fps); |
| |
| kill_video_urbs(peasycap); |
| |
| /*--------------------------------------------------------------------------*/ |
| /* |
| * SAA7113H DATASHEET PAGE 44, TABLE 42 |
| */ |
| /*--------------------------------------------------------------------------*/ |
| need = 0; itwas = 0; reg = 0x00; set = 0x00; |
| switch (peasycap_standard->mask & 0x000F) { |
| case NTSC_M_JP: { |
| reg = 0x0A; set = 0x95; |
| ir = read_saa(peasycap->pusb_device, reg); |
| if (0 > ir) |
| SAY("ERROR: cannot read SAA register 0x%02X\n", reg); |
| else |
| itwas = (unsigned int)ir; |
| |
| |
| set2to78(peasycap->pusb_device); |
| |
| |
| rc = write_saa(peasycap->pusb_device, reg, set); |
| if (0 != rc) |
| SAY("ERROR: failed to set SAA register " \ |
| "0x%02X to 0x%02X for JP standard\n", reg, set); |
| else { |
| isnow = (unsigned int)read_saa(peasycap->pusb_device, reg); |
| if (0 > ir) |
| JOT(8, "SAA register 0x%02X changed " \ |
| "to 0x%02X\n", reg, isnow); |
| else |
| JOT(8, "SAA register 0x%02X changed " \ |
| "from 0x%02X to 0x%02X\n", reg, itwas, isnow); |
| |
| set2to78(peasycap->pusb_device); |
| |
| } |
| |
| reg = 0x0B; set = 0x48; |
| ir = read_saa(peasycap->pusb_device, reg); |
| if (0 > ir) |
| SAY("ERROR: cannot read SAA register 0x%02X\n", reg); |
| else |
| itwas = (unsigned int)ir; |
| |
| set2to78(peasycap->pusb_device); |
| |
| rc = write_saa(peasycap->pusb_device, reg, set); |
| if (0 != rc) |
| SAY("ERROR: failed to set SAA register 0x%02X to 0x%02X " \ |
| "for JP standard\n", reg, set); |
| else { |
| isnow = (unsigned int)read_saa(peasycap->pusb_device, reg); |
| if (0 > ir) |
| JOT(8, "SAA register 0x%02X changed " \ |
| "to 0x%02X\n", reg, isnow); |
| else |
| JOT(8, "SAA register 0x%02X changed " \ |
| "from 0x%02X to 0x%02X\n", reg, itwas, isnow); |
| |
| set2to78(peasycap->pusb_device); |
| |
| } |
| /*--------------------------------------------------------------------------*/ |
| /* |
| * NOTE: NO break HERE: RUN ON TO NEXT CASE |
| */ |
| /*--------------------------------------------------------------------------*/ |
| } |
| case NTSC_M: |
| case PAL_BGHIN: { |
| reg = 0x0E; set = 0x01; need = 1; break; |
| } |
| case NTSC_N_443: |
| case PAL_60: { |
| reg = 0x0E; set = 0x11; need = 1; break; |
| } |
| case NTSC_443: |
| case PAL_Nc: { |
| reg = 0x0E; set = 0x21; need = 1; break; |
| } |
| case NTSC_N: |
| case PAL_M: { |
| reg = 0x0E; set = 0x31; need = 1; break; |
| } |
| case SECAM: { |
| reg = 0x0E; set = 0x51; need = 1; break; |
| } |
| default: |
| break; |
| } |
| /*--------------------------------------------------------------------------*/ |
| if (need) { |
| ir = read_saa(peasycap->pusb_device, reg); |
| if (0 > ir) |
| SAY("ERROR: failed to read SAA register 0x%02X\n", reg); |
| else |
| itwas = (unsigned int)ir; |
| |
| set2to78(peasycap->pusb_device); |
| |
| rc = write_saa(peasycap->pusb_device, reg, set); |
| if (0 != write_saa(peasycap->pusb_device, reg, set)) { |
| SAY("ERROR: failed to set SAA register " \ |
| "0x%02X to 0x%02X for table 42\n", reg, set); |
| } else { |
| isnow = (unsigned int)read_saa(peasycap->pusb_device, reg); |
| if (0 > ir) |
| JOT(8, "SAA register 0x%02X changed " \ |
| "to 0x%02X\n", reg, isnow); |
| else |
| JOT(8, "SAA register 0x%02X changed " \ |
| "from 0x%02X to 0x%02X\n", reg, itwas, isnow); |
| } |
| } |
| /*--------------------------------------------------------------------------*/ |
| /* |
| * SAA7113H DATASHEET PAGE 41 |
| */ |
| /*--------------------------------------------------------------------------*/ |
| reg = 0x08; |
| ir = read_saa(peasycap->pusb_device, reg); |
| if (0 > ir) |
| SAY("ERROR: failed to read SAA register 0x%02X " \ |
| "so cannot reset\n", reg); |
| else { |
| itwas = (unsigned int)ir; |
| if (peasycap_standard->mask & 0x0001) |
| set = itwas | 0x40 ; |
| else |
| set = itwas & ~0x40 ; |
| |
| set2to78(peasycap->pusb_device); |
| |
| rc = write_saa(peasycap->pusb_device, reg, set); |
| if (0 != rc) |
| SAY("ERROR: failed to set SAA register 0x%02X to 0x%02X\n", reg, set); |
| else { |
| isnow = (unsigned int)read_saa(peasycap->pusb_device, reg); |
| if (0 > ir) |
| JOT(8, "SAA register 0x%02X changed to 0x%02X\n", reg, isnow); |
| else |
| JOT(8, "SAA register 0x%02X changed " \ |
| "from 0x%02X to 0x%02X\n", reg, itwas, isnow); |
| } |
| } |
| /*--------------------------------------------------------------------------*/ |
| /* |
| * SAA7113H DATASHEET PAGE 51, TABLE 57 |
| */ |
| /*---------------------------------------------------------------------------*/ |
| reg = 0x40; |
| ir = read_saa(peasycap->pusb_device, reg); |
| if (0 > ir) |
| SAY("ERROR: failed to read SAA register 0x%02X " \ |
| "so cannot reset\n", reg); |
| else { |
| itwas = (unsigned int)ir; |
| if (peasycap_standard->mask & 0x0001) |
| set = itwas | 0x80 ; |
| else |
| set = itwas & ~0x80 ; |
| |
| set2to78(peasycap->pusb_device); |
| |
| rc = write_saa(peasycap->pusb_device, reg, set); |
| if (0 != rc) |
| SAY("ERROR: failed to set SAA register 0x%02X to 0x%02X\n", reg, set); |
| else { |
| isnow = (unsigned int)read_saa(peasycap->pusb_device, reg); |
| if (0 > ir) |
| JOT(8, "SAA register 0x%02X changed to 0x%02X\n", reg, isnow); |
| else |
| JOT(8, "SAA register 0x%02X changed " \ |
| "from 0x%02X to 0x%02X\n", reg, itwas, isnow); |
| } |
| } |
| /*--------------------------------------------------------------------------*/ |
| /* |
| * SAA7113H DATASHEET PAGE 53, TABLE 66 |
| */ |
| /*--------------------------------------------------------------------------*/ |
| reg = 0x5A; |
| ir = read_saa(peasycap->pusb_device, reg); |
| if (0 > ir) |
| SAY("ERROR: failed to read SAA register 0x%02X but continuing\n", reg); |
| itwas = (unsigned int)ir; |
| if (peasycap_standard->mask & 0x0001) |
| set = 0x0A ; |
| else |
| set = 0x07 ; |
| |
| set2to78(peasycap->pusb_device); |
| |
| if (0 != write_saa(peasycap->pusb_device, reg, set)) |
| SAY("ERROR: failed to set SAA register 0x%02X to 0x%02X\n", \ |
| reg, set); |
| else { |
| isnow = (unsigned int)read_saa(peasycap->pusb_device, reg); |
| if (0 > ir) |
| JOT(8, "SAA register 0x%02X changed " |
| "to 0x%02X\n", reg, isnow); |
| else |
| JOT(8, "SAA register 0x%02X changed " |
| "from 0x%02X to 0x%02X\n", reg, itwas, isnow); |
| } |
| if (0 != check_saa(peasycap->pusb_device)) |
| SAY("ERROR: check_saa() failed\n"); |
| return 0; |
| } |
| /*****************************************************************************/ |
| /*--------------------------------------------------------------------------*/ |
| /* |
| * THE ALGORITHM FOR RESPONDING TO THE VIDIO_S_FMT IOCTL DEPENDS ON THE |
| * CURRENT VALUE OF peasycap->standard_offset. |
| * PROVIDED THE ARGUMENT try IS false AND THERE IS NO PREMATURE ERROR RETURN |
| * THIS ROUTINE UPDATES THE FOLLOWING: |
| * peasycap->format_offset |
| * peasycap->pixelformat |
| * peasycap->field |
| * peasycap->height |
| * peasycap->width |
| * peasycap->bytesperpixel |
| * peasycap->byteswaporder |
| * peasycap->decimatepixel |
| * peasycap->frame_buffer_used |
| * peasycap->videofieldamount |
| * peasycap->offerfields |
| * |
| * IF SUCCESSFUL THE FUNCTION RETURNS THE OFFSET IN easycap_format[] |
| * IDENTIFYING THE FORMAT WHICH IS TO RETURNED TO THE USER. |
| * ERRORS RETURN A NEGATIVE NUMBER. |
| */ |
| /*--------------------------------------------------------------------------*/ |
| int adjust_format(struct easycap *peasycap, \ |
| __u32 width, __u32 height, __u32 pixelformat, int field, bool try) |
| { |
| struct easycap_format *peasycap_format, *peasycap_best_format; |
| __u16 mask; |
| struct usb_device *p; |
| int miss, multiplier, best; |
| char bf[5], *pc; |
| __u32 uc; |
| |
| if ((struct easycap *)NULL == peasycap) { |
| SAY("ERROR: peasycap is NULL\n"); |
| return -EFAULT; |
| } |
| p = peasycap->pusb_device; |
| if ((struct usb_device *)NULL == p) { |
| SAY("ERROR: peaycap->pusb_device is NULL\n"); |
| return -EFAULT; |
| } |
| pc = &bf[0]; |
| uc = pixelformat; memcpy((void *)pc, (void *)(&uc), 4); bf[4] = 0; |
| mask = easycap_standard[peasycap->standard_offset].mask; |
| SAY("sought: %ix%i,%s(0x%08X),%i=field,0x%02X=std mask\n", \ |
| width, height, pc, pixelformat, field, mask); |
| if (V4L2_FIELD_ANY == field) { |
| field = V4L2_FIELD_INTERLACED; |
| SAY("prefer: V4L2_FIELD_INTERLACED=field, was V4L2_FIELD_ANY\n"); |
| } |
| peasycap_best_format = (struct easycap_format *)NULL; |
| peasycap_format = &easycap_format[0]; |
| while (0 != peasycap_format->v4l2_format.fmt.pix.width) { |
| JOT(16, ".> %i %i 0x%08X %ix%i\n", \ |
| peasycap_format->mask & 0x01, |
| peasycap_format->v4l2_format.fmt.pix.field, |
| peasycap_format->v4l2_format.fmt.pix.pixelformat, |
| peasycap_format->v4l2_format.fmt.pix.width, |
| peasycap_format->v4l2_format.fmt.pix.height); |
| |
| if (((peasycap_format->mask & 0x0F) == (mask & 0x0F)) && \ |
| (peasycap_format->v4l2_format.fmt.pix.field == field) && \ |
| (peasycap_format->v4l2_format.fmt.pix.pixelformat == \ |
| pixelformat) && \ |
| (peasycap_format->v4l2_format.fmt.pix.width == width) && \ |
| (peasycap_format->v4l2_format.fmt.pix.height == height)) { |
| peasycap_best_format = peasycap_format; |
| break; |
| } |
| peasycap_format++; |
| } |
| if (0 == peasycap_format->v4l2_format.fmt.pix.width) { |
| SAY("cannot do: %ix%i with standard mask 0x%02X\n", \ |
| width, height, mask); |
| peasycap_format = &easycap_format[0]; best = -1; |
| while (0 != peasycap_format->v4l2_format.fmt.pix.width) { |
| if (((peasycap_format->mask & 0x0F) == (mask & 0x0F)) && \ |
| (peasycap_format->v4l2_format.fmt.pix\ |
| .field == field) && \ |
| (peasycap_format->v4l2_format.fmt.pix\ |
| .pixelformat == pixelformat)) { |
| miss = abs(peasycap_format->\ |
| v4l2_format.fmt.pix.width - width); |
| if ((best > miss) || (best < 0)) { |
| best = miss; |
| peasycap_best_format = peasycap_format; |
| if (!miss) |
| break; |
| } |
| } |
| peasycap_format++; |
| } |
| if (-1 == best) { |
| SAY("cannot do %ix... with standard mask 0x%02X\n", \ |
| width, mask); |
| SAY("cannot do ...x%i with standard mask 0x%02X\n", \ |
| height, mask); |
| SAY(" %ix%i unmatched\n", width, height); |
| return peasycap->format_offset; |
| } |
| } |
| if ((struct easycap_format *)NULL == peasycap_best_format) { |
| SAY("MISTAKE: peasycap_best_format is NULL"); |
| return -EINVAL; |
| } |
| peasycap_format = peasycap_best_format; |
| |
| /*...........................................................................*/ |
| if (true == try) |
| return (int)(peasycap_best_format - &easycap_format[0]); |
| /*...........................................................................*/ |
| |
| if (false != try) { |
| SAY("MISTAKE: true==try where is should be false\n"); |
| return -EINVAL; |
| } |
| SAY("actioning: %ix%i %s\n", \ |
| peasycap_format->v4l2_format.fmt.pix.width, \ |
| peasycap_format->v4l2_format.fmt.pix.height, |
| &peasycap_format->name[0]); |
| peasycap->height = peasycap_format->v4l2_format.fmt.pix.height; |
| peasycap->width = peasycap_format->v4l2_format.fmt.pix.width; |
| peasycap->pixelformat = peasycap_format->v4l2_format.fmt.pix.pixelformat; |
| peasycap->field = peasycap_format->v4l2_format.fmt.pix.field; |
| peasycap->format_offset = (int)(peasycap_format - &easycap_format[0]); |
| peasycap->bytesperpixel = (0x00F0 & peasycap_format->mask) >> 4 ; |
| if (0x0100 & peasycap_format->mask) |
| peasycap->byteswaporder = true; |
| else |
| peasycap->byteswaporder = false; |
| if (0x0800 & peasycap_format->mask) |
| peasycap->decimatepixel = true; |
| else |
| peasycap->decimatepixel = false; |
| if (0x1000 & peasycap_format->mask) |
| peasycap->offerfields = true; |
| else |
| peasycap->offerfields = false; |
| if (true == peasycap->decimatepixel) |
| multiplier = 2; |
| else |
| multiplier = 1; |
| peasycap->videofieldamount = multiplier * peasycap->width * \ |
| multiplier * peasycap->height; |
| peasycap->frame_buffer_used = peasycap->bytesperpixel * \ |
| peasycap->width * peasycap->height; |
| |
| if (true == peasycap->offerfields) { |
| SAY("WARNING: %i=peasycap->field is untested: " \ |
| "please report problems\n", peasycap->field); |
| |
| |
| /* |
| * FIXME ---- THIS IS UNTESTED, MAY BE (AND PROBABLY IS) INCORRECT: |
| * |
| * peasycap->frame_buffer_used = peasycap->frame_buffer_used / 2; |
| * |
| * SO DO NOT RISK IT YET. |
| * |
| */ |
| |
| |
| |
| } |
| |
| kill_video_urbs(peasycap); |
| |
| /*---------------------------------------------------------------------------*/ |
| /* |
| * PAL |
| */ |
| /*---------------------------------------------------------------------------*/ |
| if (0 == (0x01 & peasycap_format->mask)) { |
| if (((720 == peasycap_format->v4l2_format.fmt.pix.width) && \ |
| (576 == \ |
| peasycap_format->v4l2_format.fmt.pix.height)) || \ |
| ((360 == \ |
| peasycap_format->v4l2_format.fmt.pix.width) && \ |
| (288 == \ |
| peasycap_format->v4l2_format.fmt.pix.height))) { |
| if (0 != set_resolution(p, 0x0000, 0x0001, 0x05A0, 0x0121)) { |
| SAY("ERROR: set_resolution() failed\n"); |
| return -EINVAL; |
| } |
| } else if ((704 == peasycap_format->v4l2_format.fmt.pix.width) && \ |
| (576 == peasycap_format->v4l2_format.fmt.pix.height)) { |
| if (0 != set_resolution(p, 0x0004, 0x0001, 0x0584, 0x0121)) { |
| SAY("ERROR: set_resolution() failed\n"); |
| return -EINVAL; |
| } |
| } else if (((640 == peasycap_format->v4l2_format.fmt.pix.width) && \ |
| (480 == \ |
| peasycap_format->v4l2_format.fmt.pix.height)) || \ |
| ((320 == \ |
| peasycap_format->v4l2_format.fmt.pix.width) && \ |
| (240 == \ |
| peasycap_format->v4l2_format.fmt.pix.height))) { |
| if (0 != set_resolution(p, 0x0014, 0x0020, 0x0514, 0x0110)) { |
| SAY("ERROR: set_resolution() failed\n"); |
| return -EINVAL; |
| } |
| } else { |
| SAY("MISTAKE: bad format, cannot set resolution\n"); |
| return -EINVAL; |
| } |
| /*---------------------------------------------------------------------------*/ |
| /* |
| * NTSC |
| */ |
| /*---------------------------------------------------------------------------*/ |
| } else { |
| if (((720 == peasycap_format->v4l2_format.fmt.pix.width) && \ |
| (480 == \ |
| peasycap_format->v4l2_format.fmt.pix.height)) || \ |
| ((360 == \ |
| peasycap_format->v4l2_format.fmt.pix.width) && \ |
| (240 == \ |
| peasycap_format->v4l2_format.fmt.pix.height))) { |
| if (0 != set_resolution(p, 0x0000, 0x0003, 0x05A0, 0x00F3)) { |
| SAY("ERROR: set_resolution() failed\n"); |
| return -EINVAL; |
| } |
| } else if (((640 == peasycap_format->v4l2_format.fmt.pix.width) && \ |
| (480 == \ |
| peasycap_format->v4l2_format.fmt.pix.height)) || \ |
| ((320 == \ |
| peasycap_format->v4l2_format.fmt.pix.width) && \ |
| (240 == \ |
| peasycap_format->v4l2_format.fmt.pix.height))) { |
| if (0 != set_resolution(p, 0x0014, 0x0003, 0x0514, 0x00F3)) { |
| SAY("ERROR: set_resolution() failed\n"); |
| return -EINVAL; |
| } |
| } else { |
| SAY("MISTAKE: bad format, cannot set resolution\n"); |
| return -EINVAL; |
| } |
| } |
| /*---------------------------------------------------------------------------*/ |
| |
| check_stk(peasycap->pusb_device); |
| |
| return (int)(peasycap_best_format - &easycap_format[0]); |
| } |
| /*****************************************************************************/ |
| int adjust_brightness(struct easycap *peasycap, int value) |
| { |
| unsigned int mood; |
| int i1; |
| |
| if ((struct usb_device *)NULL == peasycap->pusb_device) { |
| SAY("ERROR: peasycap->pusb_device is NULL\n"); |
| return -EFAULT; |
| } |
| i1 = 0; |
| while (0xFFFFFFFF != easycap_control[i1].id) { |
| if (V4L2_CID_BRIGHTNESS == easycap_control[i1].id) { |
| if ((easycap_control[i1].minimum > value) || \ |
| (easycap_control[i1].maximum < value)) |
| value = easycap_control[i1].default_value; |
| peasycap->brightness = value; |
| mood = 0x00FF & (unsigned int)peasycap->brightness; |
| |
| set2to78(peasycap->pusb_device); |
| |
| if (!write_saa(peasycap->pusb_device, 0x0A, mood)) { |
| SAY("adjusting brightness to 0x%02X\n", mood); |
| return 0; |
| } else { |
| SAY("WARNING: failed to adjust brightness " \ |
| "to 0x%02X\n", mood); |
| return -ENOENT; |
| } |
| |
| set2to78(peasycap->pusb_device); |
| |
| break; |
| } |
| i1++; |
| } |
| SAY("WARNING: failed to adjust brightness: control not found\n"); |
| return -ENOENT; |
| } |
| /*****************************************************************************/ |
| int adjust_contrast(struct easycap *peasycap, int value) |
| { |
| unsigned int mood; |
| int i1; |
| |
| if ((struct usb_device *)NULL == peasycap->pusb_device) { |
| SAY("ERROR: peasycap->pusb_device is NULL\n"); |
| return -EFAULT; |
| } |
| i1 = 0; |
| while (0xFFFFFFFF != easycap_control[i1].id) { |
| if (V4L2_CID_CONTRAST == easycap_control[i1].id) { |
| if ((easycap_control[i1].minimum > value) || \ |
| (easycap_control[i1].maximum < value)) |
| value = easycap_control[i1].default_value; |
| peasycap->contrast = value; |
| mood = 0x00FF & (unsigned int) (peasycap->contrast - 128); |
| |
| set2to78(peasycap->pusb_device); |
| |
| if (!write_saa(peasycap->pusb_device, 0x0B, mood)) { |
| SAY("adjusting contrast to 0x%02X\n", mood); |
| return 0; |
| } else { |
| SAY("WARNING: failed to adjust contrast to " \ |
| "0x%02X\n", mood); |
| return -ENOENT; |
| } |
| |
| set2to78(peasycap->pusb_device); |
| |
| break; |
| } |
| i1++; |
| } |
| SAY("WARNING: failed to adjust contrast: control not found\n"); |
| return -ENOENT; |
| } |
| /*****************************************************************************/ |
| int adjust_saturation(struct easycap *peasycap, int value) |
| { |
| unsigned int mood; |
| int i1; |
| |
| if ((struct usb_device *)NULL == peasycap->pusb_device) { |
| SAY("ERROR: peasycap->pusb_device is NULL\n"); |
| return -EFAULT; |
| } |
| i1 = 0; |
| while (0xFFFFFFFF != easycap_control[i1].id) { |
| if (V4L2_CID_SATURATION == easycap_control[i1].id) { |
| if ((easycap_control[i1].minimum > value) || \ |
| (easycap_control[i1].maximum < value)) |
| value = easycap_control[i1].default_value; |
| peasycap->saturation = value; |
| mood = 0x00FF & (unsigned int) (peasycap->saturation - 128); |
| |
| set2to78(peasycap->pusb_device); |
| |
| if (!write_saa(peasycap->pusb_device, 0x0C, mood)) { |
| SAY("adjusting saturation to 0x%02X\n", mood); |
| return 0; |
| } else { |
| SAY("WARNING: failed to adjust saturation to " \ |
| "0x%02X\n", mood); |
| return -ENOENT; |
| } |
| break; |
| |
| set2to78(peasycap->pusb_device); |
| |
| } |
| i1++; |
| } |
| SAY("WARNING: failed to adjust saturation: control not found\n"); |
| return -ENOENT; |
| } |
| /*****************************************************************************/ |
| int adjust_hue(struct easycap *peasycap, int value) |
| { |
| unsigned int mood; |
| int i1, i2; |
| |
| if ((struct usb_device *)NULL == peasycap->pusb_device) { |
| SAY("ERROR: peasycap->pusb_device is NULL\n"); |
| return -EFAULT; |
| } |
| i1 = 0; |
| while (0xFFFFFFFF != easycap_control[i1].id) { |
| if (V4L2_CID_HUE == easycap_control[i1].id) { |
| if ((easycap_control[i1].minimum > value) || \ |
| (easycap_control[i1].maximum < value)) |
| value = easycap_control[i1].default_value; |
| peasycap->hue = value; |
| i2 = peasycap->hue - 128; |
| mood = 0x00FF & ((int) i2); |
| |
| set2to78(peasycap->pusb_device); |
| |
| if (!write_saa(peasycap->pusb_device, 0x0D, mood)) { |
| SAY("adjusting hue to 0x%02X\n", mood); |
| return 0; |
| } else { |
| SAY("WARNING: failed to adjust hue to 0x%02X\n", mood); |
| return -ENOENT; |
| } |
| |
| set2to78(peasycap->pusb_device); |
| |
| break; |
| } |
| i1++; |
| } |
| SAY("WARNING: failed to adjust hue: control not found\n"); |
| return -ENOENT; |
| } |
| /*****************************************************************************/ |
| int adjust_volume(struct easycap *peasycap, int value) |
| { |
| __s8 mood; |
| int i1; |
| |
| if ((struct usb_device *)NULL == peasycap->pusb_device) { |
| SAY("ERROR: peasycap->pusb_device is NULL\n"); |
| return -EFAULT; |
| } |
| i1 = 0; |
| while (0xFFFFFFFF != easycap_control[i1].id) { |
| if (V4L2_CID_AUDIO_VOLUME == easycap_control[i1].id) { |
| if ((easycap_control[i1].minimum > value) || \ |
| (easycap_control[i1].maximum < value)) |
| value = easycap_control[i1].default_value; |
| peasycap->volume = value; |
| mood = (16 > peasycap->volume) ? 16 : \ |
| ((31 < peasycap->volume) ? 31 : \ |
| (__s8) peasycap->volume); |
| if (!audio_gainset(peasycap->pusb_device, mood)) { |
| SAY("adjusting volume to 0x%01X\n", mood); |
| return 0; |
| } else { |
| SAY("WARNING: failed to adjust volume to " \ |
| "0x%1X\n", mood); |
| return -ENOENT; |
| } |
| break; |
| } |
| i1++; |
| } |
| SAY("WARNING: failed to adjust volume: control not found\n"); |
| return -ENOENT; |
| } |
| /*****************************************************************************/ |
| /*---------------------------------------------------------------------------*/ |
| /* |
| * AN ALTERNATIVE METHOD OF MUTING MIGHT SEEM TO BE: |
| * usb_set_interface(peasycap->pusb_device, \ |
| * peasycap->audio_interface, \ |
| * peasycap->audio_altsetting_off); |
| * HOWEVER, AFTER THIS COMMAND IS ISSUED ALL SUBSEQUENT URBS RECEIVE STATUS |
| * -ESHUTDOWN. THE HANDLER ROUTINE easysnd_complete() DECLINES TO RESUBMIT |
| * THE URB AND THE PIPELINE COLLAPSES IRRETRIEVABLY. BEWARE. |
| */ |
| /*---------------------------------------------------------------------------*/ |
| int adjust_mute(struct easycap *peasycap, int value) |
| { |
| int i1; |
| |
| if ((struct usb_device *)NULL == peasycap->pusb_device) { |
| SAY("ERROR: peasycap->pusb_device is NULL\n"); |
| return -EFAULT; |
| } |
| i1 = 0; |
| while (0xFFFFFFFF != easycap_control[i1].id) { |
| if (V4L2_CID_AUDIO_MUTE == easycap_control[i1].id) { |
| peasycap->mute = value; |
| switch (peasycap->mute) { |
| case 1: { |
| peasycap->audio_idle = 1; |
| peasycap->timeval0.tv_sec = 0; |
| SAY("adjusting mute: %i=peasycap->audio_idle\n", \ |
| peasycap->audio_idle); |
| return 0; |
| } |
| default: { |
| peasycap->audio_idle = 0; |
| SAY("adjusting mute: %i=peasycap->audio_idle\n", \ |
| peasycap->audio_idle); |
| return 0; |
| } |
| } |
| break; |
| } |
| i1++; |
| } |
| SAY("WARNING: failed to adjust mute: control not found\n"); |
| return -ENOENT; |
| } |
| |
| /*--------------------------------------------------------------------------*/ |
| static int easycap_ioctl_bkl(struct inode *inode, struct file *file, |
| unsigned int cmd, unsigned long arg) |
| { |
| static struct easycap *peasycap; |
| static struct usb_device *p; |
| static __u32 isequence; |
| |
| peasycap = file->private_data; |
| if (NULL == peasycap) { |
| SAY("ERROR: peasycap is NULL\n"); |
| return -1; |
| } |
| p = peasycap->pusb_device; |
| if ((struct usb_device *)NULL == p) { |
| SAY("ERROR: peasycap->pusb_device is NULL\n"); |
| return -EFAULT; |
| } |
| /*---------------------------------------------------------------------------*/ |
| /* |
| * MOST OF THE VARIABLES DECLARED static IN THE case{} BLOCKS BELOW ARE SO |
| * DECLARED SIMPLY TO AVOID A COMPILER WARNING OF THE KIND: |
| * easycap_ioctl.c: warning: |
| * the frame size of ... bytes is larger than 1024 bytes |
| */ |
| /*---------------------------------------------------------------------------*/ |
| switch (cmd) { |
| case VIDIOC_QUERYCAP: { |
| static struct v4l2_capability v4l2_capability; |
| static char version[16], *p1, *p2; |
| static int i, rc, k[3]; |
| static long lng; |
| |
| JOT(8, "VIDIOC_QUERYCAP\n"); |
| |
| if (16 <= strlen(EASYCAP_DRIVER_VERSION)) { |
| SAY("ERROR: bad driver version string\n"); return -EINVAL; |
| } |
| strcpy(&version[0], EASYCAP_DRIVER_VERSION); |
| for (i = 0; i < 3; i++) |
| k[i] = 0; |
| p2 = &version[0]; i = 0; |
| while (*p2) { |
| p1 = p2; |
| while (*p2 && ('.' != *p2)) |
| p2++; |
| if (*p2) |
| *p2++ = 0; |
| if (3 > i) { |
| rc = (int) strict_strtol(p1, 10, &lng); |
| if (0 != rc) { |
| SAY("ERROR: %i=strict_strtol(%s,.,,)\n", \ |
| rc, p1); |
| return -EINVAL; |
| } |
| k[i] = (int)lng; |
| } |
| i++; |
| } |
| |
| memset(&v4l2_capability, 0, sizeof(struct v4l2_capability)); |
| strlcpy(&v4l2_capability.driver[0], "easycap", \ |
| sizeof(v4l2_capability.driver)); |
| |
| v4l2_capability.capabilities = \ |
| V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING | \ |
| V4L2_CAP_AUDIO | V4L2_CAP_READWRITE; |
| |
| v4l2_capability.version = KERNEL_VERSION(k[0], k[1], k[2]); |
| JOT(8, "v4l2_capability.version=(%i,%i,%i)\n", k[0], k[1], k[2]); |
| |
| strlcpy(&v4l2_capability.card[0], "EasyCAP DC60", \ |
| sizeof(v4l2_capability.card)); |
| |
| if (usb_make_path(peasycap->pusb_device, &v4l2_capability.bus_info[0],\ |
| sizeof(v4l2_capability.bus_info)) < 0) { |
| strlcpy(&v4l2_capability.bus_info[0], "EasyCAP bus_info", \ |
| sizeof(v4l2_capability.bus_info)); |
| JOT(8, "%s=v4l2_capability.bus_info\n", \ |
| &v4l2_capability.bus_info[0]); |
| } |
| if (0 != copy_to_user((void __user *)arg, &v4l2_capability, \ |
| sizeof(struct v4l2_capability))) { |
| POUT; |
| return -EFAULT; |
| } |
| break; |
| } |
| /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ |
| case VIDIOC_ENUMINPUT: { |
| static struct v4l2_input v4l2_input; |
| static __u32 index; |
| |
| JOT(8, "VIDIOC_ENUMINPUT\n"); |
| |
| if (0 != copy_from_user(&v4l2_input, (void __user *)arg, \ |
| sizeof(struct v4l2_input))) { |
| POUT; |
| return -EFAULT; |
| } |
| |
| index = v4l2_input.index; |
| memset(&v4l2_input, 0, sizeof(struct v4l2_input)); |
| |
| switch (index) { |
| case 0: { |
| v4l2_input.index = index; |
| strcpy(&v4l2_input.name[0], "CVBS0"); |
| v4l2_input.type = V4L2_INPUT_TYPE_CAMERA; |
| v4l2_input.audioset = 0x01; |
| v4l2_input.tuner = 0; |
| v4l2_input.std = V4L2_STD_PAL | V4L2_STD_SECAM | \ |
| V4L2_STD_NTSC ; |
| v4l2_input.status = 0; |
| JOT(8, "%i=index: %s\n", index, &v4l2_input.name[0]); |
| break; |
| } |
| case 1: { |
| v4l2_input.index = index; |
| strcpy(&v4l2_input.name[0], "CVBS1"); |
| v4l2_input.type = V4L2_INPUT_TYPE_CAMERA; |
| v4l2_input.audioset = 0x01; |
| v4l2_input.tuner = 0; |
| v4l2_input.std = V4L2_STD_PAL | V4L2_STD_SECAM | \ |
| V4L2_STD_NTSC ; |
| v4l2_input.status = 0; |
| JOT(8, "%i=index: %s\n", index, &v4l2_input.name[0]); |
| break; |
| } |
| case 2: { |
| v4l2_input.index = index; |
| strcpy(&v4l2_input.name[0], "CVBS2"); |
| v4l2_input.type = V4L2_INPUT_TYPE_CAMERA; |
| v4l2_input.audioset = 0x01; |
| v4l2_input.tuner = 0; |
| v4l2_input.std = V4L2_STD_PAL | V4L2_STD_SECAM | \ |
| V4L2_STD_NTSC ; |
| v4l2_input.status = 0; |
| JOT(8, "%i=index: %s\n", index, &v4l2_input.name[0]); |
| break; |
| } |
| case 3: { |
| v4l2_input.index = index; |
| strcpy(&v4l2_input.name[0], "CVBS3"); |
| v4l2_input.type = V4L2_INPUT_TYPE_CAMERA; |
| v4l2_input.audioset = 0x01; |
| v4l2_input.tuner = 0; |
| v4l2_input.std = V4L2_STD_PAL | V4L2_STD_SECAM | \ |
| V4L2_STD_NTSC ; |
| v4l2_input.status = 0; |
| JOT(8, "%i=index: %s\n", index, &v4l2_input.name[0]); |
| break; |
| } |
| case 4: { |
| v4l2_input.index = index; |
| strcpy(&v4l2_input.name[0], "CVBS4"); |
| v4l2_input.type = V4L2_INPUT_TYPE_CAMERA; |
| v4l2_input.audioset = 0x01; |
| v4l2_input.tuner = 0; |
| v4l2_input.std = V4L2_STD_PAL | V4L2_STD_SECAM | \ |
| V4L2_STD_NTSC ; |
| v4l2_input.status = 0; |
| JOT(8, "%i=index: %s\n", index, &v4l2_input.name[0]); |
| break; |
| } |
| case 5: { |
| v4l2_input.index = index; |
| strcpy(&v4l2_input.name[0], "S-VIDEO"); |
| v4l2_input.type = V4L2_INPUT_TYPE_CAMERA; |
| v4l2_input.audioset = 0x01; |
| v4l2_input.tuner = 0; |
| v4l2_input.std = V4L2_STD_PAL | V4L2_STD_SECAM | \ |
| V4L2_STD_NTSC ; |
| v4l2_input.status = 0; |
| JOT(8, "%i=index: %s\n", index, &v4l2_input.name[0]); |
| break; |
| } |
| default: { |
| JOT(8, "%i=index: exhausts inputs\n", index); |
| return -EINVAL; |
| } |
| } |
| |
| if (0 != copy_to_user((void __user *)arg, &v4l2_input, \ |
| sizeof(struct v4l2_input))) { |
| POUT; |
| return -EFAULT; |
| } |
| break; |
| } |
| /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ |
| case VIDIOC_G_INPUT: { |
| static __u32 index; |
| |
| JOT(8, "VIDIOC_G_INPUT\n"); |
| index = (__u32)peasycap->input; |
| JOT(8, "user is told: %i\n", index); |
| if (0 != copy_to_user((void __user *)arg, &index, sizeof(__u32))) { |
| POUT; |
| return -EFAULT; |
| } |
| break; |
| } |
| /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ |
| case VIDIOC_S_INPUT: |
| { |
| static __u32 index; |
| |
| JOT(8, "VIDIOC_S_INPUT\n"); |
| |
| if (0 != copy_from_user(&index, (void __user *)arg, sizeof(__u32))) { |
| POUT; |
| return -EFAULT; |
| } |
| |
| JOT(8, "user requests input %i\n", index); |
| |
| if ((int)index == peasycap->input) { |
| SAY("requested input already in effect\n"); |
| break; |
| } |
| |
| if ((0 > index) || (5 < index)) { |
| JOT(8, "ERROR: bad requested input: %i\n", index); |
| return -EINVAL; |
| } |
| peasycap->input = (int)index; |
| |
| select_input(peasycap->pusb_device, peasycap->input, 9); |
| |
| break; |
| } |
| /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ |
| case VIDIOC_ENUMAUDIO: { |
| JOT(8, "VIDIOC_ENUMAUDIO\n"); |
| return -EINVAL; |
| } |
| /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ |
| case VIDIOC_ENUMAUDOUT: { |
| static struct v4l2_audioout v4l2_audioout; |
| |
| JOT(8, "VIDIOC_ENUMAUDOUT\n"); |
| |
| if (0 != copy_from_user(&v4l2_audioout, (void __user *)arg, \ |
| sizeof(struct v4l2_audioout))) { |
| POUT; |
| return -EFAULT; |
| } |
| |
| if (0 != v4l2_audioout.index) |
| return -EINVAL; |
| memset(&v4l2_audioout, 0, sizeof(struct v4l2_audioout)); |
| v4l2_audioout.index = 0; |
| strcpy(&v4l2_audioout.name[0], "Soundtrack"); |
| |
| if (0 != copy_to_user((void __user *)arg, &v4l2_audioout, \ |
| sizeof(struct v4l2_audioout))) { |
| POUT; |
| return -EFAULT; |
| } |
| break; |
| } |
| /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ |
| case VIDIOC_QUERYCTRL: { |
| static int i1; |
| static struct v4l2_queryctrl v4l2_queryctrl; |
| |
| JOT(8, "VIDIOC_QUERYCTRL\n"); |
| |
| if (0 != copy_from_user(&v4l2_queryctrl, (void __user *)arg, \ |
| sizeof(struct v4l2_queryctrl))) { |
| POUT; |
| return -EFAULT; |
| } |
| |
| i1 = 0; |
| while (0xFFFFFFFF != easycap_control[i1].id) { |
| if (easycap_control[i1].id == v4l2_queryctrl.id) { |
| JOT(8, "VIDIOC_QUERYCTRL %s=easycap_control[%i]" \ |
| ".name\n", &easycap_control[i1].name[0], i1); |
| memcpy(&v4l2_queryctrl, &easycap_control[i1], \ |
| sizeof(struct v4l2_queryctrl)); |
| break; |
| } |
| i1++; |
| } |
| if (0xFFFFFFFF == easycap_control[i1].id) { |
| JOT(8, "%i=index: exhausts controls\n", i1); |
| return -EINVAL; |
| } |
| if (0 != copy_to_user((void __user *)arg, &v4l2_queryctrl, \ |
| sizeof(struct v4l2_queryctrl))) { |
| POUT; |
| return -EFAULT; |
| } |
| break; |
| } |
| /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ |
| case VIDIOC_QUERYMENU: { |
| JOT(8, "VIDIOC_QUERYMENU unsupported\n"); |
| return -EINVAL; |
| break; |
| } |
| /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ |
| case VIDIOC_G_CTRL: { |
| static struct v4l2_control v4l2_control; |
| |
| JOT(8, "VIDIOC_G_CTRL\n"); |
| |
| if (0 != copy_from_user(&v4l2_control, (void __user *)arg, \ |
| sizeof(struct v4l2_control))) { |
| POUT; |
| return -EFAULT; |
| } |
| |
| switch (v4l2_control.id) { |
| case V4L2_CID_BRIGHTNESS: { |
| v4l2_control.value = peasycap->brightness; |
| JOT(8, "user enquires brightness: %i\n", v4l2_control.value); |
| break; |
| } |
| case V4L2_CID_CONTRAST: { |
| v4l2_control.value = peasycap->contrast; |
| JOT(8, "user enquires contrast: %i\n", v4l2_control.value); |
| break; |
| } |
| case V4L2_CID_SATURATION: { |
| v4l2_control.value = peasycap->saturation; |
| JOT(8, "user enquires saturation: %i\n", v4l2_control.value); |
| break; |
| } |
| case V4L2_CID_HUE: { |
| v4l2_control.value = peasycap->hue; |
| JOT(8, "user enquires hue: %i\n", v4l2_control.value); |
| break; |
| } |
| case V4L2_CID_AUDIO_VOLUME: { |
| v4l2_control.value = peasycap->volume; |
| JOT(8, "user enquires volume: %i\n", v4l2_control.value); |
| break; |
| } |
| case V4L2_CID_AUDIO_MUTE: { |
| if (1 == peasycap->mute) |
| v4l2_control.value = true; |
| else |
| v4l2_control.value = false; |
| JOT(8, "user enquires mute: %i\n", v4l2_control.value); |
| break; |
| } |
| default: { |
| SAY("ERROR: unknown V4L2 control: 0x%08X=id\n", \ |
| v4l2_control.id); |
| explain_cid(v4l2_control.id); |
| return -EINVAL; |
| } |
| } |
| if (0 != copy_to_user((void __user *)arg, &v4l2_control, \ |
| sizeof(struct v4l2_control))) { |
| POUT; |
| return -EFAULT; |
| } |
| break; |
| } |
| /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ |
| #if defined(VIDIOC_S_CTRL_OLD) |
| case VIDIOC_S_CTRL_OLD: { |
| JOT(8, "VIDIOC_S_CTRL_OLD required at least for xawtv\n"); |
| } |
| #endif /*VIDIOC_S_CTRL_OLD*/ |
| case VIDIOC_S_CTRL: |
| { |
| static struct v4l2_control v4l2_control; |
| |
| JOT(8, "VIDIOC_S_CTRL\n"); |
| |
| if (0 != copy_from_user(&v4l2_control, (void __user *)arg, \ |
| sizeof(struct v4l2_control))) { |
| POUT; |
| return -EFAULT; |
| } |
| |
| switch (v4l2_control.id) { |
| case V4L2_CID_BRIGHTNESS: { |
| JOT(8, "user requests brightness %i\n", v4l2_control.value); |
| if (0 != adjust_brightness(peasycap, v4l2_control.value)) |
| ; |
| break; |
| } |
| case V4L2_CID_CONTRAST: { |
| JOT(8, "user requests contrast %i\n", v4l2_control.value); |
| if (0 != adjust_contrast(peasycap, v4l2_control.value)) |
| ; |
| break; |
| } |
| case V4L2_CID_SATURATION: { |
| JOT(8, "user requests saturation %i\n", v4l2_control.value); |
| if (0 != adjust_saturation(peasycap, v4l2_control.value)) |
| ; |
| break; |
| } |
| case V4L2_CID_HUE: { |
| JOT(8, "user requests hue %i\n", v4l2_control.value); |
| if (0 != adjust_hue(peasycap, v4l2_control.value)) |
| ; |
| break; |
| } |
| case V4L2_CID_AUDIO_VOLUME: { |
| JOT(8, "user requests volume %i\n", v4l2_control.value); |
| if (0 != adjust_volume(peasycap, v4l2_control.value)) |
| ; |
| break; |
| } |
| case V4L2_CID_AUDIO_MUTE: { |
| int mute; |
| |
| JOT(8, "user requests mute %i\n", v4l2_control.value); |
| if (true == v4l2_control.value) |
| mute = 1; |
| else |
| mute = 0; |
| |
| if (0 != adjust_mute(peasycap, mute)) |
| SAY("WARNING: failed to adjust mute to %i\n", mute); |
| break; |
| } |
| default: { |
| SAY("ERROR: unknown V4L2 control: 0x%08X=id\n", \ |
| v4l2_control.id); |
| explain_cid(v4l2_control.id); |
| return -EINVAL; |
| } |
| } |
| break; |
| } |
| /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ |
| case VIDIOC_S_EXT_CTRLS: { |
| JOT(8, "VIDIOC_S_EXT_CTRLS unsupported\n"); |
| return -EINVAL; |
| } |
| /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ |
| case VIDIOC_ENUM_FMT: { |
| static __u32 index; |
| static struct v4l2_fmtdesc v4l2_fmtdesc; |
| |
| JOT(8, "VIDIOC_ENUM_FMT\n"); |
| |
| if (0 != copy_from_user(&v4l2_fmtdesc, (void __user *)arg, \ |
| sizeof(struct v4l2_fmtdesc))) { |
| POUT; |
| return -EFAULT; |
| } |
| |
| index = v4l2_fmtdesc.index; |
| memset(&v4l2_fmtdesc, 0, sizeof(struct v4l2_fmtdesc)); |
| |
| v4l2_fmtdesc.index = index; |
| v4l2_fmtdesc.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; |
| |
| switch (index) { |
| case 0: { |
| v4l2_fmtdesc.flags = 0; |
| strcpy(&v4l2_fmtdesc.description[0], "uyvy"); |
| v4l2_fmtdesc.pixelformat = V4L2_PIX_FMT_UYVY; |
| JOT(8, "%i=index: %s\n", index, &v4l2_fmtdesc.description[0]); |
| break; |
| } |
| case 1: { |
| v4l2_fmtdesc.flags = 0; |
| strcpy(&v4l2_fmtdesc.description[0], "yuy2"); |
| v4l2_fmtdesc.pixelformat = V4L2_PIX_FMT_YUYV; |
| JOT(8, "%i=index: %s\n", index, &v4l2_fmtdesc.description[0]); |
| break; |
| } |
| case 2: { |
| v4l2_fmtdesc.flags = 0; |
| strcpy(&v4l2_fmtdesc.description[0], "rgb24"); |
| v4l2_fmtdesc.pixelformat = V4L2_PIX_FMT_RGB24; |
| JOT(8, "%i=index: %s\n", index, &v4l2_fmtdesc.description[0]); |
| break; |
| } |
| case 3: { |
| v4l2_fmtdesc.flags = 0; |
| strcpy(&v4l2_fmtdesc.description[0], "rgb32"); |
| v4l2_fmtdesc.pixelformat = V4L2_PIX_FMT_RGB32; |
| JOT(8, "%i=index: %s\n", index, &v4l2_fmtdesc.description[0]); |
| break; |
| } |
| case 4: { |
| v4l2_fmtdesc.flags = 0; |
| strcpy(&v4l2_fmtdesc.description[0], "bgr24"); |
| v4l2_fmtdesc.pixelformat = V4L2_PIX_FMT_BGR24; |
| JOT(8, "%i=index: %s\n", index, &v4l2_fmtdesc.description[0]); |
| break; |
| } |
| case 5: { |
| v4l2_fmtdesc.flags = 0; |
| strcpy(&v4l2_fmtdesc.description[0], "bgr32"); |
| v4l2_fmtdesc.pixelformat = V4L2_PIX_FMT_BGR32; |
| JOT(8, "%i=index: %s\n", index, &v4l2_fmtdesc.description[0]); |
| break; |
| } |
| default: { |
| JOT(8, "%i=index: exhausts formats\n", index); |
| return -EINVAL; |
| } |
| } |
| if (0 != copy_to_user((void __user *)arg, &v4l2_fmtdesc, \ |
| sizeof(struct v4l2_fmtdesc))) { |
| POUT; |
| return -EFAULT; |
| } |
| break; |
| } |
| /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ |
| case VIDIOC_ENUM_FRAMESIZES: { |
| JOT(8, "VIDIOC_ENUM_FRAMESIZES unsupported\n"); |
| return -EINVAL; |
| } |
| case VIDIOC_ENUM_FRAMEINTERVALS: { |
| JOT(8, "VIDIOC_ENUM_FRAME_INTERVALS unsupported\n"); |
| return -EINVAL; |
| } |
| /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ |
| case VIDIOC_G_FMT: { |
| static struct v4l2_format v4l2_format; |
| static struct v4l2_pix_format v4l2_pix_format; |
| |
| JOT(8, "VIDIOC_G_FMT\n"); |
| |
| if (0 != copy_from_user(&v4l2_format, (void __user *)arg, \ |
| sizeof(struct v4l2_format))) { |
| POUT; |
| return -EFAULT; |
| } |
| |
| if (v4l2_format.type != V4L2_BUF_TYPE_VIDEO_CAPTURE) { |
| POUT; |
| return -EINVAL; |
| } |
| |
| memset(&v4l2_pix_format, 0, sizeof(struct v4l2_pix_format)); |
| v4l2_format.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; |
| memcpy(&(v4l2_format.fmt.pix), \ |
| &(easycap_format[peasycap->format_offset]\ |
| .v4l2_format.fmt.pix), sizeof(v4l2_pix_format)); |
| JOT(8, "user is told: %s\n", \ |
| &easycap_format[peasycap->format_offset].name[0]); |
| |
| if (0 != copy_to_user((void __user *)arg, &v4l2_format, \ |
| sizeof(struct v4l2_format))) { |
| POUT; |
| return -EFAULT; |
| } |
| break; |
| } |
| /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ |
| case VIDIOC_TRY_FMT: |
| case VIDIOC_S_FMT: { |
| static struct v4l2_format v4l2_format; |
| static struct v4l2_pix_format v4l2_pix_format; |
| static bool try; |
| static int best_format; |
| |
| if (VIDIOC_TRY_FMT == cmd) { |
| JOT(8, "VIDIOC_TRY_FMT\n"); |
| try = true; |
| } else { |
| JOT(8, "VIDIOC_S_FMT\n"); |
| try = false; |
| } |
| |
| if (0 != copy_from_user(&v4l2_format, (void __user *)arg, \ |
| sizeof(struct v4l2_format))) { |
| POUT; |
| return -EFAULT; |
| } |
| |
| best_format = adjust_format(peasycap, \ |
| v4l2_format.fmt.pix.width, \ |
| v4l2_format.fmt.pix.height, \ |
| v4l2_format.fmt.pix.pixelformat, \ |
| v4l2_format.fmt.pix.field, \ |
| try); |
| if (0 > best_format) { |
| JOT(8, "WARNING: adjust_format() returned %i\n", best_format); |
| return -ENOENT; |
| } |
| /*...........................................................................*/ |
| memset(&v4l2_pix_format, 0, sizeof(struct v4l2_pix_format)); |
| v4l2_format.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; |
| |
| memcpy(&(v4l2_format.fmt.pix), &(easycap_format[best_format]\ |
| .v4l2_format.fmt.pix), sizeof(v4l2_pix_format)); |
| JOT(8, "user is told: %s\n", &easycap_format[best_format].name[0]); |
| |
| if (0 != copy_to_user((void __user *)arg, &v4l2_format, \ |
| sizeof(struct v4l2_format))) { |
| POUT; |
| return -EFAULT; |
| } |
| break; |
| } |
| /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ |
| case VIDIOC_CROPCAP: { |
| static struct v4l2_cropcap v4l2_cropcap; |
| |
| JOT(8, "VIDIOC_CROPCAP\n"); |
| |
| if (0 != copy_from_user(&v4l2_cropcap, (void __user *)arg, \ |
| sizeof(struct v4l2_cropcap))) { |
| POUT; |
| return -EFAULT; |
| } |
| |
| if (v4l2_cropcap.type != V4L2_BUF_TYPE_VIDEO_CAPTURE) |
| JOT(8, "v4l2_cropcap.type != V4L2_BUF_TYPE_VIDEO_CAPTURE\n"); |
| |
| memset(&v4l2_cropcap, 0, sizeof(struct v4l2_cropcap)); |
| v4l2_cropcap.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; |
| v4l2_cropcap.bounds.left = 0; |
| v4l2_cropcap.bounds.top = 0; |
| v4l2_cropcap.bounds.width = peasycap->width; |
| v4l2_cropcap.bounds.height = peasycap->height; |
| v4l2_cropcap.defrect.left = 0; |
| v4l2_cropcap.defrect.top = 0; |
| v4l2_cropcap.defrect.width = peasycap->width; |
| v4l2_cropcap.defrect.height = peasycap->height; |
| v4l2_cropcap.pixelaspect.numerator = 1; |
| v4l2_cropcap.pixelaspect.denominator = 1; |
| |
| JOT(8, "user is told: %ix%i\n", peasycap->width, peasycap->height); |
| |
| if (0 != copy_to_user((void __user *)arg, &v4l2_cropcap, \ |
| sizeof(struct v4l2_cropcap))) { |
| POUT; |
| return -EFAULT; |
| } |
| break; |
| } |
| /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ |
| case VIDIOC_G_CROP: |
| case VIDIOC_S_CROP: { |
| JOT(8, "VIDIOC_G_CROP|VIDIOC_S_CROP unsupported\n"); |
| return -EINVAL; |
| } |
| /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ |
| case VIDIOC_QUERYSTD: { |
| JOT(8, "VIDIOC_QUERYSTD: " \ |
| "EasyCAP is incapable of detecting standard\n"); |
| return -EINVAL; |
| break; |
| } |
| /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ |
| /*---------------------------------------------------------------------------*/ |
| /* |
| * THE MANIPULATIONS INVOLVING last0,last1,last2,last3 CONSTITUTE A WORKAROUND |
| * FOR WHAT APPEARS TO BE A BUG IN 64-BIT mplayer. |
| * NOT NEEDED, BUT HOPEFULLY HARMLESS, FOR 32-BIT mplayer. |
| */ |
| /*---------------------------------------------------------------------------*/ |
| case VIDIOC_ENUMSTD: { |
| static int last0 = -1, last1 = -1, last2 = -1, last3 = -1; |
| static struct v4l2_standard v4l2_standard; |
| static __u32 index; |
| static struct easycap_standard const *peasycap_standard; |
| |
| JOT(8, "VIDIOC_ENUMSTD\n"); |
| |
| if (0 != copy_from_user(&v4l2_standard, (void __user *)arg, \ |
| sizeof(struct v4l2_standard))) { |
| POUT; |
| return -EFAULT; |
| } |
| index = v4l2_standard.index; |
| |
| last3 = last2; last2 = last1; last1 = last0; last0 = index; |
| if ((index == last3) && (index == last2) && \ |
| (index == last1) && (index == last0)) { |
| index++; |
| last3 = last2; last2 = last1; last1 = last0; last0 = index; |
| } |
| |
| memset(&v4l2_standard, 0, sizeof(struct v4l2_standard)); |
| |
| peasycap_standard = &easycap_standard[0]; |
| while (0xFFFF != peasycap_standard->mask) { |
| if ((int)(peasycap_standard - &easycap_standard[0]) == index) |
| break; |
| peasycap_standard++; |
| } |
| if (0xFFFF == peasycap_standard->mask) { |
| JOT(8, "%i=index: exhausts standards\n", index); |
| return -EINVAL; |
| } |
| JOT(8, "%i=index: %s\n", index, \ |
| &(peasycap_standard->v4l2_standard.name[0])); |
| memcpy(&v4l2_standard, &(peasycap_standard->v4l2_standard), \ |
| sizeof(struct v4l2_standard)); |
| |
| v4l2_standard.index = index; |
| |
| if (0 != copy_to_user((void __user *)arg, &v4l2_standard, \ |
| sizeof(struct v4l2_standard))) { |
| POUT; |
| return -EFAULT; |
| } |
| break; |
| } |
| /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ |
| case VIDIOC_G_STD: { |
| static v4l2_std_id std_id; |
| static struct easycap_standard const *peasycap_standard; |
| |
| JOT(8, "VIDIOC_G_STD\n"); |
| |
| if (0 != copy_from_user(&std_id, (void __user *)arg, \ |
| sizeof(v4l2_std_id))) { |
| POUT; |
| return -EFAULT; |
| } |
| |
| peasycap_standard = &easycap_standard[peasycap->standard_offset]; |
| std_id = peasycap_standard->v4l2_standard.id; |
| |
| JOT(8, "user is told: %s\n", \ |
| &peasycap_standard->v4l2_standard.name[0]); |
| |
| if (0 != copy_to_user((void __user *)arg, &std_id, \ |
| sizeof(v4l2_std_id))) { |
| POUT; |
| return -EFAULT; |
| } |
| break; |
| } |
| /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ |
| case VIDIOC_S_STD: { |
| static v4l2_std_id std_id; |
| static int rc; |
| |
| JOT(8, "VIDIOC_S_STD\n"); |
| |
| if (0 != copy_from_user(&std_id, (void __user *)arg, \ |
| sizeof(v4l2_std_id))) { |
| POUT; |
| return -EFAULT; |
| } |
| |
| rc = adjust_standard(peasycap, std_id); |
| if (0 > rc) { |
| JOT(8, "WARNING: adjust_standard() returned %i\n", rc); |
| return -ENOENT; |
| } |
| break; |
| } |
| /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ |
| case VIDIOC_REQBUFS: { |
| static int nbuffers; |
| static struct v4l2_requestbuffers v4l2_requestbuffers; |
| |
| JOT(8, "VIDIOC_REQBUFS\n"); |
| |
| if (0 != copy_from_user(&v4l2_requestbuffers, (void __user *)arg, \ |
| sizeof(struct v4l2_requestbuffers))) { |
| POUT; |
| return -EFAULT; |
| } |
| |
| if (v4l2_requestbuffers.type != V4L2_BUF_TYPE_VIDEO_CAPTURE) |
| return -EINVAL; |
| if (v4l2_requestbuffers.memory != V4L2_MEMORY_MMAP) { |
| POUT; |
| return -EINVAL; |
| } |
| nbuffers = v4l2_requestbuffers.count; |
| JOT(8, " User requests %i buffers ...\n", nbuffers); |
| if (nbuffers < 2) |
| nbuffers = 2; |
| if (nbuffers > FRAME_BUFFER_MANY) |
| nbuffers = FRAME_BUFFER_MANY; |
| if (v4l2_requestbuffers.count == nbuffers) { |
| JOT(8, " ... agree to %i buffers\n", \ |
| nbuffers); |
| } else { |
| JOT(8, " ... insist on %i buffers\n", \ |
| nbuffers); |
| v4l2_requestbuffers.count = nbuffers; |
| } |
| peasycap->frame_buffer_many = nbuffers; |
| |
| if (0 != copy_to_user((void __user *)arg, &v4l2_requestbuffers, \ |
| sizeof(struct v4l2_requestbuffers))) { |
| POUT; |
| return -EFAULT; |
| } |
| break; |
| } |
| /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ |
| case VIDIOC_QUERYBUF: { |
| static __u32 index; |
| static struct v4l2_buffer v4l2_buffer; |
| |
| JOT(8, "VIDIOC_QUERYBUF\n"); |
| |
| if (peasycap->video_eof) { |
| JOT(8, "returning -1 because %i=video_eof\n", \ |
| peasycap->video_eof); |
| return -1; |
| } |
| |
| if (0 != copy_from_user(&v4l2_buffer, (void __user *)arg, \ |
| sizeof(struct v4l2_buffer))) { |
| POUT; |
| return -EFAULT; |
| } |
| |
| if (v4l2_buffer.type != V4L2_BUF_TYPE_VIDEO_CAPTURE) |
| return -EINVAL; |
| index = v4l2_buffer.index; |
| if (index < 0 || index >= peasycap->frame_buffer_many) |
| return -EINVAL; |
| memset(&v4l2_buffer, 0, sizeof(struct v4l2_buffer)); |
| v4l2_buffer.index = index; |
| v4l2_buffer.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; |
| v4l2_buffer.bytesused = peasycap->frame_buffer_used; |
| v4l2_buffer.flags = V4L2_BUF_FLAG_MAPPED | \ |
| peasycap->done[index] | \ |
| peasycap->queued[index]; |
| v4l2_buffer.field = peasycap->field; |
| v4l2_buffer.memory = V4L2_MEMORY_MMAP; |
| v4l2_buffer.m.offset = index * FRAME_BUFFER_SIZE; |
| v4l2_buffer.length = FRAME_BUFFER_SIZE; |
| |
| JOT(16, " %10i=index\n", v4l2_buffer.index); |
| JOT(16, " 0x%08X=type\n", v4l2_buffer.type); |
| JOT(16, " %10i=bytesused\n", v4l2_buffer.bytesused); |
| JOT(16, " 0x%08X=flags\n", v4l2_buffer.flags); |
| JOT(16, " %10i=field\n", v4l2_buffer.field); |
| JOT(16, " %10li=timestamp.tv_usec\n", \ |
| (long)v4l2_buffer.timestamp.tv_usec); |
| JOT(16, " %10i=sequence\n", v4l2_buffer.sequence); |
| JOT(16, " 0x%08X=memory\n", v4l2_buffer.memory); |
| JOT(16, " %10i=m.offset\n", v4l2_buffer.m.offset); |
| JOT(16, " %10i=length\n", v4l2_buffer.length); |
| |
| if (0 != copy_to_user((void __user *)arg, &v4l2_buffer, \ |
| sizeof(struct v4l2_buffer))) { |
| POUT; |
| return -EFAULT; |
| } |
| break; |
| } |
| /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ |
| case VIDIOC_QBUF: { |
| static struct v4l2_buffer v4l2_buffer; |
| |
| JOT(8, "VIDIOC_QBUF\n"); |
| |
| if (0 != copy_from_user(&v4l2_buffer, (void __user *)arg, \ |
| sizeof(struct v4l2_buffer))) { |
| POUT; |
| return -EFAULT; |
| } |
| |
| if (v4l2_buffer.type != V4L2_BUF_TYPE_VIDEO_CAPTURE) |
| return -EINVAL; |
| if (v4l2_buffer.memory != V4L2_MEMORY_MMAP) |
| return -EINVAL; |
| if (v4l2_buffer.index < 0 || \ |
| (v4l2_buffer.index >= peasycap->frame_buffer_many)) |
| return -EINVAL; |
| v4l2_buffer.flags = V4L2_BUF_FLAG_MAPPED | V4L2_BUF_FLAG_QUEUED; |
| |
| peasycap->done[v4l2_buffer.index] = 0; |
| peasycap->queued[v4l2_buffer.index] = V4L2_BUF_FLAG_QUEUED; |
| |
| if (0 != copy_to_user((void __user *)arg, &v4l2_buffer, \ |
| sizeof(struct v4l2_buffer))) { |
| POUT; |
| return -EFAULT; |
| } |
| |
| JOT(8, "..... user queueing frame buffer %i\n", \ |
| (int)v4l2_buffer.index); |
| |
| peasycap->frame_lock = 0; |
| |
| break; |
| } |
| /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ |
| case VIDIOC_DQBUF: |
| { |
| #if defined(AUDIOTIME) |
| static struct signed_div_result sdr; |
| static long long int above, below, dnbydt, fudge, sll; |
| static unsigned long long int ull; |
| static struct timeval timeval0; |
| struct timeval timeval1; |
| #endif /*AUDIOTIME*/ |
| static struct timeval timeval, timeval2; |
| static int i, j; |
| static struct v4l2_buffer v4l2_buffer; |
| |
| JOT(8, "VIDIOC_DQBUF\n"); |
| |
| if ((peasycap->video_idle) || (peasycap->video_eof)) { |
| JOT(8, "returning -EIO because " \ |
| "%i=video_idle %i=video_eof\n", \ |
| peasycap->video_idle, peasycap->video_eof); |
| return -EIO; |
| } |
| |
| if (0 != copy_from_user(&v4l2_buffer, (void __user *)arg, \ |
| sizeof(struct v4l2_buffer))) { |
| POUT; |
| return -EFAULT; |
| } |
| |
| if (v4l2_buffer.type != V4L2_BUF_TYPE_VIDEO_CAPTURE) |
| return -EINVAL; |
| |
| if (!peasycap->video_isoc_streaming) { |
| JOT(16, "returning -EIO because video urbs not streaming\n"); |
| return -EIO; |
| } |
| /*---------------------------------------------------------------------------*/ |
| /* |
| * IF THE USER HAS PREVIOUSLY CALLED easycap_poll(), AS DETERMINED BY FINDING |
| * THE FLAG peasycap->polled SET, THERE MUST BE NO FURTHER WAIT HERE. IN THIS |
| * CASE, JUST CHOOSE THE FRAME INDICATED BY peasycap->frame_read |
| */ |
| /*---------------------------------------------------------------------------*/ |
| |
| if (!peasycap->polled) { |
| if (-EIO == easycap_dqbuf(peasycap, 0)) |
| return -EIO; |
| } else { |
| if (peasycap->video_eof) |
| return -EIO; |
| } |
| if (V4L2_BUF_FLAG_DONE != peasycap->done[peasycap->frame_read]) { |
| SAY("ERROR: V4L2_BUF_FLAG_DONE != 0x%08X\n", \ |
| peasycap->done[peasycap->frame_read]); |
| } |
| peasycap->polled = 0; |
| |
| if (!(isequence % 10)) { |
| for (i = 0; i < 179; i++) |
| peasycap->merit[i] = peasycap->merit[i+1]; |
| peasycap->merit[179] = merit_saa(peasycap->pusb_device); |
| j = 0; |
| for (i = 0; i < 180; i++) |
| j += peasycap->merit[i]; |
| if (90 < j) { |
| SAY("easycap driver shutting down " \ |
| "on condition blue\n"); |
| peasycap->video_eof = 1; peasycap->audio_eof = 1; |
| } |
| } |
| |
| v4l2_buffer.index = peasycap->frame_read; |
| v4l2_buffer.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; |
| v4l2_buffer.bytesused = peasycap->frame_buffer_used; |
| v4l2_buffer.flags = V4L2_BUF_FLAG_MAPPED | V4L2_BUF_FLAG_DONE; |
| v4l2_buffer.field = peasycap->field; |
| if (V4L2_FIELD_ALTERNATE == v4l2_buffer.field) |
| v4l2_buffer.field = \ |
| 0x000F & (peasycap->\ |
| frame_buffer[peasycap->frame_read][0].kount); |
| do_gettimeofday(&timeval); |
| timeval2 = timeval; |
| |
| #if defined(AUDIOTIME) |
| if (!peasycap->timeval0.tv_sec) { |
| timeval0 = timeval; |
| timeval1 = timeval; |
| timeval2 = timeval; |
| dnbydt = 192000; |
| |
| if (mutex_lock_interruptible(&(peasycap->mutex_timeval0))) |
| return -ERESTARTSYS; |
| peasycap->timeval0 = timeval0; |
| mutex_unlock(&(peasycap->mutex_timeval0)); |
| } else { |
| if (mutex_lock_interruptible(&(peasycap->mutex_timeval1))) |
| return -ERESTARTSYS; |
| dnbydt = peasycap->dnbydt; |
| timeval1 = peasycap->timeval1; |
| mutex_unlock(&(peasycap->mutex_timeval1)); |
| above = dnbydt * MICROSECONDS(timeval, timeval1); |
| below = 192000; |
| sdr = signed_div(above, below); |
| |
| above = sdr.quotient + timeval1.tv_usec - 350000; |
| |
| below = 1000000; |
| sdr = signed_div(above, below); |
| timeval2.tv_usec = sdr.remainder; |
| timeval2.tv_sec = timeval1.tv_sec + sdr.quotient; |
| } |
| if (!(isequence % 500)) { |
| fudge = ((long long int)(1000000)) * \ |
| ((long long int)(timeval.tv_sec - \ |
| timeval2.tv_sec)) + \ |
| (long long int)(timeval.tv_usec - \ |
| timeval2.tv_usec); |
| sdr = signed_div(fudge, 1000); |
| sll = sdr.quotient; |
| ull = sdr.remainder; |
| |
| SAY("%5lli.%-3lli=ms timestamp fudge\n", sll, ull); |
| } |
| #endif /*AUDIOTIME*/ |
| |
| v4l2_buffer.timestamp = timeval2; |
| v4l2_buffer.sequence = isequence++; |
| v4l2_buffer.memory = V4L2_MEMORY_MMAP; |
| v4l2_buffer.m.offset = v4l2_buffer.index * FRAME_BUFFER_SIZE; |
| v4l2_buffer.length = FRAME_BUFFER_SIZE; |
| |
| JOT(16, " %10i=index\n", v4l2_buffer.index); |
| JOT(16, " 0x%08X=type\n", v4l2_buffer.type); |
| JOT(16, " %10i=bytesused\n", v4l2_buffer.bytesused); |
| JOT(16, " 0x%08X=flags\n", v4l2_buffer.flags); |
| JOT(16, " %10i=field\n", v4l2_buffer.field); |
| JOT(16, " %10li=timestamp.tv_usec\n", \ |
| (long)v4l2_buffer.timestamp.tv_usec); |
| JOT(16, " %10i=sequence\n", v4l2_buffer.sequence); |
| JOT(16, " 0x%08X=memory\n", v4l2_buffer.memory); |
| JOT(16, " %10i=m.offset\n", v4l2_buffer.m.offset); |
| JOT(16, " %10i=length\n", v4l2_buffer.length); |
| |
| if (0 != copy_to_user((void __user *)arg, &v4l2_buffer, \ |
| sizeof(struct v4l2_buffer))) { |
| POUT; |
| return -EFAULT; |
| } |
| |
| JOT(8, "..... user is offered frame buffer %i\n", \ |
| peasycap->frame_read); |
| peasycap->frame_lock = 1; |
| if (peasycap->frame_read == peasycap->frame_fill) { |
| if (peasycap->frame_lock) { |
| JOT(8, "ERROR: filling frame buffer " \ |
| "while offered to user\n"); |
| } |
| } |
| break; |
| } |
| /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ |
| /*---------------------------------------------------------------------------*/ |
| /* |
| * AUDIO URBS HAVE ALREADY BEEN SUBMITTED WHEN THIS COMMAND IS RECEIVED; |
| * VIDEO URBS HAVE NOT. |
| */ |
| /*---------------------------------------------------------------------------*/ |
| case VIDIOC_STREAMON: { |
| static int i; |
| |
| JOT(8, "VIDIOC_STREAMON\n"); |
| |
| isequence = 0; |
| for (i = 0; i < 180; i++) |
| peasycap->merit[i] = 0; |
| if ((struct usb_device *)NULL == peasycap->pusb_device) { |
| SAY("ERROR: peasycap->pusb_device is NULL\n"); |
| return -EFAULT; |
| } |
| submit_video_urbs(peasycap); |
| peasycap->video_idle = 0; |
| peasycap->audio_idle = 0; |
| peasycap->video_eof = 0; |
| peasycap->audio_eof = 0; |
| break; |
| } |
| /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ |
| case VIDIOC_STREAMOFF: { |
| JOT(8, "VIDIOC_STREAMOFF\n"); |
| |
| if ((struct usb_device *)NULL == peasycap->pusb_device) { |
| SAY("ERROR: peasycap->pusb_device is NULL\n"); |
| return -EFAULT; |
| } |
| |
| peasycap->video_idle = 1; |
| peasycap->audio_idle = 1; peasycap->timeval0.tv_sec = 0; |
| /*---------------------------------------------------------------------------*/ |
| /* |
| * IF THE WAIT QUEUES ARE NOT CLEARED IN RESPONSE TO THE STREAMOFF COMMAND |
| * THE USERSPACE PROGRAM, E.G. mplayer, MAY HANG ON EXIT. BEWARE. |
| */ |
| /*---------------------------------------------------------------------------*/ |
| JOT(8, "calling wake_up on wq_video and wq_audio\n"); |
| wake_up_interruptible(&(peasycap->wq_video)); |
| wake_up_interruptible(&(peasycap->wq_audio)); |
| /*---------------------------------------------------------------------------*/ |
| break; |
| } |
| /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ |
| case VIDIOC_G_PARM: { |
| static struct v4l2_streamparm v4l2_streamparm; |
| |
| JOT(8, "VIDIOC_G_PARM\n"); |
| |
| if (0 != copy_from_user(&v4l2_streamparm, (void __user *)arg, \ |
| sizeof(struct v4l2_streamparm))) { |
| POUT; |
| return -EFAULT; |
| } |
| |
| if (v4l2_streamparm.type != V4L2_BUF_TYPE_VIDEO_CAPTURE) { |
| POUT; |
| return -EINVAL; |
| } |
| v4l2_streamparm.parm.capture.capability = 0; |
| v4l2_streamparm.parm.capture.capturemode = 0; |
| v4l2_streamparm.parm.capture.timeperframe.numerator = 1; |
| v4l2_streamparm.parm.capture.timeperframe.denominator = 30; |
| v4l2_streamparm.parm.capture.readbuffers = peasycap->frame_buffer_many; |
| v4l2_streamparm.parm.capture.extendedmode = 0; |
| if (0 != copy_to_user((void __user *)arg, &v4l2_streamparm, \ |
| sizeof(struct v4l2_streamparm))) { |
| POUT; |
| return -EFAULT; |
| } |
| break; |
| } |
| /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ |
| case VIDIOC_S_PARM: { |
| JOT(8, "VIDIOC_S_PARM unsupported\n"); |
| return -EINVAL; |
| } |
| /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ |
| case VIDIOC_G_AUDIO: { |
| JOT(8, "VIDIOC_G_AUDIO unsupported\n"); |
| return -EINVAL; |
| } |
| /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ |
| case VIDIOC_S_AUDIO: { |
| JOT(8, "VIDIOC_S_AUDIO unsupported\n"); |
| return -EINVAL; |
| } |
| /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ |
| case VIDIOC_S_TUNER: { |
| JOT(8, "VIDIOC_S_TUNER unsupported\n"); |
| return -EINVAL; |
| } |
| /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ |
| case VIDIOC_G_FBUF: |
| case VIDIOC_S_FBUF: |
| case VIDIOC_OVERLAY: { |
| JOT(8, "VIDIOC_G_FBUF|VIDIOC_S_FBUF|VIDIOC_OVERLAY unsupported\n"); |
| return -EINVAL; |
| } |
| /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ |
| case VIDIOC_G_TUNER: { |
| JOT(8, "VIDIOC_G_TUNER unsupported\n"); |
| return -EINVAL; |
| } |
| case VIDIOC_G_FREQUENCY: |
| case VIDIOC_S_FREQUENCY: { |
| JOT(8, "VIDIOC_G_FREQUENCY|VIDIOC_S_FREQUENCY unsupported\n"); |
| return -EINVAL; |
| } |
| /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ |
| default: { |
| JOT(8, "ERROR: unrecognized V4L2 IOCTL command: 0x%08X\n", cmd); |
| explain_ioctl(cmd); |
| POUT; |
| return -ENOIOCTLCMD; |
| } |
| } |
| return 0; |
| } |
| |
| long easycap_ioctl(struct file *file, unsigned int cmd, unsigned long arg) |
| { |
| struct inode *inode = file->f_dentry->d_inode; |
| long ret; |
| |
| lock_kernel(); |
| ret = easycap_ioctl_bkl(inode, file, cmd, arg); |
| unlock_kernel(); |
| |
| return ret; |
| } |
| |
| /*--------------------------------------------------------------------------*/ |
| static int easysnd_ioctl_bkl(struct inode *inode, struct file *file, |
| unsigned int cmd, unsigned long arg) |
| { |
| struct easycap *peasycap; |
| struct usb_device *p; |
| |
| peasycap = file->private_data; |
| if (NULL == peasycap) { |
| SAY("ERROR: peasycap is NULL.\n"); |
| return -1; |
| } |
| p = peasycap->pusb_device; |
| /*---------------------------------------------------------------------------*/ |
| switch (cmd) { |
| case SNDCTL_DSP_GETCAPS: { |
| int caps; |
| JOT(8, "SNDCTL_DSP_GETCAPS\n"); |
| |
| #if defined(UPSAMPLE) |
| if (true == peasycap->microphone) |
| caps = 0x04400000; |
| else |
| caps = 0x04400000; |
| #else |
| if (true == peasycap->microphone) |
| caps = 0x02400000; |
| else |
| caps = 0x04400000; |
| #endif /*UPSAMPLE*/ |
| |
| if (0 != copy_to_user((void __user *)arg, &caps, sizeof(int))) |
| return -EFAULT; |
| break; |
| } |
| case SNDCTL_DSP_GETFMTS: { |
| int incoming; |
| JOT(8, "SNDCTL_DSP_GETFMTS\n"); |
| |
| #if defined(UPSAMPLE) |
| if (true == peasycap->microphone) |
| incoming = AFMT_S16_LE; |
| else |
| incoming = AFMT_S16_LE; |
| #else |
| if (true == peasycap->microphone) |
| incoming = AFMT_S16_LE; |
| else |
| incoming = AFMT_S16_LE; |
| #endif /*UPSAMPLE*/ |
| |
| if (0 != copy_to_user((void __user *)arg, &incoming, sizeof(int))) |
| return -EFAULT; |
| break; |
| } |
| case SNDCTL_DSP_SETFMT: { |
| int incoming, outgoing; |
| JOT(8, "SNDCTL_DSP_SETFMT\n"); |
| if (0 != copy_from_user(&incoming, (void __user *)arg, sizeof(int))) |
| return -EFAULT; |
| JOT(8, "........... %i=incoming\n", incoming); |
| |
| #if defined(UPSAMPLE) |
| if (true == peasycap->microphone) |
| outgoing = AFMT_S16_LE; |
| else |
| outgoing = AFMT_S16_LE; |
| #else |
| if (true == peasycap->microphone) |
| outgoing = AFMT_S16_LE; |
| else |
| outgoing = AFMT_S16_LE; |
| #endif /*UPSAMPLE*/ |
| |
| if (incoming != outgoing) { |
| JOT(8, "........... %i=outgoing\n", outgoing); |
| JOT(8, " cf. %i=AFMT_S16_LE\n", AFMT_S16_LE); |
| JOT(8, " cf. %i=AFMT_U8\n", AFMT_U8); |
| if (0 != copy_to_user((void __user *)arg, &outgoing, \ |
| sizeof(int))) |
| return -EFAULT; |
| return -EINVAL ; |
| } |
| break; |
| } |
| case SNDCTL_DSP_STEREO: { |
| int incoming; |
| JOT(8, "SNDCTL_DSP_STEREO\n"); |
| if (0 != copy_from_user(&incoming, (void __user *)arg, sizeof(int))) |
| return -EFAULT; |
| JOT(8, "........... %i=incoming\n", incoming); |
| |
| #if defined(UPSAMPLE) |
| if (true == peasycap->microphone) |
| incoming = 1; |
| else |
| incoming = 1; |
| #else |
| if (true == peasycap->microphone) |
| incoming = 0; |
| else |
| incoming = 1; |
| #endif /*UPSAMPLE*/ |
| |
| if (0 != copy_to_user((void __user *)arg, &incoming, sizeof(int))) |
| return -EFAULT; |
| break; |
| } |
| case SNDCTL_DSP_SPEED: { |
| int incoming; |
| JOT(8, "SNDCTL_DSP_SPEED\n"); |
| if (0 != copy_from_user(&incoming, (void __user *)arg, sizeof(int))) |
| return -EFAULT; |
| JOT(8, "........... %i=incoming\n", incoming); |
| |
| #if defined(UPSAMPLE) |
| if (true == peasycap->microphone) |
| incoming = 32000; |
| else |
| incoming = 48000; |
| #else |
| if (true == peasycap->microphone) |
| incoming = 8000; |
| else |
| incoming = 48000; |
| #endif /*UPSAMPLE*/ |
| |
| if (0 != copy_to_user((void __user *)arg, &incoming, sizeof(int))) |
| return -EFAULT; |
| break; |
| } |
| case SNDCTL_DSP_GETTRIGGER: { |
| int incoming; |
| JOT(8, "SNDCTL_DSP_GETTRIGGER\n"); |
| if (0 != copy_from_user(&incoming, (void __user *)arg, sizeof(int))) |
| return -EFAULT; |
| JOT(8, "........... %i=incoming\n", incoming); |
| |
| incoming = PCM_ENABLE_INPUT; |
| if (0 != copy_to_user((void __user *)arg, &incoming, sizeof(int))) |
| return -EFAULT; |
| break; |
| } |
| case SNDCTL_DSP_SETTRIGGER: { |
| int incoming; |
| JOT(8, "SNDCTL_DSP_SETTRIGGER\n"); |
| if (0 != copy_from_user(&incoming, (void __user *)arg, sizeof(int))) |
| return -EFAULT; |
| JOT(8, "........... %i=incoming\n", incoming); |
| JOT(8, "........... cf 0x%x=PCM_ENABLE_INPUT " \ |
| "0x%x=PCM_ENABLE_OUTPUT\n", \ |
| PCM_ENABLE_INPUT, PCM_ENABLE_OUTPUT); |
| ; |
| ; |
| ; |
| ; |
| break; |
| } |
| case SNDCTL_DSP_GETBLKSIZE: { |
| int incoming; |
| JOT(8, "SNDCTL_DSP_GETBLKSIZE\n"); |
| if (0 != copy_from_user(&incoming, (void __user *)arg, sizeof(int))) |
| return -EFAULT; |
| JOT(8, "........... %i=incoming\n", incoming); |
| incoming = peasycap->audio_bytes_per_fragment; |
| if (0 != copy_to_user((void __user *)arg, &incoming, sizeof(int))) |
| return -EFAULT; |
| break; |
| } |
| case SNDCTL_DSP_GETISPACE: { |
| struct audio_buf_info audio_buf_info; |
| |
| JOT(8, "SNDCTL_DSP_GETISPACE\n"); |
| |
| audio_buf_info.bytes = peasycap->audio_bytes_per_fragment; |
| audio_buf_info.fragments = 1; |
| audio_buf_info.fragsize = 0; |
| audio_buf_info.fragstotal = 0; |
| |
| if (0 != copy_to_user((void __user *)arg, &audio_buf_info, \ |
| sizeof(int))) |
| return -EFAULT; |
| break; |
| } |
| default: { |
| JOT(8, "ERROR: unrecognized DSP IOCTL command: 0x%08X\n", cmd); |
| POUT; |
| return -ENOIOCTLCMD; |
| } |
| } |
| return 0; |
| } |
| |
| long easysnd_ioctl(struct file *file, unsigned int cmd, unsigned long arg) |
| { |
| struct inode *inode = file->f_dentry->d_inode; |
| long ret; |
| |
| lock_kernel(); |
| ret = easysnd_ioctl_bkl(inode, file, cmd, arg); |
| unlock_kernel(); |
| |
| return ret; |
| } |
| |
| /*****************************************************************************/ |
| int explain_ioctl(__u32 wot) |
| { |
| int k; |
| /*---------------------------------------------------------------------------*/ |
| /* |
| * THE DATA FOR THE ARRAY mess BELOW WERE CONSTRUCTED BY RUNNING THE FOLLOWING |
| * SHELL SCRIPT: |
| * # |
| * cat /usr/src/linux-headers-`uname -r`/include/linux/videodev2.h | \ |
| * grep "^#define VIDIOC_" - | grep -v "_OLD" - | \ |
| * sed -e "s,_IO.*$,,;p" | sed -e "N;s,\n,, " | \ |
| * sed -e "s/^#define / {/;s/#define /, \"/;s/$/\"},/" | \ |
| * sed -e "s, ,,g;s, ,,g" >ioctl.tmp |
| * echo "{0xFFFFFFFF,\"\"}" >>ioctl.tmp |
| * exit 0 |
| * # |
| * AND REINSTATING THE EXCISED "_OLD" CASES WERE LATER MANUALLY. |
| * |
| * THE DATA FOR THE ARRAY mess1 BELOW WERE CONSTRUCTED BY RUNNING THE FOLLOWING |
| * SHELL SCRIPT: |
| * cat /usr/src/linux-headers-`uname -r`/include/linux/videodev.h | \ |
| * grep "^#define VIDIOC" - | grep -v "_OLD" - | \ |
| * sed -e "s,_IO.*$,,;p" | sed -e "N;s,\n,, " | \ |
| * sed -e "s/^#define / {/;s/#define /, \"/;s/$/\"},/" | \ |
| * sed -e "s, ,,g;s, ,,g" >ioctl.tmp |
| * echo "{0xFFFFFFFF,\"\"}" >>ioctl.tmp |
| * exit 0 |
| * # |
| */ |
| /*---------------------------------------------------------------------------*/ |
| static struct mess { |
| __u32 command; |
| char name[64]; |
| } mess[] = { |
| #if defined(VIDIOC_QUERYCAP) |
| {VIDIOC_QUERYCAP, "VIDIOC_QUERYCAP"}, |
| #endif |
| #if defined(VIDIOC_RESERVED) |
| {VIDIOC_RESERVED, "VIDIOC_RESERVED"}, |
| #endif |
| #if defined(VIDIOC_ENUM_FMT) |
| {VIDIOC_ENUM_FMT, "VIDIOC_ENUM_FMT"}, |
| #endif |
| #if defined(VIDIOC_G_FMT) |
| {VIDIOC_G_FMT, "VIDIOC_G_FMT"}, |
| #endif |
| #if defined(VIDIOC_S_FMT) |
| {VIDIOC_S_FMT, "VIDIOC_S_FMT"}, |
| #endif |
| #if defined(VIDIOC_REQBUFS) |
| {VIDIOC_REQBUFS, "VIDIOC_REQBUFS"}, |
| #endif |
| #if defined(VIDIOC_QUERYBUF) |
| {VIDIOC_QUERYBUF, "VIDIOC_QUERYBUF"}, |
| #endif |
| #if defined(VIDIOC_G_FBUF) |
| {VIDIOC_G_FBUF, "VIDIOC_G_FBUF"}, |
| #endif |
| #if defined(VIDIOC_S_FBUF) |
| {VIDIOC_S_FBUF, "VIDIOC_S_FBUF"}, |
| #endif |
| #if defined(VIDIOC_OVERLAY) |
| {VIDIOC_OVERLAY, "VIDIOC_OVERLAY"}, |
| #endif |
| #if defined(VIDIOC_QBUF) |
| {VIDIOC_QBUF, "VIDIOC_QBUF"}, |
| #endif |
| #if defined(VIDIOC_DQBUF) |
| {VIDIOC_DQBUF, "VIDIOC_DQBUF"}, |
| #endif |
| #if defined(VIDIOC_STREAMON) |
| {VIDIOC_STREAMON, "VIDIOC_STREAMON"}, |
| #endif |
| #if defined(VIDIOC_STREAMOFF) |
| {VIDIOC_STREAMOFF, "VIDIOC_STREAMOFF"}, |
| #endif |
| #if defined(VIDIOC_G_PARM) |
| {VIDIOC_G_PARM, "VIDIOC_G_PARM"}, |
| #endif |
| #if defined(VIDIOC_S_PARM) |
| {VIDIOC_S_PARM, "VIDIOC_S_PARM"}, |
| #endif |
| #if defined(VIDIOC_G_STD) |
| {VIDIOC_G_STD, "VIDIOC_G_STD"}, |
| #endif |
| #if defined(VIDIOC_S_STD) |
| {VIDIOC_S_STD, "VIDIOC_S_STD"}, |
| #endif |
| #if defined(VIDIOC_ENUMSTD) |
| {VIDIOC_ENUMSTD, "VIDIOC_ENUMSTD"}, |
| #endif |
| #if defined(VIDIOC_ENUMINPUT) |
| {VIDIOC_ENUMINPUT, "VIDIOC_ENUMINPUT"}, |
| #endif |
| #if defined(VIDIOC_G_CTRL) |
| {VIDIOC_G_CTRL, "VIDIOC_G_CTRL"}, |
| #endif |
| #if defined(VIDIOC_S_CTRL) |
| {VIDIOC_S_CTRL, "VIDIOC_S_CTRL"}, |
| #endif |
| #if defined(VIDIOC_G_TUNER) |
| {VIDIOC_G_TUNER, "VIDIOC_G_TUNER"}, |
| #endif |
| #if defined(VIDIOC_S_TUNER) |
| {VIDIOC_S_TUNER, "VIDIOC_S_TUNER"}, |
| #endif |
| #if defined(VIDIOC_G_AUDIO) |
| {VIDIOC_G_AUDIO, "VIDIOC_G_AUDIO"}, |
| #endif |
| #if defined(VIDIOC_S_AUDIO) |
| {VIDIOC_S_AUDIO, "VIDIOC_S_AUDIO"}, |
| #endif |
| #if defined(VIDIOC_QUERYCTRL) |
| {VIDIOC_QUERYCTRL, "VIDIOC_QUERYCTRL"}, |
| #endif |
| #if defined(VIDIOC_QUERYMENU) |
| {VIDIOC_QUERYMENU, "VIDIOC_QUERYMENU"}, |
| #endif |
| #if defined(VIDIOC_G_INPUT) |
| {VIDIOC_G_INPUT, "VIDIOC_G_INPUT"}, |
| #endif |
| #if defined(VIDIOC_S_INPUT) |
| {VIDIOC_S_INPUT, "VIDIOC_S_INPUT"}, |
| #endif |
| #if defined(VIDIOC_G_OUTPUT) |
| {VIDIOC_G_OUTPUT, "VIDIOC_G_OUTPUT"}, |
| #endif |
| #if defined(VIDIOC_S_OUTPUT) |
| {VIDIOC_S_OUTPUT, "VIDIOC_S_OUTPUT"}, |
| #endif |
| #if defined(VIDIOC_ENUMOUTPUT) |
| {VIDIOC_ENUMOUTPUT, "VIDIOC_ENUMOUTPUT"}, |
| #endif |
| #if defined(VIDIOC_G_AUDOUT) |
| {VIDIOC_G_AUDOUT, "VIDIOC_G_AUDOUT"}, |
| #endif |
| #if defined(VIDIOC_S_AUDOUT) |
| {VIDIOC_S_AUDOUT, "VIDIOC_S_AUDOUT"}, |
| #endif |
| #if defined(VIDIOC_G_MODULATOR) |
| {VIDIOC_G_MODULATOR, "VIDIOC_G_MODULATOR"}, |
| #endif |
| #if defined(VIDIOC_S_MODULATOR) |
| {VIDIOC_S_MODULATOR, "VIDIOC_S_MODULATOR"}, |
| #endif |
| #if defined(VIDIOC_G_FREQUENCY) |
| {VIDIOC_G_FREQUENCY, "VIDIOC_G_FREQUENCY"}, |
| #endif |
| #if defined(VIDIOC_S_FREQUENCY) |
| {VIDIOC_S_FREQUENCY, "VIDIOC_S_FREQUENCY"}, |
| #endif |
| #if defined(VIDIOC_CROPCAP) |
| {VIDIOC_CROPCAP, "VIDIOC_CROPCAP"}, |
| #endif |
| #if defined(VIDIOC_G_CROP) |
| {VIDIOC_G_CROP, "VIDIOC_G_CROP"}, |
| #endif |
| #if defined(VIDIOC_S_CROP) |
| {VIDIOC_S_CROP, "VIDIOC_S_CROP"}, |
| #endif |
| #if defined(VIDIOC_G_JPEGCOMP) |
| {VIDIOC_G_JPEGCOMP, "VIDIOC_G_JPEGCOMP"}, |
| #endif |
| #if defined(VIDIOC_S_JPEGCOMP) |
| {VIDIOC_S_JPEGCOMP, "VIDIOC_S_JPEGCOMP"}, |
| #endif |
| #if defined(VIDIOC_QUERYSTD) |
| {VIDIOC_QUERYSTD, "VIDIOC_QUERYSTD"}, |
| #endif |
| #if defined(VIDIOC_TRY_FMT) |
| {VIDIOC_TRY_FMT, "VIDIOC_TRY_FMT"}, |
| #endif |
| #if defined(VIDIOC_ENUMAUDIO) |
| {VIDIOC_ENUMAUDIO, "VIDIOC_ENUMAUDIO"}, |
| #endif |
| #if defined(VIDIOC_ENUMAUDOUT) |
| {VIDIOC_ENUMAUDOUT, "VIDIOC_ENUMAUDOUT"}, |
| #endif |
| #if defined(VIDIOC_G_PRIORITY) |
| {VIDIOC_G_PRIORITY, "VIDIOC_G_PRIORITY"}, |
| #endif |
| #if defined(VIDIOC_S_PRIORITY) |
| {VIDIOC_S_PRIORITY, "VIDIOC_S_PRIORITY"}, |
| #endif |
| #if defined(VIDIOC_G_SLICED_VBI_CAP) |
| {VIDIOC_G_SLICED_VBI_CAP, "VIDIOC_G_SLICED_VBI_CAP"}, |
| #endif |
| #if defined(VIDIOC_LOG_STATUS) |
| {VIDIOC_LOG_STATUS, "VIDIOC_LOG_STATUS"}, |
| #endif |
| #if defined(VIDIOC_G_EXT_CTRLS) |
| {VIDIOC_G_EXT_CTRLS, "VIDIOC_G_EXT_CTRLS"}, |
| #endif |
| #if defined(VIDIOC_S_EXT_CTRLS) |
| {VIDIOC_S_EXT_CTRLS, "VIDIOC_S_EXT_CTRLS"}, |
| #endif |
| #if defined(VIDIOC_TRY_EXT_CTRLS) |
| {VIDIOC_TRY_EXT_CTRLS, "VIDIOC_TRY_EXT_CTRLS"}, |
| #endif |
| #if defined(VIDIOC_ENUM_FRAMESIZES) |
| {VIDIOC_ENUM_FRAMESIZES, "VIDIOC_ENUM_FRAMESIZES"}, |
| #endif |
| #if defined(VIDIOC_ENUM_FRAMEINTERVALS) |
| {VIDIOC_ENUM_FRAMEINTERVALS, "VIDIOC_ENUM_FRAMEINTERVALS"}, |
| #endif |
| #if defined(VIDIOC_G_ENC_INDEX) |
| {VIDIOC_G_ENC_INDEX, "VIDIOC_G_ENC_INDEX"}, |
| #endif |
| #if defined(VIDIOC_ENCODER_CMD) |
| {VIDIOC_ENCODER_CMD, "VIDIOC_ENCODER_CMD"}, |
| #endif |
| #if defined(VIDIOC_TRY_ENCODER_CMD) |
| {VIDIOC_TRY_ENCODER_CMD, "VIDIOC_TRY_ENCODER_CMD"}, |
| #endif |
| #if defined(VIDIOC_G_CHIP_IDENT) |
| {VIDIOC_G_CHIP_IDENT, "VIDIOC_G_CHIP_IDENT"}, |
| #endif |
| |
| #if defined(VIDIOC_OVERLAY_OLD) |
| {VIDIOC_OVERLAY_OLD, "VIDIOC_OVERLAY_OLD"}, |
| #endif |
| #if defined(VIDIOC_S_PARM_OLD) |
| {VIDIOC_S_PARM_OLD, "VIDIOC_S_PARM_OLD"}, |
| #endif |
| #if defined(VIDIOC_S_CTRL_OLD) |
| {VIDIOC_S_CTRL_OLD, "VIDIOC_S_CTRL_OLD"}, |
| #endif |
| #if defined(VIDIOC_G_AUDIO_OLD) |
| {VIDIOC_G_AUDIO_OLD, "VIDIOC_G_AUDIO_OLD"}, |
| #endif |
| #if defined(VIDIOC_G_AUDOUT_OLD) |
| {VIDIOC_G_AUDOUT_OLD, "VIDIOC_G_AUDOUT_OLD"}, |
| #endif |
| #if defined(VIDIOC_CROPCAP_OLD) |
| {VIDIOC_CROPCAP_OLD, "VIDIOC_CROPCAP_OLD"}, |
| #endif |
| {0xFFFFFFFF, ""} |
| }; |
| |
| static struct mess mess1[] = \ |
| { |
| #if defined(VIDIOCGCAP) |
| {VIDIOCGCAP, "VIDIOCGCAP"}, |
| #endif |
| #if defined(VIDIOCGCHAN) |
| {VIDIOCGCHAN, "VIDIOCGCHAN"}, |
| #endif |
| #if defined(VIDIOCSCHAN) |
| {VIDIOCSCHAN, "VIDIOCSCHAN"}, |
| #endif |
| #if defined(VIDIOCGTUNER) |
| {VIDIOCGTUNER, "VIDIOCGTUNER"}, |
| #endif |
| #if defined(VIDIOCSTUNER) |
| {VIDIOCSTUNER, "VIDIOCSTUNER"}, |
| #endif |
| #if defined(VIDIOCGPICT) |
| {VIDIOCGPICT, "VIDIOCGPICT"}, |
| #endif |
| #if defined(VIDIOCSPICT) |
| {VIDIOCSPICT, "VIDIOCSPICT"}, |
| #endif |
| #if defined(VIDIOCCAPTURE) |
| {VIDIOCCAPTURE, "VIDIOCCAPTURE"}, |
| #endif |
| #if defined(VIDIOCGWIN) |
| {VIDIOCGWIN, "VIDIOCGWIN"}, |
| #endif |
| #if defined(VIDIOCSWIN) |
| {VIDIOCSWIN, "VIDIOCSWIN"}, |
| #endif |
| #if defined(VIDIOCGFBUF) |
| {VIDIOCGFBUF, "VIDIOCGFBUF"}, |
| #endif |
| #if defined(VIDIOCSFBUF) |
| {VIDIOCSFBUF, "VIDIOCSFBUF"}, |
| #endif |
| #if defined(VIDIOCKEY) |
| {VIDIOCKEY, "VIDIOCKEY"}, |
| #endif |
| #if defined(VIDIOCGFREQ) |
| {VIDIOCGFREQ, "VIDIOCGFREQ"}, |
| #endif |
| #if defined(VIDIOCSFREQ) |
| {VIDIOCSFREQ, "VIDIOCSFREQ"}, |
| #endif |
| #if defined(VIDIOCGAUDIO) |
| {VIDIOCGAUDIO, "VIDIOCGAUDIO"}, |
| #endif |
| #if defined(VIDIOCSAUDIO) |
| {VIDIOCSAUDIO, "VIDIOCSAUDIO"}, |
| #endif |
| #if defined(VIDIOCSYNC) |
| {VIDIOCSYNC, "VIDIOCSYNC"}, |
| #endif |
| #if defined(VIDIOCMCAPTURE) |
| {VIDIOCMCAPTURE, "VIDIOCMCAPTURE"}, |
| #endif |
| #if defined(VIDIOCGMBUF) |
| {VIDIOCGMBUF, "VIDIOCGMBUF"}, |
| #endif |
| #if defined(VIDIOCGUNIT) |
| {VIDIOCGUNIT, "VIDIOCGUNIT"}, |
| #endif |
| #if defined(VIDIOCGCAPTURE) |
| {VIDIOCGCAPTURE, "VIDIOCGCAPTURE"}, |
| #endif |
| #if defined(VIDIOCSCAPTURE) |
| {VIDIOCSCAPTURE, "VIDIOCSCAPTURE"}, |
| #endif |
| #if defined(VIDIOCSPLAYMODE) |
| {VIDIOCSPLAYMODE, "VIDIOCSPLAYMODE"}, |
| #endif |
| #if defined(VIDIOCSWRITEMODE) |
| {VIDIOCSWRITEMODE, "VIDIOCSWRITEMODE"}, |
| #endif |
| #if defined(VIDIOCGPLAYINFO) |
| {VIDIOCGPLAYINFO, "VIDIOCGPLAYINFO"}, |
| #endif |
| #if defined(VIDIOCSMICROCODE) |
| {VIDIOCSMICROCODE, "VIDIOCSMICROCODE"}, |
| #endif |
| {0xFFFFFFFF, ""} |
| }; |
| |
| k = 0; |
| while (mess[k].name[0]) { |
| if (wot == mess[k].command) { |
| JOT(8, "ioctl 0x%08X is %s\n", \ |
| mess[k].command, &mess[k].name[0]); |
| return 0; |
| } |
| k++; |
| } |
| JOT(8, "ioctl 0x%08X is not in videodev2.h\n", wot); |
| |
| k = 0; |
| while (mess1[k].name[0]) { |
| if (wot == mess1[k].command) { |
| JOT(8, "ioctl 0x%08X is %s (V4L1)\n", \ |
| mess1[k].command, &mess1[k].name[0]); |
| return 0; |
| } |
| k++; |
| } |
| JOT(8, "ioctl 0x%08X is not in videodev.h\n", wot); |
| return -1; |
| } |
| /*****************************************************************************/ |
| int explain_cid(__u32 wot) |
| { |
| int k; |
| /*---------------------------------------------------------------------------*/ |
| /* |
| * THE DATA FOR THE ARRAY mess BELOW WERE CONSTRUCTED BY RUNNING THE FOLLOWING |
| * SHELL SCRIPT: |
| * # |
| * cat /usr/src/linux-headers-`uname -r`/include/linux/videodev2.h | \ |
| * grep "^#define V4L2_CID_" | \ |
| * sed -e "s,(.*$,,;p" | sed -e "N;s,\n,, " | \ |
| * sed -e "s/^#define / {/;s/#define /, \"/;s/$/\"},/" | \ |
| * sed -e "s, ,,g;s, ,,g" | grep -v "_BASE" | grep -v "MPEG" >cid.tmp |
| * echo "{0xFFFFFFFF,\"\"}" >>cid.tmp |
| * exit 0 |
| * # |
| */ |
| /*---------------------------------------------------------------------------*/ |
| static struct mess |
| { |
| __u32 command; |
| char name[64]; |
| } mess[] = { |
| #if defined(V4L2_CID_USER_CLASS) |
| {V4L2_CID_USER_CLASS, "V4L2_CID_USER_CLASS"}, |
| #endif |
| #if defined(V4L2_CID_BRIGHTNESS) |
| {V4L2_CID_BRIGHTNESS, "V4L2_CID_BRIGHTNESS"}, |
| #endif |
| #if defined(V4L2_CID_CONTRAST) |
| {V4L2_CID_CONTRAST, "V4L2_CID_CONTRAST"}, |
| #endif |
| #if defined(V4L2_CID_SATURATION) |
| {V4L2_CID_SATURATION, "V4L2_CID_SATURATION"}, |
| #endif |
| #if defined(V4L2_CID_HUE) |
| {V4L2_CID_HUE, "V4L2_CID_HUE"}, |
| #endif |
| #if defined(V4L2_CID_AUDIO_VOLUME) |
| {V4L2_CID_AUDIO_VOLUME, "V4L2_CID_AUDIO_VOLUME"}, |
| #endif |
| #if defined(V4L2_CID_AUDIO_BALANCE) |
| {V4L2_CID_AUDIO_BALANCE, "V4L2_CID_AUDIO_BALANCE"}, |
| #endif |
| #if defined(V4L2_CID_AUDIO_BASS) |
| {V4L2_CID_AUDIO_BASS, "V4L2_CID_AUDIO_BASS"}, |
| #endif |
| #if defined(V4L2_CID_AUDIO_TREBLE) |
| {V4L2_CID_AUDIO_TREBLE, "V4L2_CID_AUDIO_TREBLE"}, |
| #endif |
| #if defined(V4L2_CID_AUDIO_MUTE) |
| {V4L2_CID_AUDIO_MUTE, "V4L2_CID_AUDIO_MUTE"}, |
| #endif |
| #if defined(V4L2_CID_AUDIO_LOUDNESS) |
| {V4L2_CID_AUDIO_LOUDNESS, "V4L2_CID_AUDIO_LOUDNESS"}, |
| #endif |
| #if defined(V4L2_CID_BLACK_LEVEL) |
| {V4L2_CID_BLACK_LEVEL, "V4L2_CID_BLACK_LEVEL"}, |
| #endif |
| #if defined(V4L2_CID_AUTO_WHITE_BALANCE) |
| {V4L2_CID_AUTO_WHITE_BALANCE, "V4L2_CID_AUTO_WHITE_BALANCE"}, |
| #endif |
| #if defined(V4L2_CID_DO_WHITE_BALANCE) |
| {V4L2_CID_DO_WHITE_BALANCE, "V4L2_CID_DO_WHITE_BALANCE"}, |
| #endif |
| #if defined(V4L2_CID_RED_BALANCE) |
| {V4L2_CID_RED_BALANCE, "V4L2_CID_RED_BALANCE"}, |
| #endif |
| #if defined(V4L2_CID_BLUE_BALANCE) |
| {V4L2_CID_BLUE_BALANCE, "V4L2_CID_BLUE_BALANCE"}, |
| #endif |
| #if defined(V4L2_CID_GAMMA) |
| {V4L2_CID_GAMMA, "V4L2_CID_GAMMA"}, |
| #endif |
| #if defined(V4L2_CID_WHITENESS) |
| {V4L2_CID_WHITENESS, "V4L2_CID_WHITENESS"}, |
| #endif |
| #if defined(V4L2_CID_EXPOSURE) |
| {V4L2_CID_EXPOSURE, "V4L2_CID_EXPOSURE"}, |
| #endif |
| #if defined(V4L2_CID_AUTOGAIN) |
| {V4L2_CID_AUTOGAIN, "V4L2_CID_AUTOGAIN"}, |
| #endif |
| #if defined(V4L2_CID_GAIN) |
| {V4L2_CID_GAIN, "V4L2_CID_GAIN"}, |
| #endif |
| #if defined(V4L2_CID_HFLIP) |
| {V4L2_CID_HFLIP, "V4L2_CID_HFLIP"}, |
| #endif |
| #if defined(V4L2_CID_VFLIP) |
| {V4L2_CID_VFLIP, "V4L2_CID_VFLIP"}, |
| #endif |
| #if defined(V4L2_CID_HCENTER) |
| {V4L2_CID_HCENTER, "V4L2_CID_HCENTER"}, |
| #endif |
| #if defined(V4L2_CID_VCENTER) |
| {V4L2_CID_VCENTER, "V4L2_CID_VCENTER"}, |
| #endif |
| #if defined(V4L2_CID_POWER_LINE_FREQUENCY) |
| {V4L2_CID_POWER_LINE_FREQUENCY, "V4L2_CID_POWER_LINE_FREQUENCY"}, |
| #endif |
| #if defined(V4L2_CID_HUE_AUTO) |
| {V4L2_CID_HUE_AUTO, "V4L2_CID_HUE_AUTO"}, |
| #endif |
| #if defined(V4L2_CID_WHITE_BALANCE_TEMPERATURE) |
| {V4L2_CID_WHITE_BALANCE_TEMPERATURE, "V4L2_CID_WHITE_BALANCE_TEMPERATURE"}, |
| #endif |
| #if defined(V4L2_CID_SHARPNESS) |
| {V4L2_CID_SHARPNESS, "V4L2_CID_SHARPNESS"}, |
| #endif |
| #if defined(V4L2_CID_BACKLIGHT_COMPENSATION) |
| {V4L2_CID_BACKLIGHT_COMPENSATION, "V4L2_CID_BACKLIGHT_COMPENSATION"}, |
| #endif |
| #if defined(V4L2_CID_CHROMA_AGC) |
| {V4L2_CID_CHROMA_AGC, "V4L2_CID_CHROMA_AGC"}, |
| #endif |
| #if defined(V4L2_CID_COLOR_KILLER) |
| {V4L2_CID_COLOR_KILLER, "V4L2_CID_COLOR_KILLER"}, |
| #endif |
| #if defined(V4L2_CID_LASTP1) |
| {V4L2_CID_LASTP1, "V4L2_CID_LASTP1"}, |
| #endif |
| #if defined(V4L2_CID_CAMERA_CLASS) |
| {V4L2_CID_CAMERA_CLASS, "V4L2_CID_CAMERA_CLASS"}, |
| #endif |
| #if defined(V4L2_CID_EXPOSURE_AUTO) |
| {V4L2_CID_EXPOSURE_AUTO, "V4L2_CID_EXPOSURE_AUTO"}, |
| #endif |
| #if defined(V4L2_CID_EXPOSURE_ABSOLUTE) |
| {V4L2_CID_EXPOSURE_ABSOLUTE, "V4L2_CID_EXPOSURE_ABSOLUTE"}, |
| #endif |
| #if defined(V4L2_CID_EXPOSURE_AUTO_PRIORITY) |
| {V4L2_CID_EXPOSURE_AUTO_PRIORITY, "V4L2_CID_EXPOSURE_AUTO_PRIORITY"}, |
| #endif |
| #if defined(V4L2_CID_PAN_RELATIVE) |
| {V4L2_CID_PAN_RELATIVE, "V4L2_CID_PAN_RELATIVE"}, |
| #endif |
| #if defined(V4L2_CID_TILT_RELATIVE) |
| {V4L2_CID_TILT_RELATIVE, "V4L2_CID_TILT_RELATIVE"}, |
| #endif |
| #if defined(V4L2_CID_PAN_RESET) |
| {V4L2_CID_PAN_RESET, "V4L2_CID_PAN_RESET"}, |
| #endif |
| #if defined(V4L2_CID_TILT_RESET) |
| {V4L2_CID_TILT_RESET, "V4L2_CID_TILT_RESET"}, |
| #endif |
| #if defined(V4L2_CID_PAN_ABSOLUTE) |
| {V4L2_CID_PAN_ABSOLUTE, "V4L2_CID_PAN_ABSOLUTE"}, |
| #endif |
| #if defined(V4L2_CID_TILT_ABSOLUTE) |
| {V4L2_CID_TILT_ABSOLUTE, "V4L2_CID_TILT_ABSOLUTE"}, |
| #endif |
| #if defined(V4L2_CID_FOCUS_ABSOLUTE) |
| {V4L2_CID_FOCUS_ABSOLUTE, "V4L2_CID_FOCUS_ABSOLUTE"}, |
| #endif |
| #if defined(V4L2_CID_FOCUS_RELATIVE) |
| {V4L2_CID_FOCUS_RELATIVE, "V4L2_CID_FOCUS_RELATIVE"}, |
| #endif |
| #if defined(V4L2_CID_FOCUS_AUTO) |
| {V4L2_CID_FOCUS_AUTO, "V4L2_CID_FOCUS_AUTO"}, |
| #endif |
| {0xFFFFFFFF, ""} |
| }; |
| |
| k = 0; |
| while (mess[k].name[0]) { |
| if (wot == mess[k].command) { |
| JOT(8, "ioctl 0x%08X is %s\n", \ |
| mess[k].command, &mess[k].name[0]); |
| return 0; |
| } |
| k++; |
| } |
| JOT(8, "cid 0x%08X is not in videodev2.h\n", wot); |
| return -1; |
| } |
| /*****************************************************************************/ |