1 /* sane - Scanner Access Now Easy.
2 Copyright (C) 1997 BYTEC GmbH Germany
3 Written by Helmut Koeberle, Email: helmut.koeberle@bytec.de
4 Modified by Manuel Panea <Manuel.Panea@rzg.mpg.de>
5 and Markus Mertinat <Markus.Mertinat@Physik.Uni-Augsburg.DE>
6
7 This file is part of the SANE package.
8
9 This program is free software; you can redistribute it and/or
10 modify it under the terms of the GNU General Public License as
11 published by the Free Software Foundation; either version 2 of the
12 License, or (at your option) any later version.
13
14 This program is distributed in the hope that it will be useful, but
15 WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 General Public License for more details.
18
19 You should have received a copy of the GNU General Public License
20 along with this program. If not, see <https://www.gnu.org/licenses/>.
21
22 As a special exception, the authors of SANE give permission for
23 additional uses of the libraries contained in this release of SANE.
24
25 The exception is that, if you link a SANE library with other files
26 to produce an executable, this does not by itself cause the
27 resulting executable to be covered by the GNU General Public
28 License. Your use of that executable is in no way restricted on
29 account of linking the SANE library code into it.
30
31 This exception does not, however, invalidate any other reasons why
32 the executable file might be covered by the GNU General Public
33 License.
34
35 If you submit changes to SANE to the maintainers to be included in
36 a subsequent release, you agree by submitting the changes that
37 those changes may be distributed with this exception intact.
38
39 If you write modifications of your own for SANE, it is your choice
40 whether to permit this exception to apply to your modifications.
41 If you do not wish that, delete this exception notice. */
42
43 /* This file implements the low-level scsi-commands. */
44
45 static SANE_Status
test_unit_ready(int fd)46 test_unit_ready (int fd)
47 {
48 static u_char cmd[6];
49 int status;
50 DBG (31, ">> test_unit_ready\n");
51
52 memset (cmd, 0, sizeof (cmd));
53 status = sanei_scsi_cmd2 (fd, cmd, sizeof (cmd), NULL, 0, NULL, NULL);
54
55 DBG (31, "<< test_unit_ready\n");
56 return (status);
57 }
58
59 #ifdef IMPLEMENT_ALL_SCANNER_SCSI_COMMANDS
60 static SANE_Status
request_sense(int fd,void * buf,size_t * buf_size)61 request_sense (int fd, void *buf, size_t *buf_size)
62 {
63 static u_char cmd[6];
64 int status;
65 DBG (31, ">> request_sense\n");
66
67 memset (cmd, 0, sizeof (cmd));
68 cmd[0] = 0x03;
69 cmd[4] = 14;
70 status = sanei_scsi_cmd2 (fd, cmd, sizeof (cmd), NULL, 0, buf, buf_size);
71
72 DBG (31, "<< request_sense\n");
73 return (status);
74 }
75 #endif
76
77 static SANE_Status
inquiry(int fd,int evpd,void * buf,size_t * buf_size)78 inquiry (int fd, int evpd, void *buf, size_t *buf_size)
79 {
80 static u_char cmd[6];
81 int status;
82 DBG (31, ">> inquiry\n");
83
84 memset (cmd, 0, sizeof (cmd));
85 cmd[0] = 0x12;
86 cmd[1] = evpd;
87 cmd[2] = evpd ? 0xf0 : 0;
88 cmd[4] = evpd ? 74 : 36;
89 status = sanei_scsi_cmd2 (fd, cmd, sizeof (cmd), NULL, 0, buf, buf_size);
90
91 DBG (31, "<< inquiry\n");
92 return (status);
93 }
94
95 #ifdef IMPLEMENT_ALL_SCANNER_SCSI_COMMANDS
96 static SANE_Status
mode_select(int fd)97 mode_select (int fd)
98 {
99 static u_char cmd[6 + 12];
100 int status;
101 DBG (31, ">> mode_select\n");
102
103 memset (cmd, 0, sizeof (cmd));
104 cmd[0] = 0x15;
105 cmd[1] = 16;
106 cmd[4] = 12;
107 cmd[6 + 4] = 3;
108 cmd[6 + 5] = 6;
109 cmd[6 + 8] = 0x02;
110 cmd[6 + 9] = 0x58;
111 status = sanei_scsi_cmd (fd, cmd, sizeof (cmd), NULL, NULL);
112
113 DBG (31, "<< mode_select\n");
114 return (status);
115 }
116 #endif
117
118 static SANE_Status
reserve_unit(int fd)119 reserve_unit (int fd)
120 {
121 static u_char cmd[6];
122 int status;
123 DBG (31, ">> reserve_unit\n");
124
125 memset (cmd, 0, sizeof (cmd));
126 cmd[0] = 0x16;
127 status = sanei_scsi_cmd2 (fd, cmd, sizeof (cmd), NULL, 0, NULL, NULL);
128
129 DBG (31, "<< reserve_unit\n");
130 return (status);
131 }
132
133 #ifdef IMPLEMENT_ALL_SCANNER_SCSI_COMMANDS
134 static SANE_Status
release_unit(int fd)135 release_unit (int fd)
136 {
137 static u_char cmd[6];
138 int status;
139 DBG (31, ">> release_unit\n");
140
141 memset (cmd, 0, sizeof (cmd));
142 cmd[0] = 0x17;
143 status = sanei_scsi_cmd2 (fd, cmd, sizeof (cmd), NULL, 0, NULL, NULL);
144
145 DBG (31, "<< release_unit\n");
146 return (status);
147 }
148 #endif
149
150 static SANE_Status
mode_sense(int fd,void * buf,size_t * buf_size)151 mode_sense (int fd, void *buf, size_t *buf_size)
152 {
153 static u_char cmd[6];
154 int status;
155 DBG (31, ">> mode_sense\n");
156
157 memset (cmd, 0, sizeof (cmd));
158 cmd[0] = 0x1a;
159 cmd[2] = 3;
160 cmd[4] = 12;
161 status = sanei_scsi_cmd2 (fd, cmd, sizeof (cmd), NULL, 0, buf, buf_size);
162
163 DBG (31, "<< mode_sense\n");
164 return (status);
165 }
166
167 static SANE_Status
scan(int fd)168 scan (int fd)
169 {
170 static u_char cmd[6 + 1];
171 int status;
172 DBG (31, ">> scan\n");
173
174 memset (cmd, 0, sizeof (cmd));
175 cmd[0] = 0x1b;
176 cmd[4] = 1;
177 status = sanei_scsi_cmd (fd, cmd, sizeof (cmd), NULL, NULL);
178
179 DBG (31, "<< scan\n");
180 return (status);
181 }
182
183 static SANE_Status
send_diagnostic(int fd)184 send_diagnostic (int fd)
185 {
186 static u_char cmd[6];
187 int status;
188 DBG (31, ">> send_diagnostic\n");
189
190 memset (cmd, 0, sizeof (cmd));
191 cmd[0] = 0x1d;
192 cmd[1] = 4;
193 status = sanei_scsi_cmd2 (fd, cmd, sizeof (cmd), NULL, 0, NULL, NULL);
194
195 DBG (31, "<< send_diagnostic\n");
196 return (status);
197 }
198
199 static SANE_Status
set_window(int fd,void * data)200 set_window (int fd, void *data)
201 {
202 static u_char cmd[10];
203 int status;
204 DBG (31, ">> set_window\n");
205
206 memset (cmd, 0, sizeof (cmd));
207 cmd[0] = 0x24;
208 cmd[8] = 72;
209 status = sanei_scsi_cmd2 (fd, cmd, sizeof (cmd), data, 72, NULL, NULL);
210
211 DBG (31, "<< set_window\n");
212 return (status);
213 }
214
215 static SANE_Status
get_window(int fd,void * buf,size_t * buf_size)216 get_window (int fd, void *buf, size_t *buf_size)
217 {
218 static u_char cmd[10];
219 int status;
220 DBG (31, ">> get_window\n");
221
222 memset (cmd, 0, sizeof (cmd));
223 cmd[0] = 0x25;
224 cmd[1] = 1;
225 cmd[8] = 72;
226 status = sanei_scsi_cmd2 (fd, cmd, sizeof (cmd), NULL, 0, buf, buf_size);
227
228 DBG (31, "<< get_window\n");
229 return (status);
230 }
231
232 static SANE_Status
read_data(int fd,void * buf,size_t * buf_size)233 read_data (int fd, void *buf, size_t *buf_size)
234 {
235 static u_char cmd[10];
236 int status;
237 DBG (31, ">> read_data\n");
238
239 memset (cmd, 0, sizeof (cmd));
240 cmd[0] = 0x28;
241 cmd[6] = *buf_size >> 16;
242 cmd[7] = *buf_size >> 8;
243 cmd[8] = *buf_size;
244 status = sanei_scsi_cmd2 (fd, cmd, sizeof (cmd), NULL, 0, buf, buf_size);
245
246 DBG (31, "<< read_data\n");
247 return (status);
248 }
249
250 static SANE_Status
medium_position(int fd)251 medium_position (int fd)
252 {
253 static u_char cmd[10];
254 int status;
255 DBG (31, ">> medium_position\n");
256
257 memset (cmd, 0, sizeof (cmd));
258 cmd[0] = 0x31;
259 status = sanei_scsi_cmd2 (fd, cmd, sizeof (cmd), NULL, 0, NULL, NULL);
260
261 DBG (31, "<< medium_position\n");
262 return (status);
263 }
264
265 #ifdef IMPLEMENT_ALL_SCANNER_SCSI_COMMANDS
266 static SANE_Status
execute_shading(int fd)267 execute_shading (int fd)
268 {
269 static u_char cmd[10];
270 int status;
271 DBG (31, ">> execute shading\n");
272
273 memset (cmd, 0, sizeof (cmd));
274 cmd[0] = 0xe2;
275 status = sanei_scsi_cmd2 (fd, cmd, sizeof (cmd), NULL, 0, NULL, NULL);
276
277 DBG (31, "<< execute shading\n");
278 return (status);
279 }
280 #endif
281
282 static SANE_Status
execute_auto_focus(int fd,int AF,int speed,int AE,int count)283 execute_auto_focus (int fd, int AF, int speed, int AE, int count)
284 {
285 static u_char cmd[10];
286 int status;
287 DBG (7, ">> execute_auto_focus\n");
288 DBG (7, ">> focus: mode='%d', speed='%d', AE='%d', count='%d'\n",
289 AF, speed, AE, count);
290
291 memset (cmd, 0, sizeof (cmd));
292 cmd[0] = 0xe0;
293 cmd[1] = (u_char) AF;
294 cmd[2] = (u_char) ((speed << 7) | AE);
295 #if 1
296 cmd[4] = (u_char) count; /* seems to work, but may be unsafe */
297 #else /* The Canon software uses this: */
298 cmd[4] = (u_char) (28 * ((int) (count / 28.5)) + 16);
299 #endif
300 status = sanei_scsi_cmd2 (fd, cmd, sizeof (cmd), NULL, 0, NULL, NULL);
301
302 DBG (7, "<< execute_auto_focus\n");
303 return (status);
304 }
305
306 static SANE_Status
set_adf_mode(int fd,u_char priority)307 set_adf_mode (int fd, u_char priority)
308 {
309 static u_char cmd[6];
310 int status;
311
312 memset (cmd, 0, sizeof (cmd));
313 cmd[0] = 0xd4;
314 cmd[4] = 0x01;
315
316 status = sanei_scsi_cmd2 (fd, cmd, sizeof (cmd), &priority, 1, NULL, NULL);
317
318 return (status);
319 }
320
321 static SANE_Status
get_scan_mode(int fd,u_char page,void * buf,size_t * buf_size)322 get_scan_mode (int fd, u_char page, void *buf, size_t *buf_size)
323 {
324 static u_char cmd[6];
325 int status;
326 int PageLen = 0x00;
327
328 memset (cmd, 0, sizeof (cmd));
329 cmd[0] = 0xd5;
330 cmd[2] = page;
331
332 switch (page)
333 {
334 case AUTO_DOC_FEEDER_UNIT:
335 case TRANSPARENCY_UNIT:
336 cmd[4] = 0x0c + PageLen;
337 break;
338
339 case SCAN_CONTROL_CONDITIONS:
340 cmd[4] = 0x14 + PageLen;
341 break;
342
343 case SCAN_CONTROL_CON_FB1200:
344 cmd[2] = 0x20;
345 cmd[4] = 0x17 + PageLen;
346 break;
347
348 default:
349 cmd[4] = 0x24 + PageLen;
350 break;
351 }
352
353 DBG (31, "get scan mode: cmd[4]='0x%0X'\n", cmd[4]);
354 status = sanei_scsi_cmd2 (fd, cmd, sizeof (cmd), NULL, 0, buf, buf_size);
355
356 DBG (31, "<< get scan mode\n");
357 return (status);
358 }
359
360 static SANE_Status
define_scan_mode(int fd,u_char page,void * data)361 define_scan_mode (int fd, u_char page, void *data)
362 {
363 static u_char cmd[6];
364 u_char pdata[36];
365 size_t i;
366 int status, pdatalen;
367 DBG (31, ">> define scan mode\n");
368
369 memset (cmd, 0, sizeof (cmd));
370 memset (pdata, 0, sizeof (pdata));
371 cmd[0] = 0xd6;
372 cmd[1] = 0x10;
373 cmd[4] = (page == TRANSPARENCY_UNIT) ? 0x0c
374 : (page == TRANSPARENCY_UNIT_FB1200) ? 0x0c
375 : (page == SCAN_CONTROL_CONDITIONS) ? 0x14
376 : (page == SCAN_CONTROL_CON_FB1200) ? 0x17 : 0x24;
377
378 memcpy (pdata + 4, data, (page == TRANSPARENCY_UNIT) ? 8
379 : (page == TRANSPARENCY_UNIT_FB1200) ? 10
380 : (page == SCAN_CONTROL_CONDITIONS) ? 16
381 : (page == SCAN_CONTROL_CON_FB1200) ? 19 : 32);
382
383 for (i = 0; i < sizeof (cmd); i++)
384 DBG (31, "define scan mode: cmd[%d]='0x%0X'\n", (int) i,
385 cmd[i]);
386
387 for (i = 0; i < sizeof (pdata); i++)
388 DBG (31, "define scan mode: pdata[%d]='0x%0X'\n", (int) i,
389 pdata[i]);
390
391 pdatalen = (page == TRANSPARENCY_UNIT) ? 12
392 : (page == TRANSPARENCY_UNIT_FB1200) ? 14
393 : (page == SCAN_CONTROL_CONDITIONS) ? 20
394 : (page == SCAN_CONTROL_CON_FB1200) ? 23 : 36;
395
396 status = sanei_scsi_cmd2 (fd, cmd, sizeof (cmd), pdata, pdatalen, NULL,
397 NULL);
398 DBG (31, "<< define scan mode\n");
399 return (status);
400 }
401
402 static SANE_Status
get_density_curve(int fd,int component,void * buf,size_t * buf_size,int transfer_data_type)403 get_density_curve (int fd, int component, void *buf, size_t *buf_size,
404 int transfer_data_type)
405 {
406 static u_char cmd[10];
407 int status;
408 DBG (31, ">> get_density_curve\n");
409
410 memset (cmd, 0, sizeof (cmd));
411 cmd[0] = 0x28;
412 cmd[2] = transfer_data_type;
413 cmd[4] = component;
414 cmd[5] = 0;
415 cmd[6] = ((*buf_size) >> 16) & 0xff;
416 cmd[7] = ((*buf_size) >> 8) & 0xff;
417 cmd[8] = (*buf_size) & 0xff;
418 status = sanei_scsi_cmd2 (fd, cmd, sizeof (cmd), NULL, 0, buf, buf_size);
419
420 DBG (31, "<< get_density_curve\n");
421 return (status);
422 }
423
424 #ifdef IMPLEMENT_ALL_SCANNER_SCSI_COMMANDS
425 static SANE_Status
get_density_curve_data_format(int fd,void * buf,size_t * buf_size)426 get_density_curve_data_format (int fd, void *buf, size_t *buf_size)
427 {
428 static u_char cmd[10];
429 int status;
430 DBG (31, ">> get_density_curve_data_format\n");
431
432 memset (cmd, 0, sizeof (cmd));
433 cmd[0] = 0x28;
434 cmd[2] = 0x03;
435 cmd[4] = 0xff;
436 cmd[5] = 0;
437 cmd[6] = 0;
438 cmd[7] = 0;
439 cmd[8] = 14;
440 status = sanei_scsi_cmd2 (fd, cmd, sizeof (cmd), NULL, 0, buf, buf_size);
441
442 DBG (31, "<< get_density_curve_data_format\n");
443 return (status);
444 }
445 #endif
446
447 static SANE_Status
set_density_curve(int fd,int component,void * buf,size_t * buf_size,int transfer_data_type)448 set_density_curve (int fd, int component, void *buf, size_t *buf_size,
449 int transfer_data_type)
450 {
451 static u_char cmd[10];
452 int status;
453 DBG (31, ">> set_density_curve\n");
454
455 memset (cmd, 0, sizeof (cmd));
456 cmd[0] = 0x2a;
457 cmd[2] = transfer_data_type;
458 cmd[4] = component;
459 cmd[5] = 0;
460 cmd[6] = ((*buf_size) >> 16) & 0xff;
461 cmd[7] = ((*buf_size) >> 8) & 0xff;
462 cmd[8] = (*buf_size) & 0xff;
463
464 status =
465 sanei_scsi_cmd2 (fd, cmd, sizeof (cmd), buf, *buf_size, NULL, NULL);
466
467 DBG (31, "<< set_density_curve\n");
468 return (status);
469 }
470
471
472 /* static SANE_Status */
473 /* set_density_curve_data_format (int fd, void *buf, size_t *buf_size) */
474 /* { */
475 /* static u_char cmd[10]; */
476 /* int status, i; */
477 /* DBG (31, ">> set_density_curve_data_format\n"); */
478
479 /* memset (cmd, 0, sizeof (cmd)); */
480 /* cmd[0] = 0x2a; */
481 /* cmd[2] = 0x03; */
482 /* cmd[4] = 0xff; */
483 /* cmd[5] = 0; */
484 /* cmd[6] = 0; */
485 /* cmd[7] = 0; */
486 /* cmd[8] = 14; */
487 /* status = sanei_scsi_cmd (fd, cmd, sizeof (cmd), buf, buf_size); */
488
489 /* DBG (31, "<< set_density_curve_data_format\n"); */
490 /* return (status); */
491 /* } */
492
493 #ifdef IMPLEMENT_ALL_SCANNER_SCSI_COMMANDS
494 static SANE_Status
get_power_on_timer(int fd,void * buf,size_t * buf_size)495 get_power_on_timer (int fd, void *buf, size_t *buf_size)
496 {
497 static u_char cmd[10];
498 int status;
499 DBG (31, ">> get power on timer\n");
500
501 memset (cmd, 0, sizeof (cmd));
502 cmd[0] = 0xe3;
503 cmd[6] = 1;
504 cmd[7] = 0;
505 cmd[8] = 0;
506 status = sanei_scsi_cmd2 (fd, cmd, sizeof (cmd), NULL, 0, buf, buf_size);
507
508 DBG (31, "<< get power on timer\n");
509 return (status);
510 }
511 #endif
512
513 static SANE_Status
get_film_status(int fd,void * buf,size_t * buf_size)514 get_film_status (int fd, void *buf, size_t *buf_size)
515 {
516 static u_char cmd[10];
517 int status;
518 DBG (31, ">> get film status\n");
519
520 memset (cmd, 0, sizeof (cmd));
521 cmd[0] = 0xe1;
522 cmd[6] = 0;
523 cmd[7] = 0;
524 cmd[8] = 4;
525 status = sanei_scsi_cmd2 (fd, cmd, sizeof (cmd), NULL, 0, buf, buf_size);
526
527 DBG (31, "<< get film status\n");
528 return (status);
529 }
530
531 static SANE_Status
get_data_status(int fd,void * buf,size_t * buf_size)532 get_data_status (int fd, void *buf, size_t *buf_size)
533 {
534 static u_char cmd[10];
535 int status;
536 DBG (31, ">> get_data_status\n");
537
538 memset (cmd, 0, sizeof (cmd));
539 cmd[0] = 0x34;
540 cmd[8] = 28;
541 status = sanei_scsi_cmd2 (fd, cmd, sizeof (cmd), NULL, 0, buf, buf_size);
542
543 DBG (31, "<< get_data_status\n");
544 return (status);
545 }
546
547 /*************** modification for FB620S ***************/
548 static SANE_Status
reset_scanner(int fd)549 reset_scanner (int fd)
550 {
551 static u_char cmd[6];
552 int status;
553 DBG (31, ">> reset_scanner\n");
554
555 memset (cmd, 0, sizeof (cmd));
556 cmd[0] = 0xc1;
557 status = sanei_scsi_cmd2 (fd, cmd, sizeof (cmd), NULL, 0, NULL, NULL);
558
559 DBG (31, "<< reset_scanner \n");
560 return (status);
561 }
562
563 static SANE_Status
execute_calibration(int fd)564 execute_calibration (int fd)
565 {
566 static u_char cmd[6];
567 u_char data[2];
568 int status;
569 DBG (31, ">> execute_calibration\n");
570
571 memset (cmd, 0, sizeof (cmd));
572 memset (data, 0, sizeof (data));
573 cmd[0] = 0xc2;
574 cmd[4] = 2;
575 status = sanei_scsi_cmd2 (fd, cmd, sizeof (cmd), data, sizeof (data),
576 NULL, NULL);
577
578 DBG (31, "<< execute_calibration\n");
579 return (status);
580 }
581
582 static SANE_Status
get_calibration_status(int fd,void * buf,size_t * buf_size)583 get_calibration_status (int fd, void *buf, size_t *buf_size)
584 {
585 static u_char cmd[6];
586 int status;
587 DBG (31, ">> get_calibration_status\n");
588
589 memset (cmd, 0, sizeof (cmd));
590 cmd[0] = 0xc3;
591 cmd[4] = *buf_size;
592 status = sanei_scsi_cmd2 (fd, cmd, sizeof (cmd), NULL, 0, buf, buf_size);
593
594 DBG (31, "<< get_calibration_status\n");
595 return (status);
596 }
597
598 #if 0
599 static SANE_Status
600 get_switch_status (int fd, void *buf, size_t *buf_size)
601 {
602 static u_char cmd[6];
603 int status;
604 DBG (31, ">> get_switch_status\n");
605
606 memset (cmd, 0, sizeof (cmd));
607 cmd[0] = 0xc4;
608 cmd[4] = 2;
609 status = sanei_scsi_cmd2 (fd, cmd, sizeof (cmd), NULL, 0, buf, buf_size);
610
611 DBG (31, "<< get_switch_status\n");
612 return (status);
613 }
614
615 static SANE_Status
616 wait_ready(int fd)
617 {
618 SANE_Status status;
619 int retry = 0;
620
621 while ((status = test_unit_ready (fd)) != SANE_STATUS_GOOD)
622 {
623 DBG(5, "wait_ready failed (%d)\n", retry);
624 if (retry++ > 15)
625 return SANE_STATUS_IO_ERROR;
626 sleep(3);
627 }
628 return(status);
629 }
630 #endif
631
632 /*************** modification for FB1200S ***************/
633 static SANE_Status
cancel(int fd)634 cancel (int fd)
635 {
636 static u_char cmd[10];
637 int status;
638 DBG (31, ">> cancel_FB1200S\n");
639
640 memset (cmd, 0, sizeof (cmd));
641 cmd[0] = 0xe4;
642 status = sanei_scsi_cmd2 (fd, cmd, sizeof (cmd), NULL, 0, NULL, NULL);
643
644 DBG (31, "<< cancel_FB1200S \n");
645 return (status);
646 }
647
648 /**************************************************************************/
649 /* As long as we do not know how this scanner stores its density curves,
650 we do the gamma correction with a 8 <--> 12 bit translation table
651 stored in the CANON_Scanner structure. */
652
653 static SANE_Status
get_density_curve_fs2710(SANE_Handle handle,int component,u_char * buf,size_t * buf_size)654 get_density_curve_fs2710 (SANE_Handle handle, int component, u_char *buf,
655 size_t *buf_size)
656 {
657 CANON_Scanner *s = handle;
658 int i;
659
660 for (i = 0; i < 256; i++)
661 *buf++ = s->gamma_map[component][i << 4];
662 *buf_size = 256;
663 return (SANE_STATUS_GOOD);
664 }
665
666 static SANE_Status
set_density_curve_fs2710(SANE_Handle handle,int component,u_char * buf)667 set_density_curve_fs2710 (SANE_Handle handle, int component, u_char *buf)
668 {
669 CANON_Scanner *s = handle;
670 int i, j, hi, lo;
671 u_char *p;
672
673 for (i = 1, hi = *buf++, p = &s->gamma_map[component][0]; i <= 256; i++)
674 {
675 lo = hi;
676 hi = (i < 256) ? *buf++ : 2 * *(buf - 1) - *(buf - 2);
677 if (hi > 255)
678 hi = 255;
679 for (j = 0; j < 16; j++) /* do a linear interpolation */
680 *p++ = (u_char) (lo + ((double) ((hi - lo) * j)) / 16.0 + 0.5);
681 }
682 return (SANE_STATUS_GOOD);
683 }
684
685 static SANE_Status
set_parameters_fs2710(SANE_Handle handle)686 set_parameters_fs2710 (SANE_Handle handle)
687 {
688 CANON_Scanner *s = handle;
689 int i, j, shadow[4], hilite[4];
690 double x, b, c;
691
692 shadow[1] = s->ShadowR << 4;
693 shadow[2] = s->ShadowG << 4;
694 shadow[3] = s->ShadowB << 4;
695 hilite[1] = s->HiliteR << 4;
696 hilite[2] = s->HiliteG << 4;
697 hilite[3] = s->HiliteB << 4;
698 c = ((double) s->contrast) / 128.0;
699 b = ((double) (s->brightness - 128)) / 128.0;
700
701 for (i = 1; i < 4; i++)
702 {
703 for (j = 0; j < 4096; j++)
704 {
705 if (j <= shadow[i])
706 s->gamma_map[i][j] = (u_char) ((s->brightness >= 128) ?
707 2 * s->brightness - 256 : 0);
708 else if (j < hilite[i])
709 {
710 x = ((double) (j - shadow[i]))
711 / ((double) (hilite[i] - shadow[i]));
712 /* first do the contrast correction */
713 x = (x <= 0.5) ? 0.5 * pow (2 * x, c)
714 : 1.0 - 0.5 * pow (2 * (1.0 - x), c);
715 x = pow (x, 0.5); /* default gamma correction */
716 x += b; /* brightness correction */
717 s->gamma_map[i][j] = (u_char) MAX (0, MIN (255,
718 (int) (255.0 * x)));
719 }
720 else
721 s->gamma_map[i][j] = (u_char) ((s->brightness >= 128) ?
722 255 : 2 * s->brightness);
723 }
724 }
725
726 return (SANE_STATUS_GOOD);
727 }
728
729 /**************************************************************************/
730