summaryrefslogtreecommitdiff
path: root/backend/canon-scsi.c
diff options
context:
space:
mode:
Diffstat (limited to 'backend/canon-scsi.c')
-rw-r--r--backend/canon-scsi.c733
1 files changed, 733 insertions, 0 deletions
diff --git a/backend/canon-scsi.c b/backend/canon-scsi.c
new file mode 100644
index 0000000..423a07e
--- /dev/null
+++ b/backend/canon-scsi.c
@@ -0,0 +1,733 @@
+/* sane - Scanner Access Now Easy.
+ Copyright (C) 1997 BYTEC GmbH Germany
+ Written by Helmut Koeberle, Email: helmut.koeberle@bytec.de
+ Modified by Manuel Panea <Manuel.Panea@rzg.mpg.de>
+ and Markus Mertinat <Markus.Mertinat@Physik.Uni-Augsburg.DE>
+
+ This file is part of the SANE package.
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+ MA 02111-1307, USA.
+
+ As a special exception, the authors of SANE give permission for
+ additional uses of the libraries contained in this release of SANE.
+
+ The exception is that, if you link a SANE library with other files
+ to produce an executable, this does not by itself cause the
+ resulting executable to be covered by the GNU General Public
+ License. Your use of that executable is in no way restricted on
+ account of linking the SANE library code into it.
+
+ This exception does not, however, invalidate any other reasons why
+ the executable file might be covered by the GNU General Public
+ License.
+
+ If you submit changes to SANE to the maintainers to be included in
+ a subsequent release, you agree by submitting the changes that
+ those changes may be distributed with this exception intact.
+
+ If you write modifications of your own for SANE, it is your choice
+ whether to permit this exception to apply to your modifications.
+ If you do not wish that, delete this exception notice. */
+
+/* This file implements the low-level scsi-commands. */
+
+static SANE_Status
+test_unit_ready (int fd)
+{
+ static u_char cmd[6];
+ int status;
+ DBG (31, ">> test_unit_ready\n");
+
+ memset (cmd, 0, sizeof (cmd));
+ status = sanei_scsi_cmd2 (fd, cmd, sizeof (cmd), NULL, 0, NULL, NULL);
+
+ DBG (31, "<< test_unit_ready\n");
+ return (status);
+}
+
+#ifdef IMPLEMENT_ALL_SCANNER_SCSI_COMMANDS
+static SANE_Status
+request_sense (int fd, void *buf, size_t *buf_size)
+{
+ static u_char cmd[6];
+ int status;
+ DBG (31, ">> request_sense\n");
+
+ memset (cmd, 0, sizeof (cmd));
+ cmd[0] = 0x03;
+ cmd[4] = 14;
+ status = sanei_scsi_cmd2 (fd, cmd, sizeof (cmd), NULL, 0, buf, buf_size);
+
+ DBG (31, "<< request_sense\n");
+ return (status);
+}
+#endif
+
+static SANE_Status
+inquiry (int fd, int evpd, void *buf, size_t *buf_size)
+{
+ static u_char cmd[6];
+ int status;
+ DBG (31, ">> inquiry\n");
+
+ memset (cmd, 0, sizeof (cmd));
+ cmd[0] = 0x12;
+ cmd[1] = evpd;
+ cmd[2] = evpd ? 0xf0 : 0;
+ cmd[4] = evpd ? 74 : 36;
+ status = sanei_scsi_cmd2 (fd, cmd, sizeof (cmd), NULL, 0, buf, buf_size);
+
+ DBG (31, "<< inquiry\n");
+ return (status);
+}
+
+#ifdef IMPLEMENT_ALL_SCANNER_SCSI_COMMANDS
+static SANE_Status
+mode_select (int fd)
+{
+ static u_char cmd[6 + 12];
+ int status;
+ DBG (31, ">> mode_select\n");
+
+ memset (cmd, 0, sizeof (cmd));
+ cmd[0] = 0x15;
+ cmd[1] = 16;
+ cmd[4] = 12;
+ cmd[6 + 4] = 3;
+ cmd[6 + 5] = 6;
+ cmd[6 + 8] = 0x02;
+ cmd[6 + 9] = 0x58;
+ status = sanei_scsi_cmd (fd, cmd, sizeof (cmd), NULL, NULL);
+
+ DBG (31, "<< mode_select\n");
+ return (status);
+}
+#endif
+
+static SANE_Status
+reserve_unit (int fd)
+{
+ static u_char cmd[6];
+ int status;
+ DBG (31, ">> reserve_unit\n");
+
+ memset (cmd, 0, sizeof (cmd));
+ cmd[0] = 0x16;
+ status = sanei_scsi_cmd2 (fd, cmd, sizeof (cmd), NULL, 0, NULL, NULL);
+
+ DBG (31, "<< reserve_unit\n");
+ return (status);
+}
+
+#ifdef IMPLEMENT_ALL_SCANNER_SCSI_COMMANDS
+static SANE_Status
+release_unit (int fd)
+{
+ static u_char cmd[6];
+ int status;
+ DBG (31, ">> release_unit\n");
+
+ memset (cmd, 0, sizeof (cmd));
+ cmd[0] = 0x17;
+ status = sanei_scsi_cmd2 (fd, cmd, sizeof (cmd), NULL, 0, NULL, NULL);
+
+ DBG (31, "<< release_unit\n");
+ return (status);
+}
+#endif
+
+static SANE_Status
+mode_sense (int fd, void *buf, size_t *buf_size)
+{
+ static u_char cmd[6];
+ int status;
+ DBG (31, ">> mode_sense\n");
+
+ memset (cmd, 0, sizeof (cmd));
+ cmd[0] = 0x1a;
+ cmd[2] = 3;
+ cmd[4] = 12;
+ status = sanei_scsi_cmd2 (fd, cmd, sizeof (cmd), NULL, 0, buf, buf_size);
+
+ DBG (31, "<< mode_sense\n");
+ return (status);
+}
+
+static SANE_Status
+scan (int fd)
+{
+ static u_char cmd[6 + 1];
+ int status;
+ DBG (31, ">> scan\n");
+
+ memset (cmd, 0, sizeof (cmd));
+ cmd[0] = 0x1b;
+ cmd[4] = 1;
+ status = sanei_scsi_cmd (fd, cmd, sizeof (cmd), NULL, NULL);
+
+ DBG (31, "<< scan\n");
+ return (status);
+}
+
+static SANE_Status
+send_diagnostic (int fd)
+{
+ static u_char cmd[6];
+ int status;
+ DBG (31, ">> send_diagnostic\n");
+
+ memset (cmd, 0, sizeof (cmd));
+ cmd[0] = 0x1d;
+ cmd[1] = 4;
+ status = sanei_scsi_cmd2 (fd, cmd, sizeof (cmd), NULL, 0, NULL, NULL);
+
+ DBG (31, "<< send_diagnostic\n");
+ return (status);
+}
+
+static SANE_Status
+set_window (int fd, void *data)
+{
+ static u_char cmd[10];
+ int status;
+ DBG (31, ">> set_window\n");
+
+ memset (cmd, 0, sizeof (cmd));
+ cmd[0] = 0x24;
+ cmd[8] = 72;
+ status = sanei_scsi_cmd2 (fd, cmd, sizeof (cmd), data, 72, NULL, NULL);
+
+ DBG (31, "<< set_window\n");
+ return (status);
+}
+
+static SANE_Status
+get_window (int fd, void *buf, size_t *buf_size)
+{
+ static u_char cmd[10];
+ int status;
+ DBG (31, ">> get_window\n");
+
+ memset (cmd, 0, sizeof (cmd));
+ cmd[0] = 0x25;
+ cmd[1] = 1;
+ cmd[8] = 72;
+ status = sanei_scsi_cmd2 (fd, cmd, sizeof (cmd), NULL, 0, buf, buf_size);
+
+ DBG (31, "<< get_window\n");
+ return (status);
+}
+
+static SANE_Status
+read_data (int fd, void *buf, size_t *buf_size)
+{
+ static u_char cmd[10];
+ int status;
+ DBG (31, ">> read_data\n");
+
+ memset (cmd, 0, sizeof (cmd));
+ cmd[0] = 0x28;
+ cmd[6] = *buf_size >> 16;
+ cmd[7] = *buf_size >> 8;
+ cmd[8] = *buf_size;
+ status = sanei_scsi_cmd2 (fd, cmd, sizeof (cmd), NULL, 0, buf, buf_size);
+
+ DBG (31, "<< read_data\n");
+ return (status);
+}
+
+static SANE_Status
+medium_position (int fd)
+{
+ static u_char cmd[10];
+ int status;
+ DBG (31, ">> medium_position\n");
+
+ memset (cmd, 0, sizeof (cmd));
+ cmd[0] = 0x31;
+ status = sanei_scsi_cmd2 (fd, cmd, sizeof (cmd), NULL, 0, NULL, NULL);
+
+ DBG (31, "<< medium_position\n");
+ return (status);
+}
+
+#ifdef IMPLEMENT_ALL_SCANNER_SCSI_COMMANDS
+static SANE_Status
+execute_shading (int fd)
+{
+ static u_char cmd[10];
+ int status;
+ DBG (31, ">> execute shading\n");
+
+ memset (cmd, 0, sizeof (cmd));
+ cmd[0] = 0xe2;
+ status = sanei_scsi_cmd2 (fd, cmd, sizeof (cmd), NULL, 0, NULL, NULL);
+
+ DBG (31, "<< execute shading\n");
+ return (status);
+}
+#endif
+
+static SANE_Status
+execute_auto_focus (int fd, int AF, int speed, int AE, int count)
+{
+ static u_char cmd[10];
+ int status;
+ DBG (7, ">> execute_auto_focus\n");
+ DBG (7, ">> focus: mode='%d', speed='%d', AE='%d', count='%d'\n",
+ AF, speed, AE, count);
+
+ memset (cmd, 0, sizeof (cmd));
+ cmd[0] = 0xe0;
+ cmd[1] = (u_char) AF;
+ cmd[2] = (u_char) ((speed << 7) | AE);
+#if 1
+ cmd[4] = (u_char) count; /* seems to work, but may be unsafe */
+#else /* The Canon software uses this: */
+ cmd[4] = (u_char) (28 * ((int) (count / 28.5)) + 16);
+#endif
+ status = sanei_scsi_cmd2 (fd, cmd, sizeof (cmd), NULL, 0, NULL, NULL);
+
+ DBG (7, "<< execute_auto_focus\n");
+ return (status);
+}
+
+static SANE_Status
+set_adf_mode (int fd, u_char priority)
+{
+ static u_char cmd[6];
+ int status;
+
+ memset (cmd, 0, sizeof (cmd));
+ cmd[0] = 0xd4;
+ cmd[4] = 0x01;
+
+ status = sanei_scsi_cmd2 (fd, cmd, sizeof (cmd), &priority, 1, NULL, NULL);
+
+ return (status);
+}
+
+static SANE_Status
+get_scan_mode (int fd, u_char page, void *buf, size_t *buf_size)
+{
+ static u_char cmd[6];
+ int status;
+ int PageLen = 0x00;
+
+ memset (cmd, 0, sizeof (cmd));
+ cmd[0] = 0xd5;
+ cmd[2] = page;
+
+ switch (page)
+ {
+ case AUTO_DOC_FEEDER_UNIT:
+ case TRANSPARENCY_UNIT:
+ cmd[4] = 0x0c + PageLen;
+ break;
+
+ case SCAN_CONTROL_CONDITIONS:
+ cmd[4] = 0x14 + PageLen;
+ break;
+
+ case SCAN_CONTROL_CON_FB1200:
+ cmd[2] = 0x20;
+ cmd[4] = 0x17 + PageLen;
+ break;
+
+ default:
+ cmd[4] = 0x24 + PageLen;
+ break;
+ }
+
+ DBG (31, "get scan mode: cmd[4]='0x%0X'\n", cmd[4]);
+ status = sanei_scsi_cmd2 (fd, cmd, sizeof (cmd), NULL, 0, buf, buf_size);
+
+ DBG (31, "<< get scan mode\n");
+ return (status);
+}
+
+static SANE_Status
+define_scan_mode (int fd, u_char page, void *data)
+{
+ static u_char cmd[6];
+ u_char pdata[36];
+ size_t i;
+ int status, pdatalen;
+ DBG (31, ">> define scan mode\n");
+
+ memset (cmd, 0, sizeof (cmd));
+ memset (pdata, 0, sizeof (pdata));
+ cmd[0] = 0xd6;
+ cmd[1] = 0x10;
+ cmd[4] = (page == TRANSPARENCY_UNIT) ? 0x0c
+ : (page == TRANSPARENCY_UNIT_FB1200) ? 0x0c
+ : (page == SCAN_CONTROL_CONDITIONS) ? 0x14
+ : (page == SCAN_CONTROL_CON_FB1200) ? 0x17 : 0x24;
+
+ memcpy (pdata + 4, data, (page == TRANSPARENCY_UNIT) ? 8
+ : (page == TRANSPARENCY_UNIT_FB1200) ? 10
+ : (page == SCAN_CONTROL_CONDITIONS) ? 16
+ : (page == SCAN_CONTROL_CON_FB1200) ? 19 : 32);
+
+ for (i = 0; i < sizeof (cmd); i++)
+ DBG (31, "define scan mode: cmd[%d]='0x%0X'\n", (int) i,
+ cmd[i]);
+
+ for (i = 0; i < sizeof (pdata); i++)
+ DBG (31, "define scan mode: pdata[%d]='0x%0X'\n", (int) i,
+ pdata[i]);
+
+ pdatalen = (page == TRANSPARENCY_UNIT) ? 12
+ : (page == TRANSPARENCY_UNIT_FB1200) ? 14
+ : (page == SCAN_CONTROL_CONDITIONS) ? 20
+ : (page == SCAN_CONTROL_CON_FB1200) ? 23 : 36;
+
+ status = sanei_scsi_cmd2 (fd, cmd, sizeof (cmd), pdata, pdatalen, NULL,
+ NULL);
+ DBG (31, "<< define scan mode\n");
+ return (status);
+}
+
+static SANE_Status
+get_density_curve (int fd, int component, void *buf, size_t *buf_size,
+ int transfer_data_type)
+{
+ static u_char cmd[10];
+ int status;
+ DBG (31, ">> get_density_curve\n");
+
+ memset (cmd, 0, sizeof (cmd));
+ cmd[0] = 0x28;
+ cmd[2] = transfer_data_type;
+ cmd[4] = component;
+ cmd[5] = 0;
+ cmd[6] = ((*buf_size) >> 16) & 0xff;
+ cmd[7] = ((*buf_size) >> 8) & 0xff;
+ cmd[8] = (*buf_size) & 0xff;
+ status = sanei_scsi_cmd2 (fd, cmd, sizeof (cmd), NULL, 0, buf, buf_size);
+
+ DBG (31, "<< get_density_curve\n");
+ return (status);
+}
+
+#ifdef IMPLEMENT_ALL_SCANNER_SCSI_COMMANDS
+static SANE_Status
+get_density_curve_data_format (int fd, void *buf, size_t *buf_size)
+{
+ static u_char cmd[10];
+ int status;
+ DBG (31, ">> get_density_curve_data_format\n");
+
+ memset (cmd, 0, sizeof (cmd));
+ cmd[0] = 0x28;
+ cmd[2] = 0x03;
+ cmd[4] = 0xff;
+ cmd[5] = 0;
+ cmd[6] = 0;
+ cmd[7] = 0;
+ cmd[8] = 14;
+ status = sanei_scsi_cmd2 (fd, cmd, sizeof (cmd), NULL, 0, buf, buf_size);
+
+ DBG (31, "<< get_density_curve_data_format\n");
+ return (status);
+}
+#endif
+
+static SANE_Status
+set_density_curve (int fd, int component, void *buf, size_t *buf_size,
+ int transfer_data_type)
+{
+ static u_char cmd[10];
+ int status;
+ DBG (31, ">> set_density_curve\n");
+
+ memset (cmd, 0, sizeof (cmd));
+ cmd[0] = 0x2a;
+ cmd[2] = transfer_data_type;
+ cmd[4] = component;
+ cmd[5] = 0;
+ cmd[6] = ((*buf_size) >> 16) & 0xff;
+ cmd[7] = ((*buf_size) >> 8) & 0xff;
+ cmd[8] = (*buf_size) & 0xff;
+
+ status =
+ sanei_scsi_cmd2 (fd, cmd, sizeof (cmd), buf, *buf_size, NULL, NULL);
+
+ DBG (31, "<< set_density_curve\n");
+ return (status);
+}
+
+
+/* static SANE_Status */
+/* set_density_curve_data_format (int fd, void *buf, size_t *buf_size) */
+/* { */
+/* static u_char cmd[10]; */
+/* int status, i; */
+/* DBG (31, ">> set_density_curve_data_format\n"); */
+
+/* memset (cmd, 0, sizeof (cmd)); */
+/* cmd[0] = 0x2a; */
+/* cmd[2] = 0x03; */
+/* cmd[4] = 0xff; */
+/* cmd[5] = 0; */
+/* cmd[6] = 0; */
+/* cmd[7] = 0; */
+/* cmd[8] = 14; */
+/* status = sanei_scsi_cmd (fd, cmd, sizeof (cmd), buf, buf_size); */
+
+/* DBG (31, "<< set_density_curve_data_format\n"); */
+/* return (status); */
+/* } */
+
+#ifdef IMPLEMENT_ALL_SCANNER_SCSI_COMMANDS
+static SANE_Status
+get_power_on_timer (int fd, void *buf, size_t *buf_size)
+{
+ static u_char cmd[10];
+ int status;
+ DBG (31, ">> get power on timer\n");
+
+ memset (cmd, 0, sizeof (cmd));
+ cmd[0] = 0xe3;
+ cmd[6] = 1;
+ cmd[7] = 0;
+ cmd[8] = 0;
+ status = sanei_scsi_cmd2 (fd, cmd, sizeof (cmd), NULL, 0, buf, buf_size);
+
+ DBG (31, "<< get power on timer\n");
+ return (status);
+}
+#endif
+
+static SANE_Status
+get_film_status (int fd, void *buf, size_t *buf_size)
+{
+ static u_char cmd[10];
+ int status;
+ DBG (31, ">> get film status\n");
+
+ memset (cmd, 0, sizeof (cmd));
+ cmd[0] = 0xe1;
+ cmd[6] = 0;
+ cmd[7] = 0;
+ cmd[8] = 4;
+ status = sanei_scsi_cmd2 (fd, cmd, sizeof (cmd), NULL, 0, buf, buf_size);
+
+ DBG (31, "<< get film status\n");
+ return (status);
+}
+
+static SANE_Status
+get_data_status (int fd, void *buf, size_t *buf_size)
+{
+ static u_char cmd[10];
+ int status;
+ DBG (31, ">> get_data_status\n");
+
+ memset (cmd, 0, sizeof (cmd));
+ cmd[0] = 0x34;
+ cmd[8] = 28;
+ status = sanei_scsi_cmd2 (fd, cmd, sizeof (cmd), NULL, 0, buf, buf_size);
+
+ DBG (31, "<< get_data_status\n");
+ return (status);
+}
+
+/*************** modification for FB620S ***************/
+static SANE_Status
+reset_scanner (int fd)
+{
+ static u_char cmd[6];
+ int status;
+ DBG (31, ">> reset_scanner\n");
+
+ memset (cmd, 0, sizeof (cmd));
+ cmd[0] = 0xc1;
+ status = sanei_scsi_cmd2 (fd, cmd, sizeof (cmd), NULL, 0, NULL, NULL);
+
+ DBG (31, "<< reset_scanner \n");
+ return (status);
+}
+
+static SANE_Status
+execute_calibration (int fd)
+{
+ static u_char cmd[6];
+ u_char data[2];
+ int status;
+ DBG (31, ">> execute_calibration\n");
+
+ memset (cmd, 0, sizeof (cmd));
+ memset (data, 0, sizeof (data));
+ cmd[0] = 0xc2;
+ cmd[4] = 2;
+ status = sanei_scsi_cmd2 (fd, cmd, sizeof (cmd), data, sizeof (data),
+ NULL, NULL);
+
+ DBG (31, "<< execute_calibration\n");
+ return (status);
+}
+
+static SANE_Status
+get_calibration_status (int fd, void *buf, size_t *buf_size)
+{
+ static u_char cmd[6];
+ int status;
+ DBG (31, ">> get_calibration_status\n");
+
+ memset (cmd, 0, sizeof (cmd));
+ cmd[0] = 0xc3;
+ cmd[4] = *buf_size;
+ status = sanei_scsi_cmd2 (fd, cmd, sizeof (cmd), NULL, 0, buf, buf_size);
+
+ DBG (31, "<< get_calibration_status\n");
+ return (status);
+}
+
+#if 0
+static SANE_Status
+get_switch_status (int fd, void *buf, size_t *buf_size)
+{
+ static u_char cmd[6];
+ int status;
+ DBG (31, ">> get_switch_status\n");
+
+ memset (cmd, 0, sizeof (cmd));
+ cmd[0] = 0xc4;
+ cmd[4] = 2;
+ status = sanei_scsi_cmd2 (fd, cmd, sizeof (cmd), NULL, 0, buf, buf_size);
+
+ DBG (31, "<< get_switch_status\n");
+ return (status);
+}
+
+static SANE_Status
+wait_ready(int fd)
+{
+ SANE_Status status;
+ int retry = 0;
+
+ while ((status = test_unit_ready (fd)) != SANE_STATUS_GOOD)
+ {
+ DBG(5, "wait_ready failed (%d)\n", retry);
+ if (retry++ > 15)
+ return SANE_STATUS_IO_ERROR;
+ sleep(3);
+ }
+ return(status);
+}
+#endif
+
+/*************** modification for FB1200S ***************/
+static SANE_Status
+cancel (int fd)
+{
+ static u_char cmd[10];
+ int status;
+ DBG (31, ">> cancel_FB1200S\n");
+
+ memset (cmd, 0, sizeof (cmd));
+ cmd[0] = 0xe4;
+ status = sanei_scsi_cmd2 (fd, cmd, sizeof (cmd), NULL, 0, NULL, NULL);
+
+ DBG (31, "<< cancel_FB1200S \n");
+ return (status);
+}
+
+/**************************************************************************/
+/* As long as we do not know how this scanner stores its density curves,
+ we do the gamma correction with a 8 <--> 12 bit translation table
+ stored in the CANON_Scanner structure. */
+
+static SANE_Status
+get_density_curve_fs2710 (SANE_Handle handle, int component, u_char *buf,
+ size_t *buf_size)
+{
+ CANON_Scanner *s = handle;
+ int i;
+
+ for (i = 0; i < 256; i++)
+ *buf++ = s->gamma_map[component][i << 4];
+ *buf_size = 256;
+ return (SANE_STATUS_GOOD);
+}
+
+static SANE_Status
+set_density_curve_fs2710 (SANE_Handle handle, int component, u_char *buf)
+{
+ CANON_Scanner *s = handle;
+ int i, j, hi, lo;
+ u_char *p;
+
+ for (i = 1, hi = *buf++, p = &s->gamma_map[component][0]; i <= 256; i++)
+ {
+ lo = hi;
+ hi = (i < 256) ? *buf++ : 2 * *(buf - 1) - *(buf - 2);
+ if (hi > 255)
+ hi = 255;
+ for (j = 0; j < 16; j++) /* do a linear interpolation */
+ *p++ = (u_char) (lo + ((double) ((hi - lo) * j)) / 16.0 + 0.5);
+ }
+ return (SANE_STATUS_GOOD);
+}
+
+static SANE_Status
+set_parameters_fs2710 (SANE_Handle handle)
+{
+ CANON_Scanner *s = handle;
+ int i, j, invert, shadow[4], hilite[4];
+ double x, b, c;
+
+ shadow[1] = s->ShadowR << 4;
+ shadow[2] = s->ShadowG << 4;
+ shadow[3] = s->ShadowB << 4;
+ hilite[1] = s->HiliteR << 4;
+ hilite[2] = s->HiliteG << 4;
+ hilite[3] = s->HiliteB << 4;
+ c = ((double) s->contrast) / 128.0;
+ b = ((double) (s->brightness - 128)) / 128.0;
+
+ invert = strcmp (filmtype_list[1], s->val[OPT_NEGATIVE].s);
+
+ for (i = 1; i < 4; i++)
+ {
+ for (j = 0; j < 4096; j++)
+ {
+ if (j <= shadow[i])
+ s->gamma_map[i][j] = (u_char) ((s->brightness >= 128) ?
+ 2 * s->brightness - 256 : 0);
+ else if (j < hilite[i])
+ {
+ x = ((double) (j - shadow[i]))
+ / ((double) (hilite[i] - shadow[i]));
+ /* first do the contrast correction */
+ x = (x <= 0.5) ? 0.5 * pow (2 * x, c)
+ : 1.0 - 0.5 * pow (2 * (1.0 - x), c);
+ x = pow (x, 0.5); /* default gamma correction */
+ x += b; /* brightness correction */
+ s->gamma_map[i][j] = (u_char) MAX (0, MIN (255,
+ (int) (255.0 * x)));
+ }
+ else
+ s->gamma_map[i][j] = (u_char) ((s->brightness >= 128) ?
+ 255 : 2 * s->brightness);
+ }
+ }
+
+ return (SANE_STATUS_GOOD);
+}
+
+/**************************************************************************/