• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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