1 /* sane - Scanner Access Now Easy.
2 Copyright (C) 1997 Geoffrey T. Dairiki
3 This file is part of the SANE package.
4
5 This program is free software; you can redistribute it and/or
6 modify it under the terms of the GNU General Public License as
7 published by the Free Software Foundation; either version 2 of the
8 License, or (at your option) any later version.
9
10 This program is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with this program. If not, see <https://www.gnu.org/licenses/>.
17
18 As a special exception, the authors of SANE give permission for
19 additional uses of the libraries contained in this release of SANE.
20
21 The exception is that, if you link a SANE library with other files
22 to produce an executable, this does not by itself cause the
23 resulting executable to be covered by the GNU General Public
24 License. Your use of that executable is in no way restricted on
25 account of linking the SANE library code into it.
26
27 This exception does not, however, invalidate any other reasons why
28 the executable file might be covered by the GNU General Public
29 License.
30
31 If you submit changes to SANE to the maintainers to be included in
32 a subsequent release, you agree by submitting the changes that
33 those changes may be distributed with this exception intact.
34
35 If you write modifications of your own for SANE, it is your choice
36 whether to permit this exception to apply to your modifications.
37 If you do not wish that, delete this exception notice.
38
39 This file is part of a SANE backend for HP Scanners supporting
40 HP Scanner Control Language (SCL).
41 */
42
43 /*#define STUBS
44 extern int sanei_debug_hp;*/
45 #define DEBUG_DECLARE_ONLY
46 #include "../include/sane/config.h"
47
48 #include <stdlib.h>
49 #include <string.h>
50 #include "../include/lassert.h"
51 #include "hp-device.h"
52 #include "hp-accessor.h"
53 #include "hp-option.h"
54 #include "hp-scsi.h"
55 #include "hp-scl.h"
56
57 /* Mark an scl-command to be simulated */
58 SANE_Status
sanei_hp_device_simulate_set(const char *devname, HpScl scl, int flag)59 sanei_hp_device_simulate_set (const char *devname, HpScl scl, int flag)
60
61 {HpDeviceInfo *info;
62 int inqid;
63
64 info = sanei_hp_device_info_get ( devname );
65 if (!info) return SANE_STATUS_INVAL;
66
67 inqid = SCL_INQ_ID(scl)-HP_SCL_INQID_MIN;
68 info->simulate.sclsimulate[inqid] = flag;
69
70 DBG(3, "hp_device_simulate_set: %d set to %ssimulated\n",
71 inqid+HP_SCL_INQID_MIN, flag ? "" : "not ");
72
73 return SANE_STATUS_GOOD;
74 }
75
76 /* Clear all simulation flags */
77 void
sanei_hp_device_simulate_clear(const char *devname)78 sanei_hp_device_simulate_clear (const char *devname)
79
80 {HpDeviceInfo *info;
81
82 info = sanei_hp_device_info_get ( devname );
83 if (!info) return;
84
85 memset (&(info->simulate.sclsimulate[0]), 0,
86 sizeof (info->simulate.sclsimulate));
87
88 info->simulate.gamma_simulate = 0;
89 }
90
91 /* Get simulate flag for an scl-command */
92 hp_bool_t
sanei_hp_device_simulate_get(const char *devname, HpScl scl)93 sanei_hp_device_simulate_get (const char *devname, HpScl scl)
94
95 {HpDeviceInfo *info;
96 int inqid;
97
98 info = sanei_hp_device_info_get ( devname );
99 if (!info) return 0;
100
101 inqid = SCL_INQ_ID(scl)-HP_SCL_INQID_MIN;
102 return info->simulate.sclsimulate[inqid];
103 }
104
105 SANE_Status
sanei_hp_device_support_get(const char *devname, HpScl scl, int *minval, int *maxval)106 sanei_hp_device_support_get (const char *devname, HpScl scl,
107 int *minval, int *maxval)
108
109 {HpDeviceInfo *info;
110 HpSclSupport *sclsupport;
111 int inqid;
112
113 /* #define HP_TEST_SIMULATE */
114 #ifdef HP_TEST_SIMULATE
115 if (scl == SCL_BRIGHTNESS) return SANE_STATUS_UNSUPPORTED;
116 if (scl == SCL_CONTRAST) return SANE_STATUS_UNSUPPORTED;
117 if (scl == SCL_DOWNLOAD_TYPE)
118 {
119 *minval = 2; *maxval = 14;
120 return SANE_STATUS_GOOD;
121 }
122 #endif
123
124 info = sanei_hp_device_info_get ( devname );
125 if (!info) return SANE_STATUS_INVAL;
126
127 inqid = SCL_INQ_ID(scl)-HP_SCL_INQID_MIN;
128 sclsupport = &(info->sclsupport[inqid]);
129
130 if ( !(sclsupport->checked) ) return SANE_STATUS_INVAL;
131 if ( !(sclsupport->is_supported) ) return SANE_STATUS_UNSUPPORTED;
132
133 if (minval) *minval = sclsupport->minval;
134 if (maxval) *maxval = sclsupport->maxval;
135
136 return SANE_STATUS_GOOD;
137 }
138
139 /* Update the list of supported commands */
140 SANE_Status
sanei_hp_device_support_probe(HpScsi scsi)141 sanei_hp_device_support_probe (HpScsi scsi)
142
143 {HpDeviceInfo *info;
144 HpSclSupport *sclsupport;
145 SANE_Status status;
146 int k, val, inqid;
147 static HpScl sclprobe[] = /* The commands that should be probed */
148 {
149 SCL_AUTO_BKGRND,
150 SCL_COMPRESSION,
151 SCL_DOWNLOAD_TYPE,
152 SCL_X_SCALE,
153 SCL_Y_SCALE,
154 SCL_DATA_WIDTH,
155 SCL_INVERSE_IMAGE,
156 SCL_BW_DITHER,
157 SCL_CONTRAST,
158 SCL_BRIGHTNESS,
159 #ifdef SCL_SHARPENING
160 SCL_SHARPENING,
161 #endif
162 SCL_MIRROR_IMAGE,
163 SCL_X_RESOLUTION,
164 SCL_Y_RESOLUTION,
165 SCL_OUTPUT_DATA_TYPE,
166 SCL_PRELOAD_ADF,
167 SCL_MEDIA,
168 SCL_X_EXTENT,
169 SCL_Y_EXTENT,
170 SCL_X_POS,
171 SCL_Y_POS,
172 SCL_SPEED,
173 SCL_FILTER,
174 SCL_TONE_MAP,
175 SCL_MATRIX,
176 SCL_UNLOAD,
177 SCL_CHANGE_DOC,
178 SCL_ADF_BFEED
179 };
180 enum hp_device_compat_e compat;
181
182 DBG(1, "hp_device_support_probe: Check supported commands for %s\n",
183 sanei_hp_scsi_devicename (scsi) );
184
185 info = sanei_hp_device_info_get ( sanei_hp_scsi_devicename (scsi) );
186 assert (info);
187
188 memset (&(info->sclsupport[0]), 0, sizeof (info->sclsupport));
189
190 for (k = 0; k < (int)(sizeof (sclprobe) / sizeof (sclprobe[0])); k++)
191 {
192 inqid = SCL_INQ_ID(sclprobe[k])-HP_SCL_INQID_MIN;
193 sclsupport = &(info->sclsupport[inqid]);
194 status = sanei_hp_scl_inquire (scsi, sclprobe[k], &val,
195 &(sclsupport->minval),
196 &(sclsupport->maxval));
197 sclsupport->is_supported = (status == SANE_STATUS_GOOD);
198 sclsupport->checked = 1;
199
200 /* The OfficeJets seem to ignore brightness and contrast settings,
201 * so we'll pretend they're not supported at all. */
202 if (((sclprobe[k]==SCL_BRIGHTNESS) || (sclprobe[k]==SCL_CONTRAST)) &&
203 (sanei_hp_device_probe (&compat, scsi) == SANE_STATUS_GOOD) &&
204 (compat & HP_COMPAT_OJ_1150C)) {
205 sclsupport->is_supported=0;
206 }
207
208 if (sclsupport->is_supported)
209 {
210 DBG(1, "hp_device_support_probe: %d supported (%d..%d, %d)\n",
211 inqid+HP_SCL_INQID_MIN, sclsupport->minval, sclsupport->maxval, val);
212 }
213 else
214 {
215 DBG(1, "hp_device_support_probe: %d not supported\n",
216 inqid+HP_SCL_INQID_MIN);
217 }
218 }
219
220 return SANE_STATUS_GOOD;
221 }
222
223 SANE_Status
sanei_hp_device_probe_model(enum hp_device_compat_e *compat, HpScsi scsi, int *model_num, const char **model_name)224 sanei_hp_device_probe_model (enum hp_device_compat_e *compat, HpScsi scsi,
225 int *model_num, const char **model_name)
226 {
227 static struct {
228 HpScl cmd;
229 int model_num;
230 const char * model;
231 enum hp_device_compat_e flag;
232 } probes[] = {
233 { SCL_HP_MODEL_1, 1, "ScanJet Plus", HP_COMPAT_PLUS },
234 { SCL_HP_MODEL_2, 2, "ScanJet IIc", HP_COMPAT_2C },
235 { SCL_HP_MODEL_3, 3, "ScanJet IIp", HP_COMPAT_2P },
236 { SCL_HP_MODEL_4, 4, "ScanJet IIcx", HP_COMPAT_2CX },
237 { SCL_HP_MODEL_5, 5, "ScanJet 3c/4c/6100C", HP_COMPAT_4C },
238 { SCL_HP_MODEL_6, 6, "ScanJet 3p", HP_COMPAT_3P },
239 { SCL_HP_MODEL_8, 8, "ScanJet 4p", HP_COMPAT_4P },
240 { SCL_HP_MODEL_9, 9, "ScanJet 5p/4100C/5100C", HP_COMPAT_5P },
241 { SCL_HP_MODEL_10,10,"PhotoSmart Photo Scanner", HP_COMPAT_PS },
242 { SCL_HP_MODEL_11,11,"OfficeJet 1150C", HP_COMPAT_OJ_1150C },
243 { SCL_HP_MODEL_12,12,"OfficeJet 1170C or later", HP_COMPAT_OJ_1170C },
244 { SCL_HP_MODEL_14,14,"ScanJet 62x0C", HP_COMPAT_6200C },
245 { SCL_HP_MODEL_16,15,"ScanJet 5200C", HP_COMPAT_5200C },
246 { SCL_HP_MODEL_17,17,"ScanJet 63x0C", HP_COMPAT_6300C }
247 };
248 int i;
249 char buf[8];
250 SANE_Status status;
251 static char *last_device = NULL;
252 static enum hp_device_compat_e last_compat;
253 static int last_model_num = -1;
254 static const char *last_model_name = "Model Unknown";
255
256 assert(scsi);
257 DBG(1, "probe_scanner: Probing %s\n", sanei_hp_scsi_devicename (scsi));
258
259 if (last_device != NULL) /* Look if we already probed the device */
260 {
261 if (strcmp (last_device, sanei_hp_scsi_devicename (scsi)) == 0)
262 {
263 DBG(3, "probe_scanner: use cached compatibility flags\n");
264 *compat = last_compat;
265 if (model_num) *model_num = last_model_num;
266 if (model_name) *model_name = last_model_name;
267 return SANE_STATUS_GOOD;
268 }
269 sanei_hp_free (last_device);
270 last_device = NULL;
271 }
272 *compat = 0;
273 last_model_num = -1;
274 last_model_name = "Model Unknown";
275 for (i = 0; i < (int)(sizeof(probes)/sizeof(probes[0])); i++)
276 {
277 DBG(1,"probing %s\n",probes[i].model);
278
279 if (!FAILED( status = sanei_hp_scl_upload(scsi, probes[i].cmd,
280 buf, sizeof(buf)) ))
281 {
282 DBG(1, "probe_scanner: %s compatible (%5s)\n", probes[i].model, buf);
283 last_model_name = probes[i].model;
284 /* Some scanners have different responses */
285 if (probes[i].model_num == 9)
286 {
287 if (strncmp (buf, "5110A", 5) == 0)
288 last_model_name = "ScanJet 5p";
289 else if (strncmp (buf, "5190A", 5) == 0)
290 last_model_name = "ScanJet 5100C";
291 else if (strncmp (buf, "6290A", 5) == 0)
292 last_model_name = "ScanJet 4100C";
293 }
294 *compat |= probes[i].flag;
295 last_model_num = probes[i].model_num;
296 }
297 else if (!UNSUPPORTED( status ))
298 return status; /* SCL inquiry failed */
299 }
300 /* Save values for next call */
301 last_device = sanei_hp_strdup (sanei_hp_scsi_devicename (scsi));
302 last_compat = *compat;
303 if (model_num) *model_num = last_model_num;
304 if (model_name) *model_name = last_model_name;
305
306 return SANE_STATUS_GOOD;
307 }
308
309 SANE_Status
sanei_hp_device_probe(enum hp_device_compat_e *compat, HpScsi scsi)310 sanei_hp_device_probe (enum hp_device_compat_e *compat, HpScsi scsi)
311 {
312 return sanei_hp_device_probe_model (compat, scsi, 0, 0);
313 }
314
315 hp_bool_t
sanei_hp_device_compat(HpDevice this, enum hp_device_compat_e which)316 sanei_hp_device_compat (HpDevice this, enum hp_device_compat_e which)
317 {
318 return (this->compat & which) != 0;
319 }
320
321 static SANE_Status
hp_nonscsi_device_new(HpDevice * newp, const char * devname, HpConnect connect)322 hp_nonscsi_device_new (HpDevice * newp, const char * devname, HpConnect connect)
323 {
324 HpDevice this;
325 HpScsi scsi;
326 SANE_Status status;
327 const char * model_name = "ScanJet";
328
329 if (FAILED( sanei_hp_nonscsi_new(&scsi, devname, connect) ))
330 {
331 DBG(1, "%s: Can't open nonscsi device\n", devname);
332 return SANE_STATUS_INVAL; /* Can't open device */
333 }
334
335 /* reset scanner; returns all parameters to defaults */
336 if (FAILED( sanei_hp_scl_reset(scsi) ))
337 {
338 DBG(1, "hp_nonscsi_device_new: SCL reset failed\n");
339 sanei_hp_scsi_destroy(scsi,1);
340 return SANE_STATUS_IO_ERROR;
341 }
342
343 /* Things seem okay, allocate new device */
344 this = sanei_hp_allocz(sizeof(*this));
345 this->data = sanei_hp_data_new();
346
347 if (!this || !this->data)
348 return SANE_STATUS_NO_MEM;
349
350 this->sanedev.name = sanei_hp_strdup(devname);
351 if (!this->sanedev.name)
352 return SANE_STATUS_NO_MEM;
353 this->sanedev.vendor = "Hewlett-Packard";
354 this->sanedev.type = "flatbed scanner";
355
356 status = sanei_hp_device_probe_model (&(this->compat), scsi, 0, &model_name);
357 if (!FAILED(status))
358 {
359 sanei_hp_device_support_probe (scsi);
360 status = sanei_hp_optset_new(&(this->options), scsi, this);
361 }
362 sanei_hp_scsi_destroy(scsi,1);
363
364 if (!model_name) model_name = "ScanJet";
365 this->sanedev.model = sanei_hp_strdup (model_name);
366 if (!this->sanedev.model)
367 return SANE_STATUS_NO_MEM;
368
369 if (FAILED(status))
370 {
371 DBG(1, "hp_nonscsi_device_new: %s: probe failed (%s)\n",
372 devname, sane_strstatus(status));
373 sanei_hp_data_destroy(this->data);
374 sanei_hp_free((void *)this->sanedev.name);
375 sanei_hp_free((void *)this->sanedev.model);
376 sanei_hp_free(this);
377 return status;
378 }
379
380 DBG(1, "hp_nonscsi_device_new: %s: found HP ScanJet model %s\n",
381 devname, this->sanedev.model);
382
383 *newp = this;
384 return SANE_STATUS_GOOD;
385 }
386
387 SANE_Status
sanei_hp_device_new(HpDevice * newp, const char * devname)388 sanei_hp_device_new (HpDevice * newp, const char * devname)
389 {
390 HpDevice this;
391 HpScsi scsi;
392 HpConnect connect;
393 SANE_Status status;
394 char * str;
395
396 DBG(3, "sanei_hp_device_new: %s\n", devname);
397
398 connect = sanei_hp_get_connect (devname);
399 if ( connect != HP_CONNECT_SCSI )
400 return hp_nonscsi_device_new (newp, devname, connect);
401
402 if (FAILED( sanei_hp_scsi_new(&scsi, devname) ))
403 {
404 DBG(1, "%s: Can't open scsi device\n", devname);
405 return SANE_STATUS_INVAL; /* Can't open device */
406 }
407
408 if (sanei_hp_scsi_inq(scsi)[0] != 0x03
409 || memcmp(sanei_hp_scsi_vendor(scsi), "HP ", 8) != 0)
410 {
411 DBG(1, "%s: does not seem to be an HP scanner\n", devname);
412 sanei_hp_scsi_destroy(scsi,1);
413 return SANE_STATUS_INVAL;
414 }
415
416 /* reset scanner; returns all parameters to defaults */
417 if (FAILED( sanei_hp_scl_reset(scsi) ))
418 {
419 DBG(1, "sanei_hp_device_new: SCL reset failed\n");
420 sanei_hp_scsi_destroy(scsi,1);
421 return SANE_STATUS_IO_ERROR;
422 }
423
424 /* Things seem okay, allocate new device */
425 this = sanei_hp_allocz(sizeof(*this));
426 this->data = sanei_hp_data_new();
427
428 if (!this || !this->data)
429 return SANE_STATUS_NO_MEM;
430
431 this->sanedev.name = sanei_hp_strdup(devname);
432 str = sanei_hp_strdup(sanei_hp_scsi_model(scsi));
433 if (!this->sanedev.name || !str)
434 return SANE_STATUS_NO_MEM;
435 this->sanedev.model = str;
436 if ((str = strchr(str, ' ')) != 0)
437 *str = '\0';
438 this->sanedev.vendor = "Hewlett-Packard";
439 this->sanedev.type = "flatbed scanner";
440
441 status = sanei_hp_device_probe(&(this->compat), scsi);
442 if (!FAILED(status))
443 {
444 sanei_hp_device_support_probe (scsi);
445 status = sanei_hp_optset_new(&this->options, scsi, this);
446 }
447 sanei_hp_scsi_destroy(scsi,1);
448
449 if (FAILED(status))
450 {
451 DBG(1, "sanei_hp_device_new: %s: probe failed (%s)\n",
452 devname, sane_strstatus(status));
453 sanei_hp_data_destroy(this->data);
454 sanei_hp_free((void *)this->sanedev.name);
455 sanei_hp_free((void *)this->sanedev.model);
456 sanei_hp_free(this);
457 return status;
458 }
459
460 DBG(1, "sanei_hp_device_new: %s: found HP ScanJet model %s\n",
461 devname, this->sanedev.model);
462
463 *newp = this;
464 return SANE_STATUS_GOOD;
465 }
466
467 const SANE_Device *
sanei_hp_device_sanedevice(HpDevice this)468 sanei_hp_device_sanedevice (HpDevice this)
469 {
470 return &this->sanedev;
471 }
472