diff options
Diffstat (limited to 'backend/mustek_pp_ccd300.c')
-rw-r--r-- | backend/mustek_pp_ccd300.c | 2061 |
1 files changed, 2061 insertions, 0 deletions
diff --git a/backend/mustek_pp_ccd300.c b/backend/mustek_pp_ccd300.c new file mode 100644 index 0000000..c5351a4 --- /dev/null +++ b/backend/mustek_pp_ccd300.c @@ -0,0 +1,2061 @@ +/* sane - Scanner Access Now Easy. + Copyright (C) 2000-2003 Jochen Eisinger <jochen.eisinger@gmx.net> + 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 hardware driver scanners using a 300dpi CCD */ + +#include "mustek_pp_ccd300.h" + +#define MUSTEK_PP_CCD300 4 + +static void config_ccd_101x (Mustek_pp_Handle * dev); +static void config_ccd (Mustek_pp_Handle * dev); +static void lamp (Mustek_pp_Handle * dev, int lamp_on); + +#define CCD300_ASIC1013 0xa8 +#define CCD300_ASIC1015 0xa5 + +#define CCD300_CHANNEL_RED 0 +#define CCD300_CHANNEL_GREEN 1 +#define CCD300_CHANNEL_BLUE 2 +#define CCD300_CHANNEL_GRAY 1 + +#define CCD300_MAXHSIZE 2600 +#define CCD300_MAXVSIZE 3500 + +/* + * Here starts the driver code for the different chipsets + * + * The 1013 & 1015 chipsets share large portions of the code. This + * shared functions end with _101x. + */ + +static const u_char chan_codes_1013[] = { 0x82, 0x42, 0xC2 }; +static const u_char chan_codes_1015[] = { 0x80, 0x40, 0xC0 }; +static const u_char fullstep[] = { 0x09, 0x0C, 0x06, 0x03 }; +static const u_char halfstep[] = { 0x02, 0x03, 0x01, 0x09, + 0x08, 0x0C, 0x04, 0x06 +}; +static const u_char voltages[4][3] = { {0x5C, 0x5A, 0x63}, +{0xE6, 0xB4, 0xBE}, +{0xB4, 0xB4, 0xB4}, +{0x64, 0x50, 0x64} +}; + +/* Forward declarations of 1013/1015 functions */ +static void set_ccd_channel_1013 (Mustek_pp_Handle * dev, int channel); +static void motor_backward_1013 (Mustek_pp_Handle * dev); +static void return_home_1013 (Mustek_pp_Handle * dev); +static void motor_forward_1013 (Mustek_pp_Handle * dev); +static void config_ccd_1013 (Mustek_pp_Handle * dev); + +static void set_ccd_channel_1015 (Mustek_pp_Handle * dev, int channel); +/* static void motor_backward_1015 (Mustek_pp_Handle * dev); */ +static void return_home_1015 (Mustek_pp_Handle * dev, SANE_Bool nowait); +static void motor_forward_1015 (Mustek_pp_Handle * dev); +static void config_ccd_1015 (Mustek_pp_Handle * dev); + + +/* These functions are common to all 1013/1015 chipsets */ + +static void +set_led (Mustek_pp_Handle * dev) +{ + mustek_pp_ccd300_priv *priv = dev->priv; + + sanei_pa4s2_writebyte (dev->fd, 6, + (priv->motor_step % 5 == 0 ? 0x03 : 0x13)); + +} + +static void +set_sti (Mustek_pp_Handle * dev) +{ + mustek_pp_ccd300_priv *priv = dev->priv; + + sanei_pa4s2_writebyte (dev->fd, 3, 0); + priv->bank_count++; + priv->bank_count &= 7; + +} + +static void +get_bank_count (Mustek_pp_Handle * dev) +{ + u_char val; + mustek_pp_ccd300_priv *priv = dev->priv; + + sanei_pa4s2_readbegin (dev->fd, 3); + sanei_pa4s2_readbyte (dev->fd, &val); + sanei_pa4s2_readend (dev->fd); + + priv->bank_count = (val & 0x07); + +} + +static void +reset_bank_count (Mustek_pp_Handle * dev) +{ + sanei_pa4s2_writebyte (dev->fd, 6, 7); +} + +static void +wait_bank_change (Mustek_pp_Handle * dev, int bankcount, int niceload) +{ + struct timeval start, end; + unsigned long diff; + mustek_pp_ccd300_priv *priv = dev->priv; + int first_time = 1; + + gettimeofday (&start, NULL); + + do + { + if ((niceload == 0) && (first_time == 0)) + { + usleep (1); /* could be as well sched_yield */ + first_time = 0; + } + get_bank_count (dev); + + gettimeofday (&end, NULL); + diff = (end.tv_sec * 1000 + end.tv_usec / 1000) - + (start.tv_sec * 1000 + start.tv_usec / 1000); + + } + while ((priv->bank_count != bankcount) && (diff < priv->wait_bank)); + +} + +static void +set_dpi_value (Mustek_pp_Handle * dev) +{ + u_char val = 0; + mustek_pp_ccd300_priv *priv = dev->priv; + + sanei_pa4s2_writebyte (dev->fd, 6, 0x80); + + switch (priv->hwres) + { + case 100: + val = 0x00; + break; + case 200: + val = 0x10; + break; + case 300: + val = 0x20; + break; + } + + + if (priv->ccd_type == 1) + val |= 0x01; + + sanei_pa4s2_writebyte (dev->fd, 5, val); + + sanei_pa4s2_writebyte (dev->fd, 6, 0x00); + + DBG (5, "set_dpi_value: value 0x%02x\n", val); + +} + +static void +set_line_adjust (Mustek_pp_Handle * dev) +{ + int adjustline; + mustek_pp_ccd300_priv *priv = dev->priv; + + adjustline = (dev->bottomX - dev->topX) * priv->hwres / 300; + priv->adjustskip = priv->adjustskip * priv->hwres / 300; + + DBG (5, "set_line_adjust: ppl %u (%u), adjust %u, skip %u\n", + dev->params.pixels_per_line, (dev->bottomX - dev->topX), adjustline, + priv->adjustskip); + + + sanei_pa4s2_writebyte (dev->fd, 6, 0x11); + sanei_pa4s2_writebyte (dev->fd, 5, (adjustline + priv->adjustskip) >> 8); + sanei_pa4s2_writebyte (dev->fd, 6, 0x21); + sanei_pa4s2_writebyte (dev->fd, 5, (adjustline + priv->adjustskip) & 0xFF); + + sanei_pa4s2_writebyte (dev->fd, 6, 0x01); + +} + +static void +set_lamp (Mustek_pp_Handle * dev, int lamp_on) +{ + + int ctr; + mustek_pp_ccd300_priv *priv = dev->priv; + + sanei_pa4s2_writebyte (dev->fd, 6, 0xC3); + + for (ctr = 0; ctr < 3; ctr++) + { + sanei_pa4s2_writebyte (dev->fd, 6, (lamp_on ? 0x47 : 0x57)); + sanei_pa4s2_writebyte (dev->fd, 6, 0x77); + } + + priv->motor_step = lamp_on; + + set_led (dev); + +} + +static void +send_voltages (Mustek_pp_Handle * dev) +{ + + int voltage, sel = 8, ctr; + mustek_pp_ccd300_priv *priv = dev->priv; + + switch (priv->ccd_type) + { + case 0: + voltage = 0; + break; + case 1: + voltage = 1; + break; + default: + voltage = 2; + break; + } + + for (ctr = 0; ctr < 3; ctr++) + { + + sel <<= 1; + sanei_pa4s2_writebyte (dev->fd, 6, sel); + sanei_pa4s2_writebyte (dev->fd, 5, voltages[voltage][ctr]); + + } + + sanei_pa4s2_writebyte (dev->fd, 6, 0x00); + +} + +static int +compar (const void *a, const void *b) +{ + return (signed int) (*(const SANE_Byte *) a) - + (signed int) (*(const SANE_Byte *) b); +} + +static void +set_ccd_channel_101x (Mustek_pp_Handle * dev, int channel) +{ + mustek_pp_ccd300_priv *priv = dev->priv; + switch (priv->asic) + { + case CCD300_ASIC1013: + set_ccd_channel_1013 (dev, channel); + break; + + case CCD300_ASIC1015: + set_ccd_channel_1015 (dev, channel); + break; + } +} + +static void +motor_forward_101x (Mustek_pp_Handle * dev) +{ + mustek_pp_ccd300_priv *priv = dev->priv; + switch (priv->asic) + { + case CCD300_ASIC1013: + motor_forward_1013 (dev); + break; + + case CCD300_ASIC1015: + motor_forward_1015 (dev); + break; + } +} + +static void +motor_backward_101x (Mustek_pp_Handle * dev) +{ + mustek_pp_ccd300_priv *priv = dev->priv; + switch (priv->asic) + { + case CCD300_ASIC1013: + motor_backward_1013 (dev); + break; + + case CCD300_ASIC1015: +/* motor_backward_1015 (dev); */ + break; + } +} + +static void +move_motor_101x (Mustek_pp_Handle * dev, int forward) +{ + mustek_pp_ccd300_priv *priv = dev->priv; + if (forward == SANE_TRUE) + motor_forward_101x (dev); + else + motor_backward_101x (dev); + + wait_bank_change (dev, priv->bank_count, 1); + reset_bank_count (dev); +} + + +static void +config_ccd_101x (Mustek_pp_Handle * dev) +{ + mustek_pp_ccd300_priv *priv = dev->priv; + switch (priv->asic) + { + case CCD300_ASIC1013: + config_ccd_1013 (dev); + break; + + case CCD300_ASIC1015: + config_ccd_1015 (dev); + break; + } +} + + + +static void +read_line_101x (Mustek_pp_Handle * dev, SANE_Byte * buf, SANE_Int pixel, + SANE_Int RefBlack, SANE_Byte * calib, SANE_Int * gamma) +{ + + SANE_Byte *cal = calib; + u_char color; + mustek_pp_ccd300_priv *priv = dev->priv; + int ctr, skips = priv->adjustskip + 1, cval; + + if (pixel <= 0) + return; + + sanei_pa4s2_readbegin (dev->fd, 1); + + + if (priv->hwres == dev->res) + { + + while (skips--) + sanei_pa4s2_readbyte (dev->fd, &color); + + for (ctr = 0; ctr < pixel; ctr++) + { + + sanei_pa4s2_readbyte (dev->fd, &color); + + cval = color; + + if (cval < RefBlack) + cval = 0; + else + cval -= RefBlack; + + if (cal) + { + if (cval >= cal[ctr]) + cval = 0xFF; + else + { + cval <<= 8; + cval /= (int) cal[ctr]; + } + } + + if (gamma) + cval = gamma[cval]; + + buf[ctr] = cval; + + } + + } + else + { + + int pos = 0, bpos = 0; + + while (skips--) + sanei_pa4s2_readbyte (dev->fd, &color); + + ctr = 0; + + do + { + + sanei_pa4s2_readbyte (dev->fd, &color); + + cval = color; + + if (ctr < (pos >> SANE_FIXED_SCALE_SHIFT)) + { + ctr++; + continue; + } + + ctr++; + pos += priv->res_step; + + + if (cval < RefBlack) + cval = 0; + else + cval -= RefBlack; + + if (cal) + { + if (cval >= cal[bpos]) + cval = 0xFF; + else + { + cval <<= 8; + cval /= (int) cal[bpos]; + } + } + + if (gamma) + cval = gamma[cval]; + + buf[bpos++] = cval; + + } + while (bpos < pixel); + + } + + sanei_pa4s2_readend (dev->fd); + +} + +static void +read_average_line_101x (Mustek_pp_Handle * dev, SANE_Byte * buf, int pixel, + int RefBlack) +{ + + SANE_Byte lbuf[4][CCD300_MAXHSIZE * 2]; + int ctr, sum; + mustek_pp_ccd300_priv *priv = dev->priv; + + for (ctr = 0; ctr < 4; ctr++) + { + + wait_bank_change (dev, priv->bank_count, 1); + read_line_101x (dev, lbuf[ctr], pixel, RefBlack, NULL, NULL); + reset_bank_count (dev); + if (ctr < 3) + set_sti (dev); + + } + + for (ctr = 0; ctr < pixel; ctr++) + { + + sum = lbuf[0][ctr] + lbuf[1][ctr] + lbuf[2][ctr] + lbuf[3][ctr]; + + buf[ctr] = (sum / 4); + + } + +} + +static void +find_black_side_edge_101x (Mustek_pp_Handle * dev) +{ + SANE_Byte buf[CCD300_MAXHSIZE * 2]; + SANE_Byte blackposition[5]; + int pos = 0, ctr, blackpos; + mustek_pp_ccd300_priv *priv = dev->priv; + + + for (ctr = 0; ctr < 20; ctr++) + { + + motor_forward_101x (dev); + wait_bank_change (dev, priv->bank_count, 1); + read_line_101x (dev, buf, CCD300_MAXHSIZE, 0, NULL, NULL); + reset_bank_count (dev); + + priv->ref_black = priv->ref_red = priv->ref_green = priv->ref_blue = + buf[0]; + + blackpos = CCD300_MAXHSIZE / 4; + + while ((abs (buf[blackpos] - buf[0]) >= 15) && (blackpos > 0)) + blackpos--; + + if (blackpos > 1) + blackposition[pos++] = blackpos; + + if (pos == 5) + break; + + } + + blackpos = 0; + + for (ctr = 0; ctr < pos; ctr++) + if (blackposition[ctr] > blackpos) + blackpos = blackposition[ctr]; + + if (blackpos < 0x66) + blackpos = 0x6A; + + priv->blackpos = blackpos; + priv->saved_skipcount = (blackpos + 12) & 0xFF; + +} + +static void +min_color_levels_101x (Mustek_pp_Handle * dev) +{ + + SANE_Byte buf[CCD300_MAXHSIZE * 2]; + int ctr, sum = 0; + mustek_pp_ccd300_priv *priv = dev->priv; + + for (ctr = 0; ctr < 8; ctr++) + { + + set_ccd_channel_101x (dev, CCD300_CHANNEL_RED); + set_sti (dev); + wait_bank_change (dev, priv->bank_count, 1); + + read_line_101x (dev, buf, CCD300_MAXHSIZE, 0, NULL, NULL); + + reset_bank_count (dev); + + sum += buf[3]; + + } + + priv->ref_red = sum / 8; + + sum = 0; + + for (ctr = 0; ctr < 8; ctr++) + { + + set_ccd_channel_101x (dev, CCD300_CHANNEL_GREEN); + set_sti (dev); + wait_bank_change (dev, priv->bank_count, 1); + + read_line_101x (dev, buf, CCD300_MAXHSIZE, 0, NULL, NULL); + + reset_bank_count (dev); + + sum += buf[3]; + + } + + priv->ref_green = sum / 8; + + sum = 0; + + for (ctr = 0; ctr < 8; ctr++) + { + + set_ccd_channel_101x (dev, CCD300_CHANNEL_BLUE); + set_sti (dev); + wait_bank_change (dev, priv->bank_count, 1); + + read_line_101x (dev, buf, CCD300_MAXHSIZE, 0, NULL, NULL); + + reset_bank_count (dev); + + sum += buf[3]; + + } + + priv->ref_blue = sum / 8; + +} + + +static void +max_color_levels_101x (Mustek_pp_Handle * dev) +{ + + int ctr, line, sum; + SANE_Byte rbuf[32][CCD300_MAXHSIZE * 2]; + SANE_Byte gbuf[32][CCD300_MAXHSIZE * 2]; + SANE_Byte bbuf[32][CCD300_MAXHSIZE * 2]; + mustek_pp_ccd300_priv *priv = dev->priv; + + SANE_Byte maxbuf[32]; + + for (ctr = 0; ctr < 32; ctr++) + { + + if (dev->mode == MODE_COLOR) + { + + set_ccd_channel_101x (dev, CCD300_CHANNEL_RED); + motor_forward_101x (dev); + + read_average_line_101x (dev, rbuf[ctr], dev->params.pixels_per_line, + priv->ref_red); + + set_ccd_channel_101x (dev, CCD300_CHANNEL_GREEN); + set_sti (dev); + + read_average_line_101x (dev, gbuf[ctr], dev->params.pixels_per_line, + priv->ref_green); + + set_ccd_channel_101x (dev, CCD300_CHANNEL_BLUE); + set_sti (dev); + + read_average_line_101x (dev, bbuf[ctr], dev->params.pixels_per_line, + priv->ref_blue); + + } + else + { + + priv->channel = CCD300_CHANNEL_GRAY; + + motor_forward_101x (dev); + + read_average_line_101x (dev, gbuf[ctr], dev->params.pixels_per_line, + priv->ref_black); + + } + + } + + + for (ctr = 0; ctr < dev->params.pixels_per_line; ctr++) + { + for (line = 0; line < 32; line++) + maxbuf[line] = gbuf[line][ctr]; + + qsort (maxbuf, 32, sizeof (maxbuf[0]), compar); + + sum = maxbuf[4] + maxbuf[5] + maxbuf[6] + maxbuf[7]; + + priv->calib_g[ctr] = sum / 4; + + } + + if (dev->mode == MODE_COLOR) + { + + for (ctr = 0; ctr < dev->params.pixels_per_line; ctr++) + { + for (line = 0; line < 32; line++) + maxbuf[line] = rbuf[line][ctr]; + + qsort (maxbuf, 32, sizeof (maxbuf[0]), compar); + + sum = maxbuf[4] + maxbuf[5] + maxbuf[6] + maxbuf[7]; + + priv->calib_r[ctr] = sum / 4; + + } + + for (ctr = 0; ctr < dev->params.pixels_per_line; ctr++) + { + for (line = 0; line < 32; line++) + maxbuf[line] = bbuf[line][ctr]; + + qsort (maxbuf, 32, sizeof (maxbuf[0]), compar); + + sum = maxbuf[4] + maxbuf[5] + maxbuf[6] + maxbuf[7]; + + priv->calib_b[ctr] = sum / 4; + + } + + } + +} + +static void +find_black_top_edge_101x (Mustek_pp_Handle * dev) +{ + + int lines = 0, ctr, pos; + SANE_Byte buf[CCD300_MAXHSIZE * 2]; + mustek_pp_ccd300_priv *priv = dev->priv; + + priv->channel = CCD300_CHANNEL_GRAY; + + do + { + + motor_forward_101x (dev); + wait_bank_change (dev, priv->bank_count, 1); + + read_line_101x (dev, buf, CCD300_MAXHSIZE, priv->ref_black, NULL, NULL); + + reset_bank_count (dev); + + pos = 0; + + for (ctr = priv->blackpos; ctr > priv->blackpos - 10; ctr--) + if (buf[ctr] <= 15) + pos++; + + } + while ((pos >= 8) && (lines++ < 67)); + +} + +static void +calibrate_device_101x (Mustek_pp_Handle * dev) +{ + + int saved_ppl = dev->params.pixels_per_line, ctr; + mustek_pp_ccd300_priv *priv = dev->priv; + + priv->saved_mode = dev->mode; + priv->saved_invert = dev->invert; + priv->saved_skipcount = priv->skipcount; + priv->saved_skipimagebyte = priv->skipimagebytes; + priv->saved_adjustskip = priv->adjustskip; + priv->saved_res = dev->res; + priv->saved_hwres = priv->hwres; + priv->saved_res_step = priv->res_step; + priv->saved_line_step = priv->line_step; + priv->saved_channel = priv->channel; + + dev->params.pixels_per_line = CCD300_MAXHSIZE; + priv->hwres = dev->res = 300; + dev->mode = MODE_GRAYSCALE; + priv->skipcount = priv->skipimagebytes = 0; + dev->invert = SANE_FALSE; + priv->channel = CCD300_CHANNEL_GRAY; + + config_ccd_101x (dev); + get_bank_count (dev); + + find_black_side_edge_101x (dev); + + for (ctr = 0; ctr < 4; ctr++) + move_motor_101x (dev, SANE_TRUE); + + dev->mode = priv->saved_mode; + dev->invert = priv->saved_invert; + priv->skipcount = priv->saved_skipcount; + priv->skipimagebytes = priv->saved_skipimagebyte; + priv->adjustskip = priv->saved_adjustskip; + dev->res = priv->saved_res; + priv->hwres = priv->saved_hwres; + priv->res_step = priv->saved_res_step; + priv->line_step = priv->saved_line_step; + priv->channel = priv->saved_channel; + + priv->hwres = dev->res = 300; + priv->skipcount = priv->skipimagebytes = 0; + dev->invert = SANE_FALSE; + + config_ccd_101x (dev); + get_bank_count (dev); + + if ((dev->mode == MODE_COLOR) && (priv->ccd_type != 0)) + min_color_levels_101x (dev); + + dev->mode = priv->saved_mode; + dev->invert = priv->saved_invert; + priv->skipcount = priv->saved_skipcount; + priv->skipimagebytes = priv->saved_skipimagebyte; + priv->adjustskip = priv->saved_adjustskip; + dev->res = priv->saved_res; + priv->hwres = priv->saved_hwres; + priv->res_step = priv->saved_res_step; + priv->line_step = priv->saved_line_step; + priv->channel = priv->saved_channel; + + dev->params.pixels_per_line = saved_ppl; + dev->invert = SANE_FALSE; + + config_ccd_101x (dev); + get_bank_count (dev); + + max_color_levels_101x (dev); + + dev->params.pixels_per_line = CCD300_MAXHSIZE; + dev->mode = MODE_GRAYSCALE; + priv->hwres = dev->res = 300; + priv->skipcount = priv->skipimagebytes = 0; + dev->invert = SANE_FALSE; + + config_ccd_101x (dev); + get_bank_count (dev); + + find_black_top_edge_101x (dev); + + dev->mode = priv->saved_mode; + dev->invert = priv->saved_invert; + priv->skipcount = priv->saved_skipcount; + priv->skipimagebytes = priv->saved_skipimagebyte; + priv->adjustskip = priv->saved_adjustskip; + dev->res = priv->saved_res; + priv->hwres = priv->saved_hwres; + priv->res_step = priv->saved_res_step; + priv->line_step = priv->saved_line_step; + priv->channel = priv->saved_channel; + + dev->params.pixels_per_line = saved_ppl; + + config_ccd_101x (dev); + get_bank_count (dev); + +} + +static void +get_grayscale_line_101x (Mustek_pp_Handle * dev, SANE_Byte * buf) +{ + + int skips; + mustek_pp_ccd300_priv *priv = dev->priv; + + priv->line_diff += SANE_FIX (300.0 / (float) dev->res); + + skips = (priv->line_diff >> SANE_FIXED_SCALE_SHIFT); + + while (--skips) + { + motor_forward_101x (dev); + wait_bank_change (dev, priv->bank_count, 1); + reset_bank_count (dev); + } + + priv->line_diff &= 0xFFFF; + + motor_forward_101x (dev); + wait_bank_change (dev, priv->bank_count, 1); + + read_line_101x (dev, buf, dev->params.pixels_per_line, priv->ref_black, + priv->calib_g, NULL); + + reset_bank_count (dev); + +} + +static void +get_lineart_line_101x (Mustek_pp_Handle * dev, SANE_Byte * buf) +{ + + int ctr; + SANE_Byte gbuf[CCD300_MAXHSIZE * 2]; + mustek_pp_ccd300_priv *priv = dev->priv; + + get_grayscale_line_101x (dev, gbuf); + + memset (buf, 0xFF, dev->params.bytes_per_line); + + for (ctr = 0; ctr < dev->params.pixels_per_line; ctr++) + buf[ctr >> 3] ^= ((gbuf[ctr] > priv->bw) ? (1 << (7 - ctr % 8)) : 0); + +} + +static void +get_color_line_101x (Mustek_pp_Handle * dev, SANE_Byte * buf) +{ + + SANE_Byte *red, *blue, *src, *dest; + int gotline = 0, ctr; + int gored, goblue, gogreen; + mustek_pp_ccd300_priv *priv = dev->priv; + int step = priv->line_step; + + do + { + + red = priv->red[priv->redline]; + blue = priv->blue[priv->blueline]; + + priv->ccd_line++; + + if ((priv->rdiff >> SANE_FIXED_SCALE_SHIFT) == priv->ccd_line) + { + gored = 1; + priv->rdiff += step; + } + else + gored = 0; + + if ((priv->bdiff >> SANE_FIXED_SCALE_SHIFT) == priv->ccd_line) + { + goblue = 1; + priv->bdiff += step; + } + else + goblue = 0; + + if ((priv->gdiff >> SANE_FIXED_SCALE_SHIFT) == priv->ccd_line) + { + gogreen = 1; + priv->gdiff += step; + } + else + gogreen = 0; + + if (!gored && !goblue && !gogreen) + { + motor_forward_101x (dev); + wait_bank_change (dev, priv->bank_count, 1); + reset_bank_count (dev); + if (priv->ccd_line >= (priv->line_step >> SANE_FIXED_SCALE_SHIFT)) + priv->redline = ++priv->redline % priv->green_offs; + if (priv->ccd_line >= + priv->blue_offs + (priv->line_step >> SANE_FIXED_SCALE_SHIFT)) + priv->blueline = ++priv->blueline % priv->blue_offs; + continue; + } + + if (gored) + priv->channel = CCD300_CHANNEL_RED; + else if (goblue) + priv->channel = CCD300_CHANNEL_BLUE; + else + priv->channel = CCD300_CHANNEL_GREEN; + + motor_forward_101x (dev); + wait_bank_change (dev, priv->bank_count, 1); + + if (priv->ccd_line >= priv->green_offs && gogreen) + { + src = red; + dest = buf; + + for (ctr = 0; ctr < dev->params.pixels_per_line; ctr++) + { + *dest = *src++; + dest += 3; + } + } + + if (gored) + { + + read_line_101x (dev, red, dev->params.pixels_per_line, + priv->ref_red, priv->calib_r, NULL); + + reset_bank_count (dev); + + } + + priv->redline = ++priv->redline % priv->green_offs; + + if (priv->ccd_line >= priv->green_offs && gogreen) + { + src = blue; + dest = buf + 2; + + + for (ctr = 0; ctr < dev->params.pixels_per_line; ctr++) + { + *dest = *src++; + dest += 3; + } + + } + + if (goblue) + { + if (gored) + { + set_ccd_channel_101x (dev, CCD300_CHANNEL_BLUE); + set_sti (dev); + wait_bank_change (dev, priv->bank_count, 1); + } + + read_line_101x (dev, blue, dev->params.pixels_per_line, + priv->ref_blue, priv->calib_b, NULL); + + reset_bank_count (dev); + + } + + if (priv->ccd_line >= + priv->blue_offs + (priv->line_step >> SANE_FIXED_SCALE_SHIFT)) + priv->blueline = ++priv->blueline % priv->blue_offs; + + if (gogreen) + { + + if (gored || goblue) + { + set_ccd_channel_101x (dev, CCD300_CHANNEL_GREEN); + set_sti (dev); + wait_bank_change (dev, priv->bank_count, 1); + } + + read_line_101x (dev, priv->green, dev->params.pixels_per_line, + priv->ref_green, priv->calib_g, NULL); + + reset_bank_count (dev); + + src = priv->green; + dest = buf + 1; + + for (ctr = 0; ctr < dev->params.pixels_per_line; ctr++) + { + *dest = *src++; + dest += 3; + } + + gotline = 1; + } + + } + while (!gotline); + +} + + + +/* these functions are for the 1013 chipset */ + +static void +set_ccd_channel_1013 (Mustek_pp_Handle * dev, int channel) +{ + mustek_pp_ccd300_priv *priv = dev->priv; + priv->channel = channel; + sanei_pa4s2_writebyte (dev->fd, 6, chan_codes_1013[channel]); +} + +static void +motor_backward_1013 (Mustek_pp_Handle * dev) +{ + mustek_pp_ccd300_priv *priv = dev->priv; + + priv->motor_step++; + set_led (dev); + + if (priv->motor_phase > 3) + priv->motor_phase = 3; + + sanei_pa4s2_writebyte (dev->fd, 6, 0x62); + sanei_pa4s2_writebyte (dev->fd, 5, fullstep[priv->motor_phase]); + + priv->motor_phase = (priv->motor_phase == 0 ? 3 : priv->motor_phase - 1); + + set_ccd_channel_1013 (dev, priv->channel); + set_sti (dev); + +} + +static void +return_home_1013 (Mustek_pp_Handle * dev) +{ + u_char ishome; + int ctr; + mustek_pp_ccd300_priv *priv = dev->priv; + + /* 1013 can't return home all alone, nowait ignored */ + + for (ctr = 0; ctr < 4500; ctr++) + { + + /* check_is_home_1013 */ + sanei_pa4s2_readbegin (dev->fd, 2); + sanei_pa4s2_readbyte (dev->fd, &ishome); + sanei_pa4s2_readend (dev->fd); + + /* yes, it should be is_not_home */ + if ((ishome & 1) == 0) + break; + + motor_backward_1013 (dev); + wait_bank_change (dev, priv->bank_count, 0); + reset_bank_count (dev); + + } + +} + +static void +motor_forward_1013 (Mustek_pp_Handle * dev) +{ + + int ctr; + mustek_pp_ccd300_priv *priv = dev->priv; + + priv->motor_step++; + set_led (dev); + + for (ctr = 0; ctr < 2; ctr++) + { + + sanei_pa4s2_writebyte (dev->fd, 6, 0x62); + sanei_pa4s2_writebyte (dev->fd, 5, halfstep[priv->motor_phase]); + + priv->motor_phase = + (priv->motor_phase == 7 ? 0 : priv->motor_phase + 1); + + } + + set_ccd_channel_1013 (dev, priv->channel); + set_sti (dev); +} + + + +static void +config_ccd_1013 (Mustek_pp_Handle * dev) +{ + mustek_pp_ccd300_priv *priv = dev->priv; + + if (dev->res != 0) + priv->res_step = SANE_FIX ((float) priv->hwres / (float) dev->res); + + set_dpi_value (dev); + + /* set_start_channel_1013 (dev); */ + + sanei_pa4s2_writebyte (dev->fd, 6, 0x05); + + switch (dev->mode) + { + case MODE_BW: + case MODE_GRAYSCALE: + priv->channel = CCD300_CHANNEL_GRAY; + break; + + case MODE_COLOR: + priv->channel = CCD300_CHANNEL_RED; + break; + + } + + set_ccd_channel_1013 (dev, priv->channel); + + /* set_invert_1013 (dev); */ + + sanei_pa4s2_writebyte (dev->fd, 6, + (dev->invert == SANE_TRUE ? 0x04 : 0x14)); + + sanei_pa4s2_writebyte (dev->fd, 6, 0x37); + reset_bank_count (dev); + + sanei_pa4s2_writebyte (dev->fd, 6, 0x27); + sanei_pa4s2_writebyte (dev->fd, 6, 0x67); + sanei_pa4s2_writebyte (dev->fd, 6, 0x17); + sanei_pa4s2_writebyte (dev->fd, 6, 0x77); + + /* set_initial_skip_1013 (dev); */ + + sanei_pa4s2_writebyte (dev->fd, 6, 0x41); + + priv->adjustskip = priv->skipcount + priv->skipimagebytes; + + DBG (5, "config_ccd_1013: adjustskip %u\n", priv->adjustskip); + + sanei_pa4s2_writebyte (dev->fd, 5, priv->adjustskip / 16 + 2); + + priv->adjustskip %= 16; + + sanei_pa4s2_writebyte (dev->fd, 6, 0x81); + sanei_pa4s2_writebyte (dev->fd, 5, 0x70); + sanei_pa4s2_writebyte (dev->fd, 6, 0x01); + + + set_line_adjust (dev); + + get_bank_count (dev); + +} + +/* these functions are for the 1015 chipset */ + + +static void +motor_control_1015 (Mustek_pp_Handle * dev, u_char control) +{ + u_char val; + + DBG (5, "motor_controll_1015: control code 0x%02x\n", + (unsigned int) control); + + sanei_pa4s2_writebyte (dev->fd, 6, 0xF6); + sanei_pa4s2_writebyte (dev->fd, 6, 0x22); + sanei_pa4s2_writebyte (dev->fd, 5, control); + sanei_pa4s2_writebyte (dev->fd, 6, 0x02); + + do + { + + sanei_pa4s2_readbegin (dev->fd, 2); + sanei_pa4s2_readbyte (dev->fd, &val); + sanei_pa4s2_readend (dev->fd); + + } + while ((val & 0x08) != 0); + +} + +static void +return_home_1015 (Mustek_pp_Handle * dev, SANE_Bool nowait) +{ + + u_char ishome, control = 0xC3; + + motor_control_1015 (dev, control); + + do + { + + /* check_is_home_1015 */ + sanei_pa4s2_readbegin (dev->fd, 2); + sanei_pa4s2_readbyte (dev->fd, &ishome); + sanei_pa4s2_readend (dev->fd); + + if (nowait) + break; + + usleep (1000); /* much nicer load */ + + } + while ((ishome & 2) == 0); + +} + +static void +motor_forward_1015 (Mustek_pp_Handle * dev) +{ + u_char control = 0x1B; + mustek_pp_ccd300_priv *priv = dev->priv; + + priv->motor_step++; + set_led (dev); + + + motor_control_1015 (dev, control); + + set_ccd_channel_1015 (dev, priv->channel); + set_sti (dev); + +} + +/* +static void +motor_backward_1015 (Mustek_pp_Handle * dev) +{ + u_char control = 0x43; + mustek_pp_ccd300_priv *priv = dev->priv; + + priv->motor_step++; + + set_led (dev); + + switch (priv->ccd_type) + { + case 1: + control = 0x1B; + break; + + default: + control = 0x43; + break; + } + + motor_control_1015 (dev, control); + + set_ccd_channel_1015 (dev, priv->channel); + set_sti (dev); + +} +*/ + + +static void +set_ccd_channel_1015 (Mustek_pp_Handle * dev, int channel) +{ + + u_char chancode = chan_codes_1015[channel]; + mustek_pp_ccd300_priv *priv = dev->priv; + + priv->channel = channel; + + priv->image_control &= 0x34; + chancode |= priv->image_control; + + + priv->image_control = chancode; + + sanei_pa4s2_writebyte (dev->fd, 6, chancode); + +} + + +static void +config_ccd_1015 (Mustek_pp_Handle * dev) +{ + + u_char val; + mustek_pp_ccd300_priv *priv = dev->priv; + + if (dev->res != 0) + priv->res_step = SANE_FIX ((float) priv->hwres / (float) dev->res); + + + set_dpi_value (dev); + + priv->image_control = 4; + + /* set_start_channel_1015 (dev); */ + + switch (dev->mode) + { + case MODE_BW: + case MODE_GRAYSCALE: + priv->channel = CCD300_CHANNEL_GRAY; + break; + + case MODE_COLOR: + priv->channel = CCD300_CHANNEL_RED; + break; + + } + + set_ccd_channel_1015 (dev, priv->channel); + + + /* set_invert_1015 (dev); */ + + priv->image_control &= 0xE4; + + if (dev->invert == SANE_FALSE) + priv->image_control |= 0x10; + + + sanei_pa4s2_writebyte (dev->fd, 6, priv->image_control); + + sanei_pa4s2_writebyte (dev->fd, 6, 0x23); + sanei_pa4s2_writebyte (dev->fd, 5, 0x00); + + sanei_pa4s2_writebyte (dev->fd, 6, 0x43); + + switch (priv->ccd_type) + { + case 1: + val = 0x6B; + break; + case 4: + val = 0x9F; + break; + default: + val = 0x92; + break; + } + + sanei_pa4s2_writebyte (dev->fd, 5, val); + sanei_pa4s2_writebyte (dev->fd, 6, 0x03); + + sanei_pa4s2_writebyte (dev->fd, 6, 0x37); + reset_bank_count (dev); + + sanei_pa4s2_writebyte (dev->fd, 6, 0x27); + sanei_pa4s2_writebyte (dev->fd, 6, 0x67); + sanei_pa4s2_writebyte (dev->fd, 6, 0x17); + sanei_pa4s2_writebyte (dev->fd, 6, 0x77); + + /* set_initial_skip_1015 (dev); */ + + sanei_pa4s2_writebyte (dev->fd, 6, 0x41); + + priv->adjustskip = priv->skipcount + priv->skipimagebytes; + + /* if (dev->CCD.mode == MODE_COLOR) + dev->CCD.adjustskip <<= 3; */ + + + sanei_pa4s2_writebyte (dev->fd, 5, priv->adjustskip / 32 + 1); + + priv->adjustskip %= 32; + + + sanei_pa4s2_writebyte (dev->fd, 6, 0x81); + + /* expose time */ + switch (priv->ccd_type) + { + case 1: + + val = 0xA8; + break; + case 0: + val = 0x8A; + break; + default: + val = 0xA8; + break; + } + + sanei_pa4s2_writebyte (dev->fd, 5, val); + + sanei_pa4s2_writebyte (dev->fd, 6, 0x01); + + + set_line_adjust (dev); + + get_bank_count (dev); + +} + + +/* these functions are interfaces only */ +static void +config_ccd (Mustek_pp_Handle * dev) +{ + mustek_pp_ccd300_priv *priv = dev->priv; + + DBG (5, "config_ccd: %d dpi, mode %d, invert %d, size %d\n", + priv->hwres, dev->mode, dev->invert, dev->params.pixels_per_line); + + switch (priv->asic) + { + case CCD300_ASIC1013: + config_ccd_1013 (dev); + break; + + case CCD300_ASIC1015: + config_ccd_1015 (dev); + break; + } + +} + +static void +return_home (Mustek_pp_Handle * dev, SANE_Bool nowait) +{ + mustek_pp_ccd300_priv *priv = dev->priv; + + priv->saved_mode = dev->mode; + priv->saved_invert = dev->invert; + priv->saved_skipcount = priv->skipcount; + priv->saved_skipimagebyte = priv->skipimagebytes; + priv->saved_adjustskip = priv->adjustskip; + priv->saved_res = dev->res; + priv->saved_hwres = priv->hwres; + priv->saved_res_step = priv->res_step; + priv->saved_line_step = priv->line_step; + priv->saved_channel = priv->channel; + + + priv->hwres = dev->res = 100; + dev->mode = MODE_GRAYSCALE; + + priv->skipcount = priv->skipimagebytes = 0; + + config_ccd (dev); + + switch (priv->asic) + { + case CCD300_ASIC1013: + return_home_1013 (dev); + break; + + case CCD300_ASIC1015: + return_home_1015 (dev, nowait); + break; + } + + + dev->mode = priv->saved_mode; + dev->invert = priv->saved_invert; + priv->skipcount = priv->saved_skipcount; + priv->skipimagebytes = priv->saved_skipimagebyte; + priv->adjustskip = priv->saved_adjustskip; + dev->res = priv->saved_res; + priv->hwres = priv->saved_hwres; + priv->res_step = priv->saved_res_step; + priv->line_step = priv->saved_line_step; + priv->channel = priv->saved_channel; + priv->motor_step = 0; + + config_ccd (dev); +} + +static void +lamp (Mustek_pp_Handle * dev, int lamp_on) +{ + + set_lamp (dev, lamp_on); + +} + +static void +set_voltages (Mustek_pp_Handle * dev) +{ + send_voltages (dev); +} + +static void +move_motor (Mustek_pp_Handle * dev, int count, int forward) +{ + + int ctr; + + DBG (5, "move_motor: %u steps (%s)\n", count, + (forward == SANE_TRUE ? "forward" : "backward")); + + + for (ctr = 0; ctr < count; ctr++) + { + + move_motor_101x (dev, forward); + + } + + +} + +static void +calibrate (Mustek_pp_Handle * dev) +{ + mustek_pp_ccd300_priv *priv = dev->priv; + + DBG (5, "calibrate entered (asic = 0x%02x)\n", priv->asic); + + calibrate_device_101x (dev); + + DBG (5, "calibrate: ref_black %d, blackpos %d\n", + priv->ref_black, priv->blackpos); + +} + + +static void +get_lineart_line (Mustek_pp_Handle * dev, SANE_Byte * buf) +{ + get_lineart_line_101x (dev, buf); +} + +static void +get_grayscale_line (Mustek_pp_Handle * dev, SANE_Byte * buf) +{ + + get_grayscale_line_101x (dev, buf); +} + +static void +get_color_line (Mustek_pp_Handle * dev, SANE_Byte * buf) +{ + + get_color_line_101x (dev, buf); + +} + + +static SANE_Status +ccd300_init (SANE_Int options, SANE_String_Const port, + SANE_String_Const name, SANE_Attach_Callback attach) +{ + SANE_Status status; + unsigned char asic, ccd; + int fd; + + if (options != CAP_NOTHING) + { + DBG (1, "ccd300_init: called with unknown options (%#02x)\n", options); + return SANE_STATUS_INVAL; + } + + /* try to attach to he supplied port */ + status = sanei_pa4s2_open (port, &fd); + + if (status != SANE_STATUS_GOOD) + { + DBG (2, "ccd300_init: couldn't attach to port ``%s'' (%s)\n", + port, sane_strstatus (status)); + return status; + } + + sanei_pa4s2_enable (fd, SANE_TRUE); + sanei_pa4s2_readbegin (fd, 0); + sanei_pa4s2_readbyte (fd, &asic); + sanei_pa4s2_readend (fd); + sanei_pa4s2_readbegin (fd, 2); + sanei_pa4s2_readbyte (fd, &ccd); + sanei_pa4s2_readend (fd); + sanei_pa4s2_enable (fd, SANE_FALSE); + sanei_pa4s2_close (fd); + + if (asic != CCD300_ASIC1013 && asic != CCD300_ASIC1015) + { + DBG (2, "ccd300_init: scanner not recognized (unknown ASIC id %#02x)\n", + asic); + return SANE_STATUS_INVAL; + } + + ccd &= (asic == CCD300_ASIC1013 ? 0x04 : 0x05); + + DBG (3, "ccd_init: found scanner on port ``%s'' (ASIC id %#02x, CCD %d)\n", + port, asic, ccd); + + return attach (port, name, MUSTEK_PP_CCD300, options); + +} + +static void +ccd300_capabilities (SANE_Int info, SANE_String * model, + SANE_String * vendor, SANE_String * type, + SANE_Int * maxres, SANE_Int * minres, + SANE_Int * maxhsize, SANE_Int * maxvsize, + SANE_Int * caps) +{ + *model = strdup ("600 III EP Plus"); + *vendor = strdup ("Mustek"); + *type = strdup ("flatbed (CCD 300 dpi)"); + DBG (3, + "ccd300_capabilities: 600 III EP Plus flatbed CCD (300 dpi) scanner\n"); + + *maxres = 300; + *minres = 50; + *maxhsize = CCD300_MAXHSIZE; + *maxvsize = CCD300_MAXVSIZE; + *caps = info | CAP_INVERT | CAP_LAMP_OFF; +} + +static SANE_Status +ccd300_open (SANE_String port, SANE_Int caps, SANE_Int * fd) +{ + SANE_Status status; + + if (caps & ~(CAP_NOTHING | CAP_INVERT | CAP_LAMP_OFF)) + { + DBG (1, "ccd300_open: called with unknonw capabilities (%#02x)\n", + caps); + return SANE_STATUS_INVAL; + } + + DBG (3, "ccd300_open: called for port ``%s''\n", port); + + status = sanei_pa4s2_open (port, fd); + + if (status != SANE_STATUS_GOOD) + DBG (2, "ccd300_open: open failed (%s)\n", sane_strstatus (status)); + + return status; +} + +static void +ccd300_setup (SANE_Handle handle) +{ + Mustek_pp_Handle *dev = handle; + mustek_pp_ccd300_priv *priv; + unsigned char asic, ccd; + + DBG (3, "ccd300_setup: called for port ``%s''\n", dev->dev->port); + + if ((priv = malloc (sizeof (mustek_pp_ccd300_priv))) == NULL) + { + DBG (1, "ccd300_setup: not enough memory\n"); + return; /* can you here the shit hitting the fan? */ + } + + dev->priv = priv; + memset (priv, 0, sizeof (mustek_pp_ccd300_priv)); + + priv->bw = 128; + priv->wait_bank = 700; + priv->top = 47; + + sanei_pa4s2_enable (dev->fd, SANE_TRUE); + + sanei_pa4s2_readbegin (dev->fd, 0); + sanei_pa4s2_readbyte (dev->fd, &asic); + sanei_pa4s2_readend (dev->fd); + sanei_pa4s2_readbegin (dev->fd, 2); + sanei_pa4s2_readbyte (dev->fd, &ccd); + sanei_pa4s2_readend (dev->fd); + ccd &= (asic == CCD300_ASIC1013 ? 0x04 : 0x05); + priv->asic = asic; + priv->ccd_type = ccd; + + return_home (dev, SANE_TRUE); + lamp (dev, SANE_TRUE); + sanei_pa4s2_enable (dev->fd, SANE_FALSE); + dev->lamp_on = time (NULL); + dev->res = priv->hwres = 300; + dev->mode = MODE_COLOR; +} + +static void +ccd300_close (SANE_Handle handle) +{ + + Mustek_pp_Handle *dev = handle; + mustek_pp_ccd300_priv *priv = dev->priv; + + DBG (3, "ccd300_close: called for port ``%s''\n", dev->dev->port); + + sanei_pa4s2_enable (dev->fd, SANE_TRUE); + lamp (dev, SANE_FALSE); + return_home (dev, SANE_FALSE); + sanei_pa4s2_enable (dev->fd, SANE_FALSE); + + sanei_pa4s2_close (dev->fd); + free (priv); + + DBG (3, "ccd300_close: device shut down and all buffers freed\n"); +} + +static SANE_Status +ccd300_config (SANE_Handle handle, SANE_String_Const optname, + SANE_String_Const optval) +{ + Mustek_pp_Handle *dev = handle; + mustek_pp_ccd300_priv *priv = dev->priv; + int value = -1; + + DBG (3, "ccd300_config: called for port ``%s'' (%s%s%s)\n", + dev->dev->port, + optname, (optval ? " = " : ""), (optval ? optval : "")); + + if (!strcmp (optname, "bw")) + { + + if (!optval) + { + DBG (1, "ccd300_config: missing value for option ``bw''\n"); + return SANE_STATUS_INVAL; + } + + /* ok, ok, should be strtol... know what? send me a patch. */ + value = atoi (optval); + + if ((value < 0) || (value > 255)) + { + DBG (1, + "ccd300_config: value ``%s'' for option ``bw'' is out of range (0 <= bw <= 255)\n", + optval); + return SANE_STATUS_INVAL; + } + + priv->bw = value; + + } + else if (!strcmp (optname, "waitbank")) + { + + if (!optval) + { + DBG (1, "ccd300_config: missing value for option ``waitbank''\n"); + return SANE_STATUS_INVAL; + } + + value = atoi (optval); + + if (value < 0) + { + DBG (1, + "ccd300_config: value ``%s'' for option ``waitbank'' is out of range (>= 0)\n", + optval); + return SANE_STATUS_INVAL; + } + + priv->wait_bank = value; + } + else if (!strcmp (optname, "top")) + { + + if (!optval) + { + DBG (1, "ccd300_config: missing value for option ``top''\n"); + return SANE_STATUS_INVAL; + } + + value = atoi (optval); + + if (value < 0) + { + DBG (1, + "ccd300_config: value ``%s'' for option ``top'' is out of range (>= 0)\n", + optval); + return SANE_STATUS_INVAL; + } + + priv->top = value; + } + else + { + DBG (1, "ccd300_config: unkown option ``%s''", optname); + return SANE_STATUS_INVAL; + } + + return SANE_STATUS_GOOD; + +} + +static void +ccd300_stop (SANE_Handle handle) +{ + Mustek_pp_Handle *dev = handle; + mustek_pp_ccd300_priv *priv = dev->priv; + int cnt; + + DBG (3, "ccd300_stop: stopping scan operating on port ``%s''\n", + dev->dev->port); + + sanei_pa4s2_enable (dev->fd, SANE_TRUE); + return_home (dev, SANE_TRUE); + sanei_pa4s2_enable (dev->fd, SANE_FALSE); + + free (priv->calib_r); + free (priv->calib_g); + free (priv->calib_b); + + if (priv->red) + { + for (cnt = 0; cnt < priv->green_offs; cnt++) + free (priv->red[cnt]); + free (priv->red); + } + if (priv->blue) + { + for (cnt = 0; cnt < priv->blue_offs; cnt++) + free (priv->blue[cnt]); + free (priv->blue); + } + free (priv->green); + + priv->calib_r = priv->calib_g = priv->calib_b = NULL; + priv->red = priv->blue = NULL; + priv->green = NULL; + +} + +static SANE_Status +ccd300_start (SANE_Handle handle) +{ + Mustek_pp_Handle *dev = handle; + mustek_pp_ccd300_priv *priv = dev->priv; + + DBG (3, "ccd300_start: called for port ``%s''\n", dev->dev->port); + + if (dev->res <= 100) + priv->hwres = 100; + else if (dev->res <= 200) + priv->hwres = 200; + else if (dev->res <= 300) + priv->hwres = 300; + + DBG (4, "ccd300_start: setting hardware resolution to %d dpi\n", + priv->hwres); + + priv->skipimagebytes = dev->topX; + + sanei_pa4s2_enable (dev->fd, SANE_TRUE); + config_ccd (dev); + set_voltages (dev); + get_bank_count (dev); + + if (priv->bank_count != 0) + { + DBG (2, "ccd300_start: bank count is not zero...\n"); + } + + return_home (dev, SANE_FALSE); + + priv->motor_step = 0; + + /* allocate memory for calibration */ + if ((priv->calib_g = malloc (dev->params.pixels_per_line)) == NULL) + { + sanei_pa4s2_enable (dev->fd, SANE_FALSE); + DBG (1, "ccd300_start: not enough memory\n"); + return SANE_STATUS_NO_MEM; + } + + if (dev->mode == MODE_COLOR) + { + priv->calib_r = malloc (dev->params.pixels_per_line); + priv->calib_b = malloc (dev->params.pixels_per_line); + + if ((priv->calib_r == NULL) || (priv->calib_b == NULL)) + { + free (priv->calib_g); + free (priv->calib_r); + free (priv->calib_b); + priv->calib_r = priv->calib_g = priv->calib_b = NULL; + + sanei_pa4s2_enable (dev->fd, SANE_FALSE); + DBG (1, "ccd300_start: not enough memory\n"); + return SANE_STATUS_NO_MEM; + } + } + + calibrate (dev); + + if (priv->ccd_type == 1) + { + priv->blue_offs = 4; + priv->green_offs = 8; + } + else + { + priv->blue_offs = 8; + priv->green_offs = 16; + } + + move_motor (dev, priv->top + dev->topY - + (dev->mode == MODE_COLOR ? priv->green_offs : 0), SANE_TRUE); + + if (priv->ccd_type == 1) + sanei_pa4s2_writebyte (dev->fd, 6, 0x15); + + sanei_pa4s2_enable (dev->fd, SANE_FALSE); + + if (dev->mode == MODE_COLOR) + { + int failed = SANE_FALSE, cnt; + + priv->line_step = SANE_FIX (300.0 / (float) dev->res); + priv->rdiff = priv->line_step; + priv->bdiff = priv->rdiff + (priv->blue_offs << SANE_FIXED_SCALE_SHIFT); + priv->gdiff = + priv->rdiff + (priv->green_offs << SANE_FIXED_SCALE_SHIFT); + + priv->red = malloc (sizeof (SANE_Byte *) * priv->green_offs); + priv->blue = malloc (sizeof (SANE_Byte *) * priv->blue_offs); + priv->green = malloc (dev->params.pixels_per_line); + + if ((priv->red == NULL) || (priv->blue == NULL) + || (priv->green == NULL)) + { + free (priv->calib_r); + free (priv->calib_g); + free (priv->calib_b); + priv->calib_r = priv->calib_g = priv->calib_b = NULL; + + free (priv->red); + free (priv->green); + free (priv->blue); + priv->red = priv->blue = NULL; + priv->green = NULL; + + DBG (1, "ccd300_start: not enough memory for ld buffers\n"); + return SANE_STATUS_NO_MEM; + } + + /* note to myself: better allocate one huge chunk of memory and set + pointers */ + for (cnt = 0; cnt < priv->green_offs; cnt++) + if ((priv->red[cnt] = malloc (dev->params.pixels_per_line)) == NULL) + failed = SANE_TRUE; + + for (cnt = 0; cnt < priv->blue_offs; cnt++) + if ((priv->blue[cnt] = malloc (dev->params.pixels_per_line)) == NULL) + failed = SANE_TRUE; + + if (failed == SANE_TRUE) + { + free (priv->calib_r); + free (priv->calib_g); + free (priv->calib_b); + priv->calib_r = priv->calib_g = priv->calib_b = NULL; + + for (cnt = 0; cnt < priv->green_offs; cnt++) + free (priv->red[cnt]); + for (cnt = 0; cnt < priv->blue_offs; cnt++) + free (priv->blue[cnt]); + + free (priv->red); + free (priv->green); + free (priv->blue); + priv->red = priv->blue = NULL; + priv->green = NULL; + + DBG (1, "ccd300_start: not enough memory for ld buffers\n"); + return SANE_STATUS_NO_MEM; + } + + priv->redline = priv->blueline = priv->ccd_line = 0; + } + + priv->lines = 0; + priv->lines_left = dev->params.lines; + + DBG (3, "ccd300_start: device ready for scanning\n"); + + return SANE_STATUS_GOOD; +} + +static void +ccd300_read (SANE_Handle handle, SANE_Byte * buffer) +{ + Mustek_pp_Handle *dev = handle; + mustek_pp_ccd300_priv *priv = dev->priv; + + DBG (3, "ccd300_read: receiving one line from port ``%s''\n", + dev->dev->port); + + sanei_pa4s2_enable (dev->fd, SANE_TRUE); + + switch (dev->mode) + { + case MODE_BW: + get_lineart_line (dev, buffer); + break; + + case MODE_GRAYSCALE: + get_grayscale_line (dev, buffer); + break; + + case MODE_COLOR: + get_color_line (dev, buffer); + break; + } + + priv->lines_left--; + priv->lines++; + + DBG (4, "ccd300_read: %d lines read (%d to go)\n", priv->lines, + priv->lines_left); + + if (priv->lines_left == 0) + { + DBG (3, "ccd300_read: scan finished\n"); + return_home (dev, SANE_TRUE); + } + + sanei_pa4s2_enable (dev->fd, SANE_FALSE); + +} |