Home | History | Annotate | Line # | Download | only in isa
      1  1.7  dholland /*	$NetBSD: isv.c,v 1.7 2014/07/25 08:10:37 dholland Exp $ */
      2  1.1    dyoung 
      3  1.1    dyoung /*-
      4  1.1    dyoung  * Copyright (c) 2008 The NetBSD Foundation, Inc.
      5  1.1    dyoung  * All rights reserved.
      6  1.1    dyoung  *
      7  1.1    dyoung  * This code is derived from software contributed to The NetBSD Foundation
      8  1.1    dyoung  * by David Young.
      9  1.1    dyoung  *
     10  1.1    dyoung  * Redistribution and use in source and binary forms, with or without
     11  1.1    dyoung  * modification, are permitted provided that the following conditions
     12  1.1    dyoung  * are met:
     13  1.1    dyoung  * 1. Redistributions of source code must retain the above copyright
     14  1.1    dyoung  *    notice, this list of conditions and the following disclaimer.
     15  1.1    dyoung  * 2. Redistributions in binary form must reproduce the above copyright
     16  1.1    dyoung  *    notice, this list of conditions and the following disclaimer in the
     17  1.1    dyoung  *    documentation and/or other materials provided with the distribution.
     18  1.1    dyoung  *
     19  1.1    dyoung  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
     20  1.1    dyoung  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
     21  1.1    dyoung  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     22  1.1    dyoung  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
     23  1.1    dyoung  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
     24  1.1    dyoung  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
     25  1.1    dyoung  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
     26  1.1    dyoung  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
     27  1.1    dyoung  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
     28  1.1    dyoung  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
     29  1.1    dyoung  * POSSIBILITY OF SUCH DAMAGE.
     30  1.1    dyoung  */
     31  1.1    dyoung 
     32  1.1    dyoung #include <sys/cdefs.h>
     33  1.7  dholland __KERNEL_RCSID(0, "$NetBSD: isv.c,v 1.7 2014/07/25 08:10:37 dholland Exp $");
     34  1.1    dyoung 
     35  1.1    dyoung #include <sys/param.h>
     36  1.1    dyoung #include <sys/systm.h>
     37  1.1    dyoung #include <sys/kernel.h>
     38  1.1    dyoung #include <sys/device.h>
     39  1.1    dyoung #include <sys/conf.h>
     40  1.4  uebayasi 
     41  1.4  uebayasi #include <uvm/uvm_extern.h>
     42  1.1    dyoung 
     43  1.1    dyoung #include <sys/bus.h>
     44  1.1    dyoung 
     45  1.1    dyoung #include <dev/isa/isareg.h>
     46  1.1    dyoung #include <dev/isa/isavar.h>
     47  1.1    dyoung 
     48  1.1    dyoung #include <dev/isa/isvio.h>
     49  1.1    dyoung 
     50  1.1    dyoung #define	ISV_CONTROL	0x0		/* control: write-only */
     51  1.1    dyoung #define	ISV_CONTROL_MODE_MASK		__BIT(0)
     52  1.1    dyoung #define	ISV_CONTROL_MODE_CAPTURE	__SHIFTIN(0, ISV_CONTROL_MODE_MASK)
     53  1.1    dyoung #define	ISV_CONTROL_MODE_READ		__SHIFTIN(1, ISV_CONTROL_MODE_MASK)
     54  1.1    dyoung #define	ISV_CONTROL_COUNTER_MASK	__BIT(1)
     55  1.1    dyoung #define	ISV_CONTROL_COUNTER_RESET	__SHIFTIN(1, ISV_CONTROL_COUNTER_MASK)
     56  1.1    dyoung #define	ISV_CONTROL_COUNTER_AUTOINC	__SHIFTIN(0, ISV_CONTROL_COUNTER_MASK)
     57  1.1    dyoung 
     58  1.1    dyoung #define	ISV_DATA	ISV_CONTROL	/* data: read-only */
     59  1.1    dyoung 
     60  1.1    dyoung #define ISV_STATUS	0x2		/* status: read-only */
     61  1.1    dyoung #define ISV_STATUS_VIDEO_MASK		__BIT(15)
     62  1.1    dyoung #define ISV_STATUS_VIDEO_RETRACE	__SHIFTIN(0, ISV_STATUS_VIDEO_MASK)
     63  1.1    dyoung #define ISV_STATUS_VIDEO_WRITE		__SHIFTIN(1, ISV_STATUS_VIDEO_MASK)
     64  1.1    dyoung 
     65  1.1    dyoung struct isv_regs {
     66  1.1    dyoung 	bus_space_tag_t		ir_bt;
     67  1.1    dyoung 	bus_space_handle_t	ir_bh;
     68  1.1    dyoung };
     69  1.1    dyoung 
     70  1.1    dyoung enum isv_state {
     71  1.1    dyoung 	  ISV_S_CAPTURE0 = 0
     72  1.1    dyoung 	, ISV_S_CAPTURE1 = 1
     73  1.1    dyoung 	, ISV_S_CAPTURE2 = 2
     74  1.1    dyoung 	, ISV_S_RETRACE = 3
     75  1.1    dyoung };
     76  1.1    dyoung 
     77  1.1    dyoung struct isv_softc {
     78  1.1    dyoung 	struct isv_regs	sc_ir;
     79  1.1    dyoung 	device_t	sc_dev;
     80  1.1    dyoung 	uint16_t	*sc_frame;
     81  1.1    dyoung 	int		sc_speed;
     82  1.1    dyoung };
     83  1.1    dyoung 
     84  1.1    dyoung extern struct cfdriver isv_cd;
     85  1.1    dyoung 
     86  1.1    dyoung static dev_type_ioctl(isv_ioctl);
     87  1.1    dyoung static dev_type_open(isv_open);
     88  1.1    dyoung static dev_type_mmap(isv_mmap);
     89  1.1    dyoung 
     90  1.1    dyoung static int	isv_capture(struct isv_softc *);
     91  1.1    dyoung static int 	isv_match(device_t, cfdata_t, void *);
     92  1.1    dyoung static void 	isv_attach(device_t, device_t, void *);
     93  1.1    dyoung static int 	isv_detach(device_t, int);
     94  1.1    dyoung static uint16_t isv_read(struct isv_regs *, bus_size_t);
     95  1.1    dyoung static void	isv_write(struct isv_regs *, bus_size_t, uint16_t);
     96  1.1    dyoung static bool	isv_retrace(struct isv_regs *);
     97  1.1    dyoung static int	isv_retrace_wait(struct isv_regs *, int *,
     98  1.1    dyoung     const struct timeval *);
     99  1.1    dyoung static int	isv_capture_wait(struct isv_regs *, int *,
    100  1.1    dyoung     const struct timeval *);
    101  1.1    dyoung static bool	isv_delta(int *, bool);
    102  1.1    dyoung static int	isv_probe(struct isv_regs *);
    103  1.1    dyoung 
    104  1.1    dyoung CFATTACH_DECL_NEW(isv_isa, sizeof(struct isv_softc),
    105  1.1    dyoung     isv_match, isv_attach, isv_detach, NULL);
    106  1.1    dyoung 
    107  1.1    dyoung const struct cdevsw isv_cdevsw = {
    108  1.5  dholland 	.d_open = isv_open,
    109  1.5  dholland 	.d_close = nullclose,
    110  1.5  dholland 	.d_read = noread,
    111  1.5  dholland 	.d_write = nowrite,
    112  1.5  dholland 	.d_ioctl = isv_ioctl,
    113  1.5  dholland 	.d_stop = nostop,
    114  1.5  dholland 	.d_tty = notty,
    115  1.5  dholland 	.d_poll = nopoll,
    116  1.5  dholland 	.d_mmap = isv_mmap,
    117  1.5  dholland 	.d_kqfilter = nokqfilter,
    118  1.7  dholland 	.d_discard = nodiscard,
    119  1.5  dholland 	.d_flag = D_OTHER
    120  1.1    dyoung };
    121  1.1    dyoung 
    122  1.1    dyoung static uint16_t
    123  1.1    dyoung isv_read(struct isv_regs *ir, bus_size_t reg)
    124  1.1    dyoung {
    125  1.1    dyoung 	return bus_space_read_2(ir->ir_bt, ir->ir_bh, reg);
    126  1.1    dyoung }
    127  1.1    dyoung 
    128  1.1    dyoung static void
    129  1.1    dyoung isv_write(struct isv_regs *ir, bus_size_t reg, uint16_t val)
    130  1.1    dyoung {
    131  1.1    dyoung 	bus_space_write_2(ir->ir_bt, ir->ir_bh, reg, val);
    132  1.1    dyoung }
    133  1.1    dyoung 
    134  1.1    dyoung static bool
    135  1.1    dyoung isv_retrace(struct isv_regs *ir)
    136  1.1    dyoung {
    137  1.1    dyoung 	uint16_t video;
    138  1.1    dyoung 
    139  1.1    dyoung 	video = isv_read(ir, ISV_STATUS) & ISV_STATUS_VIDEO_MASK;
    140  1.1    dyoung 	return video == ISV_STATUS_VIDEO_RETRACE;
    141  1.1    dyoung }
    142  1.1    dyoung 
    143  1.1    dyoung #define state_and_input(__state, __retrace)	\
    144  1.1    dyoung 	(((__state) << 1) | ((__retrace) ? 1 : 0))
    145  1.1    dyoung 
    146  1.1    dyoung static bool
    147  1.1    dyoung isv_delta(int *state, bool retrace)
    148  1.1    dyoung {
    149  1.1    dyoung 	bool transition = false;
    150  1.1    dyoung 
    151  1.1    dyoung 	switch (state_and_input(*state, retrace)) {
    152  1.1    dyoung 	case state_and_input(ISV_S_CAPTURE0, false):
    153  1.1    dyoung 	case state_and_input(ISV_S_RETRACE, true):
    154  1.1    dyoung 		break;
    155  1.1    dyoung 	case state_and_input(ISV_S_CAPTURE2, true):
    156  1.1    dyoung 		transition = true;
    157  1.1    dyoung 		/*FALLTHROUGH*/
    158  1.1    dyoung 	case state_and_input(ISV_S_CAPTURE1, true):
    159  1.1    dyoung 	case state_and_input(ISV_S_CAPTURE0, true):
    160  1.1    dyoung 		(*state)++;
    161  1.1    dyoung 		break;
    162  1.1    dyoung 	case state_and_input(ISV_S_RETRACE, false):
    163  1.1    dyoung 		transition = true;
    164  1.1    dyoung 		/*FALLTHROUGH*/
    165  1.1    dyoung 	case state_and_input(ISV_S_CAPTURE2, false):
    166  1.1    dyoung 	case state_and_input(ISV_S_CAPTURE1, false):
    167  1.1    dyoung 		*state = ISV_S_CAPTURE0;
    168  1.1    dyoung 		break;
    169  1.1    dyoung 	}
    170  1.1    dyoung 	return transition;
    171  1.1    dyoung }
    172  1.1    dyoung 
    173  1.1    dyoung static int
    174  1.1    dyoung isv_probe(struct isv_regs *ir)
    175  1.1    dyoung {
    176  1.1    dyoung 	int state, transitions;
    177  1.1    dyoung 	struct timeval end, now,
    178  1.1    dyoung 	    wait = {.tv_sec = 0, .tv_usec = 1000000 * 4 / 30};
    179  1.1    dyoung 
    180  1.1    dyoung 	aprint_debug("%s: resetting\n", __func__);
    181  1.1    dyoung 	isv_write(ir, ISV_CONTROL,
    182  1.1    dyoung 	    ISV_CONTROL_MODE_CAPTURE|ISV_CONTROL_COUNTER_AUTOINC);
    183  1.1    dyoung 
    184  1.1    dyoung 	aprint_debug("%s: waiting\n", __func__);
    185  1.1    dyoung 
    186  1.1    dyoung 	microtime(&now);
    187  1.1    dyoung 	timeradd(&now, &wait, &end);
    188  1.1    dyoung 
    189  1.1    dyoung 	state = transitions = 0;
    190  1.1    dyoung 
    191  1.1    dyoung 	do {
    192  1.1    dyoung 		if (isv_delta(&state, isv_retrace(ir)))
    193  1.1    dyoung 			transitions++;
    194  1.1    dyoung 
    195  1.1    dyoung 		if (state == ISV_S_CAPTURE0 || state == ISV_S_RETRACE)
    196  1.1    dyoung 			microtime(&now);
    197  1.1    dyoung 	} while (timercmp(&now, &end, <));
    198  1.1    dyoung 
    199  1.1    dyoung 	aprint_debug("%s: %d transitions\n", __func__, transitions);
    200  1.1    dyoung 
    201  1.1    dyoung 	return transitions >= 4 && transitions <= 10;
    202  1.1    dyoung }
    203  1.1    dyoung 
    204  1.1    dyoung static int
    205  1.1    dyoung isv_match(device_t parent, cfdata_t match, void *aux)
    206  1.1    dyoung {
    207  1.1    dyoung 	struct isv_regs ir;
    208  1.1    dyoung 	struct isa_attach_args *ia = aux;
    209  1.1    dyoung 	int rv;
    210  1.1    dyoung 
    211  1.1    dyoung 	/* Must supply an address */
    212  1.1    dyoung 	if (ia->ia_nio < 1 || ia->ia_io[0].ir_addr == ISA_UNKNOWN_PORT)
    213  1.1    dyoung 		return 0;
    214  1.1    dyoung 
    215  1.1    dyoung 	ir.ir_bt = ia->ia_iot;
    216  1.1    dyoung 
    217  1.1    dyoung 	if (bus_space_map(ir.ir_bt, ia->ia_io[0].ir_addr, 8, 0, &ir.ir_bh))
    218  1.1    dyoung 		return 0;
    219  1.1    dyoung 
    220  1.1    dyoung 	rv = isv_probe(&ir);
    221  1.1    dyoung 
    222  1.1    dyoung 	bus_space_unmap(ir.ir_bt, ir.ir_bh, 8);
    223  1.1    dyoung 
    224  1.1    dyoung 	if (rv) {
    225  1.1    dyoung 		ia->ia_nio = 1;
    226  1.1    dyoung 		ia->ia_io[0].ir_size = 8;
    227  1.1    dyoung 
    228  1.1    dyoung 		ia->ia_niomem = 0;
    229  1.1    dyoung 		ia->ia_nirq = 0;
    230  1.1    dyoung 		ia->ia_ndrq = 0;
    231  1.1    dyoung 	}
    232  1.1    dyoung 
    233  1.1    dyoung 	return rv;
    234  1.1    dyoung }
    235  1.1    dyoung 
    236  1.1    dyoung 
    237  1.1    dyoung static void
    238  1.1    dyoung isv_attach(device_t parent, device_t self, void *aux)
    239  1.1    dyoung {
    240  1.1    dyoung 	struct isv_softc *sc = device_private(self);
    241  1.1    dyoung 	struct isv_regs *ir = &sc->sc_ir;
    242  1.1    dyoung 	struct isa_attach_args *ia = aux;
    243  1.1    dyoung 
    244  1.1    dyoung 	ir->ir_bt = ia->ia_iot;
    245  1.1    dyoung 
    246  1.1    dyoung 	if (bus_space_map(ir->ir_bt, ia->ia_io[0].ir_addr, 8, 0, &ir->ir_bh)) {
    247  1.1    dyoung 		aprint_error(": can't map i/o space\n");
    248  1.1    dyoung 		return;
    249  1.1    dyoung 	}
    250  1.1    dyoung 
    251  1.1    dyoung 	/* Bus-independent attachment */
    252  1.1    dyoung 	sc->sc_dev = self;
    253  1.1    dyoung 
    254  1.1    dyoung 	aprint_normal(": IDEC Supervision/16\n");
    255  1.1    dyoung 
    256  1.1    dyoung 	/* TBD */
    257  1.1    dyoung }
    258  1.1    dyoung 
    259  1.1    dyoung int
    260  1.1    dyoung isv_open(dev_t dev, int flag, int devtype, lwp_t *l)
    261  1.1    dyoung {
    262  1.1    dyoung 	vaddr_t va;
    263  1.1    dyoung 	struct isv_softc *sc = device_lookup_private(&isv_cd, minor(dev));
    264  1.1    dyoung 
    265  1.1    dyoung 	if (sc == NULL)
    266  1.1    dyoung 		return ENXIO;
    267  1.1    dyoung 
    268  1.1    dyoung 	if (sc->sc_frame != NULL)
    269  1.1    dyoung 		return 0;
    270  1.1    dyoung 
    271  1.1    dyoung 	if ((va = uvm_km_alloc(kernel_map, ISV_WIDTH * ISV_LINES, PAGE_SIZE,
    272  1.1    dyoung 	    UVM_KMF_WIRED|UVM_KMF_ZERO|UVM_KMF_CANFAIL|UVM_KMF_WAITVA)) == 0)
    273  1.1    dyoung 		return ENOMEM;
    274  1.1    dyoung 
    275  1.1    dyoung 	sc->sc_frame = (uint16_t *)(void *)va;
    276  1.1    dyoung 	return 0;
    277  1.1    dyoung }
    278  1.1    dyoung 
    279  1.1    dyoung /* wait for retrace */
    280  1.1    dyoung static int
    281  1.1    dyoung isv_retrace_wait(struct isv_regs *ir, int *state, const struct timeval *end)
    282  1.1    dyoung {
    283  1.1    dyoung 	struct timeval now;
    284  1.1    dyoung 
    285  1.1    dyoung 	for (;;) {
    286  1.1    dyoung 		if (!isv_delta(state, isv_retrace(ir))) {
    287  1.1    dyoung 			microtime(&now);
    288  1.1    dyoung 			continue;
    289  1.1    dyoung 		}
    290  1.1    dyoung 		if (*state == ISV_S_RETRACE)
    291  1.1    dyoung 			break;
    292  1.1    dyoung 		if (*state != ISV_S_CAPTURE0)
    293  1.1    dyoung 			continue;
    294  1.1    dyoung 
    295  1.1    dyoung 		microtime(&now);
    296  1.1    dyoung 		if (timercmp(&now, end, >=))
    297  1.1    dyoung 			return EIO;
    298  1.1    dyoung 	}
    299  1.1    dyoung 	return 0;
    300  1.1    dyoung }
    301  1.1    dyoung 
    302  1.1    dyoung /* wait for capture mode */
    303  1.1    dyoung static int
    304  1.1    dyoung isv_capture_wait(struct isv_regs *ir, int *state, const struct timeval *end)
    305  1.1    dyoung {
    306  1.1    dyoung 	struct timeval now;
    307  1.1    dyoung 
    308  1.1    dyoung 	for (;;) {
    309  1.1    dyoung 		if (!isv_delta(state, isv_retrace(ir))) {
    310  1.1    dyoung 			microtime(&now);
    311  1.1    dyoung 			continue;
    312  1.1    dyoung 		}
    313  1.1    dyoung 		if (*state != ISV_S_RETRACE)
    314  1.1    dyoung 			break;
    315  1.1    dyoung 
    316  1.1    dyoung 		microtime(&now);
    317  1.1    dyoung 		if (timercmp(&now, end, >=))
    318  1.1    dyoung 			return EIO;
    319  1.1    dyoung 	}
    320  1.1    dyoung 	return 0;
    321  1.1    dyoung }
    322  1.1    dyoung 
    323  1.1    dyoung 
    324  1.1    dyoung static int
    325  1.1    dyoung isv_capture(struct isv_softc *sc)
    326  1.1    dyoung {
    327  1.1    dyoung 	int speed;
    328  1.1    dyoung 	int rc, state = ISV_S_CAPTURE0;
    329  1.1    dyoung 	struct timeval diff, end, start, stop;
    330  1.1    dyoung 	static const struct timeval wait = {.tv_sec = 0, .tv_usec = 200000};
    331  1.1    dyoung 	struct isv_regs *ir = &sc->sc_ir;
    332  1.1    dyoung 
    333  1.1    dyoung 	if (sc->sc_frame == NULL)
    334  1.1    dyoung 		return EAGAIN;
    335  1.1    dyoung 
    336  1.1    dyoung 	microtime(&start);
    337  1.1    dyoung 
    338  1.1    dyoung 	timeradd(&start, &wait, &end);
    339  1.1    dyoung 
    340  1.1    dyoung 	speed = sc->sc_speed;
    341  1.1    dyoung 	sc->sc_speed = 0;
    342  1.1    dyoung 
    343  1.1    dyoung 	if (speed < 1 && (rc = isv_retrace_wait(ir, &state, &end)) != 0)
    344  1.1    dyoung 		return rc;
    345  1.1    dyoung 
    346  1.1    dyoung 	if (speed < 2 && (rc = isv_capture_wait(ir, &state, &end)) != 0)
    347  1.1    dyoung 		return rc;
    348  1.1    dyoung 
    349  1.1    dyoung 	if ((rc = isv_retrace_wait(ir, &state, &end)) != 0)
    350  1.1    dyoung 		return rc;
    351  1.1    dyoung 
    352  1.1    dyoung 	microtime(&stop);
    353  1.1    dyoung 
    354  1.1    dyoung 	timersub(&stop, &start, &diff);
    355  1.1    dyoung 
    356  1.3    dyoung 	aprint_debug_dev(sc->sc_dev, "%ssync in %" PRId64 ".%06d seconds\n",
    357  1.1    dyoung 	    (speed < 1) ? "" : ((speed < 2) ? "faster " : "fastest "),
    358  1.1    dyoung 	    diff.tv_sec, diff.tv_usec);
    359  1.1    dyoung 
    360  1.1    dyoung 	microtime(&start);
    361  1.1    dyoung 
    362  1.1    dyoung 	/* enter read mode, then toggle counter mode,
    363  1.1    dyoung 	 * autoinc -> reset -> autoinc, so that we start reading
    364  1.1    dyoung 	 * at the top of the frame.
    365  1.1    dyoung 	 */
    366  1.1    dyoung 	isv_write(ir, ISV_CONTROL,
    367  1.1    dyoung 	    ISV_CONTROL_MODE_READ|ISV_CONTROL_COUNTER_AUTOINC);
    368  1.1    dyoung 	isv_write(ir, ISV_CONTROL,
    369  1.1    dyoung 	    ISV_CONTROL_MODE_READ|ISV_CONTROL_COUNTER_RESET);
    370  1.1    dyoung 	isv_write(ir, ISV_CONTROL,
    371  1.1    dyoung 	    ISV_CONTROL_MODE_READ|ISV_CONTROL_COUNTER_AUTOINC);
    372  1.1    dyoung 	/* read one dummy word to prime the state machine on the
    373  1.1    dyoung 	 * image capture board
    374  1.1    dyoung 	 */
    375  1.6  christos 	isv_read(ir, ISV_DATA);
    376  1.1    dyoung 	bus_space_read_multi_stream_2(ir->ir_bt, ir->ir_bh, ISV_DATA,
    377  1.1    dyoung 	    sc->sc_frame, ISV_WIDTH * ISV_LINES / 2);
    378  1.1    dyoung 
    379  1.1    dyoung 	/* restore to initial conditions */
    380  1.1    dyoung 	isv_write(ir, ISV_CONTROL,
    381  1.1    dyoung 	    ISV_CONTROL_MODE_CAPTURE|ISV_CONTROL_COUNTER_AUTOINC);
    382  1.1    dyoung 
    383  1.1    dyoung 	microtime(&stop);
    384  1.1    dyoung 
    385  1.1    dyoung 	timersub(&stop, &start, &diff);
    386  1.1    dyoung 
    387  1.3    dyoung 	aprint_debug_dev(sc->sc_dev, "read in %" PRId64 ".%06d seconds\n",
    388  1.1    dyoung 		diff.tv_sec, diff.tv_usec);
    389  1.1    dyoung 
    390  1.1    dyoung 	state = 0;
    391  1.1    dyoung 
    392  1.1    dyoung 	if (isv_retrace_wait(ir, &state, &end) != 0)
    393  1.1    dyoung 		return 0;
    394  1.1    dyoung 	sc->sc_speed++;
    395  1.1    dyoung 
    396  1.1    dyoung 	if (isv_capture_wait(ir, &state, &end) != 0)
    397  1.1    dyoung 		return 0;
    398  1.1    dyoung 	sc->sc_speed++;
    399  1.1    dyoung 
    400  1.1    dyoung 	return 0;
    401  1.1    dyoung }
    402  1.1    dyoung 
    403  1.1    dyoung int
    404  1.1    dyoung isv_ioctl(dev_t dev, u_long cmd, void *data, int flag, lwp_t *l)
    405  1.1    dyoung {
    406  1.1    dyoung 	struct isv_cmd ic;
    407  1.1    dyoung 	struct isv_softc *sc = device_lookup_private(&isv_cd, minor(dev));
    408  1.1    dyoung 
    409  1.1    dyoung 	if (cmd != ISV_CMD)
    410  1.1    dyoung 		return ENOTTY;
    411  1.1    dyoung 
    412  1.1    dyoung 	memcpy(&ic, data, sizeof(ic));
    413  1.1    dyoung 
    414  1.1    dyoung 	if (ic.c_cmd != ISV_CMD_READ)
    415  1.1    dyoung 		return EINVAL;
    416  1.1    dyoung 
    417  1.1    dyoung 	ic.c_frameno = 0;
    418  1.1    dyoung 
    419  1.1    dyoung 	return isv_capture(sc);
    420  1.1    dyoung }
    421  1.1    dyoung 
    422  1.1    dyoung paddr_t
    423  1.1    dyoung isv_mmap(dev_t dev, off_t offset, int prot)
    424  1.1    dyoung {
    425  1.1    dyoung 	struct isv_softc *sc = device_lookup_private(&isv_cd, minor(dev));
    426  1.1    dyoung 	paddr_t pa;
    427  1.1    dyoung 
    428  1.1    dyoung 	if ((prot & ~(VM_PROT_READ)) != 0)
    429  1.1    dyoung 		return -1;
    430  1.1    dyoung 
    431  1.1    dyoung 	if (sc->sc_frame == NULL)
    432  1.1    dyoung 		return -1;
    433  1.1    dyoung 
    434  1.1    dyoung 	if (offset >= ISV_WIDTH * ISV_LINES)
    435  1.1    dyoung 		return -1;
    436  1.1    dyoung 
    437  1.1    dyoung 	if (!pmap_extract(pmap_kernel(), (vaddr_t)&sc->sc_frame[offset/2], &pa))
    438  1.1    dyoung 		return -1;
    439  1.1    dyoung 
    440  1.1    dyoung 	return atop(pa);
    441  1.1    dyoung }
    442  1.1    dyoung 
    443  1.1    dyoung static int
    444  1.1    dyoung isv_detach(device_t self, int flags)
    445  1.1    dyoung {
    446  1.1    dyoung 	struct isv_softc *sc = device_private(self);
    447  1.1    dyoung 	struct isv_regs *ir = &sc->sc_ir;
    448  1.1    dyoung 
    449  1.1    dyoung 	if (sc->sc_frame != NULL) {
    450  1.1    dyoung 		uvm_km_free(kernel_map, (vaddr_t)sc->sc_frame,
    451  1.1    dyoung 		    ISV_WIDTH * ISV_LINES, UVM_KMF_WIRED);
    452  1.1    dyoung 	}
    453  1.1    dyoung 	bus_space_unmap(ir->ir_bt, ir->ir_bh, 8);
    454  1.1    dyoung 	return 0;
    455  1.1    dyoung }
    456