Home | History | Annotate | Line # | Download | only in usb
      1  1.11  riastrad /* $NetBSD: auvitek_video.c,v 1.11 2022/03/13 12:49:36 riastradh Exp $ */
      2   1.1  jmcneill 
      3   1.1  jmcneill /*-
      4   1.1  jmcneill  * Copyright (c) 2010 Jared D. McNeill <jmcneill (at) invisible.ca>
      5   1.1  jmcneill  * All rights reserved.
      6   1.1  jmcneill  *
      7   1.1  jmcneill  * Redistribution and use in source and binary forms, with or without
      8   1.1  jmcneill  * modification, are permitted provided that the following conditions
      9   1.1  jmcneill  * are met:
     10   1.1  jmcneill  * 1. Redistributions of source code must retain the above copyright
     11   1.1  jmcneill  *    notice, this list of conditions and the following disclaimer.
     12   1.1  jmcneill  * 2. Redistributions in binary form must reproduce the above copyright
     13   1.1  jmcneill  *    notice, this list of conditions and the following disclaimer in the
     14   1.1  jmcneill  *    documentation and/or other materials provided with the distribution.
     15   1.1  jmcneill  *
     16   1.1  jmcneill  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
     17   1.1  jmcneill  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
     18   1.1  jmcneill  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     19   1.1  jmcneill  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
     20   1.1  jmcneill  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
     21   1.1  jmcneill  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
     22   1.1  jmcneill  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
     23   1.1  jmcneill  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
     24   1.1  jmcneill  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
     25   1.1  jmcneill  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
     26   1.1  jmcneill  * POSSIBILITY OF SUCH DAMAGE.
     27   1.1  jmcneill  */
     28   1.1  jmcneill 
     29   1.1  jmcneill /*
     30   1.1  jmcneill  * Auvitek AU0828 USB controller
     31   1.1  jmcneill  */
     32   1.1  jmcneill 
     33   1.1  jmcneill #include <sys/cdefs.h>
     34  1.11  riastrad __KERNEL_RCSID(0, "$NetBSD: auvitek_video.c,v 1.11 2022/03/13 12:49:36 riastradh Exp $");
     35   1.1  jmcneill 
     36   1.1  jmcneill #include <sys/param.h>
     37   1.1  jmcneill #include <sys/systm.h>
     38   1.1  jmcneill #include <sys/device.h>
     39   1.1  jmcneill #include <sys/conf.h>
     40   1.1  jmcneill #include <sys/kmem.h>
     41   1.1  jmcneill #include <sys/bus.h>
     42   1.1  jmcneill 
     43   1.1  jmcneill #include <dev/usb/usb.h>
     44   1.1  jmcneill #include <dev/usb/usbdi.h>
     45   1.1  jmcneill #include <dev/usb/usbdivar.h>
     46   1.1  jmcneill #include <dev/usb/usbdi_util.h>
     47   1.1  jmcneill #include <dev/usb/usbdevs.h>
     48   1.1  jmcneill 
     49   1.1  jmcneill #include <dev/video_if.h>
     50   1.1  jmcneill 
     51   1.1  jmcneill #include <dev/usb/auvitekreg.h>
     52   1.1  jmcneill #include <dev/usb/auvitekvar.h>
     53   1.1  jmcneill 
     54   1.1  jmcneill #define	AUVITEK_FORMAT_DEFAULT		0
     55   1.1  jmcneill #define	AUVITEK_STANDARD_NTSC_M		0
     56   1.1  jmcneill #define	AUVITEK_TUNER_DEFAULT		0
     57   1.1  jmcneill #define	AUVITEK_AUDIO_TELEVISION	0
     58   1.1  jmcneill #define	AUVITEK_AUDIO_LINEIN		1
     59   1.1  jmcneill #define	AUVITEK_INPUT_COMPOSITE		0
     60   1.1  jmcneill #define	AUVITEK_INPUT_SVIDEO		1
     61   1.1  jmcneill #define	AUVITEK_INPUT_TELEVISION	2
     62   1.1  jmcneill #define	AUVITEK_INPUT_CABLE		3
     63   1.1  jmcneill 
     64   1.1  jmcneill static int		auvitek_open(void *, int);
     65   1.1  jmcneill static void		auvitek_close(void *);
     66   1.1  jmcneill static const char *	auvitek_get_devname(void *);
     67   1.1  jmcneill static const char *	auvitek_get_businfo(void *);
     68   1.1  jmcneill static int		auvitek_enum_format(void *, uint32_t,
     69   1.1  jmcneill 					  struct video_format *);
     70   1.1  jmcneill static int		auvitek_get_format(void *, struct video_format *);
     71   1.1  jmcneill static int		auvitek_set_format(void *, struct video_format *);
     72   1.1  jmcneill static int		auvitek_try_format(void *, struct video_format *);
     73   1.1  jmcneill static int		auvitek_enum_standard(void *, uint32_t,
     74   1.1  jmcneill 					      enum video_standard *);
     75   1.1  jmcneill static int		auvitek_get_standard(void *, enum video_standard *);
     76   1.1  jmcneill static int		auvitek_set_standard(void *, enum video_standard);
     77   1.1  jmcneill static int		auvitek_start_transfer(void *);
     78   1.1  jmcneill static int		auvitek_stop_transfer(void *);
     79   1.1  jmcneill static int		auvitek_get_tuner(void *, struct video_tuner *);
     80   1.1  jmcneill static int		auvitek_set_tuner(void *, struct video_tuner *);
     81   1.1  jmcneill static int		auvitek_enum_audio(void *, uint32_t,
     82   1.1  jmcneill 					   struct video_audio *);
     83   1.1  jmcneill static int		auvitek_get_audio(void *, struct video_audio *);
     84   1.1  jmcneill static int		auvitek_set_audio(void *, struct video_audio *);
     85   1.1  jmcneill static int		auvitek_enum_input(void *, uint32_t,
     86   1.1  jmcneill 					   struct video_input *);
     87   1.1  jmcneill static int		auvitek_get_input(void *, struct video_input *);
     88   1.1  jmcneill static int		auvitek_set_input(void *, struct video_input *);
     89   1.1  jmcneill static int		auvitek_get_frequency(void *, struct video_frequency *);
     90   1.1  jmcneill static int		auvitek_set_frequency(void *, struct video_frequency *);
     91   1.1  jmcneill 
     92   1.1  jmcneill static int		auvitek_start_xfer(struct auvitek_softc *);
     93   1.1  jmcneill static int		auvitek_stop_xfer(struct auvitek_softc *);
     94   1.1  jmcneill static int		auvitek_isoc_start(struct auvitek_softc *);
     95   1.1  jmcneill static int		auvitek_isoc_start1(struct auvitek_isoc *);
     96   1.7     skrll static void		auvitek_isoc_intr(struct usbd_xfer *, void *,
     97   1.1  jmcneill 					  usbd_status);
     98   1.1  jmcneill static int		auvitek_isoc_process(struct auvitek_softc *,
     99   1.1  jmcneill 					     uint8_t *, uint32_t);
    100   1.1  jmcneill static void		auvitek_videobuf_weave(struct auvitek_softc *,
    101   1.1  jmcneill 					       uint8_t *, uint32_t);
    102   1.1  jmcneill 
    103   1.4  jmcneill static const struct video_hw_if auvitek_video_if = {
    104   1.1  jmcneill 	.open = auvitek_open,
    105   1.1  jmcneill 	.close = auvitek_close,
    106   1.1  jmcneill 	.get_devname = auvitek_get_devname,
    107   1.1  jmcneill 	.get_businfo = auvitek_get_businfo,
    108   1.1  jmcneill 	.enum_format = auvitek_enum_format,
    109   1.1  jmcneill 	.get_format = auvitek_get_format,
    110   1.1  jmcneill 	.set_format = auvitek_set_format,
    111   1.1  jmcneill 	.try_format = auvitek_try_format,
    112   1.1  jmcneill 	.enum_standard = auvitek_enum_standard,
    113   1.1  jmcneill 	.get_standard = auvitek_get_standard,
    114   1.1  jmcneill 	.set_standard = auvitek_set_standard,
    115   1.1  jmcneill 	.start_transfer = auvitek_start_transfer,
    116   1.1  jmcneill 	.stop_transfer = auvitek_stop_transfer,
    117   1.1  jmcneill 	.get_tuner = auvitek_get_tuner,
    118   1.1  jmcneill 	.set_tuner = auvitek_set_tuner,
    119   1.1  jmcneill 	.enum_audio = auvitek_enum_audio,
    120   1.1  jmcneill 	.get_audio = auvitek_get_audio,
    121   1.1  jmcneill 	.set_audio = auvitek_set_audio,
    122   1.1  jmcneill 	.enum_input = auvitek_enum_input,
    123   1.1  jmcneill 	.get_input = auvitek_get_input,
    124   1.1  jmcneill 	.set_input = auvitek_set_input,
    125   1.1  jmcneill 	.get_frequency = auvitek_get_frequency,
    126   1.1  jmcneill 	.set_frequency = auvitek_set_frequency,
    127   1.1  jmcneill };
    128   1.1  jmcneill 
    129   1.1  jmcneill int
    130   1.1  jmcneill auvitek_video_attach(struct auvitek_softc *sc)
    131   1.1  jmcneill {
    132   1.1  jmcneill 	snprintf(sc->sc_businfo, sizeof(sc->sc_businfo), "usb:%08x",
    133   1.7     skrll 	    sc->sc_udev->ud_cookie.cookie);
    134   1.5  jmcneill 
    135   1.5  jmcneill 	auvitek_video_rescan(sc, NULL, NULL);
    136   1.1  jmcneill 
    137   1.9     skrll 	return sc->sc_videodev != NULL;
    138   1.1  jmcneill }
    139   1.1  jmcneill 
    140   1.1  jmcneill int
    141   1.1  jmcneill auvitek_video_detach(struct auvitek_softc *sc, int flags)
    142   1.1  jmcneill {
    143   1.1  jmcneill 
    144   1.1  jmcneill 	return 0;
    145   1.1  jmcneill }
    146   1.1  jmcneill 
    147   1.1  jmcneill void
    148   1.5  jmcneill auvitek_video_rescan(struct auvitek_softc *sc, const char *ifattr,
    149   1.5  jmcneill     const int *locs)
    150   1.5  jmcneill {
    151  1.10  riastrad 	if (ifattr_match(ifattr, "videobus") && sc->sc_videodev == NULL) {
    152   1.5  jmcneill 		sc->sc_videodev = video_attach_mi(&auvitek_video_if,
    153  1.10  riastrad 		    sc->sc_dev, sc);
    154  1.10  riastrad 	}
    155   1.5  jmcneill }
    156   1.5  jmcneill 
    157   1.5  jmcneill void
    158   1.1  jmcneill auvitek_video_childdet(struct auvitek_softc *sc, device_t child)
    159   1.1  jmcneill {
    160   1.1  jmcneill 	if (sc->sc_videodev == child)
    161   1.1  jmcneill 		sc->sc_videodev = NULL;
    162   1.1  jmcneill }
    163   1.1  jmcneill 
    164   1.1  jmcneill static int
    165   1.1  jmcneill auvitek_open(void *opaque, int flags)
    166   1.1  jmcneill {
    167   1.1  jmcneill 	struct auvitek_softc *sc = opaque;
    168   1.1  jmcneill 
    169   1.1  jmcneill 	if (sc->sc_dying)
    170   1.1  jmcneill 		return EIO;
    171   1.1  jmcneill 
    172   1.6  jmcneill 	auvitek_attach_tuner(sc->sc_dev);
    173   1.1  jmcneill 
    174   1.1  jmcneill 	if (sc->sc_xc5k == NULL)
    175   1.1  jmcneill 		return ENXIO;
    176   1.1  jmcneill 
    177   1.1  jmcneill 	return 0;
    178   1.1  jmcneill }
    179   1.1  jmcneill 
    180   1.1  jmcneill static void
    181   1.1  jmcneill auvitek_close(void *opaque)
    182   1.1  jmcneill {
    183   1.1  jmcneill }
    184   1.1  jmcneill 
    185   1.1  jmcneill static const char *
    186   1.1  jmcneill auvitek_get_devname(void *opaque)
    187   1.1  jmcneill {
    188   1.1  jmcneill 	struct auvitek_softc *sc = opaque;
    189   1.1  jmcneill 
    190   1.1  jmcneill 	return sc->sc_descr;
    191   1.1  jmcneill }
    192   1.1  jmcneill 
    193   1.1  jmcneill static const char *
    194   1.1  jmcneill auvitek_get_businfo(void *opaque)
    195   1.1  jmcneill {
    196   1.1  jmcneill 	struct auvitek_softc *sc = opaque;
    197   1.1  jmcneill 
    198   1.1  jmcneill 	return sc->sc_businfo;
    199   1.1  jmcneill }
    200   1.1  jmcneill 
    201   1.1  jmcneill static int
    202   1.1  jmcneill auvitek_enum_format(void *opaque, uint32_t index, struct video_format *format)
    203   1.1  jmcneill {
    204   1.1  jmcneill 	if (index != AUVITEK_FORMAT_DEFAULT)
    205   1.1  jmcneill 		return EINVAL;
    206   1.1  jmcneill 
    207   1.1  jmcneill 	format->pixel_format = VIDEO_FORMAT_UYVY;
    208   1.1  jmcneill 
    209   1.1  jmcneill 	return 0;
    210   1.1  jmcneill }
    211   1.1  jmcneill 
    212   1.1  jmcneill static int
    213   1.1  jmcneill auvitek_get_format(void *opaque, struct video_format *format)
    214   1.1  jmcneill {
    215   1.1  jmcneill 
    216   1.1  jmcneill 	format->pixel_format = VIDEO_FORMAT_UYVY;
    217   1.1  jmcneill 	format->width = 720;
    218   1.1  jmcneill 	format->height = 480;
    219   1.1  jmcneill 	format->stride = format->width * 2;
    220   1.1  jmcneill 	format->sample_size = format->stride * format->height;
    221   1.1  jmcneill 	format->aspect_x = 4;
    222   1.1  jmcneill 	format->aspect_y = 3;
    223   1.1  jmcneill 	format->color.primaries = VIDEO_COLOR_PRIMARIES_SMPTE_170M;
    224   1.1  jmcneill 	format->color.gamma_function = VIDEO_GAMMA_FUNCTION_UNSPECIFIED;
    225   1.1  jmcneill 	format->color.matrix_coeff = VIDEO_MATRIX_COEFF_UNSPECIFIED;
    226   1.1  jmcneill 	format->interlace_flags = VIDEO_INTERLACE_ON;
    227   1.1  jmcneill 	format->priv = 0;
    228   1.1  jmcneill 
    229   1.1  jmcneill 	return 0;
    230   1.1  jmcneill }
    231   1.1  jmcneill 
    232   1.1  jmcneill static int
    233   1.1  jmcneill auvitek_set_format(void *opaque, struct video_format *format)
    234   1.1  jmcneill {
    235   1.1  jmcneill 	if (format->pixel_format != VIDEO_FORMAT_UYVY)
    236   1.1  jmcneill 		return EINVAL;
    237   1.1  jmcneill 
    238   1.1  jmcneill 	return auvitek_get_format(opaque, format);
    239   1.1  jmcneill }
    240   1.1  jmcneill 
    241   1.1  jmcneill static int
    242   1.1  jmcneill auvitek_try_format(void *opaque, struct video_format *format)
    243   1.1  jmcneill {
    244   1.1  jmcneill 	return auvitek_get_format(opaque, format);
    245   1.1  jmcneill }
    246   1.1  jmcneill 
    247   1.1  jmcneill static int
    248   1.1  jmcneill auvitek_enum_standard(void *opaque, uint32_t index, enum video_standard *vstd)
    249   1.1  jmcneill {
    250   1.1  jmcneill 	switch (index) {
    251   1.1  jmcneill 	case AUVITEK_STANDARD_NTSC_M:
    252   1.1  jmcneill 		*vstd = VIDEO_STANDARD_NTSC_M;
    253   1.1  jmcneill 		return 0;
    254   1.1  jmcneill 	default:
    255   1.1  jmcneill 		return EINVAL;
    256   1.1  jmcneill 	}
    257   1.1  jmcneill }
    258   1.1  jmcneill 
    259   1.1  jmcneill static int
    260   1.1  jmcneill auvitek_get_standard(void *opaque, enum video_standard *vstd)
    261   1.1  jmcneill {
    262   1.1  jmcneill 	*vstd = VIDEO_STANDARD_NTSC_M;
    263   1.1  jmcneill 	return 0;
    264   1.1  jmcneill }
    265   1.1  jmcneill 
    266   1.1  jmcneill static int
    267   1.1  jmcneill auvitek_set_standard(void *opaque, enum video_standard vstd)
    268   1.1  jmcneill {
    269   1.1  jmcneill 	switch (vstd) {
    270   1.1  jmcneill 	case VIDEO_STANDARD_NTSC_M:
    271   1.1  jmcneill 		return 0;
    272   1.1  jmcneill 	default:
    273   1.1  jmcneill 		return EINVAL;
    274   1.1  jmcneill 	}
    275   1.1  jmcneill }
    276   1.1  jmcneill 
    277   1.1  jmcneill static int
    278   1.1  jmcneill auvitek_start_transfer(void *opaque)
    279   1.1  jmcneill {
    280   1.1  jmcneill 	struct auvitek_softc *sc = opaque;
    281   1.1  jmcneill 	int error, s;
    282   1.1  jmcneill 	uint16_t vpos = 0, hpos = 0;
    283   1.1  jmcneill 	uint16_t hres = 720 * 2;
    284   1.1  jmcneill 	uint16_t vres = 484 / 2;
    285   1.1  jmcneill 
    286   1.1  jmcneill 	auvitek_write_1(sc, AU0828_REG_SENSORVBI_CTL, 0x00);
    287   1.1  jmcneill 
    288   1.1  jmcneill 	/* program video position and size */
    289   1.1  jmcneill 	auvitek_write_1(sc, AU0828_REG_HPOS_LO, hpos & 0xff);
    290   1.1  jmcneill 	auvitek_write_1(sc, AU0828_REG_HPOS_HI, hpos >> 8);
    291   1.1  jmcneill 	auvitek_write_1(sc, AU0828_REG_VPOS_LO, vpos & 0xff);
    292   1.1  jmcneill 	auvitek_write_1(sc, AU0828_REG_VPOS_HI, vpos >> 8);
    293   1.1  jmcneill 	auvitek_write_1(sc, AU0828_REG_HRES_LO, hres & 0xff);
    294   1.1  jmcneill 	auvitek_write_1(sc, AU0828_REG_HRES_HI, hres >> 8);
    295   1.1  jmcneill 	auvitek_write_1(sc, AU0828_REG_VRES_LO, vres & 0xff);
    296   1.1  jmcneill 	auvitek_write_1(sc, AU0828_REG_VRES_HI, vres >> 8);
    297   1.1  jmcneill 
    298   1.1  jmcneill 	auvitek_write_1(sc, AU0828_REG_SENSOR_CTL, 0xb3);
    299   1.1  jmcneill 
    300   1.1  jmcneill 	auvitek_write_1(sc, AU0828_REG_AUDIOCTL, 0x01);
    301   1.1  jmcneill 
    302   1.1  jmcneill 	s = splusb();
    303   1.1  jmcneill 	error = auvitek_start_xfer(sc);
    304   1.1  jmcneill 	splx(s);
    305   1.1  jmcneill 
    306   1.1  jmcneill 	if (error)
    307   1.1  jmcneill 		auvitek_stop_transfer(sc);
    308   1.1  jmcneill 
    309   1.1  jmcneill 	return error;
    310   1.1  jmcneill }
    311   1.1  jmcneill 
    312   1.1  jmcneill static int
    313   1.1  jmcneill auvitek_stop_transfer(void *opaque)
    314   1.1  jmcneill {
    315   1.1  jmcneill 	struct auvitek_softc *sc = opaque;
    316   1.1  jmcneill 	int error, s;
    317   1.1  jmcneill 
    318   1.1  jmcneill 	auvitek_write_1(sc, AU0828_REG_SENSOR_CTL, 0x00);
    319   1.1  jmcneill 
    320   1.1  jmcneill 	s = splusb();
    321   1.1  jmcneill 	error = auvitek_stop_xfer(sc);
    322   1.1  jmcneill 	splx(s);
    323   1.1  jmcneill 
    324   1.1  jmcneill 	return error;
    325   1.1  jmcneill }
    326   1.1  jmcneill 
    327   1.1  jmcneill static int
    328   1.1  jmcneill auvitek_get_tuner(void *opaque, struct video_tuner *vt)
    329   1.1  jmcneill {
    330   1.1  jmcneill 	struct auvitek_softc *sc = opaque;
    331   1.1  jmcneill 
    332   1.1  jmcneill 	switch (vt->index) {
    333   1.1  jmcneill 	case AUVITEK_TUNER_DEFAULT:
    334   1.1  jmcneill 		strlcpy(vt->name, "XC5000", sizeof(vt->name));
    335   1.1  jmcneill 		vt->freq_lo =  44000000 / 62500;
    336   1.1  jmcneill 		vt->freq_hi = 958000000 / 62500;
    337   1.1  jmcneill 		vt->caps = VIDEO_TUNER_F_STEREO;
    338   1.1  jmcneill 		vt->mode = VIDEO_TUNER_F_STEREO;
    339   1.1  jmcneill 		if (sc->sc_au8522)
    340   1.1  jmcneill 			vt->signal = au8522_get_signal(sc->sc_au8522);
    341   1.1  jmcneill 		else
    342   1.1  jmcneill 			vt->signal = 0;
    343   1.1  jmcneill 		break;
    344   1.1  jmcneill 	default:
    345   1.1  jmcneill 		return EINVAL;
    346   1.1  jmcneill 	}
    347   1.1  jmcneill 
    348   1.1  jmcneill 	return 0;
    349   1.1  jmcneill }
    350   1.1  jmcneill 
    351   1.1  jmcneill static int
    352   1.1  jmcneill auvitek_set_tuner(void *opaque, struct video_tuner *vt)
    353   1.1  jmcneill {
    354   1.1  jmcneill 	if (vt->index != AUVITEK_TUNER_DEFAULT)
    355   1.1  jmcneill 		return EINVAL;
    356   1.1  jmcneill 	return 0;
    357   1.1  jmcneill }
    358   1.1  jmcneill 
    359   1.1  jmcneill static int
    360   1.1  jmcneill auvitek_enum_audio(void *opaque, uint32_t index, struct video_audio *va)
    361   1.1  jmcneill {
    362   1.1  jmcneill 	switch (index) {
    363   1.1  jmcneill 	case AUVITEK_AUDIO_TELEVISION:
    364   1.1  jmcneill 		strlcpy(va->name, "Television", sizeof(va->name));
    365   1.1  jmcneill 		va->caps = VIDEO_AUDIO_F_STEREO;
    366   1.1  jmcneill 		break;
    367   1.1  jmcneill 	case AUVITEK_AUDIO_LINEIN:
    368   1.1  jmcneill 		strlcpy(va->name, "Line In", sizeof(va->name));
    369   1.1  jmcneill 		va->caps = VIDEO_AUDIO_F_STEREO;
    370   1.1  jmcneill 		break;
    371   1.1  jmcneill 	default:
    372   1.1  jmcneill 		return EINVAL;
    373   1.1  jmcneill 	}
    374   1.1  jmcneill 
    375   1.1  jmcneill 	return 0;
    376   1.1  jmcneill }
    377   1.1  jmcneill 
    378   1.1  jmcneill static int
    379   1.1  jmcneill auvitek_get_audio(void *opaque, struct video_audio *va)
    380   1.1  jmcneill {
    381   1.1  jmcneill 	struct auvitek_softc *sc = opaque;
    382   1.1  jmcneill 
    383   1.1  jmcneill 	return auvitek_enum_audio(opaque, sc->sc_ainput, va);
    384   1.1  jmcneill }
    385   1.1  jmcneill 
    386   1.1  jmcneill static int
    387   1.1  jmcneill auvitek_set_audio(void *opaque, struct video_audio *va)
    388   1.1  jmcneill {
    389   1.1  jmcneill 	struct auvitek_softc *sc = opaque;
    390   1.1  jmcneill 
    391   1.1  jmcneill 	if (va->index == sc->sc_ainput)
    392   1.1  jmcneill 		return 0;
    393   1.1  jmcneill 
    394   1.1  jmcneill 	return EINVAL;
    395   1.1  jmcneill }
    396   1.1  jmcneill 
    397   1.1  jmcneill static int
    398   1.1  jmcneill auvitek_enum_input(void *opaque, uint32_t index, struct video_input *vi)
    399   1.1  jmcneill {
    400   1.1  jmcneill 	switch (index) {
    401   1.1  jmcneill 	case AUVITEK_INPUT_COMPOSITE:
    402   1.1  jmcneill 		strlcpy(vi->name, "Composite", sizeof(vi->name));
    403   1.1  jmcneill 		vi->type = VIDEO_INPUT_TYPE_BASEBAND;
    404   1.1  jmcneill 		vi->standards = VIDEO_STANDARD_NTSC_M;
    405   1.1  jmcneill 		break;
    406   1.1  jmcneill 	case AUVITEK_INPUT_SVIDEO:
    407   1.1  jmcneill 		strlcpy(vi->name, "S-Video", sizeof(vi->name));
    408   1.1  jmcneill 		vi->type = VIDEO_INPUT_TYPE_BASEBAND;
    409   1.1  jmcneill 		vi->standards = VIDEO_STANDARD_NTSC_M;
    410   1.1  jmcneill 		break;
    411   1.1  jmcneill 	case AUVITEK_INPUT_TELEVISION:
    412   1.1  jmcneill 		strlcpy(vi->name, "Television", sizeof(vi->name));
    413   1.1  jmcneill 		vi->type = VIDEO_INPUT_TYPE_TUNER;
    414   1.1  jmcneill 		vi->standards = VIDEO_STANDARD_NTSC_M;
    415   1.1  jmcneill 		break;
    416   1.1  jmcneill 	case AUVITEK_INPUT_CABLE:
    417   1.1  jmcneill 		strlcpy(vi->name, "Cable TV", sizeof(vi->name));
    418   1.1  jmcneill 		vi->type = VIDEO_INPUT_TYPE_TUNER;
    419   1.1  jmcneill 		vi->standards = VIDEO_STANDARD_NTSC_M;
    420   1.1  jmcneill 		break;
    421   1.1  jmcneill 	default:
    422   1.1  jmcneill 		return EINVAL;
    423   1.1  jmcneill 	}
    424   1.1  jmcneill 
    425   1.1  jmcneill 	vi->index = index;
    426   1.1  jmcneill 	vi->tuner_index = AUVITEK_TUNER_DEFAULT;
    427   1.1  jmcneill 
    428   1.1  jmcneill 	return 0;
    429   1.1  jmcneill }
    430   1.1  jmcneill 
    431   1.1  jmcneill static int
    432   1.1  jmcneill auvitek_get_input(void *opaque, struct video_input *vi)
    433   1.1  jmcneill {
    434   1.1  jmcneill 	struct auvitek_softc *sc = opaque;
    435   1.1  jmcneill 
    436   1.1  jmcneill 	return auvitek_enum_input(opaque, sc->sc_vinput, vi);
    437   1.1  jmcneill }
    438   1.1  jmcneill 
    439   1.1  jmcneill static int
    440   1.1  jmcneill auvitek_set_input(void *opaque, struct video_input *vi)
    441   1.1  jmcneill {
    442   1.1  jmcneill 	struct auvitek_softc *sc = opaque;
    443   1.1  jmcneill 	struct video_frequency vf;
    444   1.1  jmcneill 	au8522_vinput_t vinput = AU8522_VINPUT_UNCONF;
    445   1.1  jmcneill 	au8522_ainput_t ainput = AU8522_AINPUT_UNCONF;
    446   1.1  jmcneill 	uint8_t r;
    447   1.1  jmcneill 
    448   1.1  jmcneill 	switch (vi->index) {
    449   1.1  jmcneill 	case AUVITEK_INPUT_COMPOSITE:
    450   1.1  jmcneill 		vinput = AU8522_VINPUT_CVBS;
    451   1.1  jmcneill 		ainput = AU8522_AINPUT_NONE;
    452   1.1  jmcneill 		sc->sc_ainput = AUVITEK_AUDIO_LINEIN;
    453   1.1  jmcneill 		break;
    454   1.1  jmcneill 	case AUVITEK_INPUT_SVIDEO:
    455   1.1  jmcneill 		vinput = AU8522_VINPUT_SVIDEO;
    456   1.1  jmcneill 		ainput = AU8522_AINPUT_NONE;
    457   1.1  jmcneill 		sc->sc_ainput = AUVITEK_AUDIO_LINEIN;
    458   1.1  jmcneill 		break;
    459   1.1  jmcneill 	case AUVITEK_INPUT_TELEVISION:
    460   1.1  jmcneill 	case AUVITEK_INPUT_CABLE:
    461   1.1  jmcneill 		vinput = AU8522_VINPUT_CVBS_TUNER;
    462   1.1  jmcneill 		ainput = AU8522_AINPUT_SIF;
    463   1.1  jmcneill 		sc->sc_ainput = AUVITEK_AUDIO_TELEVISION;
    464   1.1  jmcneill 		break;
    465   1.1  jmcneill 	default:
    466   1.1  jmcneill 		return EINVAL;
    467   1.1  jmcneill 	}
    468   1.1  jmcneill 
    469   1.1  jmcneill 	sc->sc_vinput = vi->index;
    470   1.1  jmcneill 
    471   1.1  jmcneill 	au8522_set_input(sc->sc_au8522, vinput, ainput);
    472   1.1  jmcneill 
    473   1.2  jmcneill 	/* XXX HVR-850/950Q specific */
    474   1.1  jmcneill 	r = auvitek_read_1(sc, AU0828_REG_GPIO1_OUTEN);
    475   1.1  jmcneill 	if (ainput == AU8522_AINPUT_NONE)
    476   1.1  jmcneill 		r |= 0x10;
    477   1.1  jmcneill 	else
    478   1.1  jmcneill 		r &= ~0x10;
    479   1.1  jmcneill 	auvitek_write_1(sc, AU0828_REG_GPIO1_OUTEN, r);
    480   1.1  jmcneill 
    481   1.1  jmcneill 	if (vinput == AU8522_VINPUT_CVBS_TUNER && sc->sc_curfreq > 0) {
    482   1.1  jmcneill 		vf.tuner_index = AUVITEK_TUNER_DEFAULT;
    483   1.1  jmcneill 		vf.frequency = sc->sc_curfreq;
    484   1.1  jmcneill 		auvitek_set_frequency(sc, &vf);
    485   1.1  jmcneill 	}
    486   1.1  jmcneill 
    487   1.1  jmcneill 	return 0;
    488   1.1  jmcneill }
    489   1.1  jmcneill 
    490   1.1  jmcneill static int
    491   1.1  jmcneill auvitek_get_frequency(void *opaque, struct video_frequency *vf)
    492   1.1  jmcneill {
    493   1.1  jmcneill 	struct auvitek_softc *sc = opaque;
    494   1.1  jmcneill 
    495   1.1  jmcneill 	if (sc->sc_vinput != AUVITEK_INPUT_TELEVISION &&
    496   1.1  jmcneill 	    sc->sc_vinput != AUVITEK_INPUT_CABLE)
    497   1.1  jmcneill 		return EINVAL;
    498   1.1  jmcneill 
    499   1.1  jmcneill 	vf->tuner_index = AUVITEK_TUNER_DEFAULT;
    500   1.1  jmcneill 	vf->frequency = sc->sc_curfreq;
    501   1.1  jmcneill 
    502   1.1  jmcneill 	return 0;
    503   1.1  jmcneill }
    504   1.1  jmcneill 
    505   1.1  jmcneill static int
    506   1.1  jmcneill auvitek_set_frequency(void *opaque, struct video_frequency *vf)
    507   1.1  jmcneill {
    508   1.1  jmcneill 	struct auvitek_softc *sc = opaque;
    509   1.1  jmcneill 	struct xc5k_params params;
    510   1.1  jmcneill 	int error;
    511   1.1  jmcneill 
    512   1.1  jmcneill 	if (sc->sc_vinput != AUVITEK_INPUT_TELEVISION &&
    513   1.1  jmcneill 	    sc->sc_vinput != AUVITEK_INPUT_CABLE)
    514   1.1  jmcneill 		return EINVAL;
    515   1.1  jmcneill 	if (vf->tuner_index != AUVITEK_TUNER_DEFAULT)
    516   1.1  jmcneill 		return EINVAL;
    517   1.1  jmcneill 	if (sc->sc_xc5k == NULL)
    518   1.1  jmcneill 		return ENODEV;
    519   1.1  jmcneill 
    520   1.1  jmcneill 	params.standard = VIDEO_STANDARD_NTSC_M;
    521   1.1  jmcneill 	if (sc->sc_vinput == AUVITEK_INPUT_TELEVISION)
    522   1.1  jmcneill 		params.signal_source = XC5K_SIGNAL_SOURCE_AIR;
    523   1.1  jmcneill 	else
    524   1.1  jmcneill 		params.signal_source = XC5K_SIGNAL_SOURCE_CABLE;
    525   1.1  jmcneill 	params.frequency = vf->frequency;
    526   1.3  jmcneill 	if (sc->sc_au8522)
    527   1.3  jmcneill 		au8522_set_audio(sc->sc_au8522, false);
    528   1.4  jmcneill 	error = xc5k_tune_video(sc->sc_xc5k, &params);
    529   1.3  jmcneill 	if (sc->sc_au8522)
    530   1.3  jmcneill 		au8522_set_audio(sc->sc_au8522, true);
    531   1.1  jmcneill 	if (error)
    532   1.1  jmcneill 		return error;
    533   1.1  jmcneill 
    534   1.1  jmcneill 	sc->sc_curfreq = vf->frequency;
    535   1.1  jmcneill 
    536   1.1  jmcneill 	auvitek_write_1(sc, AU0828_REG_SENSOR_CTL, 0x00);
    537   1.1  jmcneill 	delay(30000);
    538   1.1  jmcneill 	auvitek_write_1(sc, AU0828_REG_SENSOR_CTL, 0xb3);
    539   1.1  jmcneill 
    540   1.1  jmcneill 	return 0;
    541   1.1  jmcneill }
    542   1.1  jmcneill 
    543   1.1  jmcneill static int
    544   1.1  jmcneill auvitek_start_xfer(struct auvitek_softc *sc)
    545   1.1  jmcneill {
    546   1.1  jmcneill 	struct auvitek_xfer *ax = &sc->sc_ax;
    547   1.1  jmcneill 	uint32_t vframe_len, uframe_len, nframes;
    548   1.1  jmcneill 	usbd_status err;
    549   1.1  jmcneill 	int i;
    550   1.1  jmcneill 
    551   1.4  jmcneill 	err = usbd_set_interface(sc->sc_isoc_iface, AUVITEK_XFER_ALTNO);
    552   1.1  jmcneill 	if (err != USBD_NORMAL_COMPLETION) {
    553   1.1  jmcneill 		aprint_error_dev(sc->sc_dev, "couldn't set altno %d: %s\n",
    554   1.1  jmcneill 		    AUVITEK_XFER_ALTNO, usbd_errstr(err));
    555   1.1  jmcneill 		return EIO;
    556   1.1  jmcneill 	}
    557   1.1  jmcneill 
    558   1.1  jmcneill 	vframe_len = 720 * 480 * 2;
    559   1.1  jmcneill 	uframe_len = ax->ax_maxpktlen;
    560   1.1  jmcneill 	nframes = (vframe_len + uframe_len - 1) / uframe_len;
    561   1.1  jmcneill 	nframes = (nframes + 7) & ~7;
    562   1.1  jmcneill 
    563   1.1  jmcneill 	ax->ax_nframes = nframes;
    564   1.1  jmcneill 	ax->ax_uframe_len = uframe_len;
    565   1.4  jmcneill 	for (i = 0; i < AUVITEK_NISOC_XFERS; i++) {
    566   1.1  jmcneill 		struct auvitek_isoc *isoc = &ax->ax_i[i];
    567   1.1  jmcneill 		isoc->i_ax = ax;
    568   1.1  jmcneill 		isoc->i_frlengths =
    569   1.1  jmcneill 		    kmem_alloc(sizeof(isoc->i_frlengths[0]) * nframes,
    570   1.1  jmcneill 			KM_SLEEP);
    571   1.1  jmcneill 	}
    572   1.1  jmcneill 
    573   1.4  jmcneill 	err = usbd_open_pipe(sc->sc_isoc_iface, ax->ax_endpt,
    574   1.1  jmcneill 	    USBD_EXCLUSIVE_USE, &ax->ax_pipe);
    575   1.1  jmcneill 	if (err != USBD_NORMAL_COMPLETION) {
    576   1.1  jmcneill 		aprint_error_dev(sc->sc_dev, "couldn't open pipe: %s\n",
    577   1.1  jmcneill 		    usbd_errstr(err));
    578   1.1  jmcneill 		return EIO;
    579   1.1  jmcneill 	}
    580   1.1  jmcneill 
    581   1.4  jmcneill 	for (i = 0; i < AUVITEK_NISOC_XFERS; i++) {
    582   1.1  jmcneill 		struct auvitek_isoc *isoc = &ax->ax_i[i];
    583   1.1  jmcneill 
    584   1.7     skrll 		int error = usbd_create_xfer(ax->ax_pipe,
    585   1.7     skrll 		    nframes * uframe_len, 0, ax->ax_nframes, &isoc->i_xfer);
    586   1.7     skrll 		if (error) {
    587   1.1  jmcneill 			aprint_error_dev(sc->sc_dev,
    588   1.7     skrll 			    "couldn't create usb xfer\n");
    589   1.7     skrll 			return error;
    590   1.1  jmcneill 		}
    591   1.1  jmcneill 
    592   1.7     skrll 		isoc->i_buf = usbd_get_buffer(isoc->i_xfer);
    593   1.1  jmcneill 	}
    594   1.1  jmcneill 
    595   1.1  jmcneill 	return auvitek_isoc_start(sc);
    596   1.1  jmcneill }
    597   1.1  jmcneill 
    598   1.1  jmcneill static int
    599   1.1  jmcneill auvitek_stop_xfer(struct auvitek_softc *sc)
    600   1.1  jmcneill {
    601   1.1  jmcneill 	struct auvitek_xfer *ax = &sc->sc_ax;
    602   1.1  jmcneill 	usbd_status err;
    603   1.1  jmcneill 	int i;
    604   1.1  jmcneill 
    605   1.1  jmcneill 	if (ax->ax_pipe != NULL) {
    606   1.1  jmcneill 		usbd_abort_pipe(ax->ax_pipe);
    607   1.1  jmcneill 	}
    608   1.4  jmcneill 	for (i = 0; i < AUVITEK_NISOC_XFERS; i++) {
    609   1.1  jmcneill 		struct auvitek_isoc *isoc = &ax->ax_i[i];
    610   1.1  jmcneill 		if (isoc->i_xfer != NULL) {
    611   1.7     skrll 			usbd_destroy_xfer(isoc->i_xfer);
    612   1.1  jmcneill 			isoc->i_xfer = NULL;
    613   1.1  jmcneill 		}
    614   1.1  jmcneill 		if (isoc->i_frlengths != NULL) {
    615   1.1  jmcneill 			kmem_free(isoc->i_frlengths,
    616   1.1  jmcneill 			    sizeof(isoc->i_frlengths[0]) * ax->ax_nframes);
    617   1.1  jmcneill 			isoc->i_frlengths = NULL;
    618   1.1  jmcneill 		}
    619   1.1  jmcneill 	}
    620   1.7     skrll 	if (ax->ax_pipe != NULL) {
    621   1.7     skrll 		usbd_close_pipe(ax->ax_pipe);
    622   1.7     skrll 		ax->ax_pipe = NULL;
    623   1.7     skrll 	}
    624   1.1  jmcneill 
    625   1.1  jmcneill 	usbd_delay_ms(sc->sc_udev, 1000);
    626   1.4  jmcneill 	err = usbd_set_interface(sc->sc_isoc_iface, 0);
    627   1.1  jmcneill 	if (err != USBD_NORMAL_COMPLETION) {
    628   1.1  jmcneill 		aprint_error_dev(sc->sc_dev,
    629   1.1  jmcneill 		    "couldn't set zero bw interface: %s\n",
    630   1.1  jmcneill 		    usbd_errstr(err));
    631   1.1  jmcneill 		return EIO;
    632   1.1  jmcneill 	}
    633   1.1  jmcneill 
    634   1.1  jmcneill 	return 0;
    635   1.1  jmcneill }
    636   1.1  jmcneill 
    637   1.1  jmcneill static int
    638   1.1  jmcneill auvitek_isoc_start(struct auvitek_softc *sc)
    639   1.1  jmcneill {
    640   1.1  jmcneill 	struct auvitek_xfer *ax = &sc->sc_ax;
    641   1.1  jmcneill 	int i, error;
    642   1.1  jmcneill 
    643   1.1  jmcneill 	ax->ax_av.av_el = ax->ax_av.av_ol = 0;
    644   1.1  jmcneill 	ax->ax_av.av_eb = ax->ax_av.av_ob = 0;
    645   1.1  jmcneill 	ax->ax_av.av_stride = 720 * 2;
    646   1.1  jmcneill 
    647   1.4  jmcneill 	for (i = 0; i < AUVITEK_NISOC_XFERS; i++) {
    648   1.1  jmcneill 		error = auvitek_isoc_start1(&ax->ax_i[i]);
    649   1.1  jmcneill 		if (error)
    650   1.1  jmcneill 			return error;
    651   1.1  jmcneill 	}
    652   1.1  jmcneill 
    653   1.1  jmcneill 	return 0;
    654   1.1  jmcneill }
    655   1.1  jmcneill 
    656   1.1  jmcneill static int
    657   1.1  jmcneill auvitek_isoc_start1(struct auvitek_isoc *isoc)
    658   1.1  jmcneill {
    659   1.1  jmcneill 	struct auvitek_xfer *ax = isoc->i_ax;
    660   1.1  jmcneill 	struct auvitek_softc *sc = ax->ax_sc;
    661   1.1  jmcneill 	usbd_status err;
    662   1.1  jmcneill 	unsigned int i;
    663   1.1  jmcneill 
    664   1.1  jmcneill 	ax = isoc->i_ax;
    665   1.1  jmcneill 
    666   1.1  jmcneill 	for (i = 0; i < ax->ax_nframes; i++)
    667   1.1  jmcneill 		isoc->i_frlengths[i] = ax->ax_uframe_len;
    668   1.1  jmcneill 
    669   1.1  jmcneill 	usbd_setup_isoc_xfer(isoc->i_xfer,
    670   1.1  jmcneill 			     isoc,
    671   1.1  jmcneill 			     isoc->i_frlengths,
    672   1.1  jmcneill 			     ax->ax_nframes,
    673   1.7     skrll 			     USBD_SHORT_XFER_OK,
    674   1.1  jmcneill 			     auvitek_isoc_intr);
    675   1.1  jmcneill 
    676   1.1  jmcneill 	err = usbd_transfer(isoc->i_xfer);
    677   1.1  jmcneill 	if (err != USBD_IN_PROGRESS) {
    678   1.1  jmcneill 		aprint_error_dev(sc->sc_dev, "couldn't start isoc xfer: %s\n",
    679   1.1  jmcneill 				 usbd_errstr(err));
    680   1.1  jmcneill 		return ENODEV;
    681   1.1  jmcneill 	}
    682   1.1  jmcneill 
    683   1.1  jmcneill 	return 0;
    684   1.1  jmcneill }
    685   1.1  jmcneill 
    686   1.1  jmcneill static void
    687   1.7     skrll auvitek_isoc_intr(struct usbd_xfer *xfer, void * priv,
    688   1.1  jmcneill     usbd_status status)
    689   1.1  jmcneill {
    690   1.1  jmcneill 	struct auvitek_isoc *isoc = priv;
    691   1.1  jmcneill 	struct auvitek_xfer *ax = isoc->i_ax;
    692   1.1  jmcneill 	struct auvitek_softc *sc = ax->ax_sc;
    693   1.1  jmcneill 	uint32_t count;
    694   1.1  jmcneill 	uint8_t *buf;
    695   1.1  jmcneill 	unsigned int i;
    696   1.1  jmcneill 
    697   1.1  jmcneill 	if (sc->sc_dying)
    698   1.1  jmcneill 		return;
    699   1.1  jmcneill 
    700   1.1  jmcneill 	if (status != USBD_NORMAL_COMPLETION) {
    701   1.1  jmcneill 		if (status == USBD_STALLED) {
    702   1.1  jmcneill 			usbd_clear_endpoint_stall_async(ax->ax_pipe);
    703   1.1  jmcneill 			goto next;
    704   1.1  jmcneill 		}
    705   1.1  jmcneill 		return;
    706   1.1  jmcneill 	}
    707   1.1  jmcneill 
    708   1.1  jmcneill 	usbd_get_xfer_status(xfer, NULL, NULL, &count, NULL);
    709   1.1  jmcneill 
    710   1.1  jmcneill 	if (count == 0)
    711   1.1  jmcneill 		goto next;
    712   1.1  jmcneill 
    713   1.1  jmcneill 	for (i = 0, buf = isoc->i_buf;
    714   1.1  jmcneill 	     i < ax->ax_nframes;
    715   1.1  jmcneill 	     ++i, buf += ax->ax_uframe_len) {
    716   1.1  jmcneill 		status = auvitek_isoc_process(sc, buf, isoc->i_frlengths[i]);
    717   1.1  jmcneill 		if (status == USBD_IOERROR)
    718   1.1  jmcneill 			break;
    719   1.1  jmcneill 	}
    720   1.1  jmcneill 
    721   1.1  jmcneill next:
    722   1.1  jmcneill 	auvitek_isoc_start1(isoc);
    723   1.1  jmcneill }
    724   1.1  jmcneill 
    725   1.1  jmcneill static int
    726   1.1  jmcneill auvitek_isoc_process(struct auvitek_softc *sc, uint8_t *buf, uint32_t len)
    727   1.1  jmcneill {
    728   1.1  jmcneill 	struct video_payload payload;
    729   1.1  jmcneill 	bool submit = false;
    730   1.1  jmcneill 
    731   1.1  jmcneill 	if (buf[0] & 0x80) {
    732   1.1  jmcneill 		sc->sc_ax.ax_frinfo = buf[0];
    733   1.1  jmcneill 		if (sc->sc_ax.ax_frinfo & 0x40) {
    734   1.1  jmcneill 			sc->sc_ax.ax_frno = !sc->sc_ax.ax_frno;
    735   1.1  jmcneill 			submit = true;
    736   1.1  jmcneill 		}
    737   1.1  jmcneill 		buf += 4;
    738   1.1  jmcneill 		len -= 4;
    739   1.1  jmcneill 	}
    740   1.1  jmcneill 	buf += 4;
    741   1.1  jmcneill 	len -= 4;
    742   1.1  jmcneill 
    743   1.1  jmcneill 	auvitek_videobuf_weave(sc, buf, len);
    744   1.1  jmcneill 
    745   1.1  jmcneill 	if (submit) {
    746   1.1  jmcneill 		payload.end_of_frame = 1;
    747   1.1  jmcneill 		payload.data = sc->sc_ax.ax_av.av_buf;
    748   1.1  jmcneill 		payload.size = sizeof(sc->sc_ax.ax_av.av_buf);
    749   1.1  jmcneill 		payload.frameno = -1;
    750   1.1  jmcneill 
    751   1.1  jmcneill 		video_submit_payload(sc->sc_videodev, &payload);
    752   1.1  jmcneill 
    753   1.1  jmcneill 		sc->sc_ax.ax_av.av_el = sc->sc_ax.ax_av.av_ol = 0;
    754   1.1  jmcneill 		sc->sc_ax.ax_av.av_eb = sc->sc_ax.ax_av.av_ob = 0;
    755   1.1  jmcneill 	}
    756   1.1  jmcneill 
    757   1.1  jmcneill 	return USBD_NORMAL_COMPLETION;
    758   1.1  jmcneill }
    759   1.1  jmcneill 
    760   1.1  jmcneill static void
    761   1.1  jmcneill auvitek_videobuf_weave(struct auvitek_softc *sc, uint8_t *buf, uint32_t len)
    762   1.1  jmcneill {
    763   1.1  jmcneill 	struct auvitek_videobuf *av = &sc->sc_ax.ax_av;
    764   1.1  jmcneill 	uint32_t resid, wlen;
    765   1.1  jmcneill 	uint32_t *l, *b;
    766   1.1  jmcneill 	uint8_t *vp;
    767   1.1  jmcneill 
    768   1.1  jmcneill 	if (sc->sc_ax.ax_frinfo & 0x40) {
    769   1.1  jmcneill 		l = &av->av_ol;
    770   1.1  jmcneill 		b = &av->av_ob;
    771   1.1  jmcneill 		vp = av->av_buf;
    772   1.1  jmcneill 	} else {
    773   1.1  jmcneill 		l = &av->av_el;
    774   1.1  jmcneill 		b = &av->av_eb;
    775   1.1  jmcneill 		vp = av->av_buf + av->av_stride;
    776   1.1  jmcneill 	}
    777   1.1  jmcneill 
    778   1.1  jmcneill 	resid = len;
    779   1.1  jmcneill 	while (resid > 0) {
    780   1.1  jmcneill 		if (*b == av->av_stride) {
    781   1.1  jmcneill 			*l = *l + 1;
    782   1.1  jmcneill 			*b = 0;
    783   1.1  jmcneill 		}
    784   1.1  jmcneill 		if (*l >= 240) {
    785   1.1  jmcneill 			break;
    786   1.1  jmcneill 		}
    787   1.8  riastrad 		wlen = uimin(resid, av->av_stride - *b);
    788   1.1  jmcneill 		memcpy(vp + (av->av_stride * 2 * *l) + *b, buf, wlen);
    789   1.1  jmcneill 		*b += wlen;
    790   1.1  jmcneill 		buf += wlen;
    791   1.1  jmcneill 		resid -= wlen;
    792   1.1  jmcneill 	}
    793   1.1  jmcneill }
    794