ss.c revision 1.84.2.3 1 1.84.2.2 tls /* $NetBSD: ss.c,v 1.84.2.3 2017/12/03 11:37:32 jdolecek 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.3 2017/12/03 11:37:32 jdolecek 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.3 jdolecek .d_flag = D_OTHER | D_MPSAFE
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.84.2.3 jdolecek struct scsipi_periph *periph = ss->sc_periph;
203 1.84.2.3 jdolecek struct scsipi_channel *chan = periph->periph_channel;
204 1.84.2.3 jdolecek int cmaj, mn;
205 1.32 augustss
206 1.32 augustss /* locate the major number */
207 1.40 gehenna cmaj = cdevsw_lookup_major(&ss_cdevsw);
208 1.32 augustss
209 1.53 bouyer /* kill any pending restart */
210 1.84.2.3 jdolecek callout_halt(&ss->sc_callout, NULL);
211 1.53 bouyer
212 1.84.2.3 jdolecek mutex_enter(chan_mtx(chan));
213 1.32 augustss
214 1.32 augustss /* Kill off any queued buffers. */
215 1.62 yamt bufq_drain(ss->buf_queue);
216 1.32 augustss
217 1.32 augustss /* Kill off any pending commands. */
218 1.84.2.3 jdolecek scsipi_kill_pending(periph);
219 1.32 augustss
220 1.84.2.3 jdolecek mutex_exit(chan_mtx(chan));
221 1.84.2.3 jdolecek
222 1.84.2.3 jdolecek bufq_free(ss->buf_queue);
223 1.32 augustss
224 1.32 augustss /* Nuke the vnodes for any open instances */
225 1.65 thorpej mn = SSUNIT(device_unit(self));
226 1.33 augustss vdevgone(cmaj, mn, mn+SSNMINOR-1, VCHR);
227 1.32 augustss
228 1.81 mbalmer return 0;
229 1.32 augustss }
230 1.32 augustss
231 1.84 mbalmer /* open the device. */
232 1.52 thorpej static int
233 1.69 christos ssopen(dev_t dev, int flag, int mode, struct lwp *l)
234 1.1 mycroft {
235 1.1 mycroft int unit;
236 1.59 reinoud u_int ssmode;
237 1.23 thorpej int error;
238 1.1 mycroft struct ss_softc *ss;
239 1.34 bouyer struct scsipi_periph *periph;
240 1.34 bouyer struct scsipi_adapter *adapt;
241 1.1 mycroft
242 1.1 mycroft unit = SSUNIT(dev);
243 1.74 tsutsui ss = device_lookup_private(&ss_cd, unit);
244 1.74 tsutsui if (ss == NULL)
245 1.81 mbalmer return ENXIO;
246 1.1 mycroft
247 1.81 mbalmer if (!device_is_active(ss->sc_dev))
248 1.81 mbalmer return ENODEV;
249 1.32 augustss
250 1.5 mycroft ssmode = SSMODE(dev);
251 1.1 mycroft
252 1.34 bouyer periph = ss->sc_periph;
253 1.34 bouyer adapt = periph->periph_channel->chan_adapter;
254 1.34 bouyer
255 1.81 mbalmer SC_DEBUG(periph, SCSIPI_DB1,
256 1.81 mbalmer ("open: dev=0x%"PRIx64" (unit %d (of %d))\n", dev, unit,
257 1.81 mbalmer ss_cd.cd_ndevs));
258 1.1 mycroft
259 1.34 bouyer if (periph->periph_flags & PERIPH_OPEN) {
260 1.81 mbalmer aprint_error_dev(ss->sc_dev, "already open\n");
261 1.81 mbalmer return EBUSY;
262 1.1 mycroft }
263 1.1 mycroft
264 1.34 bouyer if ((error = scsipi_adapter_addref(adapt)) != 0)
265 1.81 mbalmer return error;
266 1.23 thorpej
267 1.1 mycroft /*
268 1.1 mycroft * Catch any unit attention errors.
269 1.1 mycroft *
270 1.26 thorpej * XS_CTL_IGNORE_MEDIA_CHANGE: when you have an ADF, some scanners
271 1.1 mycroft * consider paper to be a changeable media
272 1.1 mycroft *
273 1.1 mycroft */
274 1.34 bouyer error = scsipi_test_unit_ready(periph,
275 1.26 thorpej XS_CTL_IGNORE_MEDIA_CHANGE | XS_CTL_IGNORE_ILLEGAL_REQUEST |
276 1.26 thorpej (ssmode == MODE_CONTROL ? XS_CTL_IGNORE_NOT_READY : 0));
277 1.1 mycroft if (error)
278 1.1 mycroft goto bad;
279 1.1 mycroft
280 1.34 bouyer periph->periph_flags |= PERIPH_OPEN; /* unit attn now errors */
281 1.1 mycroft
282 1.1 mycroft /*
283 1.1 mycroft * If the mode is 3 (e.g. minor = 3,7,11,15)
284 1.1 mycroft * then the device has been opened to set defaults
285 1.1 mycroft * This mode does NOT ALLOW I/O, only ioctls
286 1.1 mycroft */
287 1.5 mycroft if (ssmode == MODE_CONTROL)
288 1.81 mbalmer return 0;
289 1.1 mycroft
290 1.34 bouyer SC_DEBUG(periph, SCSIPI_DB2, ("open complete\n"));
291 1.81 mbalmer return 0;
292 1.1 mycroft
293 1.1 mycroft bad:
294 1.34 bouyer scsipi_adapter_delref(adapt);
295 1.34 bouyer periph->periph_flags &= ~PERIPH_OPEN;
296 1.81 mbalmer return error;
297 1.1 mycroft }
298 1.1 mycroft
299 1.1 mycroft /*
300 1.1 mycroft * close the device.. only called if we are the LAST
301 1.1 mycroft * occurence of an open device
302 1.1 mycroft */
303 1.52 thorpej static int
304 1.69 christos ssclose(dev_t dev, int flag, int mode, struct lwp *l)
305 1.1 mycroft {
306 1.74 tsutsui struct ss_softc *ss = device_lookup_private(&ss_cd, SSUNIT(dev));
307 1.34 bouyer struct scsipi_periph *periph = ss->sc_periph;
308 1.34 bouyer struct scsipi_adapter *adapt = periph->periph_channel->chan_adapter;
309 1.1 mycroft int error;
310 1.1 mycroft
311 1.34 bouyer SC_DEBUG(ss->sc_periph, SCSIPI_DB1, ("closing\n"));
312 1.1 mycroft
313 1.1 mycroft if (SSMODE(dev) == MODE_REWIND) {
314 1.21 explorer if (ss->special && ss->special->rewind_scanner) {
315 1.1 mycroft /* call special handler to rewind/abort scan */
316 1.1 mycroft error = (ss->special->rewind_scanner)(ss);
317 1.1 mycroft if (error)
318 1.81 mbalmer return error;
319 1.82 mbalmer } else {
320 1.1 mycroft /* XXX add code to restart a SCSI2 scanner, if any */
321 1.1 mycroft }
322 1.4 mycroft ss->sio.scan_window_size = 0;
323 1.1 mycroft ss->flags &= ~SSF_TRIGGERED;
324 1.1 mycroft }
325 1.24 thorpej
326 1.34 bouyer scsipi_wait_drain(periph);
327 1.23 thorpej
328 1.34 bouyer scsipi_adapter_delref(adapt);
329 1.34 bouyer periph->periph_flags &= ~PERIPH_OPEN;
330 1.1 mycroft
331 1.81 mbalmer return 0;
332 1.1 mycroft }
333 1.1 mycroft
334 1.1 mycroft /*
335 1.84 mbalmer * trim the size of the transfer if needed, called by physio
336 1.84 mbalmer * basically the smaller of our min and the scsi driver's minphys
337 1.1 mycroft */
338 1.52 thorpej static void
339 1.32 augustss ssminphys(struct buf *bp)
340 1.1 mycroft {
341 1.74 tsutsui struct ss_softc *ss = device_lookup_private(&ss_cd, SSUNIT(bp->b_dev));
342 1.34 bouyer struct scsipi_periph *periph = ss->sc_periph;
343 1.84.2.1 tls long xmax;
344 1.1 mycroft
345 1.84.2.1 tls /* Impose any restrictions inherited down the device tree */
346 1.84.2.1 tls xmax = ss->sc_dev->dv_maxphys;
347 1.84.2.1 tls if (bp->b_bcount > xmax)
348 1.84.2.1 tls bp->b_bcount = xmax;
349 1.84.2.1 tls
350 1.84.2.1 tls /* Adapters could enforce their own limits on the
351 1.84.2.1 tls attached scsibuses via the device tree, but existing
352 1.84.2.1 tls drivers mostly do it in their own minphys routines. */
353 1.51 thorpej scsipi_adapter_minphys(periph->periph_channel, bp);
354 1.1 mycroft
355 1.1 mycroft /*
356 1.1 mycroft * trim the transfer further for special devices this is
357 1.1 mycroft * because some scanners only read multiples of a line at a
358 1.1 mycroft * time, also some cannot disconnect, so the read must be
359 1.1 mycroft * short enough to happen quickly
360 1.1 mycroft */
361 1.21 explorer if (ss->special && ss->special->minphys)
362 1.1 mycroft (ss->special->minphys)(ss, bp);
363 1.1 mycroft }
364 1.1 mycroft
365 1.1 mycroft /*
366 1.1 mycroft * Do a read on a device for a user process.
367 1.1 mycroft * Prime scanner at start of read, check uio values, call ssstrategy
368 1.1 mycroft * via physio for the actual transfer.
369 1.1 mycroft */
370 1.52 thorpej static int
371 1.69 christos ssread(dev_t dev, struct uio *uio, int flag)
372 1.1 mycroft {
373 1.74 tsutsui struct ss_softc *ss = device_lookup_private(&ss_cd, SSUNIT(dev));
374 1.1 mycroft int error;
375 1.1 mycroft
376 1.81 mbalmer if (!device_is_active(ss->sc_dev))
377 1.81 mbalmer return ENODEV;
378 1.32 augustss
379 1.1 mycroft /* if the scanner has not yet been started, do it now */
380 1.1 mycroft if (!(ss->flags & SSF_TRIGGERED)) {
381 1.21 explorer if (ss->special && ss->special->trigger_scanner) {
382 1.1 mycroft error = (ss->special->trigger_scanner)(ss);
383 1.1 mycroft if (error)
384 1.1 mycroft return (error);
385 1.1 mycroft }
386 1.1 mycroft ss->flags |= SSF_TRIGGERED;
387 1.1 mycroft }
388 1.1 mycroft
389 1.81 mbalmer return physio(ssstrategy, NULL, dev, B_READ, ssminphys, uio);
390 1.1 mycroft }
391 1.1 mycroft
392 1.1 mycroft /*
393 1.1 mycroft * Actually translate the requested transfer into one the physical
394 1.1 mycroft * driver can understand The transfer is described by a buf and will
395 1.1 mycroft * include only one physical transfer.
396 1.1 mycroft */
397 1.52 thorpej static void
398 1.52 thorpej ssstrategy(struct buf *bp)
399 1.1 mycroft {
400 1.74 tsutsui struct ss_softc *ss = device_lookup_private(&ss_cd, SSUNIT(bp->b_dev));
401 1.34 bouyer struct scsipi_periph *periph = ss->sc_periph;
402 1.84.2.3 jdolecek struct scsipi_channel *chan = periph->periph_channel;
403 1.1 mycroft
404 1.34 bouyer SC_DEBUG(ss->sc_periph, SCSIPI_DB1,
405 1.81 mbalmer ("ssstrategy %d bytes @ blk %" PRId64 "\n", bp->b_bcount,
406 1.81 mbalmer bp->b_blkno));
407 1.25 bouyer
408 1.81 mbalmer /* If the device has been made invalid, error out */
409 1.81 mbalmer if (!device_is_active(ss->sc_dev)) {
410 1.34 bouyer if (periph->periph_flags & PERIPH_OPEN)
411 1.32 augustss bp->b_error = EIO;
412 1.32 augustss else
413 1.32 augustss bp->b_error = ENODEV;
414 1.32 augustss goto done;
415 1.32 augustss }
416 1.32 augustss
417 1.25 bouyer /* If negative offset, error */
418 1.25 bouyer if (bp->b_blkno < 0) {
419 1.25 bouyer bp->b_error = EINVAL;
420 1.25 bouyer goto done;
421 1.25 bouyer }
422 1.6 mycroft
423 1.6 mycroft if (bp->b_bcount > ss->sio.scan_window_size)
424 1.6 mycroft bp->b_bcount = ss->sio.scan_window_size;
425 1.1 mycroft
426 1.81 mbalmer /* If it's a null transfer, return immediatly */
427 1.1 mycroft if (bp->b_bcount == 0)
428 1.1 mycroft goto done;
429 1.1 mycroft
430 1.84.2.3 jdolecek mutex_enter(chan_mtx(chan));
431 1.1 mycroft
432 1.1 mycroft /*
433 1.1 mycroft * Place it in the queue of activities for this scanner
434 1.1 mycroft * at the end (a bit silly because we only have on user..
435 1.1 mycroft * (but it could fork()))
436 1.1 mycroft */
437 1.76 yamt bufq_put(ss->buf_queue, bp);
438 1.1 mycroft
439 1.1 mycroft /*
440 1.1 mycroft * Tell the device to get going on the transfer if it's
441 1.1 mycroft * not doing anything, otherwise just wait for completion
442 1.1 mycroft * (All a bit silly if we're only allowing 1 open but..)
443 1.1 mycroft */
444 1.84.2.3 jdolecek ssstart(periph);
445 1.1 mycroft
446 1.84.2.3 jdolecek mutex_exit(chan_mtx(chan));
447 1.1 mycroft return;
448 1.1 mycroft done:
449 1.81 mbalmer /* Correctly set the buf to indicate a completed xfer */
450 1.1 mycroft bp->b_resid = bp->b_bcount;
451 1.1 mycroft biodone(bp);
452 1.1 mycroft }
453 1.1 mycroft
454 1.1 mycroft /*
455 1.1 mycroft * ssstart looks to see if there is a buf waiting for the device
456 1.1 mycroft * and that the device is not already busy. If both are true,
457 1.1 mycroft * It dequeues the buf and creates a scsi command to perform the
458 1.16 bouyer * transfer required. The transfer request will call scsipi_done
459 1.1 mycroft * on completion, which will in turn call this routine again
460 1.1 mycroft * so that the next queued transfer is performed.
461 1.1 mycroft * The bufs are queued by the strategy routine (ssstrategy)
462 1.1 mycroft *
463 1.1 mycroft * This routine is also called after other non-queued requests
464 1.1 mycroft * have been made of the scsi driver, to ensure that the queue
465 1.1 mycroft * continues to be drained.
466 1.84.2.3 jdolecek * ssstart() is called with channel lock held.
467 1.1 mycroft */
468 1.52 thorpej static void
469 1.52 thorpej ssstart(struct scsipi_periph *periph)
470 1.1 mycroft {
471 1.81 mbalmer struct ss_softc *ss = device_private(periph->periph_dev);
472 1.30 augustss struct buf *bp;
473 1.1 mycroft
474 1.34 bouyer SC_DEBUG(periph, SCSIPI_DB2, ("ssstart "));
475 1.84 mbalmer
476 1.84 mbalmer /* See if there is a buf to do and we are not already doing one */
477 1.34 bouyer while (periph->periph_active < periph->periph_openings) {
478 1.1 mycroft /* if a special awaits, let it proceed first */
479 1.34 bouyer if (periph->periph_flags & PERIPH_WAITING) {
480 1.34 bouyer periph->periph_flags &= ~PERIPH_WAITING;
481 1.84.2.3 jdolecek cv_broadcast(periph_cv_periph(periph));
482 1.1 mycroft return;
483 1.1 mycroft }
484 1.1 mycroft
485 1.84 mbalmer /* See if there is a buf with work for us to do.. */
486 1.76 yamt if ((bp = bufq_peek(ss->buf_queue)) == NULL)
487 1.1 mycroft return;
488 1.1 mycroft
489 1.81 mbalmer if (ss->special && ss->special->read)
490 1.1 mycroft (ss->special->read)(ss, bp);
491 1.83 mbalmer else {
492 1.1 mycroft /* generic scsi2 scanner read */
493 1.1 mycroft /* XXX add code for SCSI2 scanner read */
494 1.1 mycroft }
495 1.1 mycroft }
496 1.1 mycroft }
497 1.1 mycroft
498 1.55 mycroft void
499 1.53 bouyer ssrestart(void *v)
500 1.53 bouyer {
501 1.84.2.3 jdolecek struct scsipi_periph *periph = v;
502 1.84.2.3 jdolecek struct scsipi_channel *chan = periph->periph_channel;
503 1.84.2.3 jdolecek
504 1.84.2.3 jdolecek mutex_enter(chan_mtx(chan));
505 1.84.2.3 jdolecek ssstart(periph);
506 1.84.2.3 jdolecek mutex_exit(chan_mtx(chan));
507 1.53 bouyer }
508 1.54 mycroft
509 1.54 mycroft static void
510 1.54 mycroft ssdone(struct scsipi_xfer *xs, int error)
511 1.54 mycroft {
512 1.54 mycroft struct buf *bp = xs->bp;
513 1.54 mycroft
514 1.54 mycroft if (bp) {
515 1.54 mycroft bp->b_error = error;
516 1.54 mycroft bp->b_resid = xs->resid;
517 1.54 mycroft biodone(bp);
518 1.54 mycroft }
519 1.54 mycroft }
520 1.53 bouyer
521 1.53 bouyer
522 1.1 mycroft /*
523 1.1 mycroft * Perform special action on behalf of the user;
524 1.1 mycroft * knows about the internals of this device
525 1.1 mycroft */
526 1.1 mycroft int
527 1.70 christos ssioctl(dev_t dev, u_long cmd, void *addr, int flag, struct lwp *l)
528 1.1 mycroft {
529 1.74 tsutsui struct ss_softc *ss = device_lookup_private(&ss_cd, SSUNIT(dev));
530 1.1 mycroft int error = 0;
531 1.1 mycroft struct scan_io *sio;
532 1.32 augustss
533 1.81 mbalmer if (!device_is_active(ss->sc_dev))
534 1.81 mbalmer return ENODEV;
535 1.1 mycroft
536 1.1 mycroft switch (cmd) {
537 1.1 mycroft case SCIOCGET:
538 1.21 explorer if (ss->special && ss->special->get_params) {
539 1.1 mycroft /* call special handler */
540 1.3 mycroft error = (ss->special->get_params)(ss);
541 1.3 mycroft if (error)
542 1.81 mbalmer return error;
543 1.81 mbalmer } else
544 1.1 mycroft /* XXX add code for SCSI2 scanner, if any */
545 1.81 mbalmer return EOPNOTSUPP;
546 1.36 thorpej memcpy(addr, &ss->sio, sizeof(struct scan_io));
547 1.1 mycroft break;
548 1.1 mycroft case SCIOCSET:
549 1.1 mycroft sio = (struct scan_io *)addr;
550 1.1 mycroft
551 1.21 explorer if (ss->special && ss->special->set_params) {
552 1.1 mycroft /* call special handler */
553 1.3 mycroft error = (ss->special->set_params)(ss, sio);
554 1.3 mycroft if (error)
555 1.81 mbalmer return error;
556 1.81 mbalmer } else
557 1.1 mycroft /* XXX add code for SCSI2 scanner, if any */
558 1.81 mbalmer return EOPNOTSUPP;
559 1.1 mycroft break;
560 1.1 mycroft case SCIOCRESTART:
561 1.21 explorer if (ss->special && ss->special->rewind_scanner ) {
562 1.1 mycroft /* call special handler */
563 1.3 mycroft error = (ss->special->rewind_scanner)(ss);
564 1.3 mycroft if (error)
565 1.81 mbalmer return error;
566 1.1 mycroft } else
567 1.1 mycroft /* XXX add code for SCSI2 scanner, if any */
568 1.81 mbalmer return EOPNOTSUPP;
569 1.1 mycroft ss->flags &= ~SSF_TRIGGERED;
570 1.1 mycroft break;
571 1.1 mycroft #ifdef NOTYET
572 1.1 mycroft case SCAN_USE_ADF:
573 1.1 mycroft break;
574 1.1 mycroft #endif
575 1.1 mycroft default:
576 1.81 mbalmer return scsipi_do_ioctl(ss->sc_periph, dev, cmd, addr, flag, l);
577 1.1 mycroft }
578 1.81 mbalmer return error;
579 1.1 mycroft }
580