Home | History | Annotate | Line # | Download | only in scsipi
ss.c revision 1.84.2.2
      1  1.84.2.2       tls /*	$NetBSD: ss.c,v 1.84.2.2 2014/08/20 00:03:50 tls Exp $	*/
      2       1.1   mycroft 
      3       1.1   mycroft /*
      4       1.1   mycroft  * Copyright (c) 1995 Kenneth Stailey.  All rights reserved.
      5       1.1   mycroft  *   modified for configurable scanner support by Joachim Koenig
      6       1.1   mycroft  *
      7       1.1   mycroft  * Redistribution and use in source and binary forms, with or without
      8       1.1   mycroft  * modification, are permitted provided that the following conditions
      9       1.1   mycroft  * are met:
     10       1.1   mycroft  * 1. Redistributions of source code must retain the above copyright
     11       1.1   mycroft  *    notice, this list of conditions and the following disclaimer.
     12       1.1   mycroft  * 2. Redistributions in binary form must reproduce the above copyright
     13       1.1   mycroft  *    notice, this list of conditions and the following disclaimer in the
     14       1.1   mycroft  *    documentation and/or other materials provided with the distribution.
     15       1.1   mycroft  * 3. All advertising materials mentioning features or use of this software
     16       1.1   mycroft  *    must display the following acknowledgement:
     17       1.1   mycroft  *	This product includes software developed by Kenneth Stailey.
     18       1.1   mycroft  * 4. The name of the author may not be used to endorse or promote products
     19       1.1   mycroft  *    derived from this software without specific prior written permission.
     20       1.1   mycroft  *
     21       1.1   mycroft  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
     22       1.1   mycroft  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
     23       1.1   mycroft  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
     24       1.1   mycroft  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
     25       1.1   mycroft  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
     26       1.1   mycroft  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
     27       1.1   mycroft  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
     28       1.1   mycroft  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     29       1.1   mycroft  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
     30       1.1   mycroft  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     31       1.1   mycroft  */
     32      1.37     lukem 
     33      1.37     lukem #include <sys/cdefs.h>
     34  1.84.2.2       tls __KERNEL_RCSID(0, "$NetBSD: ss.c,v 1.84.2.2 2014/08/20 00:03:50 tls Exp $");
     35       1.1   mycroft 
     36       1.1   mycroft #include <sys/param.h>
     37       1.1   mycroft #include <sys/systm.h>
     38       1.1   mycroft #include <sys/fcntl.h>
     39       1.1   mycroft #include <sys/errno.h>
     40       1.1   mycroft #include <sys/ioctl.h>
     41       1.1   mycroft #include <sys/malloc.h>
     42       1.1   mycroft #include <sys/buf.h>
     43      1.57      yamt #include <sys/bufq.h>
     44       1.1   mycroft #include <sys/proc.h>
     45       1.1   mycroft #include <sys/device.h>
     46       1.9  christos #include <sys/conf.h>
     47      1.32  augustss #include <sys/vnode.h>
     48       1.1   mycroft #include <sys/scanio.h>
     49       1.1   mycroft 
     50      1.16    bouyer #include <dev/scsipi/scsi_all.h>
     51      1.16    bouyer #include <dev/scsipi/scsipi_all.h>
     52      1.16    bouyer #include <dev/scsipi/scsi_scanner.h>
     53      1.16    bouyer #include <dev/scsipi/scsiconf.h>
     54      1.16    bouyer #include <dev/scsipi/ssvar.h>
     55       1.1   mycroft 
     56      1.16    bouyer #include <dev/scsipi/ss_mustek.h>
     57       1.1   mycroft 
     58       1.1   mycroft #define SSMODE(z)	( minor(z)       & 0x03)
     59       1.1   mycroft #define SSUNIT(z)	((minor(z) >> 4)       )
     60      1.33  augustss #define SSNMINOR 16
     61       1.1   mycroft 
     62       1.1   mycroft /*
     63       1.1   mycroft  * If the mode is 3 (e.g. minor = 3,7,11,15)
     64       1.1   mycroft  * then the device has been openned to set defaults
     65       1.1   mycroft  * This mode does NOT ALLOW I/O, only ioctls
     66       1.1   mycroft  */
     67       1.1   mycroft #define MODE_REWIND	0
     68       1.1   mycroft #define MODE_NONREWIND	1
     69       1.1   mycroft #define MODE_CONTROL	3
     70       1.1   mycroft 
     71      1.78    cegger static int	ssmatch(device_t, cfdata_t, void *);
     72      1.78    cegger static void	ssattach(device_t, device_t, void *);
     73      1.78    cegger static int	ssdetach(device_t self, int flags);
     74       1.1   mycroft 
     75      1.81   mbalmer CFATTACH_DECL_NEW(
     76      1.81   mbalmer 	ss,
     77      1.81   mbalmer 	sizeof(struct ss_softc),
     78      1.81   mbalmer 	ssmatch,
     79      1.81   mbalmer 	ssattach,
     80      1.81   mbalmer 	ssdetach,
     81      1.81   mbalmer 	NULL
     82      1.81   mbalmer );
     83       1.8   thorpej 
     84      1.19   thorpej extern struct cfdriver ss_cd;
     85       1.1   mycroft 
     86      1.52   thorpej static dev_type_open(ssopen);
     87      1.52   thorpej static dev_type_close(ssclose);
     88      1.52   thorpej static dev_type_read(ssread);
     89      1.52   thorpej static dev_type_ioctl(ssioctl);
     90      1.40   gehenna 
     91      1.40   gehenna const struct cdevsw ss_cdevsw = {
     92  1.84.2.2       tls 	.d_open = ssopen,
     93  1.84.2.2       tls 	.d_close = ssclose,
     94  1.84.2.2       tls 	.d_read = ssread,
     95  1.84.2.2       tls 	.d_write = nowrite,
     96  1.84.2.2       tls 	.d_ioctl = ssioctl,
     97  1.84.2.2       tls 	.d_stop = nostop,
     98  1.84.2.2       tls 	.d_tty = notty,
     99  1.84.2.2       tls 	.d_poll = nopoll,
    100  1.84.2.2       tls 	.d_mmap = nommap,
    101  1.84.2.2       tls 	.d_kqfilter = nokqfilter,
    102  1.84.2.2       tls 	.d_discard = nodiscard,
    103  1.84.2.2       tls 	.d_flag = D_OTHER
    104      1.40   gehenna };
    105      1.40   gehenna 
    106      1.52   thorpej static void	ssstrategy(struct buf *);
    107      1.52   thorpej static void	ssstart(struct scsipi_periph *);
    108      1.54   mycroft static void	ssdone(struct scsipi_xfer *, int);
    109      1.52   thorpej static void	ssminphys(struct buf *);
    110       1.1   mycroft 
    111      1.52   thorpej static const struct scsipi_periphsw ss_switch = {
    112       1.1   mycroft 	NULL,
    113       1.1   mycroft 	ssstart,
    114       1.1   mycroft 	NULL,
    115      1.54   mycroft 	ssdone,
    116       1.1   mycroft };
    117       1.1   mycroft 
    118      1.52   thorpej static const struct scsipi_inquiry_pattern ss_patterns[] = {
    119       1.1   mycroft 	{T_SCANNER, T_FIXED,
    120       1.1   mycroft 	 "",         "",                 ""},
    121       1.1   mycroft 	{T_SCANNER, T_REMOV,
    122       1.1   mycroft 	 "",         "",                 ""},
    123       1.1   mycroft 	{T_PROCESSOR, T_FIXED,
    124      1.41       chs 	 "HP      ", "C1130A          ", ""},
    125      1.41       chs 	{T_PROCESSOR, T_FIXED,
    126       1.1   mycroft 	 "HP      ", "C1750A          ", ""},
    127       1.1   mycroft 	{T_PROCESSOR, T_FIXED,
    128       1.1   mycroft 	 "HP      ", "C2500A          ", ""},
    129      1.14   thorpej 	{T_PROCESSOR, T_FIXED,
    130      1.41       chs 	 "HP      ", "C2520A          ", ""},
    131      1.18  augustss 	{T_PROCESSOR, T_FIXED,
    132      1.18  augustss 	 "HP      ", "C5110A          ", ""},
    133      1.31      phil 	{T_PROCESSOR, T_FIXED,
    134      1.31      phil 	 "HP      ", "C7670A          ", ""},
    135      1.41       chs 	{T_PROCESSOR, T_FIXED,
    136      1.41       chs 	 "HP      ", "", ""},
    137       1.1   mycroft };
    138       1.1   mycroft 
    139      1.52   thorpej static int
    140      1.81   mbalmer ssmatch(device_t parent, cfdata_t match, void *aux)
    141       1.1   mycroft {
    142      1.16    bouyer 	struct scsipibus_attach_args *sa = aux;
    143       1.1   mycroft 	int priority;
    144       1.1   mycroft 
    145      1.16    bouyer 	(void)scsipi_inqmatch(&sa->sa_inqbuf,
    146      1.61  christos 	    ss_patterns, sizeof(ss_patterns) / sizeof(ss_patterns[0]),
    147       1.1   mycroft 	    sizeof(ss_patterns[0]), &priority);
    148      1.81   mbalmer 	return priority;
    149       1.1   mycroft }
    150       1.1   mycroft 
    151       1.1   mycroft /*
    152       1.1   mycroft  * The routine called by the low level scsi routine when it discovers
    153       1.1   mycroft  * A device suitable for this driver
    154       1.1   mycroft  * If it is a know special, call special attach routine to install
    155       1.1   mycroft  * special handlers into the ss_softc structure
    156       1.1   mycroft  */
    157      1.52   thorpej static void
    158      1.78    cegger ssattach(device_t parent, device_t self, void *aux)
    159       1.1   mycroft {
    160      1.66   thorpej 	struct ss_softc *ss = device_private(self);
    161      1.16    bouyer 	struct scsipibus_attach_args *sa = aux;
    162      1.34    bouyer 	struct scsipi_periph *periph = sa->sa_periph;
    163       1.1   mycroft 
    164      1.34    bouyer 	SC_DEBUG(periph, SCSIPI_DB2, ("ssattach: "));
    165      1.81   mbalmer 	ss->sc_dev = self;
    166       1.1   mycroft 
    167      1.20        pk 	ss->flags |= SSF_AUTOCONF;
    168      1.20        pk 
    169      1.81   mbalmer 	/* Store information needed to contact our base driver */
    170      1.34    bouyer 	ss->sc_periph = periph;
    171      1.81   mbalmer 	periph->periph_dev = ss->sc_dev;
    172      1.34    bouyer 	periph->periph_switch = &ss_switch;
    173      1.28       abs 
    174      1.28       abs 	printf("\n");
    175       1.1   mycroft 
    176      1.81   mbalmer 	/* Set up the buf queue for this device */
    177      1.62      yamt 	bufq_alloc(&ss->buf_queue, "fcfs", 0);
    178      1.39   hannken 
    179      1.71        ad 	callout_init(&ss->sc_callout, 0);
    180      1.53    bouyer 
    181      1.39   hannken 	/*
    182       1.1   mycroft 	 * look for non-standard scanners with help of the quirk table
    183       1.1   mycroft 	 * and install functions for special handling
    184       1.1   mycroft 	 */
    185      1.35    bouyer 	SC_DEBUG(periph, SCSIPI_DB2, ("ssattach:\n"));
    186      1.32  augustss 	if (memcmp(sa->sa_inqbuf.vendor, "MUSTEK", 6) == 0)
    187       1.1   mycroft 		mustek_attach(ss, sa);
    188      1.32  augustss 	if (memcmp(sa->sa_inqbuf.vendor, "HP      ", 8) == 0 &&
    189      1.32  augustss 	    memcmp(sa->sa_inqbuf.product, "ScanJet 5300C", 13) != 0)
    190       1.1   mycroft 		scanjet_attach(ss, sa);
    191      1.82   mbalmer 
    192       1.1   mycroft 	if (ss->special == NULL) {
    193       1.1   mycroft 		/* XXX add code to restart a SCSI2 scanner, if any */
    194       1.1   mycroft 	}
    195      1.20        pk 	ss->flags &= ~SSF_AUTOCONF;
    196       1.1   mycroft }
    197       1.1   mycroft 
    198      1.52   thorpej static int
    199      1.78    cegger ssdetach(device_t self, int flags)
    200      1.32  augustss {
    201      1.66   thorpej 	struct ss_softc *ss = device_private(self);
    202      1.32  augustss 	int s, cmaj, mn;
    203      1.32  augustss 
    204      1.32  augustss 	/* locate the major number */
    205      1.40   gehenna 	cmaj = cdevsw_lookup_major(&ss_cdevsw);
    206      1.32  augustss 
    207      1.53    bouyer 	/* kill any pending restart */
    208      1.53    bouyer 	callout_stop(&ss->sc_callout);
    209      1.53    bouyer 
    210      1.32  augustss 	s = splbio();
    211      1.32  augustss 
    212      1.32  augustss 	/* Kill off any queued buffers. */
    213      1.62      yamt 	bufq_drain(ss->buf_queue);
    214      1.32  augustss 
    215      1.62      yamt 	bufq_free(ss->buf_queue);
    216      1.39   hannken 
    217      1.32  augustss 	/* Kill off any pending commands. */
    218      1.34    bouyer 	scsipi_kill_pending(ss->sc_periph);
    219      1.32  augustss 
    220      1.32  augustss 	splx(s);
    221      1.32  augustss 
    222      1.32  augustss 	/* Nuke the vnodes for any open instances */
    223      1.65   thorpej 	mn = SSUNIT(device_unit(self));
    224      1.33  augustss 	vdevgone(cmaj, mn, mn+SSNMINOR-1, VCHR);
    225      1.32  augustss 
    226      1.81   mbalmer 	return 0;
    227      1.32  augustss }
    228      1.32  augustss 
    229      1.84   mbalmer /*  open the device. */
    230      1.52   thorpej static int
    231      1.69  christos ssopen(dev_t dev, int flag, int mode, struct lwp *l)
    232       1.1   mycroft {
    233       1.1   mycroft 	int unit;
    234      1.59   reinoud 	u_int ssmode;
    235      1.23   thorpej 	int error;
    236       1.1   mycroft 	struct ss_softc *ss;
    237      1.34    bouyer 	struct scsipi_periph *periph;
    238      1.34    bouyer 	struct scsipi_adapter *adapt;
    239       1.1   mycroft 
    240       1.1   mycroft 	unit = SSUNIT(dev);
    241      1.74   tsutsui 	ss = device_lookup_private(&ss_cd, unit);
    242      1.74   tsutsui 	if (ss == NULL)
    243      1.81   mbalmer 		return ENXIO;
    244       1.1   mycroft 
    245      1.81   mbalmer 	if (!device_is_active(ss->sc_dev))
    246      1.81   mbalmer 		return ENODEV;
    247      1.32  augustss 
    248       1.5   mycroft 	ssmode = SSMODE(dev);
    249       1.1   mycroft 
    250      1.34    bouyer 	periph = ss->sc_periph;
    251      1.34    bouyer 	adapt = periph->periph_channel->chan_adapter;
    252      1.34    bouyer 
    253      1.81   mbalmer 	SC_DEBUG(periph, SCSIPI_DB1,
    254      1.81   mbalmer 	    ("open: dev=0x%"PRIx64" (unit %d (of %d))\n", dev, unit,
    255      1.81   mbalmer 	    ss_cd.cd_ndevs));
    256       1.1   mycroft 
    257      1.34    bouyer 	if (periph->periph_flags & PERIPH_OPEN) {
    258      1.81   mbalmer 		aprint_error_dev(ss->sc_dev, "already open\n");
    259      1.81   mbalmer 		return EBUSY;
    260       1.1   mycroft 	}
    261       1.1   mycroft 
    262      1.34    bouyer 	if ((error = scsipi_adapter_addref(adapt)) != 0)
    263      1.81   mbalmer 		return error;
    264      1.23   thorpej 
    265       1.1   mycroft 	/*
    266       1.1   mycroft 	 * Catch any unit attention errors.
    267       1.1   mycroft 	 *
    268      1.26   thorpej 	 * XS_CTL_IGNORE_MEDIA_CHANGE: when you have an ADF, some scanners
    269       1.1   mycroft 	 * consider paper to be a changeable media
    270       1.1   mycroft 	 *
    271       1.1   mycroft 	 */
    272      1.34    bouyer 	error = scsipi_test_unit_ready(periph,
    273      1.26   thorpej 	    XS_CTL_IGNORE_MEDIA_CHANGE | XS_CTL_IGNORE_ILLEGAL_REQUEST |
    274      1.26   thorpej 	    (ssmode == MODE_CONTROL ? XS_CTL_IGNORE_NOT_READY : 0));
    275       1.1   mycroft 	if (error)
    276       1.1   mycroft 		goto bad;
    277       1.1   mycroft 
    278      1.34    bouyer 	periph->periph_flags |= PERIPH_OPEN;	/* unit attn now errors */
    279       1.1   mycroft 
    280       1.1   mycroft 	/*
    281       1.1   mycroft 	 * If the mode is 3 (e.g. minor = 3,7,11,15)
    282       1.1   mycroft 	 * then the device has been opened to set defaults
    283       1.1   mycroft 	 * This mode does NOT ALLOW I/O, only ioctls
    284       1.1   mycroft 	 */
    285       1.5   mycroft 	if (ssmode == MODE_CONTROL)
    286      1.81   mbalmer 		return 0;
    287       1.1   mycroft 
    288      1.34    bouyer 	SC_DEBUG(periph, SCSIPI_DB2, ("open complete\n"));
    289      1.81   mbalmer 	return 0;
    290       1.1   mycroft 
    291       1.1   mycroft bad:
    292      1.34    bouyer 	scsipi_adapter_delref(adapt);
    293      1.34    bouyer 	periph->periph_flags &= ~PERIPH_OPEN;
    294      1.81   mbalmer 	return error;
    295       1.1   mycroft }
    296       1.1   mycroft 
    297       1.1   mycroft /*
    298       1.1   mycroft  * close the device.. only called if we are the LAST
    299       1.1   mycroft  * occurence of an open device
    300       1.1   mycroft  */
    301      1.52   thorpej static int
    302      1.69  christos ssclose(dev_t dev, int flag, int mode, struct lwp *l)
    303       1.1   mycroft {
    304      1.74   tsutsui 	struct ss_softc *ss = device_lookup_private(&ss_cd, SSUNIT(dev));
    305      1.34    bouyer 	struct scsipi_periph *periph = ss->sc_periph;
    306      1.34    bouyer 	struct scsipi_adapter *adapt = periph->periph_channel->chan_adapter;
    307       1.1   mycroft 	int error;
    308       1.1   mycroft 
    309      1.34    bouyer 	SC_DEBUG(ss->sc_periph, SCSIPI_DB1, ("closing\n"));
    310       1.1   mycroft 
    311       1.1   mycroft 	if (SSMODE(dev) == MODE_REWIND) {
    312      1.21  explorer 		if (ss->special && ss->special->rewind_scanner) {
    313       1.1   mycroft 			/* call special handler to rewind/abort scan */
    314       1.1   mycroft 			error = (ss->special->rewind_scanner)(ss);
    315       1.1   mycroft 			if (error)
    316      1.81   mbalmer 				return error;
    317      1.82   mbalmer 		} else {
    318       1.1   mycroft 			/* XXX add code to restart a SCSI2 scanner, if any */
    319       1.1   mycroft 		}
    320       1.4   mycroft 		ss->sio.scan_window_size = 0;
    321       1.1   mycroft 		ss->flags &= ~SSF_TRIGGERED;
    322       1.1   mycroft 	}
    323      1.24   thorpej 
    324      1.34    bouyer 	scsipi_wait_drain(periph);
    325      1.23   thorpej 
    326      1.34    bouyer 	scsipi_adapter_delref(adapt);
    327      1.34    bouyer 	periph->periph_flags &= ~PERIPH_OPEN;
    328       1.1   mycroft 
    329      1.81   mbalmer 	return 0;
    330       1.1   mycroft }
    331       1.1   mycroft 
    332       1.1   mycroft /*
    333      1.84   mbalmer  * trim the size of the transfer if needed, called by physio
    334      1.84   mbalmer  * basically the smaller of our min and the scsi driver's minphys
    335       1.1   mycroft  */
    336      1.52   thorpej static void
    337      1.32  augustss ssminphys(struct buf *bp)
    338       1.1   mycroft {
    339      1.74   tsutsui 	struct ss_softc *ss = device_lookup_private(&ss_cd, SSUNIT(bp->b_dev));
    340      1.34    bouyer 	struct scsipi_periph *periph = ss->sc_periph;
    341  1.84.2.1       tls 	long xmax;
    342       1.1   mycroft 
    343  1.84.2.1       tls 	/* Impose any restrictions inherited down the device tree */
    344  1.84.2.1       tls 	xmax = ss->sc_dev->dv_maxphys;
    345  1.84.2.1       tls 	if (bp->b_bcount > xmax)
    346  1.84.2.1       tls 		bp->b_bcount = xmax;
    347  1.84.2.1       tls 
    348  1.84.2.1       tls 	/* Adapters could enforce their own limits on the
    349  1.84.2.1       tls 	   attached scsibuses via the device tree, but existing
    350  1.84.2.1       tls 	   drivers mostly do it in their own minphys routines. */
    351      1.51   thorpej 	scsipi_adapter_minphys(periph->periph_channel, bp);
    352       1.1   mycroft 
    353       1.1   mycroft 	/*
    354       1.1   mycroft 	 * trim the transfer further for special devices this is
    355       1.1   mycroft 	 * because some scanners only read multiples of a line at a
    356       1.1   mycroft 	 * time, also some cannot disconnect, so the read must be
    357       1.1   mycroft 	 * short enough to happen quickly
    358       1.1   mycroft 	 */
    359      1.21  explorer 	if (ss->special && ss->special->minphys)
    360       1.1   mycroft 		(ss->special->minphys)(ss, bp);
    361       1.1   mycroft }
    362       1.1   mycroft 
    363       1.1   mycroft /*
    364       1.1   mycroft  * Do a read on a device for a user process.
    365       1.1   mycroft  * Prime scanner at start of read, check uio values, call ssstrategy
    366       1.1   mycroft  * via physio for the actual transfer.
    367       1.1   mycroft  */
    368      1.52   thorpej static int
    369      1.69  christos ssread(dev_t dev, struct uio *uio, int flag)
    370       1.1   mycroft {
    371      1.74   tsutsui 	struct ss_softc *ss = device_lookup_private(&ss_cd, SSUNIT(dev));
    372       1.1   mycroft 	int error;
    373       1.1   mycroft 
    374      1.81   mbalmer 	if (!device_is_active(ss->sc_dev))
    375      1.81   mbalmer 		return ENODEV;
    376      1.32  augustss 
    377       1.1   mycroft 	/* if the scanner has not yet been started, do it now */
    378       1.1   mycroft 	if (!(ss->flags & SSF_TRIGGERED)) {
    379      1.21  explorer 		if (ss->special && ss->special->trigger_scanner) {
    380       1.1   mycroft 			error = (ss->special->trigger_scanner)(ss);
    381       1.1   mycroft 			if (error)
    382       1.1   mycroft 				return (error);
    383       1.1   mycroft 		}
    384       1.1   mycroft 		ss->flags |= SSF_TRIGGERED;
    385       1.1   mycroft 	}
    386       1.1   mycroft 
    387      1.81   mbalmer 	return physio(ssstrategy, NULL, dev, B_READ, ssminphys, uio);
    388       1.1   mycroft }
    389       1.1   mycroft 
    390       1.1   mycroft /*
    391       1.1   mycroft  * Actually translate the requested transfer into one the physical
    392       1.1   mycroft  * driver can understand The transfer is described by a buf and will
    393       1.1   mycroft  * include only one physical transfer.
    394       1.1   mycroft  */
    395      1.52   thorpej static void
    396      1.52   thorpej ssstrategy(struct buf *bp)
    397       1.1   mycroft {
    398      1.74   tsutsui 	struct ss_softc *ss = device_lookup_private(&ss_cd, SSUNIT(bp->b_dev));
    399      1.34    bouyer 	struct scsipi_periph *periph = ss->sc_periph;
    400       1.1   mycroft 	int s;
    401       1.1   mycroft 
    402      1.34    bouyer 	SC_DEBUG(ss->sc_periph, SCSIPI_DB1,
    403      1.81   mbalmer 	    ("ssstrategy %d bytes @ blk %" PRId64 "\n", bp->b_bcount,
    404      1.81   mbalmer 	    bp->b_blkno));
    405      1.25    bouyer 
    406      1.81   mbalmer 	/* If the device has been made invalid, error out */
    407      1.81   mbalmer 	if (!device_is_active(ss->sc_dev)) {
    408      1.34    bouyer 		if (periph->periph_flags & PERIPH_OPEN)
    409      1.32  augustss 			bp->b_error = EIO;
    410      1.32  augustss 		else
    411      1.32  augustss 			bp->b_error = ENODEV;
    412      1.32  augustss 		goto done;
    413      1.32  augustss 	}
    414      1.32  augustss 
    415      1.25    bouyer 	/* If negative offset, error */
    416      1.25    bouyer 	if (bp->b_blkno < 0) {
    417      1.25    bouyer 		bp->b_error = EINVAL;
    418      1.25    bouyer 		goto done;
    419      1.25    bouyer 	}
    420       1.6   mycroft 
    421       1.6   mycroft 	if (bp->b_bcount > ss->sio.scan_window_size)
    422       1.6   mycroft 		bp->b_bcount = ss->sio.scan_window_size;
    423       1.1   mycroft 
    424      1.81   mbalmer 	/* If it's a null transfer, return immediatly */
    425       1.1   mycroft 	if (bp->b_bcount == 0)
    426       1.1   mycroft 		goto done;
    427       1.1   mycroft 
    428       1.1   mycroft 	s = splbio();
    429       1.1   mycroft 
    430       1.1   mycroft 	/*
    431       1.1   mycroft 	 * Place it in the queue of activities for this scanner
    432       1.1   mycroft 	 * at the end (a bit silly because we only have on user..
    433       1.1   mycroft 	 * (but it could fork()))
    434       1.1   mycroft 	 */
    435      1.76      yamt 	bufq_put(ss->buf_queue, bp);
    436       1.1   mycroft 
    437       1.1   mycroft 	/*
    438       1.1   mycroft 	 * Tell the device to get going on the transfer if it's
    439       1.1   mycroft 	 * not doing anything, otherwise just wait for completion
    440       1.1   mycroft 	 * (All a bit silly if we're only allowing 1 open but..)
    441       1.1   mycroft 	 */
    442      1.34    bouyer 	ssstart(ss->sc_periph);
    443       1.1   mycroft 
    444       1.1   mycroft 	splx(s);
    445       1.1   mycroft 	return;
    446       1.1   mycroft done:
    447      1.81   mbalmer 	/* Correctly set the buf to indicate a completed xfer */
    448       1.1   mycroft 	bp->b_resid = bp->b_bcount;
    449       1.1   mycroft 	biodone(bp);
    450       1.1   mycroft }
    451       1.1   mycroft 
    452       1.1   mycroft /*
    453       1.1   mycroft  * ssstart looks to see if there is a buf waiting for the device
    454       1.1   mycroft  * and that the device is not already busy. If both are true,
    455       1.1   mycroft  * It dequeues the buf and creates a scsi command to perform the
    456      1.16    bouyer  * transfer required. The transfer request will call scsipi_done
    457       1.1   mycroft  * on completion, which will in turn call this routine again
    458       1.1   mycroft  * so that the next queued transfer is performed.
    459       1.1   mycroft  * The bufs are queued by the strategy routine (ssstrategy)
    460       1.1   mycroft  *
    461       1.1   mycroft  * This routine is also called after other non-queued requests
    462       1.1   mycroft  * have been made of the scsi driver, to ensure that the queue
    463       1.1   mycroft  * continues to be drained.
    464       1.1   mycroft  * ssstart() is called at splbio
    465       1.1   mycroft  */
    466      1.52   thorpej static void
    467      1.52   thorpej ssstart(struct scsipi_periph *periph)
    468       1.1   mycroft {
    469      1.81   mbalmer 	struct ss_softc *ss = device_private(periph->periph_dev);
    470      1.30  augustss 	struct buf *bp;
    471       1.1   mycroft 
    472      1.34    bouyer 	SC_DEBUG(periph, SCSIPI_DB2, ("ssstart "));
    473      1.84   mbalmer 
    474      1.84   mbalmer 	/* See if there is a buf to do and we are not already doing one */
    475      1.34    bouyer 	while (periph->periph_active < periph->periph_openings) {
    476       1.1   mycroft 		/* if a special awaits, let it proceed first */
    477      1.34    bouyer 		if (periph->periph_flags & PERIPH_WAITING) {
    478      1.34    bouyer 			periph->periph_flags &= ~PERIPH_WAITING;
    479      1.70  christos 			wakeup((void *)periph);
    480       1.1   mycroft 			return;
    481       1.1   mycroft 		}
    482       1.1   mycroft 
    483      1.84   mbalmer 		/* See if there is a buf with work for us to do.. */
    484      1.76      yamt 		if ((bp = bufq_peek(ss->buf_queue)) == NULL)
    485       1.1   mycroft 			return;
    486       1.1   mycroft 
    487      1.81   mbalmer 		if (ss->special && ss->special->read)
    488       1.1   mycroft 			(ss->special->read)(ss, bp);
    489      1.83   mbalmer 		else {
    490       1.1   mycroft 			/* generic scsi2 scanner read */
    491       1.1   mycroft 			/* XXX add code for SCSI2 scanner read */
    492       1.1   mycroft 		}
    493       1.1   mycroft 	}
    494       1.1   mycroft }
    495       1.1   mycroft 
    496      1.55   mycroft void
    497      1.53    bouyer ssrestart(void *v)
    498      1.53    bouyer {
    499      1.53    bouyer 	int s = splbio();
    500      1.53    bouyer 	ssstart((struct scsipi_periph *)v);
    501      1.53    bouyer 	splx(s);
    502      1.53    bouyer }
    503      1.54   mycroft 
    504      1.54   mycroft static void
    505      1.54   mycroft ssdone(struct scsipi_xfer *xs, int error)
    506      1.54   mycroft {
    507      1.54   mycroft 	struct buf *bp = xs->bp;
    508      1.54   mycroft 
    509      1.54   mycroft 	if (bp) {
    510      1.54   mycroft 		bp->b_error = error;
    511      1.54   mycroft 		bp->b_resid = xs->resid;
    512      1.54   mycroft 		biodone(bp);
    513      1.54   mycroft 	}
    514      1.54   mycroft }
    515      1.53    bouyer 
    516      1.53    bouyer 
    517       1.1   mycroft /*
    518       1.1   mycroft  * Perform special action on behalf of the user;
    519       1.1   mycroft  * knows about the internals of this device
    520       1.1   mycroft  */
    521       1.1   mycroft int
    522      1.70  christos ssioctl(dev_t dev, u_long cmd, void *addr, int flag, struct lwp *l)
    523       1.1   mycroft {
    524      1.74   tsutsui 	struct ss_softc *ss = device_lookup_private(&ss_cd, SSUNIT(dev));
    525       1.1   mycroft 	int error = 0;
    526       1.1   mycroft 	struct scan_io *sio;
    527      1.32  augustss 
    528      1.81   mbalmer 	if (!device_is_active(ss->sc_dev))
    529      1.81   mbalmer 		return ENODEV;
    530       1.1   mycroft 
    531       1.1   mycroft 	switch (cmd) {
    532       1.1   mycroft 	case SCIOCGET:
    533      1.21  explorer 		if (ss->special && ss->special->get_params) {
    534       1.1   mycroft 			/* call special handler */
    535       1.3   mycroft 			error = (ss->special->get_params)(ss);
    536       1.3   mycroft 			if (error)
    537      1.81   mbalmer 				return error;
    538      1.81   mbalmer 		} else
    539       1.1   mycroft 			/* XXX add code for SCSI2 scanner, if any */
    540      1.81   mbalmer 			return EOPNOTSUPP;
    541      1.36   thorpej 		memcpy(addr, &ss->sio, sizeof(struct scan_io));
    542       1.1   mycroft 		break;
    543       1.1   mycroft 	case SCIOCSET:
    544       1.1   mycroft 		sio = (struct scan_io *)addr;
    545       1.1   mycroft 
    546      1.21  explorer 		if (ss->special && ss->special->set_params) {
    547       1.1   mycroft 			/* call special handler */
    548       1.3   mycroft 			error = (ss->special->set_params)(ss, sio);
    549       1.3   mycroft 			if (error)
    550      1.81   mbalmer 				return error;
    551      1.81   mbalmer 		} else
    552       1.1   mycroft 			/* XXX add code for SCSI2 scanner, if any */
    553      1.81   mbalmer 			return EOPNOTSUPP;
    554       1.1   mycroft 		break;
    555       1.1   mycroft 	case SCIOCRESTART:
    556      1.21  explorer 		if (ss->special && ss->special->rewind_scanner ) {
    557       1.1   mycroft 			/* call special handler */
    558       1.3   mycroft 			error = (ss->special->rewind_scanner)(ss);
    559       1.3   mycroft 			if (error)
    560      1.81   mbalmer 				return error;
    561       1.1   mycroft 		} else
    562       1.1   mycroft 			/* XXX add code for SCSI2 scanner, if any */
    563      1.81   mbalmer 			return EOPNOTSUPP;
    564       1.1   mycroft 		ss->flags &= ~SSF_TRIGGERED;
    565       1.1   mycroft 		break;
    566       1.1   mycroft #ifdef NOTYET
    567       1.1   mycroft 	case SCAN_USE_ADF:
    568       1.1   mycroft 		break;
    569       1.1   mycroft #endif
    570       1.1   mycroft 	default:
    571      1.81   mbalmer 		return scsipi_do_ioctl(ss->sc_periph, dev, cmd, addr, flag, l);
    572       1.1   mycroft 	}
    573      1.81   mbalmer 	return error;
    574       1.1   mycroft }
    575