Annotation of sys/scsi/ss_scanjet.c, Revision 1.1.1.1
1.1 nbrk 1: /* $OpenBSD: ss_scanjet.c,v 1.31 2007/06/01 20:59:04 moritz Exp $ */
2: /* $NetBSD: ss_scanjet.c,v 1.6 1996/05/18 22:58:01 christos Exp $ */
3:
4: /*
5: * Copyright (c) 1995 Kenneth Stailey. All rights reserved.
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: /*
34: * special functions for the HP ScanJet IIc and IIcx
35: */
36:
37: #include <sys/types.h>
38: #include <sys/param.h>
39: #include <sys/systm.h>
40: #include <sys/fcntl.h>
41: #include <sys/errno.h>
42: #include <sys/ioctl.h>
43: #include <sys/malloc.h>
44: #include <sys/buf.h>
45: #include <sys/proc.h>
46: #include <sys/user.h>
47: #include <sys/device.h>
48: #include <sys/conf.h> /* for cdevsw */
49: #include <sys/scanio.h>
50:
51: #include <scsi/scsi_all.h>
52: #include <scsi/scsi_scanner.h>
53: #include <scsi/scsiconf.h>
54: #include <scsi/ssvar.h>
55:
56: #define SCANJET_RETRIES 4
57:
58: int scanjet_set_params(struct ss_softc *, struct scan_io *);
59: int scanjet_trigger_scanner(struct ss_softc *);
60: int scanjet_read(struct ss_softc *, struct buf *);
61:
62: /* only used internally */
63: int scanjet_ctl_write(struct ss_softc *, char *, u_int, int);
64: int scanjet_ctl_read(struct ss_softc *, char *, u_int, int);
65: int scanjet_set_window(struct ss_softc *, int);
66: int scanjet_compute_sizes(struct ss_softc *, int);
67: /* Maybe move to libkern? */
68: #define atoi local_atoi
69: __inline static int atoi(const char *);
70:
71:
72: /*
73: * structure for the special handlers
74: */
75: struct ss_special scanjet_special = {
76: scanjet_set_params,
77: scanjet_trigger_scanner,
78: NULL,
79: NULL, /* no special minphys */
80: scanjet_read, /* scsi 6-byte read */
81: NULL, /* no "rewind" code (yet?) */
82: NULL, /* no adf support right now */
83: NULL /* no adf support right now */
84: };
85:
86: /*
87: * scanjet_attach: attach special functions to ss
88: */
89: void
90: scanjet_attach(ss, sa)
91: struct ss_softc *ss;
92: struct scsi_attach_args *sa;
93: {
94: #ifdef SCSIDEBUG
95: struct scsi_link *sc_link = sa->sa_sc_link;
96: #endif
97: int error;
98:
99: SC_DEBUG(sc_link, SDEV_DB1, ("scanjet_attach: start\n"));
100: ss->sio.scan_scanner_type = 0;
101:
102: printf("\n%s: ", ss->sc_dev.dv_xname);
103:
104: /* first, check the model (which determines nothing yet) */
105:
106: if (!bcmp(sa->sa_inqbuf->product, "C1750A", 6)) {
107: ss->sio.scan_scanner_type = HP_SCANJET_IIC;
108: printf("HP ScanJet IIc");
109: }
110: /* The IIp is a grayscale-only HP SCL scanner */
111: if (!bcmp(sa->sa_inqbuf->product, "C1790A", 6)) {
112: ss->sio.scan_scanner_type = HP_SCANJET_IIC;
113: printf("HP ScanJet IIp");
114: }
115: if (!bcmp(sa->sa_inqbuf->product, "C2500A", 6)) {
116: ss->sio.scan_scanner_type = HP_SCANJET_IIC;
117: printf("HP ScanJet IIcx");
118: }
119: /* The 3p is a grayscale-only HP SCL scanner */
120: if (!bcmp(sa->sa_inqbuf->product, "C2570A", 6)) {
121: ss->sio.scan_scanner_type = HP_SCANJET_IIC;
122: printf("HP ScanJet 3p");
123: }
124: /* The 3c/4c/6100C report as the same? */
125: if (!bcmp(sa->sa_inqbuf->product, "C2520A", 6)) {
126: ss->sio.scan_scanner_type = HP_SCANJET_IIC;
127: printf("HP ScanJet 3c/4c/6100C");
128: }
129: if (!bcmp(sa->sa_inqbuf->product, "C1130A", 6)) {
130: ss->sio.scan_scanner_type = HP_SCANJET_IIC;
131: printf("HP ScanJet 4p");
132: }
133: if (!bcmp(sa->sa_inqbuf->product, "C5110A", 6)) {
134: ss->sio.scan_scanner_type = HP_SCANJET_IIC;
135: printf("HP ScanJet 5p");
136: }
137: if (!bcmp(sa->sa_inqbuf->product, "C6290A", 6)) {
138: ss->sio.scan_scanner_type = HP_SCANJET_IIC;
139: printf("HP ScanJet 4100C");
140: }
141: if (!bcmp(sa->sa_inqbuf->product, "C5190A", 6)) {
142: ss->sio.scan_scanner_type = HP_SCANJET_IIC;
143: printf("HP ScanJet 5100C");
144: }
145: if (!bcmp(sa->sa_inqbuf->product, "C7190A", 6)) {
146: ss->sio.scan_scanner_type = HP_SCANJET_IIC;
147: printf("HP ScanJet 5200C");
148: }
149: if (!bcmp(sa->sa_inqbuf->product, "C6270A", 6)) {
150: ss->sio.scan_scanner_type = HP_SCANJET_IIC;
151: printf("HP ScanJet 6200C");
152: }
153: if (!bcmp(sa->sa_inqbuf->product, "C7670A", 6)) {
154: ss->sio.scan_scanner_type = HP_SCANJET_IIC;
155: printf("HP ScanJet 6300C");
156: }
157:
158: SC_DEBUG(sc_link, SDEV_DB1, ("scanjet_attach: scanner_type = %d\n",
159: ss->sio.scan_scanner_type));
160:
161: /* now install special handlers */
162: ss->special = scanjet_special;
163:
164: /*
165: * fill in the rest of the scan_io struct by calling
166: * set_window and compute_sizes routines
167: */
168: error = scanjet_set_window(ss, SCSI_POLL);
169: if (error) {
170: printf(" set_window failed\n");
171: return;
172: }
173:
174: error = scanjet_compute_sizes(ss, SCSI_POLL);
175: if (error) {
176: printf(" compute_sizes failed\n");
177: return;
178: }
179:
180: printf("\n");
181: }
182:
183: /*
184: * check the parameters if the scanjet is capable of fulfilling it
185: * but don't send the command to the scanner in case the user wants
186: * to change parameters by more than one call
187: */
188: int
189: scanjet_set_params(ss, sio)
190: struct ss_softc *ss;
191: struct scan_io *sio;
192: {
193: int error;
194:
195: #if 0
196: /*
197: * if the scanner is triggered, then rewind it
198: */
199: if (ss->flags & SSF_TRIGGERED) {
200: error = scanjet_rewind_scanner(ss);
201: if (error)
202: return (error);
203: }
204: #endif
205:
206: /* size constraints... */
207: if (sio->scan_width == 0 ||
208: sio->scan_x_origin + sio->scan_width > 10200 || /* 8.5" */
209: sio->scan_height == 0 ||
210: sio->scan_y_origin + sio->scan_height > 16800) /* 14" */
211: return (EINVAL);
212:
213: /* resolution (dpi)... */
214: if (sio->scan_x_resolution < 100 ||
215: sio->scan_x_resolution > 400 ||
216: sio->scan_y_resolution < 100 ||
217: sio->scan_y_resolution > 400)
218: return (EINVAL);
219:
220: switch (sio->scan_image_mode) {
221: case SIM_BINARY_MONOCHROME:
222: case SIM_DITHERED_MONOCHROME:
223: case SIM_GRAYSCALE:
224: case SIM_COLOR:
225: break;
226: default:
227: return (EINVAL);
228: }
229:
230: /* change ss_softc to the new values, but save ro-variables */
231: sio->scan_scanner_type = ss->sio.scan_scanner_type;
232: bcopy(sio, &ss->sio, sizeof(struct scan_io));
233:
234: error = scanjet_set_window(ss, 0);
235: if (error) {
236: uprintf("%s: set_window failed\n", ss->sc_dev.dv_xname);
237: return (error);
238: }
239: error = scanjet_compute_sizes(ss, 0);
240: if (error) {
241: uprintf("%s: compute_sizes failed\n", ss->sc_dev.dv_xname);
242: return (error);
243: }
244:
245: return (0);
246: }
247:
248: /*
249: * trigger the scanner to start a scan operation
250: * this includes sending the mode- and window-data,
251: * and starting the scanner
252: */
253: int
254: scanjet_trigger_scanner(ss)
255: struct ss_softc *ss;
256: {
257: static char *escape_codes = "\033*f0S";
258: int error;
259:
260: error = scanjet_set_window(ss, 0);
261: if (error) {
262: uprintf("%s: set_window failed\n", ss->sc_dev.dv_xname);
263: return (error);
264: }
265: error = scanjet_compute_sizes(ss, 0);
266: if (error) {
267: uprintf("%s: compute_sizes failed\n", ss->sc_dev.dv_xname);
268: return (error);
269: }
270:
271: /* send "trigger" operation */
272: error = scanjet_ctl_write(ss, escape_codes, strlen(escape_codes), 0);
273: if (error) {
274: uprintf("%s: trigger_scanner failed\n", ss->sc_dev.dv_xname);
275: return (error);
276: }
277:
278: return (0);
279: }
280:
281: int
282: scanjet_read(ss, bp)
283: struct ss_softc *ss;
284: struct buf *bp;
285: {
286: struct scsi_rw_scanner cmd;
287: struct scsi_link *sc_link = ss->sc_link;
288:
289: /*
290: * Fill out the scsi command
291: */
292: bzero(&cmd, sizeof(cmd));
293: cmd.opcode = READ;
294:
295: /*
296: * Handle "fixed-block-mode" tape drives by using the
297: * block count instead of the length.
298: */
299: _lto3b(bp->b_bcount, cmd.len);
300:
301: /*
302: * go ask the adapter to do all this for us
303: */
304: if (scsi_scsi_cmd(sc_link, (struct scsi_generic *) &cmd, sizeof(cmd),
305: (u_char *) bp->b_data, bp->b_bcount, SCANJET_RETRIES, 100000, bp,
306: SCSI_NOSLEEP | SCSI_DATA_IN) != SUCCESSFULLY_QUEUED)
307: printf("%s: not queued\n", ss->sc_dev.dv_xname);
308: else {
309: if (bp->b_bcount >= ss->sio.scan_window_size)
310: ss->sio.scan_window_size = 0;
311: else
312: ss->sio.scan_window_size -= bp->b_bcount;
313: }
314:
315: return (0);
316: }
317:
318:
319: /*
320: * Do a synchronous write. Used to send control messages.
321: */
322: int
323: scanjet_ctl_write(ss, buf, size, flags)
324: struct ss_softc *ss;
325: char *buf;
326: u_int size;
327: int flags;
328: {
329: struct scsi_rw_scanner cmd;
330:
331: bzero(&cmd, sizeof(cmd));
332: cmd.opcode = WRITE;
333: _lto3b(size, cmd.len);
334: return (scsi_scsi_cmd(ss->sc_link, (struct scsi_generic *) &cmd,
335: sizeof(cmd), (u_char *) buf, size, 0, 100000, NULL,
336: flags | SCSI_DATA_OUT));
337: }
338:
339:
340: /*
341: * Do a synchronous read. Used to read responses to control messages.
342: */
343: int
344: scanjet_ctl_read(ss, buf, size, flags)
345: struct ss_softc *ss;
346: char *buf;
347: u_int size;
348: int flags;
349: {
350: struct scsi_rw_scanner cmd;
351:
352: bzero(&cmd, sizeof(cmd));
353: cmd.opcode = READ;
354: _lto3b(size, cmd.len);
355: return (scsi_scsi_cmd(ss->sc_link, (struct scsi_generic *) &cmd,
356: sizeof(cmd), (u_char *) buf, size, 0, 100000, NULL,
357: flags | SCSI_DATA_IN));
358: }
359:
360:
361: #ifdef SCANJETDEBUG
362: static void show_es(char *es)
363: {
364: char *p = es;
365:
366: while (*p) {
367: if (*p == '\033')
368: printf("[Esc]");
369: else
370: printf("%c", *p);
371: ++p;
372: }
373: printf("\n");
374: }
375: #endif
376:
377: /*
378: * simulate SCSI_SET_WINDOW for ScanJets
379: */
380: int
381: scanjet_set_window(ss, flags)
382: struct ss_softc *ss;
383: int flags;
384: {
385: char escape_codes[128];
386: size_t len;
387: int n;
388:
389: snprintf(escape_codes, sizeof escape_codes,
390: "\033*f%ldP\033*f%ldQ\033*f%ldX\033*f%ldY\033*a%dR\033*a%dS",
391: ss->sio.scan_width / 4,
392: ss->sio.scan_height / 4,
393: ss->sio.scan_x_origin / 4,
394: ss->sio.scan_y_origin / 4,
395: ss->sio.scan_x_resolution,
396: ss->sio.scan_y_resolution);
397:
398: switch (ss->sio.scan_image_mode) {
399: case SIM_BINARY_MONOCHROME:
400: ss->sio.scan_bits_per_pixel = 1;
401: /*
402: * Use line art mode (\033*aoT) and make image data be
403: * min-is-white ala PBM (\033*a0I).
404: */
405: strlcat(escape_codes, "\033*a0T\033*a0I", sizeof escape_codes);
406: break;
407: case SIM_DITHERED_MONOCHROME:
408: ss->sio.scan_bits_per_pixel = 1;
409: /*
410: * Use dithered mode (\033*a3T) and make image data be
411: * min-is-white ala PBM (\033*a0I).
412: */
413: strlcat(escape_codes, "\033*a3T\033*a0I", sizeof escape_codes);
414: break;
415: case SIM_GRAYSCALE:
416: ss->sio.scan_bits_per_pixel = 8;
417: /*
418: * Use grayscale mode (\033*a4T) and make image data be
419: * min-is-black ala PGM (\033*a1I)
420: */
421: strlcat(escape_codes, "\033*a4T\033*a1I", sizeof escape_codes);
422: break;
423: case SIM_COLOR:
424: ss->sio.scan_bits_per_pixel = 24;
425: /*
426: * Use RGB color mode (\033*a5T), make image data be
427: * min-is-black ala PPM (\033*a1I) and use pass-through matrix,
428: * i.e. disable NTSC (\033*u2T).
429: */
430: strlcat(escape_codes, "\033*a5T\033*a1I\033*u2T",
431: sizeof escape_codes);
432: break;
433: }
434:
435: /*
436: * If the escape sequence has been truncated at this point, appending
437: * the next sequence will also cause truncation, and this time we pay
438: * attention.
439: */
440: len = strlen(escape_codes);
441: n = snprintf(escape_codes + len, sizeof escape_codes - len,
442: "\033*a%dG\033*a%dL\033*a%dK",
443: ss->sio.scan_bits_per_pixel,
444: (int)(ss->sio.scan_brightness) - 128,
445: (int)(ss->sio.scan_contrast) - 128);
446:
447: if (n >= sizeof escape_codes - len)
448: return (ENOMEM);
449: len += n;
450:
451: return (scanjet_ctl_write(ss, escape_codes, len, flags));
452: }
453:
454: /* atoi() is from /sys/arch/amiga/dev/ite.c
455: and is only used in scanjet_compute_sizes */
456:
457: __inline static int
458: atoi(cp)
459: const char *cp;
460: {
461: int n;
462:
463: for (n = 0; *cp && *cp >= '0' && *cp <= '9'; cp++)
464: n = n * 10 + *cp - '0';
465:
466: return (n);
467: }
468:
469: int
470: scanjet_compute_sizes(ss, flags)
471: struct ss_softc *ss;
472: int flags;
473: {
474: int error;
475: static char *wfail = "%s: interrogate write failed\n";
476: static char *rfail = "%s: interrogate read failed\n";
477: static char *dfail = "%s: bad data returned\n";
478: static char *mono = "\033*s1025E"; /* bytes wide */
479: static char *color = "\033*s1024E"; /* pixels wide */
480: static char *high = "\033*s1026E"; /* pixels high */
481: char response[20];
482: char *p;
483:
484: /*
485: * Deal with the fact that the HP ScanJet IIc uses 1/300" not 1/1200"
486: * as its base unit of measurement. PINT uses 1/1200" (yes I know
487: * ScanJet II's use decipoints as well but 1200 % 720 != 0)
488: */
489: ss->sio.scan_width = (ss->sio.scan_width + 3) & 0xfffffffc;
490: ss->sio.scan_height = (ss->sio.scan_height + 3) & 0xfffffffc;
491:
492: switch (ss->sio.scan_image_mode) {
493: case SIM_BINARY_MONOCHROME:
494: case SIM_DITHERED_MONOCHROME:
495: error = scanjet_ctl_write(ss, mono, strlen(mono), flags);
496: break;
497: case SIM_GRAYSCALE:
498: case SIM_COLOR:
499: error = scanjet_ctl_write(ss, color, strlen(color), flags);
500: break;
501: default:
502: error = EIO;
503: break;
504: }
505: if (error) {
506: uprintf(wfail, ss->sc_dev.dv_xname);
507: return (error);
508: }
509: error = scanjet_ctl_read(ss, response, 20, flags);
510: if (error) {
511: uprintf(rfail, ss->sc_dev.dv_xname);
512: return (error);
513: }
514: p = strchr(response, 'd');
515: if (p == NULL) {
516: uprintf(dfail, ss->sc_dev.dv_xname);
517: return (EIO);
518: }
519: ss->sio.scan_pixels_per_line = atoi(p + 1);
520: if (ss->sio.scan_image_mode < SIM_GRAYSCALE)
521: ss->sio.scan_pixels_per_line *= 8;
522:
523: error = scanjet_ctl_write(ss, high, strlen(high), flags);
524: if (error) {
525: uprintf(wfail, ss->sc_dev.dv_xname);
526: return (error);
527: }
528: error = scanjet_ctl_read(ss, response, 20, flags);
529: if (error) {
530: uprintf(rfail, ss->sc_dev.dv_xname);
531: return (error);
532: }
533: p = strchr(response, 'd');
534: if (p == NULL) {
535: uprintf(dfail, ss->sc_dev.dv_xname);
536: return (EIO);
537: }
538: ss->sio.scan_lines = atoi(p + 1);
539:
540: ss->sio.scan_window_size = ss->sio.scan_lines *
541: ((ss->sio.scan_pixels_per_line * ss->sio.scan_bits_per_pixel) / 8);
542:
543: return (0);
544: }
CVSweb