LCOV - code coverage report
Current view: top level - dev/usb - utvfu.c (source / functions) Hit Total Coverage
Test: 6.4 Lines: 0 793 0.0 %
Date: 2018-10-19 03:25:38 Functions: 0 76 0.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*      $OpenBSD: utvfu.c,v 1.9 2016/09/19 06:46:44 ratchov Exp $ */
       2             : /*
       3             :  * Copyright (c) 2013 Lubomir Rintel
       4             :  * Copyright (c) 2013 Federico Simoncelli
       5             :  * All rights reserved.
       6             :  *
       7             :  * Redistribution and use in source and binary forms, with or without
       8             :  * modification, are permitted provided that the following conditions
       9             :  * are met:
      10             :  * 1. Redistributions of source code must retain the above copyright
      11             :  *    notice, this list of conditions, and the following disclaimer,
      12             :  *    without modification.
      13             :  * 2. The name of the author may not be used to endorse or promote products
      14             :  *    derived from this software without specific prior written permission.
      15             :  *
      16             :  * Alternatively, this software may be distributed under the terms of the
      17             :  * GNU General Public License ("GPL").
      18             :  *
      19             :  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
      20             :  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
      21             :  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
      22             :  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
      23             :  * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
      24             :  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
      25             :  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
      26             :  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
      27             :  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
      28             :  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
      29             :  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
      30             :  */
      31             : /*
      32             :  * Fushicai USBTV007 Audio-Video Grabber Driver
      33             :  *
      34             :  * Product web site:
      35             :  * http://www.fushicai.com/products_detail/&productId=d05449ee-b690-42f9-a661-aa7353894bed.html
      36             :  *
      37             :  * Following LWN articles were very useful in construction of this driver:
      38             :  * Video4Linux2 API series: http://lwn.net/Articles/203924/
      39             :  * videobuf2 API explanation: http://lwn.net/Articles/447435/
      40             :  * Thanks go to Jonathan Corbet for providing this quality documentation.
      41             :  * He is awesome.
      42             :  *
      43             :  * No physical hardware was harmed running Windows during the
      44             :  * reverse-engineering activity
      45             :  */
      46             : 
      47             : #include <sys/param.h>
      48             : #include <sys/systm.h>
      49             : #include <sys/fcntl.h>
      50             : #include <sys/kernel.h>
      51             : #include <sys/kthread.h>
      52             : #include <sys/malloc.h>
      53             : #include <sys/device.h>
      54             : #include <sys/audioio.h>
      55             : #include <sys/videoio.h>
      56             : 
      57             : #include <uvm/uvm_extern.h>
      58             : 
      59             : #include <machine/bus.h>
      60             : 
      61             : #include <dev/audio_if.h>
      62             : #include <dev/usb/usb.h>
      63             : #include <dev/usb/usbdi.h>
      64             : #include <dev/usb/usbdivar.h>
      65             : #include <dev/usb/usb_mem.h>
      66             : #include <dev/usb/usbdi_util.h>
      67             : #include <dev/usb/usbdevs.h>
      68             : #include <dev/video_if.h>
      69             : 
      70             : #include "utvfu.h"
      71             : 
      72             : #ifdef UTVFU_DEBUG
      73             : int utvfu_debug = 1;
      74             : #define DPRINTF(l, x...) do { if ((l) <= utvfu_debug) printf(x); } while (0)
      75             : #else
      76             : #define DPRINTF(l, x...)
      77             : #endif
      78             : 
      79             : #define DEVNAME(_s) ((_s)->sc_dev.dv_xname)
      80             : 
      81             : struct utvfu_norm_params utvfu_norm_params[] = {
      82             :         {
      83             :                 .norm = V4L2_STD_525_60,
      84             :                 .cap_width = 720,
      85             :                 .cap_height = 480,
      86             :                 /* 4 bytes/2 pixel YUYV/YUV 4:2:2 */
      87             :                 .frame_len = (720 * 480 * 2),
      88             :         },
      89             :         {
      90             :                 .norm = V4L2_STD_PAL,
      91             :                 .cap_width = 720,
      92             :                 .cap_height = 576,
      93             :                 /* 4 bytes/2 pixel YUYV/YUV 4:2:2 */
      94             :                 .frame_len = (720 * 576 * 2),
      95             :         }
      96             : };
      97             : 
      98             : int
      99           0 : utvfu_set_regs(struct utvfu_softc *sc, const uint16_t regs[][2], int size)
     100             : {
     101             :         int i;
     102             :         usbd_status error;
     103           0 :         usb_device_request_t req;
     104             : 
     105           0 :         req.bmRequestType = UT_WRITE_VENDOR_DEVICE;
     106           0 :         req.bRequest = UTVFU_REQUEST_REG;
     107           0 :         USETW(req.wLength, 0);
     108             : 
     109           0 :         for (i = 0; i < size; i++) {
     110           0 :                 USETW(req.wIndex, regs[i][0]);
     111           0 :                 USETW(req.wValue, regs[i][1]);
     112             : 
     113           0 :                 error = usbd_do_request(sc->sc_udev, &req, NULL);
     114           0 :                 if (error != USBD_NORMAL_COMPLETION) {
     115             :                         DPRINTF(1, "%s: %s: exit EINVAL\n",
     116             :                             DEVNAME(sc), __func__);
     117           0 :                         return (EINVAL);
     118             :                 }
     119             :         }
     120             : 
     121           0 :         return (0);
     122           0 : }
     123             : 
     124             : int
     125           0 : utvfu_max_frame_size(void)
     126             : {
     127             :         int     i, sz = 0;
     128           0 :         for (i = 0; i < nitems(utvfu_norm_params); i++) {
     129           0 :                 if (sz < utvfu_norm_params[i].frame_len)
     130           0 :                         sz = utvfu_norm_params[i].frame_len;
     131             :         }
     132           0 :         return (sz);
     133             : }
     134             : 
     135             : int
     136           0 : utvfu_configure_for_norm(struct utvfu_softc *sc, v4l2_std_id norm)
     137             : {
     138             :         int i, ret = EINVAL;
     139             :         struct utvfu_norm_params *params = NULL;
     140             : 
     141           0 :         for (i = 0; i < nitems(utvfu_norm_params); i++) {
     142           0 :                 if (utvfu_norm_params[i].norm & norm) {
     143             :                         params = &utvfu_norm_params[i];
     144           0 :                         break;
     145             :                 }
     146             :         }
     147             : 
     148           0 :         if (params != NULL) {
     149           0 :                 sc->sc_normi = i;
     150           0 :                 sc->sc_nchunks = params->cap_width * params->cap_height
     151           0 :                     / 4 / UTVFU_CHUNK;
     152             :                 ret = 0;
     153           0 :         }
     154             : 
     155           0 :         return (ret);
     156             : }
     157             : 
     158             : int
     159           0 : utvfu_select_input(struct utvfu_softc *sc, int input)
     160             : {
     161             :         int ret;
     162             : 
     163             :         static const uint16_t composite[][2] = {
     164             :                 { UTVFU_BASE + 0x0105, 0x0060 },
     165             :                 { UTVFU_BASE + 0x011f, 0x00f2 },
     166             :                 { UTVFU_BASE + 0x0127, 0x0060 },
     167             :                 { UTVFU_BASE + 0x00ae, 0x0010 },
     168             :                 { UTVFU_BASE + 0x0239, 0x0060 },
     169             :         };
     170             : 
     171             :         static const uint16_t svideo[][2] = {
     172             :                 { UTVFU_BASE + 0x0105, 0x0010 },
     173             :                 { UTVFU_BASE + 0x011f, 0x00ff },
     174             :                 { UTVFU_BASE + 0x0127, 0x0060 },
     175             :                 { UTVFU_BASE + 0x00ae, 0x0030 },
     176             :                 { UTVFU_BASE + 0x0239, 0x0060 },
     177             :         };
     178             : 
     179           0 :         switch (input) {
     180             :         case UTVFU_COMPOSITE_INPUT:
     181           0 :                 ret = utvfu_set_regs(sc, composite, nitems(composite));
     182           0 :                 break;
     183             :         case UTVFU_SVIDEO_INPUT:
     184           0 :                 ret = utvfu_set_regs(sc, svideo, nitems(svideo));
     185           0 :                 break;
     186             :         default:
     187             :                 ret = EINVAL;
     188           0 :         }
     189             : 
     190           0 :         if (ret == 0)
     191           0 :                 sc->sc_input = input;
     192             : 
     193           0 :         return (ret);
     194             : }
     195             : 
     196             : int
     197           0 : utvfu_select_norm(struct utvfu_softc *sc, v4l2_std_id norm)
     198             : {
     199             :         int ret;
     200             :         static const uint16_t pal[][2] = {
     201             :                 { UTVFU_BASE + 0x001a, 0x0068 },
     202             :                 { UTVFU_BASE + 0x010e, 0x0072 },
     203             :                 { UTVFU_BASE + 0x010f, 0x00a2 },
     204             :                 { UTVFU_BASE + 0x0112, 0x00b0 },
     205             :                 { UTVFU_BASE + 0x0117, 0x0001 },
     206             :                 { UTVFU_BASE + 0x0118, 0x002c },
     207             :                 { UTVFU_BASE + 0x012d, 0x0010 },
     208             :                 { UTVFU_BASE + 0x012f, 0x0020 },
     209             :                 { UTVFU_BASE + 0x024f, 0x0002 },
     210             :                 { UTVFU_BASE + 0x0254, 0x0059 },
     211             :                 { UTVFU_BASE + 0x025a, 0x0016 },
     212             :                 { UTVFU_BASE + 0x025b, 0x0035 },
     213             :                 { UTVFU_BASE + 0x0263, 0x0017 },
     214             :                 { UTVFU_BASE + 0x0266, 0x0016 },
     215             :                 { UTVFU_BASE + 0x0267, 0x0036 }
     216             :         };
     217             : 
     218             :         static const uint16_t ntsc[][2] = {
     219             :                 { UTVFU_BASE + 0x001a, 0x0079 },
     220             :                 { UTVFU_BASE + 0x010e, 0x0068 },
     221             :                 { UTVFU_BASE + 0x010f, 0x009c },
     222             :                 { UTVFU_BASE + 0x0112, 0x00f0 },
     223             :                 { UTVFU_BASE + 0x0117, 0x0000 },
     224             :                 { UTVFU_BASE + 0x0118, 0x00fc },
     225             :                 { UTVFU_BASE + 0x012d, 0x0004 },
     226             :                 { UTVFU_BASE + 0x012f, 0x0008 },
     227             :                 { UTVFU_BASE + 0x024f, 0x0001 },
     228             :                 { UTVFU_BASE + 0x0254, 0x005f },
     229             :                 { UTVFU_BASE + 0x025a, 0x0012 },
     230             :                 { UTVFU_BASE + 0x025b, 0x0001 },
     231             :                 { UTVFU_BASE + 0x0263, 0x001c },
     232             :                 { UTVFU_BASE + 0x0266, 0x0011 },
     233             :                 { UTVFU_BASE + 0x0267, 0x0005 }
     234             :         };
     235             : 
     236           0 :         ret = utvfu_configure_for_norm(sc, norm);
     237             : 
     238           0 :         if (ret == 0) {
     239           0 :                 if (norm & V4L2_STD_525_60)
     240           0 :                         ret = utvfu_set_regs(sc, ntsc, nitems(ntsc));
     241           0 :                 else if (norm & V4L2_STD_PAL)
     242           0 :                         ret = utvfu_set_regs(sc, pal, nitems(pal));
     243             :         }
     244             : 
     245           0 :         return (ret);
     246             : }
     247             : 
     248             : int
     249           0 : utvfu_setup_capture(struct utvfu_softc *sc)
     250             : {
     251             :         int ret;
     252             :         static const uint16_t setup[][2] = {
     253             :                 /* These seem to enable the device. */
     254             :                 { UTVFU_BASE + 0x0008, 0x0001 },
     255             :                 { UTVFU_BASE + 0x01d0, 0x00ff },
     256             :                 { UTVFU_BASE + 0x01d9, 0x0002 },
     257             : 
     258             :                 /*
     259             :                  * These seem to influence color parameters, such as
     260             :                  * brightness, etc.
     261             :                  */
     262             :                 { UTVFU_BASE + 0x0239, 0x0040 },
     263             :                 { UTVFU_BASE + 0x0240, 0x0000 },
     264             :                 { UTVFU_BASE + 0x0241, 0x0000 },
     265             :                 { UTVFU_BASE + 0x0242, 0x0002 },
     266             :                 { UTVFU_BASE + 0x0243, 0x0080 },
     267             :                 { UTVFU_BASE + 0x0244, 0x0012 },
     268             :                 { UTVFU_BASE + 0x0245, 0x0090 },
     269             :                 { UTVFU_BASE + 0x0246, 0x0000 },
     270             : 
     271             :                 { UTVFU_BASE + 0x0278, 0x002d },
     272             :                 { UTVFU_BASE + 0x0279, 0x000a },
     273             :                 { UTVFU_BASE + 0x027a, 0x0032 },
     274             :                 { 0xf890, 0x000c },
     275             :                 { 0xf894, 0x0086 },
     276             : 
     277             :                 { UTVFU_BASE + 0x00ac, 0x00c0 },
     278             :                 { UTVFU_BASE + 0x00ad, 0x0000 },
     279             :                 { UTVFU_BASE + 0x00a2, 0x0012 },
     280             :                 { UTVFU_BASE + 0x00a3, 0x00e0 },
     281             :                 { UTVFU_BASE + 0x00a4, 0x0028 },
     282             :                 { UTVFU_BASE + 0x00a5, 0x0082 },
     283             :                 { UTVFU_BASE + 0x00a7, 0x0080 },
     284             :                 { UTVFU_BASE + 0x0000, 0x0014 },
     285             :                 { UTVFU_BASE + 0x0006, 0x0003 },
     286             :                 { UTVFU_BASE + 0x0090, 0x0099 },
     287             :                 { UTVFU_BASE + 0x0091, 0x0090 },
     288             :                 { UTVFU_BASE + 0x0094, 0x0068 },
     289             :                 { UTVFU_BASE + 0x0095, 0x0070 },
     290             :                 { UTVFU_BASE + 0x009c, 0x0030 },
     291             :                 { UTVFU_BASE + 0x009d, 0x00c0 },
     292             :                 { UTVFU_BASE + 0x009e, 0x00e0 },
     293             :                 { UTVFU_BASE + 0x0019, 0x0006 },
     294             :                 { UTVFU_BASE + 0x008c, 0x00ba },
     295             :                 { UTVFU_BASE + 0x0101, 0x00ff },
     296             :                 { UTVFU_BASE + 0x010c, 0x00b3 },
     297             :                 { UTVFU_BASE + 0x01b2, 0x0080 },
     298             :                 { UTVFU_BASE + 0x01b4, 0x00a0 },
     299             :                 { UTVFU_BASE + 0x014c, 0x00ff },
     300             :                 { UTVFU_BASE + 0x014d, 0x00ca },
     301             :                 { UTVFU_BASE + 0x0113, 0x0053 },
     302             :                 { UTVFU_BASE + 0x0119, 0x008a },
     303             :                 { UTVFU_BASE + 0x013c, 0x0003 },
     304             :                 { UTVFU_BASE + 0x0150, 0x009c },
     305             :                 { UTVFU_BASE + 0x0151, 0x0071 },
     306             :                 { UTVFU_BASE + 0x0152, 0x00c6 },
     307             :                 { UTVFU_BASE + 0x0153, 0x0084 },
     308             :                 { UTVFU_BASE + 0x0154, 0x00bc },
     309             :                 { UTVFU_BASE + 0x0155, 0x00a0 },
     310             :                 { UTVFU_BASE + 0x0156, 0x00a0 },
     311             :                 { UTVFU_BASE + 0x0157, 0x009c },
     312             :                 { UTVFU_BASE + 0x0158, 0x001f },
     313             :                 { UTVFU_BASE + 0x0159, 0x0006 },
     314             :                 { UTVFU_BASE + 0x015d, 0x0000 },
     315             : 
     316             :                 { UTVFU_BASE + 0x0003, 0x0004 },
     317             :                 { UTVFU_BASE + 0x0100, 0x00d3 },
     318             :                 { UTVFU_BASE + 0x0115, 0x0015 },
     319             :                 { UTVFU_BASE + 0x0220, 0x002e },
     320             :                 { UTVFU_BASE + 0x0225, 0x0008 },
     321             :                 { UTVFU_BASE + 0x024e, 0x0002 },
     322             :                 { UTVFU_BASE + 0x024e, 0x0002 },
     323             :                 { UTVFU_BASE + 0x024f, 0x0002 },
     324             :         };
     325             : 
     326           0 :         ret = utvfu_set_regs(sc, setup, nitems(setup));
     327           0 :         if (ret)
     328           0 :                 return (ret);
     329             : 
     330           0 :         ret = utvfu_select_norm(sc, utvfu_norm_params[sc->sc_normi].norm);
     331           0 :         if (ret)
     332           0 :                 return (ret);
     333             : 
     334           0 :         ret = utvfu_select_input(sc, sc->sc_input);
     335           0 :         if (ret)
     336           0 :                 return (ret);
     337             : 
     338           0 :         return (0);
     339           0 : }
     340             : 
     341             : /*
     342             :  * Copy data from chunk into a frame buffer, deinterlacing the data
     343             :  * into every second line. Unfortunately, they don't align nicely into
     344             :  * 720 pixel lines, as the chunk is 240 words long, which is 480 pixels.
     345             :  * Therefore, we break down the chunk into two halves before copying,
     346             :  * so that we can interleave a line if needed.
     347             :  *
     348             :  * Each "chunk" is 240 words; a word in this context equals 4 bytes.
     349             :  * Image format is YUYV/YUV 4:2:2, consisting of Y Cr Y Cb, defining two
     350             :  * pixels, the Cr and Cb shared between the two pixels, but each having
     351             :  * separate Y values. Thus, the 240 words equal 480 pixels. It therefore,
     352             :  * takes 1.5 chunks to make a 720 pixel-wide line for the frame.
     353             :  * The image is interlaced, so there is a "scan" of odd lines, followed
     354             :  * by "scan" of even numbered lines.
     355             :  *
     356             :  * Following code is writing the chunks in correct sequence, skipping
     357             :  * the rows based on "odd" value.
     358             :  * line 1: chunk[0][  0..479] chunk[0][480..959] chunk[1][  0..479]
     359             :  * line 3: chunk[1][480..959] chunk[2][  0..479] chunk[2][480..959]
     360             :  * ...etc
     361             :  */
     362             : void
     363           0 : utvfu_chunk_to_vbuf(uint8_t *frame, uint8_t *src, int chunk_no, int odd)
     364             : {
     365             :         uint8_t *dst;
     366             :         int half, line, part_no, part_index;
     367             :         #define UTVFU_STRIDE    (UTVFU_CHUNK/2 * 4)
     368             : 
     369           0 :         for (half = 0; half < 2; half++) {
     370           0 :                 part_no = chunk_no * 2 + half;
     371           0 :                 line = part_no / 3;
     372           0 :                 part_index = (line * 2 + !odd) * 3 + (part_no % 3);
     373             : 
     374           0 :                 dst = &frame[part_index * UTVFU_STRIDE];
     375             : 
     376           0 :                 memcpy(dst, src, UTVFU_STRIDE);
     377           0 :                 src += UTVFU_STRIDE;
     378             :         }
     379             :         #undef  UTVFU_STRIDE
     380           0 : }
     381             : 
     382             : /*
     383             :  * Called for each 256-byte image chunk.
     384             :  * First word identifies the chunk, followed by 240 words of image
     385             :  * data and padding.
     386             :  */
     387             : void
     388           0 : utvfu_image_chunk(struct utvfu_softc *sc, u_char *chunk)
     389             : {
     390             :         int frame_id, odd, chunk_no, frame_len;
     391             :         uint32_t hdr;
     392             : 
     393           0 :         memcpy(&hdr, chunk, sizeof(hdr));
     394           0 :         chunk += sizeof(hdr);
     395           0 :         hdr = be32toh(hdr);
     396             : 
     397             :         /* Ignore corrupted lines. */
     398           0 :         if (!UTVFU_MAGIC_OK(hdr)) {
     399             :                 DPRINTF(2, "%s: bad magic=0x%08x\n",
     400             :                     DEVNAME(sc), UTVFU_MAGIC(hdr));
     401           0 :                 return;
     402             :         }
     403             : 
     404           0 :         frame_id = UTVFU_FRAME_ID(hdr);
     405           0 :         odd = UTVFU_ODD(hdr);
     406           0 :         chunk_no = UTVFU_CHUNK_NO(hdr);
     407           0 :         if (chunk_no >= sc->sc_nchunks) {
     408             :                 DPRINTF(2, "%s: chunk_no=%d >= sc_nchunks=%d\n",
     409             :                     DEVNAME(sc), chunk_no, sc->sc_nchunks);
     410           0 :                 return;
     411             :         }
     412             : 
     413             :         /* Beginning of a frame. */
     414           0 :         if (chunk_no == 0) {
     415           0 :                 sc->sc_fb.fid = frame_id;
     416           0 :                 sc->sc_fb.chunks_done = 0;
     417           0 :         }
     418           0 :         else if (sc->sc_fb.fid != frame_id) {
     419             :                 DPRINTF(2, "%s: frame id mismatch expecting=%d got=%d\n",
     420             :                     DEVNAME(sc), sc->sc_fb.fid, frame_id);
     421           0 :                 return;
     422             :         }
     423             : 
     424           0 :         frame_len = utvfu_norm_params[sc->sc_normi].frame_len;
     425             : 
     426             :         /* Copy the chunk data. */
     427           0 :         utvfu_chunk_to_vbuf(sc->sc_fb.buf, chunk, chunk_no, odd);
     428           0 :         sc->sc_fb.chunks_done++;
     429             : 
     430             :         /* Last chunk in a field */
     431           0 :         if (chunk_no == sc->sc_nchunks-1) {
     432             :                 /* Last chunk in a frame, signalling an end */
     433           0 :                 if (odd && !sc->sc_fb.last_odd) {
     434           0 :                         if (sc->sc_fb.chunks_done != sc->sc_nchunks) {
     435             :                                 DPRINTF(1, "%s: chunks_done=%d != nchunks=%d\n",
     436             :                                     DEVNAME(sc),
     437             :                                     sc->sc_fb.chunks_done, sc->sc_nchunks);
     438             :                         }
     439             : 
     440           0 :                         if (sc->sc_flags & UTVFU_FLAG_MMAP) {
     441           0 :                                 utvfu_mmap_queue(sc, sc->sc_fb.buf, frame_len);
     442           0 :                         }
     443             :                         else {
     444           0 :                                 utvfu_read(sc, sc->sc_fb.buf, frame_len);
     445             :                         }
     446             :                 }
     447           0 :                 sc->sc_fb.last_odd = odd;
     448           0 :         }
     449           0 : }
     450             : 
     451             : int
     452           0 : utvfu_start_capture(struct utvfu_softc *sc)
     453             : {
     454             :         usbd_status error;
     455             :         int restart_au;
     456             : 
     457             :         DPRINTF(1, "%s: %s\n", DEVNAME(sc), __func__);
     458             : 
     459           0 :         restart_au = ISSET(sc->sc_flags, UTVFU_FLAG_AS_RUNNING);
     460           0 :         utvfu_audio_stop(sc);
     461             : 
     462             :         /* default video stream interface */
     463           0 :         error = usbd_set_interface(sc->sc_uifaceh, UTVFU_DFLT_IFACE_IDX);
     464           0 :         if (error != USBD_NORMAL_COMPLETION)
     465           0 :                 return (EINVAL);
     466             : 
     467           0 :         if (utvfu_setup_capture(sc) != 0)
     468           0 :                 return (EINVAL);
     469             : 
     470             :         /* alt setting */
     471           0 :         error = usbd_set_interface(sc->sc_uifaceh, UTVFU_ALT_IFACE_IDX);
     472           0 :         if (error != USBD_NORMAL_COMPLETION)
     473           0 :                 return (EINVAL);
     474             : 
     475           0 :         if (restart_au)
     476           0 :                 utvfu_audio_start(sc);
     477             : 
     478           0 :         return (0);
     479           0 : }
     480             : 
     481             : int
     482           0 : utvfu_querycap(void *v, struct v4l2_capability *cap)
     483             : {
     484           0 :         struct utvfu_softc *sc = v;
     485             : 
     486           0 :         memset(cap, 0, sizeof(*cap));
     487           0 :         strlcpy(cap->driver, DEVNAME(sc), sizeof(cap->driver));
     488           0 :         strlcpy(cap->card, "utvfu", sizeof(cap->card));
     489           0 :         strlcpy(cap->bus_info, "usb", sizeof(cap->bus_info));
     490           0 :         cap->device_caps = V4L2_CAP_VIDEO_CAPTURE;
     491           0 :         cap->device_caps |= V4L2_CAP_READWRITE | V4L2_CAP_STREAMING;
     492           0 :         cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS;
     493           0 :         return (0);
     494             : }
     495             : 
     496             : int
     497           0 : utvfu_enum_input(void *v, struct v4l2_input *i)
     498             : {
     499           0 :         struct utvfu_softc *sc = v;
     500             : 
     501           0 :         switch (i->index) {
     502             :         case UTVFU_COMPOSITE_INPUT:
     503           0 :                 strlcpy(i->name, "Composite", sizeof(i->name));
     504           0 :                 break;
     505             :         case UTVFU_SVIDEO_INPUT:
     506           0 :                 strlcpy(i->name, "S-Video", sizeof(i->name));
     507           0 :                 break;
     508             :         default:
     509           0 :                 return (EINVAL);
     510             :         }
     511             : 
     512           0 :         i->type = V4L2_INPUT_TYPE_CAMERA;
     513           0 :         i->std = utvfu_norm_params[sc->sc_normi].norm;
     514           0 :         return (0);
     515           0 : }
     516             : 
     517             : int
     518           0 : utvfu_enum_fmt_vid_cap(void *v, struct v4l2_fmtdesc *f)
     519             : {
     520           0 :         if (f->type != V4L2_BUF_TYPE_VIDEO_CAPTURE || f->index != 0)
     521           0 :                 return (EINVAL);
     522             : 
     523           0 :         strlcpy(f->description, "16 bpp YUY2, 4:2:2, packed",
     524             :                                         sizeof(f->description));
     525           0 :         f->pixelformat = V4L2_PIX_FMT_YUYV;
     526           0 :         return (0);
     527           0 : }
     528             : 
     529             : int
     530           0 : utvfu_enum_fsizes(void *v, struct v4l2_frmsizeenum *fsizes)
     531             : {
     532           0 :         struct utvfu_softc *sc = v;
     533             : 
     534           0 :         if (fsizes->pixel_format != V4L2_PIX_FMT_YUYV)
     535           0 :                 return (EINVAL);
     536             : 
     537           0 :         fsizes->type = V4L2_FRMSIZE_TYPE_DISCRETE;
     538           0 :         fsizes->discrete.width = utvfu_norm_params[sc->sc_normi].cap_width;
     539           0 :         fsizes->discrete.height = utvfu_norm_params[sc->sc_normi].cap_height;
     540           0 :         return (0);
     541           0 : }
     542             : 
     543             : int
     544           0 : utvfu_g_fmt(void *v, struct v4l2_format *f)
     545             : {
     546           0 :         struct utvfu_softc *sc = v;
     547             : 
     548           0 :         f->fmt.pix.width = utvfu_norm_params[sc->sc_normi].cap_width;
     549           0 :         f->fmt.pix.height = utvfu_norm_params[sc->sc_normi].cap_height;
     550           0 :         f->fmt.pix.pixelformat = V4L2_PIX_FMT_YUYV;
     551           0 :         f->fmt.pix.field = V4L2_FIELD_INTERLACED;
     552           0 :         f->fmt.pix.bytesperline = f->fmt.pix.width * 2;
     553           0 :         f->fmt.pix.sizeimage = (f->fmt.pix.bytesperline * f->fmt.pix.height);
     554           0 :         f->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M;
     555           0 :         return (0);
     556             : }
     557             : 
     558             : int
     559           0 : utvfu_s_fmt(void *v, struct v4l2_format *f)
     560             : {
     561           0 :         if (f->fmt.pix.pixelformat != V4L2_PIX_FMT_YUYV)
     562           0 :                 return (EINVAL);
     563           0 :         return (0);
     564           0 : }
     565             : 
     566             : int
     567           0 : utvfu_g_std(void *v, v4l2_std_id *norm)
     568             : {
     569           0 :         struct utvfu_softc *sc = v;
     570           0 :         *norm = utvfu_norm_params[sc->sc_normi].norm;
     571           0 :         return (0);
     572             : }
     573             : 
     574             : int
     575           0 : utvfu_s_std(void *v, v4l2_std_id norm)
     576             : {
     577             :         int ret = EINVAL;
     578           0 :         struct utvfu_softc *sc = v;
     579             : 
     580           0 :         if ((norm & V4L2_STD_525_60) || (norm & V4L2_STD_PAL))
     581           0 :                 ret = utvfu_select_norm(sc, norm);
     582             : 
     583           0 :         return (ret);
     584             : }
     585             : 
     586             : int
     587           0 : utvfu_g_input(void *v, int *i)
     588             : {
     589           0 :         struct utvfu_softc *sc = v;
     590           0 :         *i = sc->sc_input;
     591           0 :         return (0);
     592             : }
     593             : 
     594             : int
     595           0 : utvfu_s_input(void *v, int i)
     596             : {
     597           0 :         return utvfu_select_input(v, i);
     598             : }
     599             : 
     600             : /* A U D I O */
     601             : 
     602             : void
     603           0 : utvfu_audio_decode(struct utvfu_softc *sc, int len)
     604             : {
     605             :         uint8_t *dst, *src;
     606             :         int n, chunk, ncopied;
     607             : 
     608           0 :         if (sc->sc_audio.blksize == 0)
     609           0 :                 return;
     610             : 
     611           0 :         src = KERNADDR(&sc->sc_audio.iface.xfer->dmabuf, 0);
     612           0 :         dst = sc->sc_audio.cur;
     613           0 :         ncopied = sc->sc_audio.cur - sc->sc_audio.start;
     614             :         /* b/c region start->end is a multiple blksize chunks */
     615           0 :         ncopied %= sc->sc_audio.blksize;
     616             : 
     617           0 :         while (len >= UTVFU_CHUNK_SIZE) {
     618             :                 /*
     619             :                  * The header, skipped here, ranges from 0xdd000000 to
     620             :                  * 0xdd0003ff.  The 0xdd seems to be the "magic" and
     621             :                  * 0x3ff masks the chunk number.
     622             :                  */
     623           0 :                 src += UTVFU_AUDIO_HDRSIZE;
     624             :                 chunk = UTVFU_CHUNK;
     625           0 :                 while (chunk > 0) {
     626           0 :                         n = min(chunk, sc->sc_audio.blksize - ncopied);
     627           0 :                         memcpy(dst, src, n);
     628           0 :                         dst += n;
     629           0 :                         src += n;
     630           0 :                         chunk -= n;
     631           0 :                         ncopied += n;
     632           0 :                         if (ncopied >= sc->sc_audio.blksize) {
     633           0 :                                 mtx_enter(&audio_lock);
     634           0 :                                 (*sc->sc_audio.intr)(sc->sc_audio.intr_arg);
     635           0 :                                 mtx_leave(&audio_lock);
     636           0 :                                 ncopied -= sc->sc_audio.blksize;
     637           0 :                         }
     638           0 :                         if (dst > sc->sc_audio.end)
     639           0 :                                 dst = sc->sc_audio.start;
     640             :                 }
     641           0 :                 len -= UTVFU_CHUNK_SIZE; /* _CHUNK + _AUDIO_HDRSIZE */
     642             :         }
     643           0 :         sc->sc_audio.cur = dst;
     644           0 : }
     645             : 
     646             : int
     647           0 : utvfu_audio_start_chip(struct utvfu_softc *sc)
     648             : {
     649             :         static const uint16_t setup[][2] = {
     650             :                 /* These seem to enable the device. */
     651             :                 { UTVFU_BASE + 0x0008, 0x0001 },
     652             :                 { UTVFU_BASE + 0x01d0, 0x00ff },
     653             :                 { UTVFU_BASE + 0x01d9, 0x0002 },
     654             : 
     655             :                 { UTVFU_BASE + 0x01da, 0x0013 },
     656             :                 { UTVFU_BASE + 0x01db, 0x0012 },
     657             :                 { UTVFU_BASE + 0x01e9, 0x0002 },
     658             :                 { UTVFU_BASE + 0x01ec, 0x006c },
     659             :                 { UTVFU_BASE + 0x0294, 0x0020 },
     660             :                 { UTVFU_BASE + 0x0255, 0x00cf },
     661             :                 { UTVFU_BASE + 0x0256, 0x0020 },
     662             :                 { UTVFU_BASE + 0x01eb, 0x0030 },
     663             :                 { UTVFU_BASE + 0x027d, 0x00a6 },
     664             :                 { UTVFU_BASE + 0x0280, 0x0011 },
     665             :                 { UTVFU_BASE + 0x0281, 0x0040 },
     666             :                 { UTVFU_BASE + 0x0282, 0x0011 },
     667             :                 { UTVFU_BASE + 0x0283, 0x0040 },
     668             :                 { 0xf891, 0x0010 },
     669             : 
     670             :                 /* this sets the input from composite */
     671             :                 { UTVFU_BASE + 0x0284, 0x00aa },
     672             :         };
     673             : 
     674             :         /* starting the stream */
     675           0 :         utvfu_set_regs(sc, setup, nitems(setup));
     676             : 
     677           0 :         return (0);
     678             : }
     679             : 
     680             : int
     681           0 : utvfu_audio_stop_chip(struct utvfu_softc *sc)
     682             : {
     683             :         static const uint16_t setup[][2] = {
     684             :         /*
     685             :          * The original windows driver sometimes sends also:
     686             :          *   { UTVFU_BASE + 0x00a2, 0x0013 }
     687             :          * but it seems useless and its real effects are untested at
     688             :          * the moment.
     689             :          */
     690             :                 { UTVFU_BASE + 0x027d, 0x0000 },
     691             :                 { UTVFU_BASE + 0x0280, 0x0010 },
     692             :                 { UTVFU_BASE + 0x0282, 0x0010 },
     693             :         };
     694             : 
     695           0 :         utvfu_set_regs(sc, setup, nitems(setup));
     696             : 
     697           0 :         return (0);
     698             : }
     699             : 
     700             : /*
     701             :  * Copyright (c) 2008 Robert Nagy <robert@openbsd.org>
     702             :  * Copyright (c) 2008 Marcus Glocker <mglocker@openbsd.org>
     703             :  * Copyright (c) 2016 Patrick Keshishian <patrick@boxsoft.com>
     704             :  *
     705             :  * Permission to use, copy, modify, and distribute this software for any
     706             :  * purpose with or without fee is hereby granted, provided that the above
     707             :  * copyright notice and this permission notice appear in all copies.
     708             :  *
     709             :  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
     710             :  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
     711             :  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
     712             :  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
     713             :  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
     714             :  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
     715             :  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
     716             :  */
     717             : /*
     718             :  * Heavily based on uvideo.c source.
     719             :  */
     720             : 
     721             : int             utvfu_match(struct device *, void *, void *);
     722             : void            utvfu_attach(struct device *, struct device *, void *);
     723             : int             utvfu_detach(struct device *, int);
     724             : 
     725             : usbd_status     utvfu_parse_desc(struct utvfu_softc *);
     726             : 
     727             : void            utvfu_vs_close(struct utvfu_softc *);
     728             : void            utvfu_vs_free_frame(struct utvfu_softc *);
     729             : void            utvfu_vs_free_isoc(struct utvfu_softc *);
     730             : void            utvfu_vs_start_isoc_ixfer(struct utvfu_softc *,
     731             :                     struct utvfu_isoc_xfer *);
     732             : void            utvfu_vs_cb(struct usbd_xfer *, void *, usbd_status);
     733             : 
     734             : void            utvfu_vs_free(struct utvfu_softc *);
     735             : int             utvfu_vs_init(struct utvfu_softc *);
     736             : int             utvfu_vs_alloc_frame(struct utvfu_softc *);
     737             : usbd_status     utvfu_vs_alloc_isoc(struct utvfu_softc *);
     738             : 
     739             : int             utvfu_open(void *, int, int *, uint8_t *,
     740             :                     void (*)(void *), void *);
     741             : int             utvfu_close(void *);
     742             : int             utvfu_querycap(void *, struct v4l2_capability *);
     743             : int             utvfu_enum_fmt_vid_cap(void *, struct v4l2_fmtdesc *);
     744             : int             utvfu_enum_fsizes(void *, struct v4l2_frmsizeenum *);
     745             : int             utvfu_g_fmt(void *, struct v4l2_format *);
     746             : int             utvfu_s_fmt(void *, struct v4l2_format *);
     747             : int             utvfu_g_parm(void *, struct v4l2_streamparm *);
     748             : int             utvfu_s_parm(void *, struct v4l2_streamparm *);
     749             : int             utvfu_enum_input(void *, struct v4l2_input *);
     750             : int             utvfu_s_input(void *, int);
     751             : int             utvfu_g_input(void *, int *);
     752             : 
     753             : int             utvfu_reqbufs(void *, struct v4l2_requestbuffers *);
     754             : int             utvfu_querybuf(void *, struct v4l2_buffer *);
     755             : int             utvfu_qbuf(void *, struct v4l2_buffer *);
     756             : int             utvfu_dqbuf(void *, struct v4l2_buffer *);
     757             : int             utvfu_streamon(void *, int);
     758             : int             utvfu_streamoff(void *, int);
     759             : int             utvfu_queryctrl(void *, struct v4l2_queryctrl *);
     760             : caddr_t         utvfu_mappage(void *, off_t, int);
     761             : int             utvfu_get_bufsize(void *);
     762             : int             utvfu_start_read(void *);
     763             : 
     764             : int             utvfu_as_init(struct utvfu_softc *);
     765             : void            utvfu_as_free(struct utvfu_softc *);
     766             : 
     767             : usbd_status     utvfu_as_open(struct utvfu_softc *);
     768             : int             utvfu_as_alloc_bulk(struct utvfu_softc *);
     769             : void            utvfu_as_free_bulk(struct utvfu_softc *);
     770             : int             utvfu_as_start_bulk(struct utvfu_softc *);
     771             : void            utvfu_as_bulk_thread(void *);
     772             : 
     773             : int             utvfu_audio_open(void *, int);
     774             : void            utvfu_audio_close(void *);
     775             : int             utvfu_audio_set_params(void *, int, int,
     776             :                     struct audio_params *, struct audio_params *);
     777             : int             utvfu_audio_halt_out(void *);
     778             : int             utvfu_audio_halt_in(void *);
     779             : int             utvfu_audio_mixer_set_port(void *, struct mixer_ctrl *);
     780             : int             utvfu_audio_mixer_get_port(void *, struct mixer_ctrl *);
     781             : int             utvfu_audio_query_devinfo(void *, struct mixer_devinfo *);
     782             : int             utvfu_audio_get_props(void *);
     783             : int             utvfu_audio_trigger_output(void *, void *, void *, int,
     784             :                     void (*)(void *), void *, struct audio_params *);
     785             : int             utvfu_audio_trigger_input(void *, void *, void *, int,
     786             :                     void (*)(void *), void *, struct audio_params *);
     787             : 
     788             : struct cfdriver utvfu_cd = {
     789             :         NULL, "utvfu", DV_DULL
     790             : };
     791             : 
     792             : const struct cfattach utvfu_ca = {
     793             :         sizeof(struct utvfu_softc),
     794             :         utvfu_match,
     795             :         utvfu_attach,
     796             :         utvfu_detach,
     797             :         NULL
     798             : };
     799             : 
     800             : struct video_hw_if utvfu_vid_hw_if = {
     801             :         utvfu_open,             /* open */
     802             :         utvfu_close,            /* close */
     803             :         utvfu_querycap,         /* VIDIOC_QUERYCAP */
     804             :         utvfu_enum_fmt_vid_cap, /* VIDIOC_ENUM_FMT */
     805             :         utvfu_enum_fsizes,      /* VIDIOC_ENUM_FRAMESIZES */
     806             :         NULL,                   /* VIDIOC_ENUM_FRAMEINTERVALS */
     807             :         utvfu_s_fmt,            /* VIDIOC_S_FMT */
     808             :         utvfu_g_fmt,            /* VIDIOC_G_FMT */
     809             :         utvfu_s_parm,           /* VIDIOC_S_PARM */
     810             :         utvfu_g_parm,           /* VIDIOC_G_PARM */
     811             :         utvfu_enum_input,       /* VIDIOC_ENUMINPUT */
     812             :         utvfu_s_input,          /* VIDIOC_S_INPUT */
     813             :         utvfu_g_input,          /* VIDIOC_G_INPUT */
     814             :         utvfu_reqbufs,          /* VIDIOC_REQBUFS */
     815             :         utvfu_querybuf,         /* VIDIOC_QUERYBUF */
     816             :         utvfu_qbuf,             /* VIDIOC_QBUF */
     817             :         utvfu_dqbuf,            /* VIDIOC_DQBUF */
     818             :         utvfu_streamon,         /* VIDIOC_STREAMON */
     819             :         utvfu_streamoff,        /* VIDIOC_STREAMOFF */
     820             :         NULL,                   /* VIDIOC_TRY_FMT */
     821             :         utvfu_queryctrl,        /* VIDIOC_QUERYCTRL */
     822             :         NULL,                   /* VIDIOC_G_CTRL */
     823             :         NULL,                   /* VIDIOC_S_CTRL */
     824             :         utvfu_mappage,          /* mmap */
     825             :         utvfu_get_bufsize,      /* read */
     826             :         utvfu_start_read        /* start stream for read */
     827             : };
     828             : 
     829             : struct audio_hw_if utvfu_au_hw_if = {
     830             :         utvfu_audio_open,               /* open hardware */
     831             :         utvfu_audio_close,              /* close hardware */
     832             :         utvfu_audio_set_params,
     833             :         NULL,
     834             :         NULL,
     835             :         NULL,
     836             :         NULL,
     837             :         NULL,
     838             :         NULL,
     839             :         utvfu_audio_halt_out,
     840             :         utvfu_audio_halt_in,
     841             :         NULL,
     842             :         NULL,
     843             :         utvfu_audio_mixer_set_port,
     844             :         utvfu_audio_mixer_get_port,
     845             :         utvfu_audio_query_devinfo,
     846             :         NULL,
     847             :         NULL,
     848             :         NULL,
     849             :         utvfu_audio_get_props,
     850             :         utvfu_audio_trigger_output,
     851             :         utvfu_audio_trigger_input
     852             : };
     853             : 
     854             : int
     855           0 : utvfu_match(struct device *parent, void *match, void *aux)
     856             : {
     857           0 :         struct usb_attach_arg *uaa = aux;
     858             :         const struct usb_descriptor *ud;
     859           0 :         struct usbd_desc_iter iter;
     860             :         struct usb_interface_descriptor *uid = NULL;
     861             :         const struct usb_endpoint_descriptor *ued = NULL;
     862             :         usb_device_descriptor_t *dd;
     863             :         int ret = UMATCH_NONE;
     864             :         int nep, nalt;
     865             :         uint16_t psize = 0;
     866             : 
     867           0 :         if (uaa->iface == NULL)
     868           0 :                 return ret;
     869             : 
     870           0 :         dd = usbd_get_device_descriptor(uaa->device);
     871             : 
     872           0 :         if (UGETW(dd->idVendor) == USB_VENDOR_FUSHICAI &&
     873           0 :             UGETW(dd->idProduct) == USB_PRODUCT_FUSHICAI_USBTV007)
     874           0 :                 ret = UMATCH_VENDOR_PRODUCT;
     875             :         /*
     876             :          * This seems like a fragile check, but the original driver ensures
     877             :          * there are two alternate settings for the interface, and alternate
     878             :          * setting 1 has four endpoints.
     879             :          *
     880             :          * Comment says "Checks that the device is what we think it is."
     881             :          *
     882             :          * Adding check that wMaxPacketSize for the video endpoint is > 0.
     883             :          */
     884             :         nep = nalt = 0;
     885           0 :         usbd_desc_iter_init(uaa->device, &iter);
     886           0 :         while ((ud = usbd_desc_iter_next(&iter)) != NULL) {
     887           0 :                 switch (ud->bDescriptorType) {
     888             :                 default:
     889             :                         break;
     890             :                 case UDESC_INTERFACE:
     891           0 :                         uid = (void *)ud;
     892           0 :                         if (uid->bInterfaceNumber == 0)
     893           0 :                                 nalt++;
     894             :                         break;
     895             :                 case UDESC_ENDPOINT:
     896           0 :                         if (uid->bAlternateSetting == 1) {
     897           0 :                                 ued = (void *)ud;
     898           0 :                                 if (ued->bEndpointAddress == UTVFU_VIDEO_ENDP)
     899           0 :                                         psize = UGETW(ued->wMaxPacketSize);
     900           0 :                                 nep++;
     901           0 :                         }
     902             :                         break;
     903             :                 }
     904           0 :                 if (uid != NULL && uid->bInterfaceNumber > 0)
     905             :                         break;
     906             :         }
     907             : 
     908           0 :         if (nalt != 2 || nep != 4 || psize == 0)
     909           0 :                 ret = UMATCH_NONE;
     910             : 
     911           0 :         return (ret);
     912           0 : }
     913             : 
     914             : void
     915           0 : utvfu_attach(struct device *parent, struct device *self, void *aux)
     916             : {
     917             :         int i;
     918           0 :         struct utvfu_softc *sc = (struct utvfu_softc *)self;
     919           0 :         struct usb_attach_arg *uaa = aux;
     920             : 
     921           0 :         sc->sc_udev = uaa->device;
     922           0 :         for (i = 0; i < uaa->nifaces; i++) {
     923           0 :                 if (usbd_iface_claimed(sc->sc_udev, i))
     924             :                         continue;
     925           0 :                 usbd_claim_iface(sc->sc_udev, i);
     926           0 :         }
     927             : 
     928           0 :         utvfu_parse_desc(sc);
     929             : 
     930             :         /* init mmap queue */
     931           0 :         SIMPLEQ_INIT(&sc->sc_mmap_q);
     932           0 :         sc->sc_mmap_count = 0;
     933             : 
     934           0 :         sc->sc_max_frame_sz = utvfu_max_frame_size();
     935             : 
     936             :         /* calculate optimal isoc xfer size */
     937           0 :         sc->sc_nframes = (sc->sc_max_frame_sz + sc->sc_iface.psize - 1)
     938           0 :             / sc->sc_iface.psize;
     939           0 :         if (sc->sc_nframes > UTVFU_NFRAMES_MAX)
     940           0 :                 sc->sc_nframes = UTVFU_NFRAMES_MAX;
     941             :         DPRINTF(1, "%s: nframes=%d\n", DEVNAME(sc), sc->sc_nframes);
     942             : 
     943           0 :         rw_init(&sc->sc_audio.rwlock, "audiorwl");
     944             : 
     945           0 :         sc->sc_audiodev = audio_attach_mi(&utvfu_au_hw_if, sc, &sc->sc_dev);
     946           0 :         sc->sc_videodev = video_attach_mi(&utvfu_vid_hw_if, sc, &sc->sc_dev);
     947           0 : }
     948             : 
     949             : int
     950           0 : utvfu_detach(struct device *self, int flags)
     951             : {
     952           0 :         struct utvfu_softc *sc = (struct utvfu_softc *)self;
     953             :         int rv = 0;
     954             : 
     955             :         /* Wait for outstanding requests to complete */
     956           0 :         usbd_delay_ms(sc->sc_udev, UTVFU_NFRAMES_MAX); /* XXX meh? */
     957             : 
     958           0 :         if (sc->sc_videodev != NULL)
     959           0 :                 rv = config_detach(sc->sc_videodev, flags);
     960             : 
     961           0 :         if (sc->sc_audiodev != NULL)
     962           0 :                 rv += config_detach(sc->sc_audiodev, flags);
     963             : 
     964           0 :         utvfu_as_free(sc);
     965           0 :         utvfu_vs_free(sc);
     966             : 
     967           0 :         sc->sc_flags = 0;
     968             : 
     969           0 :         return (rv);
     970             : }
     971             : 
     972             : usbd_status
     973           0 : utvfu_parse_desc(struct utvfu_softc *sc)
     974             : {
     975             :         int nif, nep;
     976             :         uint32_t psize;
     977           0 :         struct usbd_desc_iter iter;
     978             :         const struct usb_descriptor *ud;
     979             :         struct usb_endpoint_descriptor *ued;
     980             :         struct usb_interface_descriptor *uid = NULL;
     981             : 
     982             :         nif = nep = 0;
     983           0 :         usbd_desc_iter_init(sc->sc_udev, &iter);
     984           0 :         while ((ud = usbd_desc_iter_next(&iter)) != NULL) {
     985           0 :                 if (ud->bDescriptorType != UDESC_INTERFACE)
     986           0 :                         continue;
     987             :                 /* looking for interface 0, alt-setting 1 */
     988           0 :                 uid = (void *)ud;
     989           0 :                 if (uid->bInterfaceNumber > 0)
     990             :                         break;
     991           0 :                 if (uid->bAlternateSetting == 1)
     992             :                         break;
     993             :         }
     994             : 
     995             :         /* this should not fail as it was ensured during match */
     996           0 :         if (uid == NULL || uid->bInterfaceNumber != 0 ||
     997           0 :             uid->bAlternateSetting != 1) {
     998           0 :                 printf("%s: no valid alternate interface found!\n",
     999           0 :                     DEVNAME(sc));
    1000           0 :                 return (USBD_INVAL);
    1001             :         }
    1002             : 
    1003             :         /* bInterfaceNumber = 0 */
    1004           0 :         sc->sc_uifaceh = &sc->sc_udev->ifaces[0];
    1005             : 
    1006             :         /* looking for video endpoint to on alternate setting 1 */
    1007           0 :         while ((ud = usbd_desc_iter_next(&iter)) != NULL) {
    1008           0 :                 if (ud->bDescriptorType != UDESC_ENDPOINT)
    1009             :                         break;
    1010             : 
    1011           0 :                 ued = (void *)ud;
    1012           0 :                 if (ued->bEndpointAddress != UTVFU_VIDEO_ENDP)
    1013           0 :                         continue;
    1014             : 
    1015           0 :                 psize = UGETW(ued->wMaxPacketSize);
    1016           0 :                 psize = UE_GET_SIZE(psize) * (1 + UE_GET_TRANS(psize));
    1017           0 :                 sc->sc_iface.psize = psize;
    1018           0 :                 break;
    1019             :         }
    1020             : 
    1021           0 :         return (USBD_NORMAL_COMPLETION);
    1022           0 : }
    1023             : 
    1024             : int
    1025           0 : utvfu_open(void *addr, int flags, int *size, uint8_t *buffer,
    1026             :     void (*intr)(void *), void *arg)
    1027             : {
    1028           0 :         struct utvfu_softc *sc = addr;
    1029             :         int rv;
    1030             : 
    1031             :         DPRINTF(1, "%s: utvfu_open: sc=%p\n", DEVNAME(sc), sc);
    1032             : 
    1033           0 :         if (usbd_is_dying(sc->sc_udev))
    1034           0 :                 return (EIO);
    1035             : 
    1036           0 :         if ((rv = utvfu_vs_init(sc)) != 0)
    1037           0 :                 return (rv);
    1038             : 
    1039             :         /* pointers to upper video layer */
    1040           0 :         sc->sc_uplayer_arg = arg;
    1041           0 :         sc->sc_uplayer_fsize = size;
    1042           0 :         sc->sc_uplayer_fbuffer = buffer;
    1043           0 :         sc->sc_uplayer_intr = intr;
    1044             : 
    1045           0 :         sc->sc_flags &= ~UTVFU_FLAG_MMAP;
    1046             : 
    1047           0 :         return (0);
    1048           0 : }
    1049             : 
    1050             : int
    1051           0 : utvfu_close(void *addr)
    1052             : {
    1053           0 :         struct utvfu_softc *sc = addr;
    1054             : 
    1055             :         DPRINTF(1, "%s: utvfu_close: sc=%p\n", DEVNAME(sc), sc);
    1056             : 
    1057             :         /* free & clean up video stream */
    1058           0 :         utvfu_vs_free(sc);
    1059             : 
    1060           0 :         return (0);
    1061             : }
    1062             : 
    1063             : usbd_status
    1064           0 : utvfu_as_open(struct utvfu_softc *sc)
    1065             : {
    1066             :         usb_endpoint_descriptor_t *ed;
    1067             :         usbd_status error;
    1068             : 
    1069             :         DPRINTF(1, "%s: %s\n", DEVNAME(sc), __func__);
    1070             : 
    1071           0 :         if (sc->sc_audio.iface.pipeh != NULL) {
    1072           0 :                 printf("%s: %s called while sc_audio.iface.pipeh not NULL\n",
    1073           0 :                     DEVNAME(sc), __func__);
    1074           0 :                 return (USBD_INVAL);
    1075             :         }
    1076             : 
    1077           0 :         ed = usbd_get_endpoint_descriptor(sc->sc_uifaceh, UTVFU_AUDIO_ENDP);
    1078           0 :         if (ed == NULL) {
    1079           0 :                 printf("%s: no endpoint descriptor for AS iface\n",
    1080           0 :                     DEVNAME(sc));
    1081           0 :                 return (USBD_INVAL);
    1082             :         }
    1083             :         DPRINTF(1, "%s: open pipe for ", DEVNAME(sc));
    1084             :         DPRINTF(1, "bEndpointAddress=0x%02x (0x%02x), wMaxPacketSize="
    1085             :             "0x%04x (%d)\n",
    1086             :             UE_GET_ADDR(ed->bEndpointAddress),
    1087             :             UTVFU_AUDIO_ENDP,
    1088             :             UGETW(ed->wMaxPacketSize),
    1089             :             UE_GET_SIZE(UGETW(ed->wMaxPacketSize))
    1090             :             * (1 + UE_GET_TRANS(UGETW(ed->wMaxPacketSize))));
    1091             : 
    1092           0 :         error = usbd_open_pipe(
    1093           0 :             sc->sc_uifaceh,
    1094             :             UTVFU_AUDIO_ENDP,
    1095             :             USBD_EXCLUSIVE_USE,
    1096             :             &sc->sc_audio.iface.pipeh);
    1097           0 :         if (error != USBD_NORMAL_COMPLETION) {
    1098           0 :                 printf("%s: could not open AS pipe: %s\n",
    1099           0 :                     DEVNAME(sc), usbd_errstr(error));
    1100           0 :         }
    1101             : 
    1102           0 :         return (error);
    1103           0 : }
    1104             : 
    1105             : usbd_status
    1106           0 : utvfu_vs_open(struct utvfu_softc *sc)
    1107             : {
    1108             :         usb_endpoint_descriptor_t *ed;
    1109             :         usbd_status error;
    1110             : 
    1111             :         DPRINTF(1, "%s: %s\n", DEVNAME(sc), __func__);
    1112             : 
    1113           0 :         if (sc->sc_iface.pipeh != NULL) {
    1114           0 :                 printf("%s: %s called while sc_iface.pipeh not NULL\n",
    1115           0 :                     DEVNAME(sc), __func__);
    1116           0 :                 return (USBD_INVAL);
    1117             :         }
    1118             : 
    1119           0 :         ed = usbd_get_endpoint_descriptor(sc->sc_uifaceh, UTVFU_VIDEO_ENDP);
    1120           0 :         if (ed == NULL) {
    1121           0 :                 printf("%s: no endpoint descriptor for VS iface\n",
    1122           0 :                     DEVNAME(sc));
    1123           0 :                 return (USBD_INVAL);
    1124             :         }
    1125             :         DPRINTF(1, "%s: open pipe for ", DEVNAME(sc));
    1126             :         DPRINTF(1, "bEndpointAddress=0x%02x (0x%02x), wMaxPacketSize="
    1127             :             "0x%04x (%d)\n",
    1128             :             UE_GET_ADDR(ed->bEndpointAddress),
    1129             :             UTVFU_VIDEO_ENDP,
    1130             :             UGETW(ed->wMaxPacketSize),
    1131             :             sc->sc_iface.psize);
    1132             : 
    1133           0 :         error = usbd_open_pipe(
    1134           0 :             sc->sc_uifaceh,
    1135             :             UTVFU_VIDEO_ENDP,
    1136             :             USBD_EXCLUSIVE_USE,
    1137             :             &sc->sc_iface.pipeh);
    1138           0 :         if (error != USBD_NORMAL_COMPLETION) {
    1139           0 :                 printf("%s: could not open VS pipe: %s\n",
    1140           0 :                     DEVNAME(sc), usbd_errstr(error));
    1141           0 :         }
    1142             : 
    1143           0 :         return (error);
    1144           0 : }
    1145             : 
    1146             : void
    1147           0 : utvfu_as_close(struct utvfu_softc *sc)
    1148             : {
    1149             :         DPRINTF(1, "%s: %s\n", DEVNAME(sc), __func__);
    1150             : 
    1151           0 :         CLR(sc->sc_flags, UTVFU_FLAG_AS_RUNNING);
    1152             : 
    1153           0 :         if (sc->sc_audio.iface.pipeh != NULL) {
    1154           0 :                 usbd_abort_pipe(sc->sc_audio.iface.pipeh);
    1155             : 
    1156           0 :                 usbd_ref_wait(sc->sc_udev);
    1157             : 
    1158           0 :                 usbd_close_pipe(sc->sc_audio.iface.pipeh);
    1159           0 :                 sc->sc_audio.iface.pipeh = NULL;
    1160           0 :         }
    1161           0 : }
    1162             : 
    1163             : void
    1164           0 : utvfu_vs_close(struct utvfu_softc *sc)
    1165             : {
    1166           0 :         if (sc->sc_iface.pipeh != NULL) {
    1167           0 :                 usbd_abort_pipe(sc->sc_iface.pipeh);
    1168           0 :                 usbd_close_pipe(sc->sc_iface.pipeh);
    1169           0 :                 sc->sc_iface.pipeh = NULL;
    1170           0 :         }
    1171             : 
    1172             :         /*
    1173             :          * Some devices need time to shutdown before we switch back to
    1174             :          * the default interface (0).  Not doing so can leave the device
    1175             :          * back in a undefined condition.
    1176             :          */
    1177           0 :         usbd_delay_ms(sc->sc_udev, 100);
    1178             : 
    1179             :         /* switch back to default interface (turns off cam LED) */
    1180           0 :         (void)usbd_set_interface(sc->sc_uifaceh, UTVFU_DFLT_IFACE_IDX);
    1181           0 : }
    1182             : 
    1183             : void
    1184           0 : utvfu_read(struct utvfu_softc *sc, uint8_t *buf, int len)
    1185             : {
    1186             :         /*
    1187             :          * Copy video frame to upper layer buffer and call
    1188             :          * upper layer interrupt.
    1189             :          */
    1190           0 :         *sc->sc_uplayer_fsize = len;
    1191           0 :         memcpy(sc->sc_uplayer_fbuffer, buf, len);
    1192           0 :         (*sc->sc_uplayer_intr)(sc->sc_uplayer_arg);
    1193           0 : }
    1194             : 
    1195             : int
    1196           0 : utvfu_as_start_bulk(struct utvfu_softc *sc)
    1197             : {
    1198             :         int error;
    1199             : 
    1200           0 :         if (ISSET(sc->sc_flags, UTVFU_FLAG_AS_RUNNING))
    1201           0 :                 return (0);
    1202           0 :         if (sc->sc_audio.iface.pipeh == NULL)
    1203           0 :                 return (ENXIO);
    1204             : 
    1205           0 :         SET(sc->sc_flags, UTVFU_FLAG_AS_RUNNING);
    1206           0 :         error = kthread_create(utvfu_as_bulk_thread, sc, NULL, DEVNAME(sc));
    1207           0 :         if (error) {
    1208           0 :                 CLR(sc->sc_flags, UTVFU_FLAG_AS_RUNNING);
    1209           0 :                 printf("%s: can't create kernel thread!", DEVNAME(sc));
    1210           0 :         }
    1211             : 
    1212           0 :         return (error);
    1213           0 : }
    1214             : 
    1215             : void
    1216           0 : utvfu_as_bulk_thread(void *arg)
    1217             : {
    1218           0 :         struct utvfu_softc *sc = arg;
    1219             :         struct utvfu_as_iface *iface;
    1220             :         usbd_status error;
    1221           0 :         uint32_t actlen;
    1222             : 
    1223             :         DPRINTF(1, "%s %s\n", DEVNAME(sc), __func__);
    1224             : 
    1225           0 :         iface = &sc->sc_audio.iface;
    1226           0 :         usbd_ref_incr(sc->sc_udev);
    1227           0 :         while (ISSET(sc->sc_flags, UTVFU_FLAG_AS_RUNNING)) {
    1228           0 :                 usbd_setup_xfer(
    1229           0 :                     iface->xfer,
    1230           0 :                     iface->pipeh,
    1231             :                     0,
    1232             :                     NULL,
    1233             :                     UTVFU_AUDIO_URBSIZE,
    1234             :                     USBD_NO_COPY | USBD_SHORT_XFER_OK | USBD_SYNCHRONOUS,
    1235             :                     0,
    1236             :                     NULL);
    1237           0 :                 error = usbd_transfer(iface->xfer);
    1238             : 
    1239           0 :                 if (error != USBD_NORMAL_COMPLETION) {
    1240             :                         DPRINTF(1, "%s: error in bulk xfer: %s!\n",
    1241             :                             DEVNAME(sc), usbd_errstr(error));
    1242             :                         break;
    1243             :                 }
    1244             : 
    1245           0 :                 usbd_get_xfer_status(iface->xfer, NULL, NULL, &actlen,
    1246             :                     NULL);
    1247             :                 DPRINTF(2, "%s: *** buffer len = %d\n", DEVNAME(sc), actlen);
    1248             : 
    1249           0 :                 rw_enter_read(&sc->sc_audio.rwlock);
    1250           0 :                 utvfu_audio_decode(sc, actlen);
    1251           0 :                 rw_exit_read(&sc->sc_audio.rwlock);
    1252             :         }
    1253             : 
    1254           0 :         CLR(sc->sc_flags, UTVFU_FLAG_AS_RUNNING);
    1255           0 :         usbd_ref_decr(sc->sc_udev);
    1256             : 
    1257             :         DPRINTF(1, "%s %s: exiting\n", DEVNAME(sc), __func__);
    1258             : 
    1259           0 :         kthread_exit(0);
    1260             : }
    1261             : 
    1262             : void
    1263           0 : utvfu_vs_start_isoc(struct utvfu_softc *sc)
    1264             : {
    1265             :         int i;
    1266           0 :         for (i = 0; i < UTVFU_ISOC_TRANSFERS; i++)
    1267           0 :                 utvfu_vs_start_isoc_ixfer(sc, &sc->sc_iface.ixfer[i]);
    1268           0 : }
    1269             : 
    1270             : void
    1271           0 : utvfu_vs_start_isoc_ixfer(struct utvfu_softc *sc,
    1272             :         struct utvfu_isoc_xfer *ixfer)
    1273             : {
    1274             :         int i;
    1275             :         usbd_status error;
    1276             : 
    1277             :         DPRINTF(2, "%s: %s\n", DEVNAME(sc), __func__);
    1278             : 
    1279           0 :         if (usbd_is_dying(sc->sc_udev))
    1280           0 :                 return;
    1281             : 
    1282           0 :         for (i = 0; i < sc->sc_nframes; i++)
    1283           0 :                 ixfer->size[i] = sc->sc_iface.psize;
    1284             : 
    1285           0 :         usbd_setup_isoc_xfer(
    1286           0 :             ixfer->xfer,
    1287           0 :             sc->sc_iface.pipeh,
    1288           0 :             ixfer,
    1289           0 :             ixfer->size,
    1290             :             sc->sc_nframes,
    1291             :             USBD_NO_COPY | USBD_SHORT_XFER_OK,
    1292             :             utvfu_vs_cb);
    1293             : 
    1294           0 :         error = usbd_transfer(ixfer->xfer);
    1295           0 :         if (error && error != USBD_IN_PROGRESS) {
    1296             :                 DPRINTF(1, "%s: usbd_transfer error=%s!\n",
    1297             :                     DEVNAME(sc), usbd_errstr(error));
    1298             :         }
    1299           0 : }
    1300             : 
    1301             : /*
    1302             :  * Each packet contains a number of 256-byte chunks composing the image frame.
    1303             :  */
    1304             : void
    1305           0 : utvfu_vs_cb(struct usbd_xfer *xfer, void *priv, usbd_status status)
    1306             : {
    1307           0 :         struct utvfu_isoc_xfer *ixfer = priv;
    1308           0 :         struct utvfu_softc *sc = ixfer->sc;
    1309             :         int i, off, frame_size;
    1310           0 :         uint32_t actlen;
    1311             :         uint8_t *frame;
    1312             : 
    1313             :         DPRINTF(2, "%s: %s\n", DEVNAME(sc), __func__);
    1314             : 
    1315           0 :         if (status != USBD_NORMAL_COMPLETION) {
    1316             :                 DPRINTF(1, "%s: %s: %s\n", DEVNAME(sc), __func__,
    1317             :                     usbd_errstr(status));
    1318           0 :                 return;
    1319             :         }
    1320           0 :         usbd_get_xfer_status(xfer, NULL, NULL, &actlen, NULL);
    1321             : 
    1322             :         DPRINTF(2, "%s: *** buffer len = %d\n", DEVNAME(sc), actlen);
    1323           0 :         if (actlen == 0)
    1324             :                 goto skip;
    1325             : 
    1326           0 :         frame = KERNADDR(&xfer->dmabuf, 0);
    1327           0 :         for (i = 0; i < sc->sc_nframes; i++, frame += sc->sc_iface.psize) {
    1328           0 :                 frame_size = ixfer->size[i];
    1329             : 
    1330           0 :                 if (frame_size == 0)
    1331             :                         /* frame is empty */
    1332             :                         continue;
    1333             : 
    1334             :                 #define CHUNK_STRIDE    (UTVFU_CHUNK_SIZE*4)
    1335           0 :                 for (off = 0; off + CHUNK_STRIDE <= frame_size;
    1336             :                      off += CHUNK_STRIDE) {
    1337           0 :                         utvfu_image_chunk(sc, frame + off);
    1338             :                 }
    1339             :                 #undef  CHUNK_STRIDE
    1340             :         }
    1341             : 
    1342             : skip:   /* setup new transfer */
    1343           0 :         utvfu_vs_start_isoc_ixfer(sc, ixfer);
    1344           0 : }
    1345             : 
    1346             : int
    1347           0 : utvfu_find_queued(struct utvfu_softc *sc)
    1348             : {
    1349             :         int     i;
    1350             : 
    1351             :         /* find a buffer which is ready for queueing */
    1352           0 :         for (i = 0; i < sc->sc_mmap_count; i++) {
    1353           0 :                 if (sc->sc_mmap[i].v4l2_buf.flags & V4L2_BUF_FLAG_DONE)
    1354             :                         continue;
    1355           0 :                 if (sc->sc_mmap[i].v4l2_buf.flags & V4L2_BUF_FLAG_QUEUED)
    1356           0 :                         return (i);
    1357             :         }
    1358           0 :         return (-1);
    1359           0 : }
    1360             : 
    1361             : int
    1362           0 : utvfu_mmap_queue(struct utvfu_softc *sc, uint8_t *buf, int len)
    1363             : {
    1364             :         int i;
    1365             : 
    1366           0 :         if (sc->sc_mmap_count == 0 || sc->sc_mmap_buffer == NULL)
    1367           0 :                 panic("%s: mmap buffers not allocated", __func__);
    1368             : 
    1369             :         /* find a buffer which is ready for queueing */
    1370           0 :         if ((i = utvfu_find_queued(sc)) == -1) {
    1371             :                 DPRINTF(2, "%s: mmap queue is full!\n", DEVNAME(sc));
    1372           0 :                 return (ENOMEM);
    1373             :         }
    1374             : 
    1375             :         /* copy frame to mmap buffer and report length */
    1376           0 :         memcpy(sc->sc_mmap[i].buf, buf, len);
    1377           0 :         sc->sc_mmap[i].v4l2_buf.bytesused = len;
    1378             : 
    1379             :         /* timestamp it */
    1380           0 :         getmicrotime(&sc->sc_mmap[i].v4l2_buf.timestamp);
    1381             : 
    1382             :         /* appropriately set/clear flags */
    1383           0 :         sc->sc_mmap[i].v4l2_buf.flags &= ~V4L2_BUF_FLAG_QUEUED;
    1384           0 :         sc->sc_mmap[i].v4l2_buf.flags |= V4L2_BUF_FLAG_DONE;
    1385             : 
    1386             :         /* queue it */
    1387           0 :         SIMPLEQ_INSERT_TAIL(&sc->sc_mmap_q, &sc->sc_mmap[i], q_frames);
    1388             :         DPRINTF(2, "%s: %s: frame queued on index %d\n",
    1389             :             DEVNAME(sc), __func__, i);
    1390             : 
    1391           0 :         wakeup(sc);
    1392             : 
    1393             :         /*
    1394             :          * In case userland uses poll(2), signal that we have a frame
    1395             :          * ready to dequeue.
    1396             :          */
    1397           0 :         (*sc->sc_uplayer_intr)(sc->sc_uplayer_arg);
    1398             : 
    1399           0 :         return (0);
    1400           0 : }
    1401             : 
    1402             : caddr_t
    1403           0 : utvfu_mappage(void *v, off_t off, int prot)
    1404             : {
    1405           0 :         struct utvfu_softc *sc = v;
    1406             :         caddr_t p = NULL;
    1407             : 
    1408           0 :         if (off < sc->sc_mmap_bufsz) {
    1409           0 :                 if ((sc->sc_flags & UTVFU_FLAG_MMAP) == 0)
    1410           0 :                         sc->sc_flags |= UTVFU_FLAG_MMAP;
    1411             : 
    1412           0 :                 p = sc->sc_mmap_buffer + off;
    1413           0 :         }
    1414             : 
    1415           0 :         return (p);
    1416             : }
    1417             : 
    1418             : int
    1419           0 : utvfu_get_bufsize(void *v)
    1420             : {
    1421           0 :         struct utvfu_softc *sc = v;
    1422             :         /* YUYV/YUV-422: 4 bytes/2 pixel */
    1423           0 :         return (utvfu_norm_params[sc->sc_normi].cap_width *
    1424           0 :             utvfu_norm_params[sc->sc_normi].cap_height * 2);
    1425             : }
    1426             : 
    1427             : int
    1428           0 : utvfu_start_read(void *v)
    1429             : {
    1430           0 :         struct utvfu_softc *sc = v;
    1431             :         usbd_status error;
    1432             : 
    1433           0 :         if (sc->sc_flags & UTVFU_FLAG_MMAP)
    1434           0 :                 sc->sc_flags &= ~UTVFU_FLAG_MMAP;
    1435             : 
    1436             :         /* open video stream pipe */
    1437           0 :         error = utvfu_vs_open(sc);
    1438           0 :         if (error != USBD_NORMAL_COMPLETION)
    1439           0 :                 return (EINVAL);
    1440             : 
    1441           0 :         utvfu_vs_start_isoc(sc);
    1442             : 
    1443           0 :         return (0);
    1444           0 : }
    1445             : 
    1446             : void
    1447           0 : utvfu_audio_clear_client(struct utvfu_softc *sc)
    1448             : {
    1449           0 :         rw_enter_write(&sc->sc_audio.rwlock);
    1450             : 
    1451           0 :         sc->sc_audio.intr = NULL;
    1452           0 :         sc->sc_audio.intr_arg = NULL;
    1453           0 :         sc->sc_audio.start = NULL;
    1454           0 :         sc->sc_audio.end = NULL;
    1455           0 :         sc->sc_audio.cur = NULL;
    1456           0 :         sc->sc_audio.blksize = 0;
    1457             : 
    1458           0 :         rw_exit_write(&sc->sc_audio.rwlock);
    1459           0 : }
    1460             : 
    1461             : void
    1462           0 : utvfu_as_free(struct utvfu_softc *sc)
    1463             : {
    1464             :         DPRINTF(1, "%s: %s\n", DEVNAME(sc), __func__);
    1465             : 
    1466           0 :         utvfu_as_close(sc);
    1467           0 :         utvfu_as_free_bulk(sc);
    1468           0 : }
    1469             : 
    1470             : void
    1471           0 : utvfu_vs_free(struct utvfu_softc *sc)
    1472             : {
    1473             :         DPRINTF(1, "%s: %s\n", DEVNAME(sc), __func__);
    1474           0 :         utvfu_vs_close(sc);
    1475           0 :         utvfu_vs_free_isoc(sc);
    1476           0 :         utvfu_vs_free_frame(sc);
    1477           0 : }
    1478             : 
    1479             : int
    1480           0 : utvfu_as_init(struct utvfu_softc *sc)
    1481             : {
    1482             :         DPRINTF(1, "%s: %s\n", DEVNAME(sc), __func__);
    1483             : 
    1484           0 :         if (sc->sc_audio.iface.xfer != NULL)
    1485           0 :                 return (0);
    1486             : 
    1487             :         /* allocate audio and video stream xfer buffer */
    1488           0 :         return utvfu_as_alloc_bulk(sc);
    1489           0 : }
    1490             : 
    1491             : int
    1492           0 : utvfu_vs_init(struct utvfu_softc *sc)
    1493             : {
    1494             :         DPRINTF(1, "%s: %s\n", DEVNAME(sc), __func__);
    1495             : 
    1496           0 :         if (utvfu_start_capture(sc) != 0)
    1497           0 :                 return (EINVAL);
    1498             : 
    1499           0 :         if (utvfu_vs_alloc_isoc(sc) != 0 || utvfu_vs_alloc_frame(sc) != 0)
    1500           0 :                 return (ENOMEM);
    1501             : 
    1502           0 :         return (0);
    1503           0 : }
    1504             : 
    1505             : int
    1506           0 : utvfu_vs_alloc_frame(struct utvfu_softc *sc)
    1507             : {
    1508           0 :         struct utvfu_frame_buf *fb = &sc->sc_fb;
    1509             : 
    1510           0 :         fb->size = sc->sc_max_frame_sz;
    1511           0 :         fb->buf = malloc(fb->size, M_DEVBUF, M_NOWAIT);
    1512           0 :         if (fb->buf == NULL) {
    1513           0 :                 printf("%s: can't allocate frame buffer!\n", DEVNAME(sc));
    1514           0 :                 return (ENOMEM);
    1515             :         }
    1516             : 
    1517             :         DPRINTF(1, "%s: %s: allocated %d bytes frame buffer\n",
    1518             :             DEVNAME(sc), __func__, fb->size);
    1519             : 
    1520           0 :         fb->chunks_done = 0;
    1521           0 :         fb->fid = 0;
    1522           0 :         fb->last_odd = 1;
    1523             : 
    1524           0 :         return (0);
    1525           0 : }
    1526             : 
    1527             : void
    1528           0 : utvfu_vs_free_frame(struct utvfu_softc *sc)
    1529             : {
    1530           0 :         struct utvfu_frame_buf *fb = &sc->sc_fb;
    1531             : 
    1532           0 :         if (fb->buf != NULL) {
    1533           0 :                 free(fb->buf, M_DEVBUF, fb->size);
    1534           0 :                 fb->buf = NULL;
    1535           0 :         }
    1536             : 
    1537           0 :         if (sc->sc_mmap_buffer != NULL) {
    1538           0 :                 free(sc->sc_mmap_buffer, M_DEVBUF, sc->sc_mmap_bufsz);
    1539           0 :                 sc->sc_mmap_buffer = NULL;
    1540           0 :                 memset(sc->sc_mmap, 0, sizeof(sc->sc_mmap));
    1541           0 :         }
    1542             : 
    1543           0 :         while (!SIMPLEQ_EMPTY(&sc->sc_mmap_q))
    1544           0 :                 SIMPLEQ_REMOVE_HEAD(&sc->sc_mmap_q, q_frames);
    1545             : 
    1546           0 :         sc->sc_mmap_count = 0;
    1547           0 : }
    1548             : 
    1549             : usbd_status
    1550           0 : utvfu_vs_alloc_isoc(struct utvfu_softc *sc)
    1551             : {
    1552             :         int size, i;
    1553             :         void *buf;
    1554             : 
    1555             :         DPRINTF(1, "%s: %s\n", DEVNAME(sc), __func__);
    1556             : 
    1557           0 :         for (i = 0; i < UTVFU_ISOC_TRANSFERS; i++) {
    1558           0 :                 sc->sc_iface.ixfer[i].sc = sc;
    1559           0 :                 sc->sc_iface.ixfer[i].xfer = usbd_alloc_xfer(sc->sc_udev);        
    1560           0 :                 if (sc->sc_iface.ixfer[i].xfer == NULL) {
    1561           0 :                         printf("%s: could not allocate isoc VS xfer!\n",
    1562           0 :                             DEVNAME(sc));
    1563           0 :                         return (USBD_NOMEM);    
    1564             :                 }
    1565             : 
    1566           0 :                 size = sc->sc_iface.psize * sc->sc_nframes;
    1567             : 
    1568           0 :                 buf = usbd_alloc_buffer(sc->sc_iface.ixfer[i].xfer, size);
    1569           0 :                 if (buf == NULL) {
    1570           0 :                         printf("%s: could not allocate isoc VS buffer!\n",
    1571           0 :                             DEVNAME(sc));
    1572           0 :                         return (USBD_NOMEM);
    1573             :                 }
    1574             :                 DPRINTF(1, "%s: allocated %d bytes isoc VS xfer buffer\n",
    1575             :                     DEVNAME(sc), size);
    1576             :         }
    1577             : 
    1578           0 :         return (USBD_NORMAL_COMPLETION);
    1579           0 : }
    1580             : 
    1581             : int
    1582           0 : utvfu_as_alloc_bulk(struct utvfu_softc *sc)
    1583             : {
    1584             :         struct usbd_xfer *xfer;
    1585             : 
    1586           0 :         xfer = usbd_alloc_xfer(sc->sc_udev);
    1587           0 :         if (xfer == NULL) {
    1588           0 :                 printf("%s: could not allocate bulk AUDIO xfer!\n",
    1589           0 :                     DEVNAME(sc));
    1590           0 :                 return (ENOMEM);
    1591             :         }
    1592             : 
    1593           0 :         if (usbd_alloc_buffer(xfer, UTVFU_AUDIO_URBSIZE) == NULL) {
    1594           0 :                 usbd_free_xfer(xfer);
    1595           0 :                 printf("%s: could not allocate bulk AUDIO buffer!\n",
    1596           0 :                     DEVNAME(sc));
    1597           0 :                 return (ENOMEM);
    1598             :         }
    1599             :         DPRINTF(1, "%s: allocated %d bytes bulk AUDIO xfer buffer\n",
    1600             :             DEVNAME(sc), UTVFU_AUDIO_URBSIZE);
    1601             : 
    1602           0 :         sc->sc_audio.iface.xfer = xfer;
    1603             : 
    1604           0 :         return (0);
    1605           0 : }
    1606             : 
    1607             : void
    1608           0 : utvfu_vs_free_isoc(struct utvfu_softc *sc)
    1609             : {
    1610             :         int i;
    1611             : 
    1612             :         DPRINTF(1, "%s: %s\n", DEVNAME(sc), __func__);
    1613             : 
    1614           0 :         for (i = 0; i < UTVFU_ISOC_TRANSFERS; i++) {
    1615           0 :                 if (sc->sc_iface.ixfer[i].xfer != NULL) {
    1616           0 :                         usbd_free_xfer(sc->sc_iface.ixfer[i].xfer);
    1617           0 :                         sc->sc_iface.ixfer[i].xfer = NULL;
    1618           0 :                 }
    1619             :         }
    1620           0 : }
    1621             : 
    1622             : void
    1623           0 : utvfu_as_free_bulk(struct utvfu_softc *sc)
    1624             : {
    1625             :         DPRINTF(1, "%s: %s\n", DEVNAME(sc), __func__);
    1626             : 
    1627           0 :         if (sc->sc_audio.iface.xfer != NULL) {
    1628           0 :                 usbd_free_xfer(sc->sc_audio.iface.xfer);
    1629           0 :                 sc->sc_audio.iface.xfer = NULL;
    1630           0 :         }
    1631           0 : }
    1632             : 
    1633             : int
    1634           0 : utvfu_reqbufs(void *v, struct v4l2_requestbuffers *rb)
    1635             : {
    1636           0 :         struct utvfu_softc *sc = v;
    1637             :         int i;
    1638             : 
    1639             :         DPRINTF(1, "%s: %s: count=%d\n", DEVNAME(sc), __func__, rb->count);
    1640             : 
    1641             :         /* We do not support freeing buffers via reqbufs(0) */
    1642           0 :         if (rb->count == 0)
    1643           0 :                 return (EINVAL);
    1644             : 
    1645           0 :         if (sc->sc_mmap_count > 0 || sc->sc_mmap_buffer != NULL) {
    1646             :                 DPRINTF(1, "%s: %s: mmap buffers already allocated\n",
    1647             :                     DEVNAME(sc), __func__);
    1648           0 :                 return (EINVAL);
    1649             :         }
    1650             : 
    1651             :         /* limit the buffers */
    1652           0 :         if (rb->count > UTVFU_MAX_BUFFERS)
    1653           0 :                 sc->sc_mmap_count = UTVFU_MAX_BUFFERS;
    1654             :         else
    1655           0 :                 sc->sc_mmap_count = rb->count;
    1656             : 
    1657             :         /* allocate the total mmap buffer */    
    1658           0 :         sc->sc_mmap_bufsz = sc->sc_max_frame_sz;
    1659           0 :         if (INT_MAX / sc->sc_mmap_count < sc->sc_max_frame_sz) /* overflow */
    1660           0 :                 return (ENOMEM);
    1661           0 :         sc->sc_mmap_bufsz *= sc->sc_mmap_count;
    1662           0 :         sc->sc_mmap_bufsz = round_page(sc->sc_mmap_bufsz); /* page align */
    1663           0 :         sc->sc_mmap_buffer = malloc(sc->sc_mmap_bufsz, M_DEVBUF, M_NOWAIT);
    1664           0 :         if (sc->sc_mmap_buffer == NULL) {
    1665           0 :                 printf("%s: can't allocate mmap buffer!\n", DEVNAME(sc));
    1666           0 :                 return (ENOMEM);
    1667             :         }
    1668             :         DPRINTF(1, "%s: allocated %d bytes mmap buffer\n",
    1669             :             DEVNAME(sc), sc->sc_mmap_bufsz);
    1670             : 
    1671             :         /* fill the v4l2_buffer structure */
    1672           0 :         for (i = 0; i < sc->sc_mmap_count; i++) {
    1673           0 :                 sc->sc_mmap[i].buf = sc->sc_mmap_buffer
    1674           0 :                     + (i * sc->sc_max_frame_sz);
    1675           0 :                 sc->sc_mmap[i].v4l2_buf.index = i;
    1676           0 :                 sc->sc_mmap[i].v4l2_buf.m.offset = i * sc->sc_max_frame_sz;
    1677           0 :                 sc->sc_mmap[i].v4l2_buf.length = sc->sc_max_frame_sz;
    1678           0 :                 sc->sc_mmap[i].v4l2_buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
    1679           0 :                 sc->sc_mmap[i].v4l2_buf.sequence = 0;
    1680           0 :                 sc->sc_mmap[i].v4l2_buf.field = V4L2_FIELD_NONE;
    1681           0 :                 sc->sc_mmap[i].v4l2_buf.memory = V4L2_MEMORY_MMAP;
    1682           0 :                 sc->sc_mmap[i].v4l2_buf.flags = V4L2_BUF_FLAG_MAPPED;
    1683             : 
    1684             :                 DPRINTF(1, "%s: %s: index=%d, offset=%d, length=%d\n",
    1685             :                     DEVNAME(sc), __func__,
    1686             :                     sc->sc_mmap[i].v4l2_buf.index,
    1687             :                     sc->sc_mmap[i].v4l2_buf.m.offset,
    1688             :                     sc->sc_mmap[i].v4l2_buf.length);
    1689             :         }
    1690             : 
    1691             :         /* tell how many buffers we have really allocated */
    1692           0 :         rb->count = sc->sc_mmap_count;
    1693             : 
    1694           0 :         return (0);
    1695           0 : }
    1696             : 
    1697             : int
    1698           0 : utvfu_querybuf(void *v, struct v4l2_buffer *qb)
    1699             : {
    1700           0 :         struct utvfu_softc *sc = v;
    1701             : 
    1702           0 :         if (qb->type != V4L2_BUF_TYPE_VIDEO_CAPTURE ||
    1703           0 :             qb->memory != V4L2_MEMORY_MMAP ||
    1704           0 :             qb->index >= sc->sc_mmap_count)
    1705           0 :                 return (EINVAL);
    1706             : 
    1707           0 :         memcpy(qb, &sc->sc_mmap[qb->index].v4l2_buf,
    1708             :             sizeof(struct v4l2_buffer));
    1709             : 
    1710             :         DPRINTF(1, "%s: %s: index=%d, offset=%d, length=%d\n",
    1711             :             DEVNAME(sc), __func__, qb->index, qb->m.offset, qb->length);
    1712             : 
    1713           0 :         return (0);
    1714           0 : }
    1715             : 
    1716             : int
    1717           0 : utvfu_qbuf(void *v, struct v4l2_buffer *qb)
    1718             : {
    1719           0 :         struct utvfu_softc *sc = v;
    1720             : 
    1721           0 :         if (qb->type != V4L2_BUF_TYPE_VIDEO_CAPTURE ||
    1722           0 :             qb->memory != V4L2_MEMORY_MMAP ||
    1723           0 :             qb->index >= sc->sc_mmap_count)
    1724           0 :                 return (EINVAL);
    1725             : 
    1726           0 :         sc->sc_mmap[qb->index].v4l2_buf.flags &= ~V4L2_BUF_FLAG_DONE;
    1727           0 :         sc->sc_mmap[qb->index].v4l2_buf.flags |= V4L2_BUF_FLAG_MAPPED;
    1728           0 :         sc->sc_mmap[qb->index].v4l2_buf.flags |= V4L2_BUF_FLAG_QUEUED;
    1729             : 
    1730             :         DPRINTF(2, "%s: %s: buffer on index %d ready for queueing\n",
    1731             :             DEVNAME(sc), __func__, qb->index);
    1732             : 
    1733           0 :         return (0);
    1734           0 : }
    1735             : 
    1736             : int
    1737           0 : utvfu_dqbuf(void *v, struct v4l2_buffer *dqb)
    1738             : {
    1739           0 :         struct utvfu_softc *sc = v;
    1740             :         struct utvfu_mmap *mmap;
    1741             :         int error;
    1742             : 
    1743           0 :         if (dqb->type != V4L2_BUF_TYPE_VIDEO_CAPTURE ||
    1744           0 :             dqb->memory != V4L2_MEMORY_MMAP)
    1745           0 :                 return (EINVAL);
    1746             : 
    1747           0 :         if (SIMPLEQ_EMPTY(&sc->sc_mmap_q)) {
    1748             :                 /* mmap queue is empty, block until first frame is queued */
    1749           0 :                 error = tsleep(sc, 0, "vid_mmap", 10 * hz);
    1750           0 :                 if (error)
    1751           0 :                         return (EINVAL);
    1752             :         }
    1753             : 
    1754           0 :         mmap = SIMPLEQ_FIRST(&sc->sc_mmap_q);
    1755           0 :         if (mmap == NULL)
    1756           0 :                 panic("utvfu_dqbuf: NULL pointer!");
    1757             : 
    1758           0 :         memcpy(dqb, &mmap->v4l2_buf, sizeof(struct v4l2_buffer));
    1759             : 
    1760           0 :         mmap->v4l2_buf.flags &= ~(V4L2_BUF_FLAG_DONE|V4L2_BUF_FLAG_QUEUED);
    1761           0 :         mmap->v4l2_buf.flags |= V4L2_BUF_FLAG_MAPPED;
    1762             : 
    1763             :         DPRINTF(2, "%s: %s: frame dequeued from index %d\n",
    1764             :             DEVNAME(sc), __func__, mmap->v4l2_buf.index);
    1765           0 :         SIMPLEQ_REMOVE_HEAD(&sc->sc_mmap_q, q_frames);
    1766             : 
    1767           0 :         return (0);
    1768           0 : }
    1769             : 
    1770             : int
    1771           0 : utvfu_streamon(void *v, int type)
    1772             : {
    1773           0 :         struct utvfu_softc *sc = v;
    1774             :         usbd_status error;
    1775             : 
    1776             :         /* open video stream pipe */
    1777           0 :         error = utvfu_vs_open(sc);
    1778           0 :         if (error != USBD_NORMAL_COMPLETION)
    1779           0 :                 return (EINVAL);
    1780             : 
    1781           0 :         utvfu_vs_start_isoc(sc);
    1782             : 
    1783           0 :         return (0);
    1784           0 : }
    1785             : 
    1786             : int
    1787           0 : utvfu_streamoff(void *v, int type)
    1788             : {
    1789           0 :         utvfu_vs_close(v);
    1790           0 :         return (0);
    1791             : }
    1792             : 
    1793             : int
    1794           0 : utvfu_queryctrl(void *v, struct v4l2_queryctrl *qctrl)
    1795             : {
    1796           0 :         qctrl->flags = V4L2_CTRL_FLAG_DISABLED;
    1797           0 :         return (0);
    1798             : }
    1799             : 
    1800             : int
    1801           0 : utvfu_g_parm(void *v, struct v4l2_streamparm *parm)
    1802             : {
    1803           0 :         struct utvfu_softc *sc = v;
    1804             : 
    1805           0 :         if (parm->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
    1806           0 :                 return (EINVAL);
    1807             :         /*
    1808             :          * XXX Unsure whether there is a way to negotiate this with the
    1809             :          * device, but returning 0 will allow xenocara's video to run
    1810             :          */
    1811           0 :         switch (utvfu_norm_params[sc->sc_normi].norm) {
    1812             :         default:
    1813           0 :                 return (EINVAL);
    1814             :         case V4L2_STD_525_60:
    1815           0 :                 parm->parm.capture.capability = V4L2_CAP_TIMEPERFRAME;
    1816           0 :                 parm->parm.capture.capturemode = 0;
    1817           0 :                 parm->parm.capture.timeperframe.numerator = 30;
    1818           0 :                 parm->parm.capture.timeperframe.denominator = 1;
    1819           0 :                 break;
    1820             :         case V4L2_STD_PAL:
    1821           0 :                 parm->parm.capture.capability = V4L2_CAP_TIMEPERFRAME;
    1822           0 :                 parm->parm.capture.capturemode = 0;
    1823           0 :                 parm->parm.capture.timeperframe.numerator = 25;
    1824           0 :                 parm->parm.capture.timeperframe.denominator = 1;
    1825           0 :                 break;
    1826             :         }
    1827           0 :         return (0);
    1828           0 : }
    1829             : 
    1830             : int
    1831           0 : utvfu_s_parm(void *v, struct v4l2_streamparm *parm)
    1832             : {
    1833           0 :         if (parm->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
    1834           0 :                 return (EINVAL);
    1835           0 :         return (0);
    1836           0 : }
    1837             : 
    1838             : /*
    1839             :  * A U D I O   O P S
    1840             :  */
    1841             : 
    1842             : int
    1843           0 : utvfu_audio_open(void *v, int flags)
    1844             : {
    1845           0 :         struct utvfu_softc *sc = v;
    1846             : 
    1847           0 :         if (usbd_is_dying(sc->sc_udev))
    1848           0 :                 return (EIO);
    1849             : 
    1850           0 :         if ((flags & FWRITE))
    1851           0 :                 return (ENXIO);
    1852             : 
    1853           0 :         if (ISSET(sc->sc_flags, UTVFU_FLAG_AS_RUNNING))
    1854           0 :                 return (EBUSY);
    1855             : 
    1856           0 :         return utvfu_as_init(sc);
    1857           0 : }
    1858             : 
    1859             : void
    1860           0 : utvfu_audio_close(void *v)
    1861             : {
    1862           0 :         struct utvfu_softc *sc = v;
    1863             : 
    1864             :         DPRINTF(1, "%s: %s\n", DEVNAME(sc), __func__);
    1865             : 
    1866           0 :         utvfu_audio_stop(sc);
    1867           0 :         utvfu_audio_clear_client(sc);
    1868           0 : }
    1869             : 
    1870             : int
    1871           0 : utvfu_audio_set_params(void *v, int setmode, int usemode,
    1872             :     struct audio_params *play, struct audio_params *rec)
    1873             : {
    1874           0 :         struct utvfu_softc *sc = v;
    1875             : 
    1876           0 :         if (usbd_is_dying(sc->sc_udev))
    1877           0 :                 return (EIO);
    1878             : 
    1879             :         DPRINTF(1, "%s %s\n", DEVNAME(sc), __func__);
    1880             : 
    1881             :         /* XXX ? */
    1882           0 :         play->sample_rate = 0;
    1883           0 :         play->encoding = AUDIO_ENCODING_NONE;
    1884             : 
    1885           0 :         rec->sample_rate = 48000;
    1886           0 :         rec->encoding = AUDIO_ENCODING_SLINEAR_LE;
    1887           0 :         rec->precision = 16;
    1888           0 :         rec->bps = 2;
    1889           0 :         rec->msb = 1;
    1890           0 :         rec->channels = 2;
    1891             : 
    1892           0 :         return (0);
    1893           0 : }
    1894             : 
    1895             : int
    1896           0 : utvfu_audio_halt_out(void *v)
    1897             : {
    1898           0 :         return (EIO);
    1899             : }
    1900             : 
    1901             : int
    1902           0 : utvfu_audio_halt_in(void *v)
    1903             : {
    1904           0 :         struct utvfu_softc *sc = v;
    1905             : 
    1906           0 :         if (usbd_is_dying(sc->sc_udev))
    1907           0 :                 return (EIO);
    1908             : 
    1909             :         DPRINTF(1, "%s: %s\n", DEVNAME(sc), __func__);
    1910             : 
    1911           0 :         utvfu_audio_stop(sc);
    1912           0 :         utvfu_audio_clear_client(sc);
    1913             : 
    1914           0 :         return (0);
    1915           0 : }
    1916             : 
    1917             : int
    1918           0 : utvfu_audio_mixer_set_port(void *v, struct mixer_ctrl *cp)
    1919             : {
    1920           0 :         struct utvfu_softc *sc = v;
    1921             : 
    1922           0 :         if (usbd_is_dying(sc->sc_udev))
    1923           0 :                 return (EIO);
    1924             : 
    1925             :         DPRINTF(1, "%s %s\n", DEVNAME(sc), __func__);
    1926             : 
    1927           0 :         if (cp->type != AUDIO_MIXER_ENUM ||
    1928           0 :             cp->un.ord < 0 || cp->un.ord > 1)
    1929           0 :                 return (EINVAL);
    1930             : /* XXX TODO */
    1931             :         DPRINTF(1, "%s %s: cp->un.ord=%d\n", DEVNAME(sc), __func__, cp->un.ord);
    1932           0 :         return (0);
    1933           0 : }
    1934             : 
    1935             : int
    1936           0 : utvfu_audio_mixer_get_port(void *v, struct mixer_ctrl *cp)
    1937             : {
    1938           0 :         struct utvfu_softc *sc = v;
    1939             : 
    1940           0 :         if (usbd_is_dying(sc->sc_udev))
    1941           0 :                 return (EIO);
    1942             : 
    1943             :         DPRINTF(1, "%s %s\n", DEVNAME(sc), __func__);
    1944             : 
    1945           0 :         if (cp->type != AUDIO_MIXER_ENUM ||
    1946           0 :             cp->un.ord < 0 || cp->un.ord > 1)
    1947           0 :                 return (EINVAL);
    1948             : /* XXX TODO */
    1949             :         DPRINTF(1, "%s %s: cp->un.ord=%d\n", DEVNAME(sc), __func__, cp->un.ord);
    1950           0 :         return (0);
    1951           0 : }
    1952             : 
    1953             : int
    1954           0 : utvfu_audio_query_devinfo(void *v, struct mixer_devinfo *mi)
    1955             : {
    1956           0 :         struct utvfu_softc *sc = v;
    1957             : 
    1958           0 :         if (usbd_is_dying(sc->sc_udev))
    1959           0 :                 return (EIO);
    1960             : 
    1961             :         DPRINTF(1, "%s %s\n", DEVNAME(sc), __func__);
    1962             : 
    1963           0 :         if (mi->index != 0)
    1964           0 :                 return (EINVAL);
    1965             : 
    1966             : /* XXX SOMEONE WITH AUDIO EXPERTIZE NEEDS TO HELP HERE */
    1967           0 :         strlcpy(mi->label.name, "mix0-i0", sizeof(mi->label.name));
    1968           0 :         mi->type = AUDIO_MIXER_ENUM;
    1969           0 :         mi->un.e.num_mem = 2;
    1970           0 :         mi->un.e.member[0].ord = 0;
    1971           0 :         strlcpy(mi->un.e.member[0].label.name, AudioNoff,
    1972             :             sizeof(mi->un.e.member[0].label.name));
    1973           0 :         mi->un.e.member[1].ord = 1;
    1974           0 :         strlcpy(mi->un.e.member[1].label.name, AudioNon,
    1975             :             sizeof(mi->un.e.member[1].label.name));
    1976             : 
    1977           0 :         return (0);
    1978           0 : }
    1979             : 
    1980             : int
    1981           0 : utvfu_audio_get_props(void *v)
    1982             : {
    1983           0 :         return (0);
    1984             : }
    1985             : 
    1986             : int
    1987           0 : utvfu_audio_trigger_output(void *v, void *start, void *end, int blksize,
    1988             :     void (*intr)(void *), void *arg, struct audio_params *param)
    1989             : {
    1990           0 :         return (EIO);
    1991             : }
    1992             : 
    1993             : int
    1994           0 : utvfu_audio_trigger_input(void *v, void *start, void *end, int blksize,
    1995             :     void (*intr)(void *), void *arg, struct audio_params *param)
    1996             : {
    1997           0 :         struct utvfu_softc *sc = v;
    1998             : 
    1999           0 :         if (usbd_is_dying(sc->sc_udev))
    2000           0 :                 return (EIO);
    2001             : 
    2002           0 :         rw_enter_write(&sc->sc_audio.rwlock);
    2003             : 
    2004           0 :         sc->sc_audio.intr_arg = arg;
    2005           0 :         sc->sc_audio.intr = intr;
    2006           0 :         sc->sc_audio.start = start;
    2007           0 :         sc->sc_audio.end = end;
    2008           0 :         sc->sc_audio.cur = start;
    2009           0 :         sc->sc_audio.blksize = blksize;
    2010             : 
    2011           0 :         rw_exit_write(&sc->sc_audio.rwlock);
    2012             : 
    2013             :         DPRINTF(1, "%s %s: start=%p end=%p diff=%lu blksize=%d\n",
    2014             :             DEVNAME(sc), __func__, start, end,
    2015             :             ((u_char *)end - (u_char *)start), blksize);
    2016             : 
    2017           0 :         return utvfu_audio_start(sc);
    2018           0 : }
    2019             : 
    2020             : int
    2021           0 : utvfu_audio_start(struct utvfu_softc *sc)
    2022             : {
    2023             :         DPRINTF(1, "%s: %s\n", DEVNAME(sc), __func__);
    2024             : 
    2025           0 :         if (ISSET(sc->sc_flags, UTVFU_FLAG_AS_RUNNING))
    2026           0 :                 return (0);
    2027             : 
    2028           0 :         utvfu_audio_start_chip(sc);
    2029             : 
    2030           0 :         if (utvfu_as_init(sc) != 0)
    2031           0 :                 return (ENOMEM);
    2032           0 :         if (sc->sc_audio.iface.pipeh == NULL) {
    2033           0 :                 if (utvfu_as_open(sc) != USBD_NORMAL_COMPLETION)
    2034           0 :                         return (ENOMEM);
    2035             :         }
    2036             : 
    2037           0 :         return utvfu_as_start_bulk(sc);
    2038           0 : }
    2039             : 
    2040             : int
    2041           0 : utvfu_audio_stop(struct utvfu_softc *sc)
    2042             : {
    2043             :         DPRINTF(1, "%s: %s\n", DEVNAME(sc), __func__);
    2044             : 
    2045           0 :         utvfu_audio_stop_chip(sc);
    2046           0 :         utvfu_as_free(sc);
    2047             : 
    2048           0 :         return (0);
    2049             : }

Generated by: LCOV version 1.13