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