diff options
author | Jörg Frings-Fürst <debian@jff-webhosting.net> | 2014-10-06 14:00:40 +0200 |
---|---|---|
committer | Jörg Frings-Fürst <debian@jff-webhosting.net> | 2014-10-06 14:00:40 +0200 |
commit | 6e9c41a892ed0e0da326e0278b3221ce3f5713b8 (patch) | |
tree | 2e301d871bbeeb44aa57ff9cc070fcf3be484487 /backend/mustek_usb_low.c |
Initial import of sane-backends version 1.0.24-1.2
Diffstat (limited to 'backend/mustek_usb_low.c')
-rw-r--r-- | backend/mustek_usb_low.c | 2914 |
1 files changed, 2914 insertions, 0 deletions
diff --git a/backend/mustek_usb_low.c b/backend/mustek_usb_low.c new file mode 100644 index 0000000..e626b65 --- /dev/null +++ b/backend/mustek_usb_low.c @@ -0,0 +1,2914 @@ +/* sane - Scanner Access Now Easy. + + Copyright (C) 2000 Mustek. + Originally maintained by Tom Wang <tom.wang@mustek.com.tw> + + Copyright (C) 2001 - 2004 by Henning Meier-Geinitz. + + 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 a SANE backend for Mustek 1200UB and similar + USB flatbed scanners. */ + +#include <unistd.h> + +#include "../include/sane/sane.h" +#include "../include/sane/sanei_usb.h" +#include "mustek_usb_low.h" + + +SANE_Status +usb_low_init (ma1017 ** chip_address) +{ + SANE_Int i; + ma1017 *chip; + + DBG (7, "usb_low_init: start\n"); + if (!chip_address) + return SANE_STATUS_INVAL; + + chip = (ma1017 *) malloc (sizeof (ma1017)); + + if (!chip) + { + DBG (3, "usb_low_init: couldn't malloc %ld bytes for chip\n", + (long int) sizeof (ma1017)); + *chip_address = 0; + return SANE_STATUS_NO_MEM; + } + *chip_address = chip; + + /* io */ + chip->is_rowing = SANE_FALSE; + chip->is_opened = SANE_FALSE; + chip->fd = -1; + + /* Construction/Destruction */ + chip->is_opened = SANE_FALSE; + chip->is_rowing = SANE_FALSE; + + /* A2 */ + chip->append = 0x00; + chip->test_sram = 0x00; + chip->fix_pattern = 0x00; + /* A4 */ + chip->select = 0x00; + chip->frontend = 0x00; + /* A6 */ + chip->rgb_sel_pin = 0x02; + chip->asic_io_pins = 0x9c; + /* A7 */ + chip->timing = 0xe8; + chip->sram_bank = 0x02; + /* A8 */ + chip->dummy_msb = 0x00; + chip->ccd_width_msb = 0x00; + chip->cmt_table_length = 0x00; + /* A9 */ + chip->cmt_second_pos = 0x00; + /* A10 + A8ID5 */ + chip->ccd_width = 0x0c80; + /* A11 + A8ID6 */ + chip->dummy = 0x0020; + /* A12 + A13 */ + chip->byte_width = 0x09f6; + /* A14 + A30W */ + chip->loop_count = 0x0db5; + /* A15 */ + chip->motor_enable = 0x00; + chip->motor_movement = 0x60; + chip->motor_direction = 0x10; + chip->motor_signal = 0x00; + chip->motor_home = 0x00; + /* A16 */ + chip->pixel_depth = 0x00; + chip->image_invert = 0x00; + chip->optical_600 = 0x00; + chip->sample_way = 0x06; + /* A17 + A18 + A19 */ + chip->red_ref = 0xff; + chip->green_ref = 0xff; + chip->blue_ref = 0xff; + /* A20 + A21 + A22 */ + chip->red_pd = 0x00; + chip->green_pd = 0x00; + chip->blue_pd = 0x00; + /* A23 */ + chip->a23 = 0x80; + /* A24 */ + chip->fy1_delay = 0x00; + chip->special_ad = 0x00; + /* A27 */ + chip->sclk = 0x00; + chip->sen = 0x00; + chip->serial_length = 0x10; + + /* Use for Rowing */ + chip->get_row = NULL; + + chip->cmt_table_length_word = 0x00000000; + chip->cmt_second_pos_word = 0x00000000; + chip->row_size = 0x00; + chip->soft_resample = 0x01; + chip->total_lines = 0x00; + chip->lines_left = 0x00; + for (i = 0; i < 32; i++) + chip->is_transfer_table[i] = SANE_FALSE; + chip->sensor = ST_CANON600; + chip->motor = MT_1200; + + chip->total_read_urbs = 0; + chip->total_write_urbs = 0; + DBG (7, "usb_low_init: exit\n"); + return SANE_STATUS_GOOD; +} + +SANE_Status +usb_low_exit (ma1017 * chip) +{ + DBG (7, "usb_low_exit: chip = %p\n", (void *) chip); + if (chip) + { + if (chip->fd >= 0 && chip->is_opened) + usb_low_close (chip); + DBG (7, "usb_low_exit: freeing chip\n"); + free (chip); + } + DBG (5, "usb_low_exit: read %d URBs, wrote %d URBs\n", + chip->total_read_urbs, chip->total_write_urbs); + DBG (7, "usb_low_exit: exit\n"); + return SANE_STATUS_GOOD; +} + +/* A0 ~ A1 */ +SANE_Status +usb_low_set_cmt_table (ma1017 * chip, SANE_Int index, Channel channel, + SANE_Bool is_move_motor, SANE_Bool is_transfer) +{ + SANE_Byte pattern = ((SANE_Byte) index) << 4; + SANE_Byte reg_no = 0; + SANE_Status status; + + DBG (7, "usb_low_set_cmt_table: start\n"); + + if (!chip->is_opened) + { + DBG (3, "usb_low_set_cmt_table: not opened yet\n"); + return SANE_STATUS_INVAL; + } + if (chip->is_rowing) + { + DBG (3, "usb_low_set_cmt_table: stop rowing first\n"); + return SANE_STATUS_INVAL; + } + if ((unsigned int) index > 31) + { + DBG (7, "usb_low_set_cmt_table: CMT index (%d) exceed 31", index); + return SANE_STATUS_INVAL; + } + + switch (channel) + { + case CH_RED: + pattern |= 0x04; + break; + case CH_GREEN: + pattern |= 0x08; + break; + case CH_BLUE: + pattern |= 0x0c; + break; + default: + break; + } + if (is_move_motor) + pattern |= 0x02; + if (is_transfer) + pattern |= 0x01; + if (index > 15) + reg_no++; + + RIE (usb_low_write_reg (chip, reg_no, pattern)); + + chip->is_transfer_table[index] = is_transfer; + + DBG (7, "usb_low_set_cmt_table: exit\n"); + + return SANE_STATUS_GOOD; +} + +/* A2 */ +SANE_Status +usb_low_get_a2 (ma1017 * chip, SANE_Byte * value) +{ + SANE_Byte pattern; + SANE_Status status; + + DBG (7, "usb_low_get_a2: start\n"); + if (!chip->is_opened) + { + DBG (3, "usb_low_get_a2: not opened yet\n"); + return SANE_STATUS_INVAL; + } + if (chip->is_rowing) + { + DBG (3, "usb_low_get_a2: stop rowing first\n"); + return SANE_STATUS_INVAL; + } + RIE (usb_low_read_reg (chip, 2, &pattern)); + + chip->append = pattern & 0x10; + chip->test_sram = pattern & 0x20; + chip->fix_pattern = pattern & 0x80; + if (value) + *value = pattern; + DBG (7, "usb_low_get_a2: exit, value =%d\n", pattern); + return SANE_STATUS_GOOD; +} + +SANE_Status +usb_low_start_cmt_table (ma1017 * chip) +{ + SANE_Byte data_field[2]; + SANE_Status status; + size_t n; + + DBG (7, "usb_low_start_cmt_table: start\n"); + + data_field[0] = 0x02 | chip->append | chip->test_sram | chip->fix_pattern; + data_field[1] = 2; + + if (!chip->is_opened) + { + DBG (3, "usb_low_start_cmt_table: not opened yet\n"); + return SANE_STATUS_INVAL; + } + if (chip->is_rowing) + { + DBG (7, "usb_low_start_cmt_table: Already Rowing\n"); + return SANE_STATUS_INVAL; + } + + data_field[1] |= 0x60; + n = 2; + status = sanei_usb_write_bulk (chip->fd, data_field, &n); + if (status != SANE_STATUS_GOOD || n != 2) + { + DBG (3, "usb_low_start_cmt_table: can't write, wanted 2 bytes, " + "wrote %lu bytes\n", (unsigned long int) n); + return SANE_STATUS_IO_ERROR; + } + chip->total_write_urbs++; + chip->is_rowing = SANE_TRUE; + DBG (7, "usb_low_start_cmt_table: exit\n"); + return SANE_STATUS_GOOD; +} + +SANE_Status +usb_low_stop_cmt_table (ma1017 * chip) +{ + SANE_Byte data_field[2]; + SANE_Byte read_byte; + size_t n; + SANE_Status status; + + DBG (7, "usb_low_stop_cmt_table: start\n"); + + if (!chip->is_opened) + { + DBG (3, "usb_low_stop_cmt_table: not opened yet\n"); + return SANE_STATUS_INVAL; + } + if (!chip->is_rowing) + { + DBG (7, "usb_low_stop_cmt_table: Not Rowing yet\n"); + return SANE_STATUS_INVAL; + } + + data_field[0] = 0x01 | chip->append | chip->test_sram | chip->fix_pattern; + data_field[1] = 2; + data_field[1] |= 0x80; + n = 2; + status = sanei_usb_write_bulk (chip->fd, data_field, &n); + if (status != SANE_STATUS_GOOD || n != 2) + { + DBG (3, "usb_low_stop_cmt_table: couldn't write, wanted 2 bytes, wrote " + "%lu bytes\n", (unsigned long int) n); + return SANE_STATUS_IO_ERROR; + } + chip->total_write_urbs++; + n = 1; + status = sanei_usb_read_bulk (chip->fd, &read_byte, &n); + if (status != SANE_STATUS_GOOD || n != 1) + { + DBG (3, "usb_low_stop_cmt_table: couldn't read, wanted 1 byte, got %lu " + "bytes\n", (unsigned long int) n); + return SANE_STATUS_IO_ERROR; + } + chip->total_read_urbs++; + chip->is_rowing = SANE_FALSE; + + DBG (7, "usb_low_stop_cmt_table: exit\n"); + + return SANE_STATUS_GOOD; +} + +SANE_Status +usb_low_set_test_sram_mode (ma1017 * chip, SANE_Bool is_test) +{ + SANE_Byte data, reg_no; + SANE_Status status; + + DBG (7, "usb_low_set_test_sram_mode: start\n"); + + data = chip->append | chip->test_sram | chip->fix_pattern; + reg_no = 2; + + if (!chip->is_opened) + { + DBG (3, "usb_low_set_test_sram_mode: not opened yet\n"); + return SANE_STATUS_INVAL; + } + if (chip->is_rowing) + { + DBG (3, "usb_low_set_test_sram_mode: stop rowing first\n"); + return SANE_STATUS_INVAL; + } + + if (is_test) + chip->test_sram = 0x20; + else + chip->test_sram = 0x00; + + RIE (usb_low_write_reg (chip, reg_no, data)); + + DBG (7, "usb_low_set_test_sram_mode: exit\n"); + return SANE_STATUS_GOOD; +} + +SANE_Status +usb_low_set_fix_pattern (ma1017 * chip, SANE_Bool is_fix) +{ + SANE_Byte data, reg_no; + SANE_Status status; + + DBG (7, "usb_low_set_fix_pattern: start\n"); + + data = chip->append | chip->test_sram | chip->fix_pattern; + reg_no = 2; + + if (!chip->is_opened) + { + DBG (3, "usb_low_set_fix_pattern: not opened yet\n"); + return SANE_STATUS_INVAL; + } + if (chip->is_rowing) + { + DBG (3, "usb_low_set_fix_pattern: stop rowing first\n"); + return SANE_STATUS_INVAL; + } + + if (is_fix) + chip->fix_pattern = 0x80; + else + chip->fix_pattern = 0x00; + + RIE (usb_low_write_reg (chip, reg_no, data)); + + DBG (7, "usb_low_set_fix_pattern: exit\n"); + return SANE_STATUS_GOOD; +} + +SANE_Status +usb_low_adjust_timing (ma1017 * chip, SANE_Byte data) +{ + SANE_Status status; + SANE_Byte reg_no; + + DBG (7, "usb_low_adjust_timing: start\n"); + + reg_no = 3; + + if (!chip->is_opened) + { + DBG (3, "usb_low_adjust_timing: not opened yet\n"); + return SANE_STATUS_INVAL; + } + if (chip->is_rowing) + { + DBG (3, "usb_low_adjust_timing: stop rowing first\n"); + return SANE_STATUS_INVAL; + } + + RIE (usb_low_write_reg (chip, reg_no, data)); + + DBG (7, "usb_low_adjust_timing: exit\n"); + + return SANE_STATUS_GOOD; +} + +/* A4 */ +SANE_Status +usb_low_get_a4 (ma1017 * chip, SANE_Byte * value) +{ + SANE_Status status; + SANE_Byte pattern; + + DBG (7, "usb_low_get_a4: start\n"); + if (!chip->is_opened) + { + DBG (3, "usb_low_get_a4: not opened yet\n"); + return SANE_STATUS_INVAL; + } + if (chip->is_rowing) + { + DBG (3, "usb_low_get_a4: stop rowing first\n"); + return SANE_STATUS_INVAL; + } + + RIE (usb_low_read_reg (chip, 4, &pattern)); + + chip->select = pattern & 0xfe; + chip->frontend = pattern & 0x01; + + if (value) + *value = pattern; + + DBG (7, "usb_low_get_a4: exit, value=%d\n", pattern); + + return SANE_STATUS_GOOD; +} + +SANE_Status +usb_low_select_timing (ma1017 * chip, SANE_Byte data) +{ + SANE_Status status; + SANE_Byte reg_no; + + DBG (7, "usb_low_select_timing: start\n"); + + reg_no = 4; + + if (!chip->is_opened) + { + DBG (3, "usb_low_select_timing: not opened yet\n"); + return SANE_STATUS_INVAL; + } + if (chip->is_rowing) + { + DBG (3, "usb_low_select_timing: stop rowing first\n"); + return SANE_STATUS_INVAL; + } + + chip->select = data & 0xfe; + chip->frontend = data & 0x01; + + RIE (usb_low_write_reg (chip, reg_no, data)); + + DBG (7, "usb_low_select_timing: exit\n"); + return SANE_STATUS_GOOD; +} + +SANE_Status +usb_low_turn_frontend_mode (ma1017 * chip, SANE_Bool is_on) +{ + SANE_Status status; + SANE_Byte data, reg_no; + + DBG (7, "usb_low_turn_frontend_mode: start\n"); + if (!chip->is_opened) + { + DBG (3, "usb_low_turn_frontend_mode: not opened yet\n"); + return SANE_STATUS_INVAL; + } + if (chip->is_rowing) + { + DBG (3, "usb_low_turn_frontend_mode: stop rowing first\n"); + return SANE_STATUS_INVAL; + } + + if (is_on) + chip->frontend = 0x01; + else + chip->frontend = 0x00; + + data = chip->select | chip->frontend; + reg_no = 4; + + RIE (usb_low_write_reg (chip, reg_no, data)); + + DBG (7, "usb_low_turn_frontend_mode: exit\n"); + return SANE_STATUS_GOOD; +} + +/* A6 */ +SANE_Status +usb_low_get_a6 (ma1017 * chip, SANE_Byte * value) +{ + SANE_Byte pattern; + SANE_Status status; + + DBG (7, "usb_low_get_a6: start\n"); + + if (!chip->is_opened) + { + DBG (3, "usb_low_get_a6: not opened yet\n"); + return SANE_STATUS_INVAL; + } + if (chip->is_rowing) + { + DBG (3, "usb_low_get_a6: stop rowing first\n"); + return SANE_STATUS_INVAL; + } + RIE (usb_low_read_reg (chip, 6, &pattern)); + + chip->asic_io_pins = pattern & 0xdc; + chip->rgb_sel_pin = pattern & 0x03; + + if (value) + *value = pattern; + + DBG (7, "usb_low_get_a6: exit\n"); + + return SANE_STATUS_GOOD; +} + +SANE_Status +usb_low_set_asic_io_pins (ma1017 * chip, SANE_Byte data) +{ + SANE_Status status; + SANE_Byte reg_no; + + DBG (7, "usb_low_set_asic_io_pins: start\n"); + + if (!chip->is_opened) + { + DBG (3, "usb_low_set_asic_io_pins: not opened yet\n"); + return SANE_STATUS_INVAL; + } + if (chip->is_rowing) + { + DBG (3, "usb_low_set_asic_io_pins: stop rowing first\n"); + return SANE_STATUS_INVAL; + } + + chip->asic_io_pins = data & 0xdc; + + data = chip->asic_io_pins | chip->rgb_sel_pin; + reg_no = 6; + + RIE (usb_low_write_reg (chip, reg_no, data)); + + DBG (7, "usb_low_set_asic_io_pins: exit\n"); + return SANE_STATUS_GOOD; +} + +SANE_Status +usb_low_set_rgb_sel_pins (ma1017 * chip, SANE_Byte data) +{ + SANE_Status status; + SANE_Byte reg_no; + + DBG (7, "usb_low_set_rgb_sel_pins: start\n"); + + if (!chip->is_opened) + { + DBG (3, "usb_low_set_rgb_sel_pins: not opened yet\n"); + return SANE_STATUS_INVAL; + } + if (chip->is_rowing) + { + DBG (3, "usb_low_set_rgb_sel_pins: stop rowing first\n"); + return SANE_STATUS_INVAL; + } + chip->rgb_sel_pin = data & 0x03; + data = chip->asic_io_pins | chip->rgb_sel_pin; + reg_no = 6; + + RIE (usb_low_write_reg (chip, reg_no, data)); + + DBG (7, "usb_low_set_rgb_sel_pins: exit\n"); + return SANE_STATUS_GOOD; /* was false? */ +} + +/* A7 */ +SANE_Status +usb_low_get_a7 (ma1017 * chip, SANE_Byte * value) +{ + SANE_Byte pattern; + SANE_Status status; + + DBG (7, "usb_low_get_a7: start\n"); + if (!chip->is_opened) + { + DBG (3, "usb_low_get_a7: not opened yet\n"); + return SANE_STATUS_INVAL; + } + if (chip->is_rowing) + { + DBG (3, "usb_low_get_a7: stop rowing first\n"); + return SANE_STATUS_INVAL; + } + RIE (usb_low_read_reg (chip, 7, &pattern)); + + if (value) + *value = pattern; + + chip->timing = pattern & 0xfc; + chip->sram_bank = pattern & 0x03; + + DBG (7, "usb_low_get_a7: exit\n"); + + return SANE_STATUS_GOOD; +} + +SANE_Status +usb_low_set_timing (ma1017 * chip, SANE_Byte data) +{ + SANE_Status status; + SANE_Byte reg_no; + + DBG (7, "usb_low_set_timing: start\n"); + if (!chip->is_opened) + { + DBG (3, "usb_low_set_timing: not opened yet\n"); + return SANE_STATUS_INVAL; + } + if (chip->is_rowing) + { + DBG (3, "usb_low_set_timing: stop rowing first\n"); + return SANE_STATUS_INVAL; + } + + chip->timing = data & 0xfc; + data = chip->timing | chip->sram_bank; + reg_no = 7; + + RIE (usb_low_write_reg (chip, reg_no, data)); + + DBG (7, "usb_low_set_timing: exit\n"); + return SANE_STATUS_GOOD; +} + +SANE_Status +usb_low_set_sram_bank (ma1017 * chip, Banksize banksize) +{ + SANE_Status status; + SANE_Byte data, reg_no; + + DBG (7, "usb_low_set_sram_bank: start\n"); + if (!chip->is_opened) + { + DBG (3, "usb_low_set_sram_bank: not opened yet\n"); + return SANE_STATUS_INVAL; + } + if (chip->is_rowing) + { + DBG (3, "usb_low_set_sram_bank: stop rowing first\n"); + return SANE_STATUS_INVAL; + } + + switch (banksize) + { + case BS_4K: + chip->sram_bank = 0x00; + break; + case BS_8K: + chip->sram_bank = 0x01; + break; + case BS_16K: + chip->sram_bank = 0x02; + break; + default: + DBG (3, "usb_low_set_sram_bank: bsBankSize error\n"); + return SANE_STATUS_INVAL; + break; + } + data = chip->timing | chip->sram_bank; + reg_no = 7; + + RIE (usb_low_write_reg (chip, reg_no, data)); + + DBG (7, "usb_low_set_sram_bank: exit\n"); + return SANE_STATUS_GOOD; +} + +/* A8 */ +SANE_Status +usb_low_get_a8 (ma1017 * chip, SANE_Byte * value) +{ + SANE_Byte pattern; + SANE_Status status; + + DBG (7, "usb_low_get_a8: start\n"); + if (!chip->is_opened) + { + DBG (3, "usb_low_get_a8: not opened yet\n"); + return SANE_STATUS_INVAL; + } + if (chip->is_rowing) + { + DBG (3, "usb_low_get_a8: stop rowing first\n"); + return SANE_STATUS_INVAL; + } + + RIE (usb_low_read_reg (chip, 8, &pattern)); + + chip->dummy_msb = pattern & 0x40; + chip->ccd_width_msb = pattern & 0x20; + chip->cmt_table_length = pattern & 0x1f; + chip->ccd_width = + ((chip->ccd_width / 32) & 0x00ff) * 32 + + ((chip->ccd_width_msb == 0) ? 0 : 0x0100 * 32); + chip->dummy = + ((chip->dummy / 32) & 0x00ff) * 32 + + ((chip->dummy_msb == 0) ? 0 : 0x0100 * 32); + + if (value) + *value = pattern; + + DBG (7, "usb_low_get_a8: exit\n"); + return SANE_STATUS_GOOD; +} + +SANE_Status +usb_low_set_cmt_table_length (ma1017 * chip, SANE_Byte table_length) +{ + SANE_Status status; + SANE_Byte data, reg_no; + + DBG (7, "usb_low_set_cmt_table_length: start\n"); + if (!chip->is_opened) + { + DBG (3, "usb_low_set_cmt_table_length: not opened yet\n"); + return SANE_STATUS_INVAL; + } + if (chip->is_rowing) + { + DBG (3, "usb_low_set_cmt_table_length: stop rowing first\n"); + return SANE_STATUS_INVAL; + } + if (table_length > 32) + { + DBG (3, "usb_low_set_cmt_table_length: length %d exceeds 32\n", + (int) table_length); + return SANE_STATUS_INVAL; + } + if (table_length == 0) + { + DBG (3, "usb_low_set_cmt_table_length: length is 0\n"); + return SANE_STATUS_INVAL; + } + + chip->cmt_table_length = table_length - 1; + chip->cmt_table_length_word = (SANE_Word) table_length; + data = chip->cmt_table_length | chip->ccd_width_msb | chip->dummy_msb; + reg_no = 8; + + RIE (usb_low_write_reg (chip, reg_no, data)); + + DBG (7, "usb_low_set_cmt_table_length: exit\n"); + return SANE_STATUS_GOOD; +} + +/* A9 */ +SANE_Status +usb_low_get_a9 (ma1017 * chip, SANE_Byte * value) +{ + SANE_Byte pattern; + SANE_Status status; + + DBG (7, "usb_low_get_a9: start\n"); + + if (!chip->is_opened) + { + DBG (3, "usb_low_get_a9: not opened yet\n"); + return SANE_STATUS_INVAL; + } + if (chip->is_rowing) + { + DBG (3, "usb_low_get_a9: stop rowing first\n"); + return SANE_STATUS_INVAL; + } + RIE (usb_low_read_reg (chip, 9, &pattern)); + + chip->cmt_second_pos = pattern & 0x1f; + + if (value) + *value = pattern; + + DBG (7, "usb_low_get_a9: exit\n"); + return SANE_STATUS_GOOD; +} + +SANE_Status +usb_low_set_cmt_second_position (ma1017 * chip, SANE_Byte position) +{ + SANE_Byte data, reg_no; + SANE_Status status; + + DBG (7, "usb_low_set_cmt_second_position: start\n"); + + if (!chip->is_opened) + { + DBG (3, "usb_low_set_cmt_second_position: not opened yet\n"); + return SANE_STATUS_INVAL; + } + if (chip->is_rowing) + { + DBG (3, "usb_low_set_cmt_second_position: stop rowing first\n"); + return SANE_STATUS_INVAL; + } + if (position > 31) + { + DBG (3, "usb_low_set_cmt_second_position: length: %d exceeds 31\n", + (int) position); + return SANE_STATUS_INVAL; + } + + chip->cmt_second_pos = position; + chip->cmt_second_pos_word = (SANE_Word) (position); + data = chip->cmt_second_pos; + reg_no = 9; + + RIE (usb_low_write_reg (chip, reg_no, data)); + + DBG (7, "usb_low_set_cmt_second_position: exit\n"); + + return SANE_STATUS_GOOD; +} + +/* A10 + A8ID5 */ +SANE_Status +usb_low_get_a10 (ma1017 * chip, SANE_Byte * value) +{ + SANE_Byte pattern; + SANE_Status status; + + DBG (7, "usb_low_get_a10: start\n"); + + if (!chip->is_opened) + { + DBG (3, "usb_low_get_a10: not opened yet\n"); + return SANE_STATUS_INVAL; + } + if (chip->is_rowing) + { + DBG (3, "usb_low_get_a10: stop rowing first\n"); + return SANE_STATUS_INVAL; + } + + RIE (usb_low_read_reg (chip, 10, &pattern)); + + chip->ccd_width = + ((SANE_Word) (pattern)) * 32 + + ((chip->ccd_width_msb == 0) ? 0 : 0x0100 * 32); + + if (value) + *value = pattern; + + DBG (7, "usb_low_get_a10: exit\n"); + + return SANE_STATUS_GOOD; +} + +SANE_Status +usb_low_set_ccd_width (ma1017 * chip, SANE_Word ccd_width) +{ + SANE_Status status; + SANE_Byte data, reg_no; + + DBG (7, "usb_low_set_ccd_width: start\n"); + + if (!chip->is_opened) + { + DBG (3, "usb_low_set_ccd_width: not opened yet\n"); + return SANE_STATUS_INVAL; + } + if (chip->is_rowing) + { + DBG (3, "usb_low_set_ccd_width: stop rowing first\n"); + return SANE_STATUS_INVAL; + } + if (ccd_width / 32 > 0x01ff) + { + DBG (3, "usb_low_set_ccd_width: width %d too high\n", (int) ccd_width); + return SANE_STATUS_INVAL; + } + + chip->ccd_width = ccd_width; + ccd_width /= 32; + if (HIBYTE (ccd_width) == 0x01) + chip->ccd_width_msb = 0x20; + else + chip->ccd_width_msb = 0x00; + + data = chip->cmt_table_length | chip->ccd_width_msb | chip->dummy_msb; + reg_no = 8; + RIE (usb_low_write_reg (chip, reg_no, data)); + + data = LOBYTE (ccd_width); + reg_no = 10; + RIE (usb_low_write_reg (chip, reg_no, data)); + + DBG (7, "usb_low_set_ccd_width: exit\n"); + return SANE_STATUS_GOOD; +} + +/* A11 + A8ID6 */ +SANE_Status +usb_low_get_a11 (ma1017 * chip, SANE_Byte * value) +{ + SANE_Byte pattern; + SANE_Status status; + + DBG (7, "usb_low_get_a11: start\n"); + + if (!chip->is_opened) + { + DBG (3, "usb_low_get_a11: not opened yet\n"); + return SANE_STATUS_INVAL; + } + if (chip->is_rowing) + { + DBG (3, "usb_low_get_a11: stop rowing first\n"); + return SANE_STATUS_INVAL; + } + + RIE (usb_low_read_reg (chip, 11, &pattern)); + + chip->dummy = + ((SANE_Word) (pattern)) * 32 + ((chip->dummy_msb == 0) ? 0 : 0x0100 * 32); + + if (value) + *value = pattern; + + DBG (7, "usb_low_get_a11: exit\n"); + return SANE_STATUS_GOOD; +} + +SANE_Status +usb_low_set_dummy (ma1017 * chip, SANE_Word dummy) +{ + SANE_Status status; + SANE_Byte data, reg_no; + + DBG (7, "usb_low_set_dummy: start\n"); + + if (!chip->is_opened) + { + DBG (3, "usb_low_set_dummy: not opened yet\n"); + return SANE_STATUS_INVAL; + } + if (chip->is_rowing) + { + DBG (3, "usb_low_set_dummy: stop rowing first\n"); + return SANE_STATUS_INVAL; + } + if (dummy / 32 > 0x01ff) + { + DBG (7, "usb_low_set_dummy: width %d exceeded\n", (int) dummy); + return SANE_STATUS_INVAL; + } + + chip->dummy = dummy; + dummy /= 32; + dummy++; + if (HIBYTE (dummy) == 0x01) + chip->dummy_msb = 0x40; + else + chip->dummy_msb = 0x00; + data = chip->cmt_table_length | chip->ccd_width_msb | chip->dummy_msb; + reg_no = 8; + RIE (usb_low_write_reg (chip, reg_no, data)); + + data = LOBYTE (dummy); + reg_no = 11; + RIE (usb_low_write_reg (chip, reg_no, data)); + + DBG (7, "usb_low_set_dummy: exit\n"); + return SANE_STATUS_GOOD; +} + +/* A12 + A13 */ +SANE_Status +usb_low_get_a12 (ma1017 * chip, SANE_Byte * value) +{ + SANE_Byte pattern; + SANE_Status status; + + DBG (7, "usb_low_get_a12: start\n"); + + if (!chip->is_opened) + { + DBG (3, "usb_low_get_a12: not opened yet\n"); + return SANE_STATUS_INVAL; + } + if (chip->is_rowing) + { + DBG (3, "usb_low_get_a12: stop rowing first\n"); + return SANE_STATUS_INVAL; + } + + RIE (usb_low_read_reg (chip, 12, &pattern)); + + chip->byte_width = (chip->byte_width & 0x3f00) + ((SANE_Word) pattern); + chip->soft_resample = (chip->soft_resample == 0) ? 1 : chip->soft_resample; + chip->get_row = + (chip->soft_resample == 1) + ? &usb_low_get_row_direct : &usb_low_get_row_resample; + chip->row_size = chip->byte_width / chip->soft_resample; + + if (value) + *value = pattern; + + DBG (7, "usb_low_get_a12: exit\n"); + return SANE_STATUS_GOOD; +} + +SANE_Status +usb_low_get_a13 (ma1017 * chip, SANE_Byte * value) +{ + SANE_Byte pattern; + SANE_Status status; + + DBG (7, "usb_low_get_a13: start\n"); + + if (!chip->is_opened) + { + DBG (3, "usb_low_get_a13: not opened yet\n"); + return SANE_STATUS_INVAL; + } + if (chip->is_rowing) + { + DBG (3, "usb_low_get_a13: stop rowing first\n"); + return SANE_STATUS_INVAL; + } + + RIE (usb_low_read_reg (chip, 13, &pattern)); + + chip->byte_width = + (chip->byte_width & 0x00ff) + (((SANE_Word) (pattern & 0x3f)) << 8); + chip->soft_resample = (chip->soft_resample == 0) ? 1 : chip->soft_resample; + chip->get_row = + (chip->soft_resample == + 1) ? &usb_low_get_row_direct : &usb_low_get_row_resample; + chip->row_size = chip->byte_width / chip->soft_resample; + + if (value) + *value = pattern; + + DBG (7, "usb_low_get_a13: exit\n"); + return SANE_STATUS_GOOD; +} + +SANE_Status +usb_low_set_image_byte_width (ma1017 * chip, SANE_Word row_size) +{ + SANE_Byte data, reg_no; + SANE_Status status; + + DBG (7, "usb_low_set_image_byte_width: start\n"); + + if (!chip->is_opened) + { + DBG (3, "usb_low_set_image_byte_width: not opened yet\n"); + return SANE_STATUS_INVAL; + } + if (chip->is_rowing) + { + DBG (3, "usb_low_set_image_byte_width: stop rowing first\n"); + return SANE_STATUS_INVAL; + } + + chip->row_size = row_size; + chip->soft_resample = (chip->soft_resample == 0) ? 1 : chip->soft_resample; + chip->get_row = (chip->soft_resample == 1) ? &usb_low_get_row_direct + : &usb_low_get_row_resample; + chip->byte_width = chip->row_size * chip->soft_resample; + if (chip->byte_width > 0x3fff) + { + DBG (3, "usb_low_set_image_byte_width: width %d exceeded\n", + (int) chip->byte_width); + return SANE_STATUS_INVAL; + } + + data = LOBYTE (chip->byte_width); + reg_no = 12; + RIE (usb_low_write_reg (chip, reg_no, data)); + + data = HIBYTE (chip->byte_width); + reg_no = 13; + RIE (usb_low_write_reg (chip, reg_no, data)); + + DBG (7, "usb_low_set_image_byte_width: exit\n"); + + return SANE_STATUS_GOOD; +} + +SANE_Status +usb_low_set_soft_resample (ma1017 * chip, SANE_Word soft_resample) +{ + SANE_Byte data, reg_no; + SANE_Status status; + + DBG (7, "usb_low_set_soft_resample: start\n"); + + if (!chip->is_opened) + { + DBG (3, "usb_low_set_soft_resample: not opened yet\n"); + return SANE_STATUS_INVAL; + } + if (chip->is_rowing) + { + DBG (3, "usb_low_set_soft_resample: stop rowing first\n"); + return SANE_STATUS_INVAL; + } + if (soft_resample == 0x00) + { + DBG (3, "usb_low_set_soft_resample: soft_resample==0\n"); + return SANE_STATUS_INVAL; + } + + chip->soft_resample = soft_resample; + chip->get_row = (chip->soft_resample == 1) ? &usb_low_get_row_direct + : &usb_low_get_row_resample; + chip->byte_width = chip->row_size * chip->soft_resample; + if (chip->byte_width > 0x3fff) + { + DBG (3, "usb_low_set_soft_resample: width %d exceeded", + (int) chip->byte_width); + return SANE_STATUS_INVAL; + } + + data = LOBYTE (chip->byte_width); + reg_no = 12; + RIE (usb_low_write_reg (chip, reg_no, data)); + + data = HIBYTE (chip->byte_width); + reg_no = 13; + RIE (usb_low_write_reg (chip, reg_no, data)); + + DBG (7, "usb_low_set_soft_resample: exit\n"); + return SANE_STATUS_GOOD; +} + +/* A14 + A30W */ +SANE_Status +usb_low_set_cmt_loop_count (ma1017 * chip, SANE_Word loop_count) +{ + SANE_Byte data, reg_no; + SANE_Status status; + + DBG (7, "usb_low_set_cmt_loop_count: start\n"); + + if (!chip->is_opened) + { + DBG (3, "usb_low_set_cmt_loop_count: not opened yet\n"); + return SANE_STATUS_INVAL; + } + if (chip->is_rowing) + { + DBG (3, "usb_low_set_cmt_loop_count: stop rowing first\n"); + return SANE_STATUS_INVAL; + } + + chip->loop_count = loop_count; + + data = LOBYTE (loop_count); + reg_no = 14; + RIE (usb_low_write_reg (chip, reg_no, data)); + + data = HIBYTE (loop_count); + reg_no = 30; + RIE (usb_low_write_reg (chip, reg_no, data)); + + DBG (7, "usb_low_set_cmt_loop_count: exit\n"); + return SANE_STATUS_GOOD; +} + +/* A15 */ +SANE_Status +usb_low_get_a15 (ma1017 * chip, SANE_Byte * value) +{ + SANE_Byte pattern; + SANE_Status status; + + DBG (7, "usb_low_get_a15: start\n"); + + if (!chip->is_opened) + { + DBG (3, "usb_low_get_a15: not opened yet\n"); + return SANE_STATUS_INVAL; + } + if (chip->is_rowing) + { + DBG (3, "usb_low_get_a15: stop rowing first\n"); + return SANE_STATUS_INVAL; + } + + RIE (usb_low_read_reg (chip, 15, &pattern)); + + chip->motor_enable = pattern & 0x80; + chip->motor_movement = pattern & 0x68; + chip->motor_direction = pattern & 10; + chip->motor_signal = pattern & 0x06; + chip->motor_home = pattern & 0x01; + + if (value) + *value = pattern; + + DBG (7, "usb_low_get_a15: exit\n"); + return SANE_STATUS_GOOD; +} + +SANE_Status +usb_low_enable_motor (ma1017 * chip, SANE_Bool is_enable) +{ + SANE_Byte data, reg_no; + SANE_Status status; + + DBG (7, "usb_low_enable_motor: start\n"); + if (!chip->is_opened) + { + DBG (3, "usb_low_enable_motor: not opened yet\n"); + return SANE_STATUS_INVAL; + } + if (chip->is_rowing) + { + DBG (3, "usb_low_enable_motor: stop rowing first\n"); + return SANE_STATUS_INVAL; + } + + chip->motor_enable = 0x00; + if (is_enable) + chip->motor_enable |= 0x80; + data = chip->motor_enable | chip->motor_movement + | chip->motor_direction | chip->motor_signal | chip->motor_home; + reg_no = 15; + RIE (usb_low_write_reg (chip, reg_no, data)); + + DBG (7, "usb_low_enable_motor: exit\n"); + return SANE_STATUS_GOOD; +} + +SANE_Status +usb_low_set_motor_movement (ma1017 * chip, SANE_Bool is_full_step, + SANE_Bool is_double_phase, SANE_Bool is_two_step) +{ + SANE_Byte data, reg_no; + SANE_Status status; + + DBG (7, "usb_low_set_motor_movement: start\n"); + if (!chip->is_opened) + { + DBG (3, "usb_low_set_motor_movement: not opened yet\n"); + return SANE_STATUS_INVAL; + } + if (chip->is_rowing) + { + DBG (3, "usb_low_set_motor_movement: stop rowing first\n"); + return SANE_STATUS_INVAL; + } + + chip->motor_movement = 0x00; + if (is_full_step) + chip->motor_movement |= 0x40; + if (is_double_phase) + chip->motor_movement |= 0x20; + if (is_two_step) + chip->motor_movement |= 0x08; + data = chip->motor_enable | chip->motor_movement + | chip->motor_direction | chip->motor_signal | chip->motor_home; + reg_no = 15; + RIE (usb_low_write_reg (chip, reg_no, data)); + + DBG (7, "usb_low_set_motor_movement: exit\n"); + return SANE_STATUS_GOOD; +} + +SANE_Status +usb_low_set_motor_direction (ma1017 * chip, SANE_Bool is_backward) +{ + SANE_Byte data, reg_no; + SANE_Status status; + + DBG (7, "usb_low_set_motor_direction: start\n"); + + if (!chip->is_opened) + { + DBG (3, "usb_low_set_motor_direction: not opened yet\n"); + return SANE_STATUS_INVAL; + } + if (chip->is_rowing) + { + DBG (3, "usb_low_set_motor_direction: stop rowing first\n"); + return SANE_STATUS_INVAL; + } + + chip->motor_direction = 0x00; + if (is_backward) + chip->motor_direction |= 0x10; + data = chip->motor_enable | chip->motor_movement + | chip->motor_direction | chip->motor_signal | chip->motor_home; + reg_no = 15; + RIE (usb_low_write_reg (chip, reg_no, data)); + + DBG (7, "usb_low_set_motor_direction: exit\n"); + return SANE_STATUS_GOOD; +} + +SANE_Status +usb_low_set_motor_signal (ma1017 * chip, SANE_Byte signal) +{ + SANE_Byte data, reg_no; + SANE_Status status; + + DBG (7, "usb_low_set_motor_signal: start\n"); + + if (!chip->is_opened) + { + DBG (3, "usb_low_set_motor_signal: not opened yet\n"); + return SANE_STATUS_INVAL; + } + if (chip->is_rowing) + { + DBG (3, "usb_low_set_motor_signal: stop rowing first\n"); + return SANE_STATUS_INVAL; + } + + chip->motor_signal = signal & 0x06; + data = chip->motor_enable | chip->motor_movement + | chip->motor_direction | chip->motor_signal | chip->motor_home; + reg_no = 15; + RIE (usb_low_write_reg (chip, reg_no, data)); + + DBG (7, "usb_low_set_motor_signal: exit\n"); + return SANE_STATUS_GOOD; +} + +SANE_Status +usb_low_move_motor_home (ma1017 * chip, SANE_Bool is_home, + SANE_Bool is_backward) +{ + SANE_Byte data, reg_no; + SANE_Status status; + + DBG (7, "usb_low_move_motor_home: start\n"); + + if (!chip->is_opened) + { + DBG (3, "usb_low_move_motor_home: not opened yet\n"); + return SANE_STATUS_INVAL; + } + if (chip->is_rowing) + { + DBG (3, "usb_low_move_motor_home: stop rowing first\n"); + return SANE_STATUS_INVAL; + } + + chip->motor_enable = 0x00; + chip->motor_direction = 0x00; + chip->motor_home = 0x00; + if (is_backward) + chip->motor_direction |= 0x10; + if (is_home) + { + chip->motor_enable |= 0x80; + chip->motor_home |= 0x01; + } + data = chip->motor_enable | chip->motor_movement + | chip->motor_direction | chip->motor_signal | chip->motor_home; + reg_no = 15; + RIE (usb_low_write_reg (chip, reg_no, data)); + + DBG (7, "usb_low_move_motor_home: exit\n"); + return SANE_STATUS_GOOD; +} + +/* A16 */ +SANE_Status +usb_low_get_a16 (ma1017 * chip, SANE_Byte * value) +{ + SANE_Byte pattern; + SANE_Status status; + + DBG (7, "usb_low_get_a16: start\n"); + + if (!chip->is_opened) + { + DBG (3, "usb_low_get_a16: not opened yet\n"); + return SANE_STATUS_INVAL; + } + if (chip->is_rowing) + { + DBG (3, "usb_low_get_a16: stop rowing first\n"); + return SANE_STATUS_INVAL; + } + + RIE (usb_low_read_reg (chip, 16, &pattern)); + + chip->pixel_depth = pattern & 0xe0; + chip->image_invert = pattern & 0x10; + chip->optical_600 = pattern & 0x08; + chip->sample_way = pattern & 0x07; + + if (value) + *value = pattern; + + DBG (7, "usb_low_get_a16: exit\n"); + return SANE_STATUS_GOOD; +} + +SANE_Status +usb_low_set_image_dpi (ma1017 * chip, SANE_Bool is_optical600, + Sampleway sampleway) +{ + SANE_Byte data, reg_no; + SANE_Status status; + + DBG (7, "usb_low_set_image_dpi: start\n"); + + if (!chip->is_opened) + { + DBG (3, "usb_low_set_image_dpi: not opened yet\n"); + return SANE_STATUS_INVAL; + } + if (chip->is_rowing) + { + DBG (3, "usb_low_set_image_dpi: stop rowing first\n"); + return SANE_STATUS_INVAL; + } + + chip->optical_600 = 0x00; + chip->sample_way = 0x00; + if (is_optical600) + chip->optical_600 |= 0x08; + switch (sampleway) + { + case SW_P1P6: + chip->sample_way = 0x01; + break; + case SW_P2P6: + chip->sample_way = 0x02; + break; + case SW_P3P6: + chip->sample_way = 0x03; + break; + case SW_P4P6: + chip->sample_way = 0x04; + break; + case SW_P5P6: + chip->sample_way = 0x05; + break; + case SW_P6P6: + chip->sample_way = 0x06; + break; + default: + DBG (3, "usb_low_set_image_dpi: swsample_way error\n"); + return SANE_STATUS_INVAL; + break; + } + data = chip->pixel_depth | chip->image_invert | chip->optical_600 + | chip->sample_way; + reg_no = 16; + RIE (usb_low_write_reg (chip, reg_no, data)); + + DBG (7, "usb_low_set_image_dpi: exit\n"); + return SANE_STATUS_GOOD; +} + +SANE_Status +usb_low_set_pixel_depth (ma1017 * chip, Pixeldepth pixeldepth) +{ + SANE_Byte data, reg_no; + SANE_Status status; + + DBG (7, "usb_low_set_pixel_depth: start\n"); + if (!chip->is_opened) + { + DBG (3, "usb_low_set_pixel_depth: not opened yet\n"); + return SANE_STATUS_INVAL; + } + if (chip->is_rowing) + { + DBG (3, "usb_low_set_pixel_depth: stop rowing first\n"); + return SANE_STATUS_INVAL; + } + + chip->pixel_depth = 0x00; + switch (pixeldepth) + { + case PD_1BIT: + chip->pixel_depth = 0x80; + break; + case PD_4BIT: + chip->pixel_depth = 0xc0; + break; + case PD_8BIT: + chip->pixel_depth = 0x00; + break; + case PD_12BIT: + chip->pixel_depth = 0x20; + break; + default: + DBG (3, "usb_low_set_pixel_depth: pdPixelDepth error\n"); + return SANE_STATUS_INVAL; + } + data = chip->pixel_depth | chip->image_invert | chip->optical_600 + | chip->sample_way; + reg_no = 16; + RIE (usb_low_write_reg (chip, reg_no, data)); + + DBG (7, "usb_low_SetPixelDeepth: exit\n"); + return SANE_STATUS_GOOD; +} + +SANE_Status +usb_low_invert_image (ma1017 * chip, SANE_Bool is_invert) +{ + SANE_Byte data, reg_no; + SANE_Status status; + + DBG (7, "usb_low_invert_image: start\n"); + if (!chip->is_opened) + { + DBG (3, "usb_low_invert_image: not opened yet\n"); + return SANE_STATUS_INVAL; + } + if (chip->is_rowing) + { + DBG (3, "usb_low_invert_image: stop rowing first\n"); + return SANE_STATUS_INVAL; + } + + chip->image_invert = 0x00; + if (is_invert) + chip->image_invert |= 0x10; + data = chip->pixel_depth | chip->image_invert | chip->optical_600 + | chip->sample_way; + reg_no = 16; + RIE (usb_low_write_reg (chip, reg_no, data)); + + DBG (7, "usb_low_invert_image: exit\n"); + return SANE_STATUS_GOOD; +} + +/* A17 + A18 + A19 */ +SANE_Status +usb_low_get_a17 (ma1017 * chip, SANE_Byte * value) +{ + SANE_Byte pattern; + SANE_Status status; + + DBG (7, "usb_low_get_a17: start\n"); + if (!chip->is_opened) + { + DBG (3, "usb_low_get_a17: not opened yet\n"); + return SANE_STATUS_INVAL; + } + if (chip->is_rowing) + { + DBG (3, "usb_low_get_a17: stop rowing first\n"); + return SANE_STATUS_INVAL; + } + + RIE (usb_low_read_reg (chip, 17, &pattern)); + + chip->red_ref = pattern; + + if (value) + *value = pattern; + + DBG (7, "usb_low_get_a17: exit\n"); + return SANE_STATUS_GOOD; +} + +SANE_Status +usb_low_get_a18 (ma1017 * chip, SANE_Byte * value) +{ + SANE_Byte pattern; + SANE_Status status; + + DBG (7, "usb_low_get_a18: start\n"); + if (!chip->is_opened) + { + DBG (3, "usb_low_get_a18: not opened yet\n"); + return SANE_STATUS_INVAL; + } + if (chip->is_rowing) + { + DBG (3, "usb_low_get_a18: stop rowing first\n"); + return SANE_STATUS_INVAL; + } + + RIE (usb_low_read_reg (chip, 18, &pattern)); + + chip->green_ref = pattern; + + if (value) + *value = pattern; + + DBG (7, "usb_low_get_a18: exit\n"); + return SANE_STATUS_GOOD; +} + +SANE_Status +usb_low_get_a19 (ma1017 * chip, SANE_Byte * value) +{ + SANE_Byte pattern; + SANE_Status status; + + DBG (7, "usb_low_get_a19: start\n"); + if (!chip->is_opened) + { + DBG (3, "usb_low_get_a19: not opened yet\n"); + return SANE_STATUS_INVAL; + } + if (chip->is_rowing) + { + DBG (3, "usb_low_get_a19:stop rowing first\n"); + return SANE_STATUS_INVAL; + } + + RIE (usb_low_read_reg (chip, 19, &pattern)); + + chip->blue_ref = pattern; + + if (value) + *value = pattern; + + DBG (7, "usb_low_get_a19: exit\n"); + return SANE_STATUS_GOOD; +} + +SANE_Status +usb_low_set_red_ref (ma1017 * chip, SANE_Byte red_ref) +{ + SANE_Byte data, reg_no; + SANE_Status status; + + DBG (7, "usb_low_set_red_ref: start\n"); + + if (!chip->is_opened) + { + DBG (3, "usb_low_set_red_ref: not opened yet\n"); + return SANE_STATUS_INVAL; + } + if (chip->is_rowing) + { + DBG (3, "usb_low_set_red_ref: stop rowing first\n"); + return SANE_STATUS_INVAL; + } + + chip->red_ref = red_ref; + data = red_ref; + reg_no = 17; + RIE (usb_low_write_reg (chip, reg_no, data)); + + DBG (7, "usb_low_set_red_ref: stop\n"); + return SANE_STATUS_GOOD; +} + +SANE_Status +usb_low_set_green_ref (ma1017 * chip, SANE_Byte green_ref) +{ + SANE_Byte data, reg_no; + SANE_Status status; + + DBG (7, "usb_low_set_green_ref: start\n"); + + + if (!chip->is_opened) + { + DBG (3, "usb_low_set_green_ref: not opened yet\n"); + return SANE_STATUS_INVAL; + } + if (chip->is_rowing) + { + DBG (3, "usb_low_set_green_ref: stop rowing first\n"); + return SANE_STATUS_INVAL; + } + + chip->green_ref = green_ref; + + data = green_ref; + reg_no = 18; + RIE (usb_low_write_reg (chip, reg_no, data)); + + DBG (7, "usb_low_set_green_ref: exit\n"); + return SANE_STATUS_GOOD; +} + +SANE_Status +usb_low_set_blue_ref (ma1017 * chip, SANE_Byte blue_ref) +{ + SANE_Byte data, reg_no; + SANE_Status status; + + DBG (7, "usb_low_set_blue_ref: start\n"); + + if (!chip->is_opened) + { + DBG (3, "usb_low_set_blue_ref: not opened yet\n"); + return SANE_STATUS_INVAL; + } + if (chip->is_rowing) + { + DBG (3, "usb_low_set_blue_ref: stop rowing first\n"); + return SANE_STATUS_INVAL; + } + + chip->blue_ref = blue_ref; + + data = blue_ref; + reg_no = 19; + RIE (usb_low_write_reg (chip, reg_no, data)); + + DBG (7, "usb_low_set_blue_ref: stop\n"); + return SANE_STATUS_GOOD; +} + +/* A20 + A21 + A22 */ +SANE_Status +usb_low_get_a20 (ma1017 * chip, SANE_Byte * value) +{ + SANE_Byte pattern; + SANE_Status status; + + DBG (7, "usb_low_get_a20: start\n"); + + if (!chip->is_opened) + { + DBG (3, "usb_low_get_a20: not opened yet\n"); + return SANE_STATUS_INVAL; + } + if (chip->is_rowing) + { + DBG (3, "usb_low_get_a20: stop rowing first\n"); + return SANE_STATUS_INVAL; + } + RIE (usb_low_read_reg (chip, 20, &pattern)); + + chip->red_pd = pattern; + + if (value) + *value = pattern; + + DBG (7, "usb_low_get_a20: stop\n"); + return SANE_STATUS_GOOD; +} + +SANE_Status +usb_low_get_a21 (ma1017 * chip, SANE_Byte * value) +{ + SANE_Byte pattern; + SANE_Status status; + + DBG (7, "usb_low_get_a21: start\n"); + + if (!chip->is_opened) + { + DBG (3, "usb_low_get_a21: not opened yet\n"); + return SANE_STATUS_INVAL; + } + if (chip->is_rowing) + { + DBG (3, "usb_low_get_a21: stop rowing first\n"); + return SANE_STATUS_INVAL; + } + + RIE (usb_low_read_reg (chip, 21, &pattern)); + + chip->green_pd = pattern; + + if (value) + *value = pattern; + + DBG (7, "usb_low_get_a21: exit\n"); + return SANE_STATUS_GOOD; +} + +SANE_Status +usb_low_get_a22 (ma1017 * chip, SANE_Byte * value) +{ + SANE_Byte pattern; + SANE_Status status; + + DBG (7, "usb_low_get_a22: start\n"); + + if (!chip->is_opened) + { + DBG (3, "usb_low_get_a22: not opened yet\n"); + return SANE_STATUS_INVAL; + } + if (chip->is_rowing) + { + DBG (3, "usb_low_get_a22: stop rowing first\n"); + return SANE_STATUS_INVAL; + } + + RIE (usb_low_read_reg (chip, 22, &pattern)); + + chip->blue_pd = pattern; + + if (value) + *value = pattern; + + DBG (7, "usb_low_get_a22: exit\n"); + return SANE_STATUS_GOOD; +} + +SANE_Status +usb_low_set_red_pd (ma1017 * chip, SANE_Byte red_pd) +{ + SANE_Byte data, reg_no; + SANE_Status status; + + DBG (7, "usb_low_set_red_pd: start\n"); + + if (!chip->is_opened) + { + DBG (3, "usb_low_set_red_pd: not opened yet\n"); + return SANE_STATUS_INVAL; + } + if (chip->is_rowing) + { + DBG (3, "usb_low_set_red_pd: stop rowing first\n"); + return SANE_STATUS_INVAL; + } + + chip->red_pd = red_pd; + + data = chip->red_pd; + reg_no = 20; + RIE (usb_low_write_reg (chip, reg_no, data)); + + DBG (7, "usb_low_set_red_pd: exit\n"); + return SANE_STATUS_GOOD; +} + +SANE_Status +usb_low_set_green_pd (ma1017 * chip, SANE_Byte green_pd) +{ + SANE_Byte data, reg_no; + SANE_Status status; + + DBG (7, "usb_low_set_green_pd: start\n"); + + if (!chip->is_opened) + { + DBG (3, "usb_low_set_green_pd: not opened yet\n"); + return SANE_STATUS_INVAL; + } + if (chip->is_rowing) + { + DBG (3, "usb_low_set_green_pd: stop rowing first\n"); + return SANE_STATUS_INVAL; + } + + chip->green_pd = green_pd; + data = chip->green_pd; + reg_no = 21; + RIE (usb_low_write_reg (chip, reg_no, data)); + + DBG (7, "usb_low_set_green_pd: exit\n"); + return SANE_STATUS_GOOD; +} + +SANE_Status +usb_low_set_blue_pd (ma1017 * chip, SANE_Byte blue_pd) +{ + SANE_Byte data, reg_no; + SANE_Status status; + + DBG (7, "usb_low_set_blue_pd: start\n"); + + if (!chip->is_opened) + { + DBG (3, "usb_low_set_blue_pd: not opened yet\n"); + return SANE_STATUS_INVAL; + } + if (chip->is_rowing) + { + DBG (3, "usb_low_set_blue_pd: stop rowing first\n"); + return SANE_STATUS_INVAL; + } + + chip->blue_pd = blue_pd; + + data = chip->blue_pd; + reg_no = 22; + RIE (usb_low_write_reg (chip, reg_no, data)); + + DBG (7, "usb_low_set_blue_pd: exit\n"); + return SANE_STATUS_GOOD; +} + +/* A23 */ +SANE_Status +usb_low_get_a23 (ma1017 * chip, SANE_Byte * value) +{ + SANE_Byte pattern; + SANE_Status status; + + DBG (7, "usb_low_get_a23: start\n"); + if (!chip->is_opened) + { + DBG (3, "usb_low_get_a23: not opened yet\n"); + return SANE_STATUS_INVAL; + } + if (chip->is_rowing) + { + DBG (3, "usb_low_get_a23: stop rowing first\n"); + return SANE_STATUS_INVAL; + } + + RIE (usb_low_read_reg (chip, 23, &pattern)); + + chip->a23 = pattern; + + if (value) + *value = pattern; + + DBG (7, "usb_low_get_a23: exit\n"); + return SANE_STATUS_GOOD; +} + +SANE_Status +usb_low_turn_peripheral_power (ma1017 * chip, SANE_Bool is_on) +{ + SANE_Byte data, reg_no; + SANE_Status status; + + DBG (7, "usb_low_turn_peripheral_power: start\n"); + + if (!chip->is_opened) + { + DBG (3, "usb_low_turn_peripheral_power: not opened yet\n"); + return SANE_STATUS_INVAL; + } + if (chip->is_rowing) + { + DBG (3, "usb_low_turn_peripheral_power: stop rowing first\n"); + return SANE_STATUS_INVAL; + } + + chip->a23 &= 0x7f; + if (is_on) + chip->a23 |= 0x80; + data = chip->a23; + reg_no = 23; + RIE (usb_low_write_reg (chip, reg_no, data)); + + DBG (7, "usb_low_turn_peripheral_power: exit\n"); + return SANE_STATUS_GOOD; +} + +SANE_Status +usb_low_turn_lamp_power (ma1017 * chip, SANE_Bool is_on) +{ + SANE_Byte data, reg_no; + SANE_Status status; + + DBG (7, "usb_low_turn_lamp_power: start\n"); + + if (!chip->is_opened) + { + DBG (3, "usb_low_turn_lamp_power: not opened yet\n"); + return SANE_STATUS_INVAL; + } + if (chip->is_rowing) + { + DBG (3, "usb_low_turn_lamp_power: stop rowing first\n"); + return SANE_STATUS_INVAL; + } + + chip->a23 &= 0xbf; + if (is_on) + chip->a23 |= 0x40; + + data = chip->a23; + reg_no = 23; + RIE (usb_low_write_reg (chip, reg_no, data)); + + DBG (7, "usb_low_turn_lamp_power: exit\n"); + return SANE_STATUS_GOOD; +} + +SANE_Status +usb_low_set_io_3 (ma1017 * chip, SANE_Bool is_high) +{ + SANE_Byte data, reg_no; + SANE_Status status; + + DBG (7, "usb_low_set_io_3: start\n"); + + if (!chip->is_opened) + { + DBG (3, "usb_low_set_io_3: not opened yet\n"); + return SANE_STATUS_INVAL; + } + if (chip->is_rowing) + { + DBG (3, "usb_low_set_io_3: stop rowing first\n"); + return SANE_STATUS_INVAL; + } + + chip->a23 &= 0xf7; + if (is_high) + chip->a23 |= 0x08; + + data = chip->a23; + reg_no = 23; + RIE (usb_low_write_reg (chip, reg_no, data)); + + DBG (7, "usb_low_set_io_3: exit\n"); + return SANE_STATUS_GOOD; +} + +SANE_Status +usb_low_set_led_light_all (ma1017 * chip, SANE_Bool is_light_all) +{ + SANE_Byte data, reg_no; + SANE_Status status; + + DBG (7, "usb_low_set_led_light_all: start\n"); + + if (!chip->is_opened) + { + DBG (3, "usb_low_set_led_light_all: not opened yet\n"); + return SANE_STATUS_INVAL; + } + if (chip->is_rowing) + { + DBG (3, "usb_low_set_led_light_all: stop rowing first\n"); + return SANE_STATUS_INVAL; + } + + chip->a23 &= 0xfe; + if (is_light_all) + chip->a23 |= 0x01; + + data = chip->a23; + reg_no = 23; + RIE (usb_low_write_reg (chip, reg_no, data)); + + DBG (7, "usb_low_set_led_light_all: exit\n"); + return SANE_STATUS_GOOD; +} + +/* A24 */ +SANE_Status +usb_low_get_a24 (ma1017 * chip, SANE_Byte * value) +{ + SANE_Byte pattern; + SANE_Status status; + + DBG (7, "usb_low_get_a24: start\n"); + + if (!chip->is_opened) + { + DBG (3, "usb_low_get_a24: not opened yet\n"); + return SANE_STATUS_INVAL; + } + if (chip->is_rowing) + { + DBG (3, "usb_low_get_a24: stop rowing first\n"); + return SANE_STATUS_INVAL; + } + + RIE (usb_low_read_reg (chip, 24, &pattern)); + + chip->fy1_delay = pattern & 0x01; + chip->special_ad = pattern & 0x02; + + if (value) + *value = pattern; + + DBG (7, "usb_low_get_a24: exit\n"); + return SANE_STATUS_GOOD; +} + +SANE_Status +usb_low_set_ad_timing (ma1017 * chip, SANE_Byte data) +{ + SANE_Byte reg_no; + SANE_Status status; + + DBG (7, "usb_low_set_ad_timing: start\n"); + + if (!chip->is_opened) + { + DBG (3, "usb_low_set_ad_timing: not opened yet\n"); + return SANE_STATUS_INVAL; + } + if (chip->is_rowing) + { + DBG (3, "usb_low_set_ad_timing: stop rowing first\n"); + return SANE_STATUS_INVAL; + } + + chip->fy1_delay = data & 0x01; + chip->special_ad = data & 0x02; + + data = chip->special_ad | chip->fy1_delay; + reg_no = 24; + RIE (usb_low_write_reg (chip, reg_no, data)); + + DBG (7, "usb_low_set_ad_timing: exit\n"); + return SANE_STATUS_GOOD; +} + +/* A25 + A26 */ +SANE_Status +usb_low_set_serial_byte1 (ma1017 * chip, SANE_Byte data) +{ + SANE_Byte reg_no; + SANE_Status status; + + DBG (7, "usb_low_set_serial_byte1: start\n"); + + if (!chip->is_opened) + { + DBG (3, "usb_low_set_serial_byte1: not opened\n"); + return SANE_STATUS_INVAL; + } + if (chip->is_rowing) + { + DBG (3, "usb_low_set_serial_byte1: stop rowing first\n"); + return SANE_STATUS_INVAL; + } + + reg_no = 25; + RIE (usb_low_write_reg (chip, reg_no, data)); + + DBG (7, "usb_low_set_serial_byte1: exit\n"); + return SANE_STATUS_GOOD; +} + +SANE_Status +usb_low_set_serial_byte2 (ma1017 * chip, SANE_Byte data) +{ + SANE_Byte reg_no; + SANE_Status status; + + DBG (7, "usb_low_set_serial_byte2: start\n"); + + if (!chip->is_opened) + { + DBG (3, "usb_low_set_serial_byte2: not opened yet\n"); + return SANE_STATUS_INVAL; + } + if (chip->is_rowing) + { + DBG (3, "usb_low_set_serial_byte2: stop rowing first\n"); + return SANE_STATUS_INVAL; + } + + reg_no = 26; + RIE (usb_low_write_reg (chip, reg_no, data)); + + DBG (7, "usb_low_set_serial_byte2: exit\n"); + return SANE_STATUS_GOOD; +} + +/* A27 */ +SANE_Status +usb_low_get_a27 (ma1017 * chip, SANE_Byte * value) +{ + SANE_Byte pattern; + SANE_Status status; + + DBG (7, "usb_low_get_a27: start\n"); + + if (!chip->is_opened) + { + DBG (3, "usb_low_get_a27: not opened yet\n"); + return SANE_STATUS_INVAL; + } + if (chip->is_rowing) + { + DBG (3, "usb_low_get_a27: stop rowing first\n"); + return SANE_STATUS_INVAL; + } + + RIE (usb_low_read_reg (chip, 27, &pattern)); + + chip->sclk = pattern & 0x80; + chip->sen = pattern & 0x40; + chip->serial_length = pattern & 0x1f; + + if (value) + *value = pattern; + + DBG (7, "usb_low_get_a27: exit\n"); + return SANE_STATUS_GOOD; +} + +SANE_Status +usb_low_set_serial_format (ma1017 * chip, SANE_Byte data) +{ + SANE_Byte reg_no; + SANE_Status status; + + DBG (7, "usb_low_set_serial_format: start\n"); + + if (!chip->is_opened) + { + DBG (3, "usb_low_set_serial_format: not opened yet\n"); + return SANE_STATUS_INVAL; + } + if (chip->is_rowing) + { + DBG (3, "usb_low_set_serial_format: stop rowing first\n"); + return SANE_STATUS_INVAL; + } + + + chip->sclk = data & 0x80; + chip->sen = data & 0x40; + chip->serial_length = data & 0x1f; + + reg_no = 27; + RIE (usb_low_write_reg (chip, reg_no, data)); + + DBG (7, "usb_low_set_serial_format: exit\n"); + return SANE_STATUS_GOOD; +} + +SANE_Status +usb_low_get_home_sensor (ma1017 * chip) +{ + SANE_Byte data; + SANE_Status status; + + DBG (7, "usb_low_get_home_sensor: start\n"); + + if (!chip->is_opened) + { + DBG (3, "usb_low_get_home_sensor: not opened yet\n"); + return SANE_STATUS_INVAL; + } + if (chip->is_rowing) + { + DBG (3, "usb_low_get_home_sensor: stop rowing first\n"); + return SANE_STATUS_INVAL; + } + + RIE (usb_low_read_reg (chip, 31, &data)); + + DBG (7, "usb_low_get_home_sensor: exit\n"); + if ((data & 0x80) != 0) + return SANE_STATUS_GOOD; + else + return SANE_STATUS_IO_ERROR; +} + +/* Special Mode */ +SANE_Status +usb_low_start_rowing (ma1017 * chip) +{ + SANE_Word line_of_first = 0; + SANE_Word line_of_second = 0; + SANE_Int i; + SANE_Status status; + + DBG (7, "usb_low_start_rowing: start\n"); + + if (chip->loop_count == 0) + { + DBG (3, "usb_low_start_rowing loop_count hasn't been set yet\n"); + return SANE_STATUS_INVAL; + } + if (chip->cmt_table_length_word == 0) + { + DBG (3, "usb_low_start_rowing: cmt_table_length_word hasn't been set " + "yet\n"); + return SANE_STATUS_INVAL; + } + if (chip->cmt_table_length_word <= chip->cmt_second_pos_word) + { + DBG (3, "usb_low_start_rowing: cmt_second_pos_word cannot be larger " + "than cmt_table_length_word\n"); + return SANE_STATUS_INVAL; + } + + for (i = 0; i < (int) chip->cmt_second_pos_word; i++) + { + if (chip->is_transfer_table[i]) + line_of_first++; + } + for (; i < (int) chip->cmt_table_length_word; i++) + { + if (chip->is_transfer_table[i]) + { + line_of_first++; + line_of_second++; + } + } + + chip->total_lines = + ((SANE_Word) (chip->loop_count - 1)) * line_of_second + line_of_first; + chip->lines_left = chip->total_lines; + + RIE (usb_low_start_cmt_table (chip)); + + DBG (7, "usb_low_start_rowing: exit\n"); + return SANE_STATUS_GOOD; +} + +SANE_Status +usb_low_stop_rowing (ma1017 * chip) +{ + SANE_Status status; + + DBG (7, "usb_low_stop_rowing: start\n"); + + RIE (usb_low_stop_cmt_table (chip)); + + DBG (7, "usb_low_stop_rowing: exit\n"); + return SANE_STATUS_GOOD; + +} + +SANE_Status +usb_low_wait_rowing_stop (ma1017 * chip) +{ + SANE_Status status; + + DBG (7, "usb_low_wait_rowing_stop: start\n"); + if (chip->total_lines != 0) + { + DBG (3, "usb_low_wait_rowing_stop: total_lines must be 0\n"); + return SANE_STATUS_INVAL; + } + + RIE (usb_low_wait_rowing (chip)); + chip->is_rowing = SANE_FALSE; + DBG (7, "usb_low_wait_rowing_stop: exit\n"); + return SANE_STATUS_GOOD; +} + +SANE_Status +usb_low_read_all_registers (ma1017 * chip) +{ + SANE_Status status; + + DBG (7, "usb_low_read_all_registers: start\n"); + + RIE (usb_low_get_a2 (chip, 0)); + RIE (usb_low_get_a4 (chip, 0)); + RIE (usb_low_get_a6 (chip, 0)); + RIE (usb_low_get_a7 (chip, 0)); + RIE (usb_low_get_a8 (chip, 0)); + RIE (usb_low_get_a9 (chip, 0)); + RIE (usb_low_get_a10 (chip, 0)); + RIE (usb_low_get_a11 (chip, 0)); + RIE (usb_low_get_a12 (chip, 0)); + RIE (usb_low_get_a13 (chip, 0)); + RIE (usb_low_get_a15 (chip, 0)); + RIE (usb_low_get_a16 (chip, 0)); + RIE (usb_low_get_a17 (chip, 0)); + RIE (usb_low_get_a18 (chip, 0)); + RIE (usb_low_get_a19 (chip, 0)); + RIE (usb_low_get_a20 (chip, 0)); + RIE (usb_low_get_a21 (chip, 0)); + RIE (usb_low_get_a22 (chip, 0)); + RIE (usb_low_get_a23 (chip, 0)); + RIE (usb_low_get_a24 (chip, 0)); + RIE (usb_low_get_a27 (chip, 0)); + + return SANE_STATUS_GOOD; + DBG (7, "usb_low_read_all_registers: exit\n"); +} + +SANE_Status +usb_low_get_row (ma1017 * chip, SANE_Byte * data, SANE_Word * lines_left) +{ + SANE_Status status; + + DBG (7, "usb_low_get_row: start\n"); + RIE ((*chip->get_row) (chip, data, lines_left)); + DBG (7, "usb_low_get_row: exit\n"); + return SANE_STATUS_GOOD;; +} + +SANE_Status +usb_low_get_row_direct (ma1017 * chip, SANE_Byte * data, + SANE_Word * lines_left) +{ + SANE_Status status; + + DBG (7, "usb_low_get_row_direct: start\n"); + if (chip->lines_left == 0) + { + DBG (3, "usb_low_get_row_direct: lines_left == 0\n"); + return SANE_STATUS_INVAL; + } + + if (chip->lines_left <= 1) + { + RIE (usb_low_read_rows (chip, data, chip->byte_width)); + RIE (usb_low_wait_rowing (chip)); + + chip->lines_left = 0x00; + chip->is_rowing = SANE_FALSE; + *lines_left = 0; + } + else + { + RIE (usb_low_read_rows (chip, data, chip->byte_width)); + chip->lines_left--; + *lines_left = chip->lines_left; + } + DBG (7, "usb_low_get_row_direct: exit\n"); + return SANE_STATUS_GOOD; +} + +SANE_Status +usb_low_get_row_resample (ma1017 * chip, SANE_Byte * data, + SANE_Word * lines_left) +{ + static SANE_Byte resample_buffer[8 * 1024]; + SANE_Word *pixel_temp; + SANE_Word i; + SANE_Word j; + SANE_Word k; + SANE_Status status; + + DBG (7, "usb_low_get_row_resample: start\n"); + + if (chip->lines_left == 0) + { + DBG (3, "usb_low_get_row_resample: lines_left == 0\n"); + return SANE_STATUS_INVAL; + } + + if (chip->lines_left <= 1) + { + RIE (usb_low_read_rows (chip, resample_buffer, chip->byte_width)); + + if ((chip->sensor == ST_CANON600) && (chip->pixel_depth == 0x20)) + { + pixel_temp = (SANE_Word *) malloc (6 * 1024 * sizeof (SANE_Word)); + if (!pixel_temp) + return SANE_STATUS_NO_MEM; + + j = 0; + for (i = 0; i < chip->byte_width; i += 3) + { + pixel_temp[j] = (SANE_Word) resample_buffer[i]; + pixel_temp[j] |= ((SANE_Word) + (resample_buffer[i + 1] & 0xf0)) << 4; + j++; + pixel_temp[j] = ((SANE_Word) + (resample_buffer[i + 1] & 0x0f)) << 8; + pixel_temp[j] |= (SANE_Word) resample_buffer[i + 2]; + j++; + } + + k = 0; + for (i = 0; i < j; i += chip->soft_resample * 2) + { + data[k] = (SANE_Byte) (pixel_temp[i] & 0x00ff); + k++; + data[k] = (SANE_Byte) ((pixel_temp[i] & 0x0f00) >> 4); + data[k] |= (SANE_Byte) ((pixel_temp[i + 2] & 0x0f00) >> 8); + k++; + data[k] = (SANE_Byte) (pixel_temp[i + 2] & 0x00ff); + k++; + } + free (pixel_temp); + } + else /* fixme ? */ + { + for (i = 0; i < chip->byte_width; i += chip->soft_resample) + *(data++) = resample_buffer[i]; + } + RIE (usb_low_wait_rowing (chip)); + + chip->lines_left = 0x00; + chip->is_rowing = SANE_FALSE; + *lines_left = 0; + } + else + { + RIE (usb_low_read_rows (chip, resample_buffer, chip->byte_width)); + + if ((chip->sensor == ST_CANON600) && (chip->pixel_depth == 0x20)) + { + pixel_temp = (SANE_Word *) malloc (6 * 1024 * sizeof (SANE_Word)); + if (!pixel_temp) + return SANE_STATUS_NO_MEM; + + j = 0; + for (i = 0; i < chip->byte_width; i += 3) + { + pixel_temp[j] = (SANE_Word) resample_buffer[i]; + pixel_temp[j] |= + ((SANE_Word) (resample_buffer[i + 1] & 0xf0)) << 4; + j++; + pixel_temp[j] = + ((SANE_Word) (resample_buffer[i + 1] & 0x0f)) << 8; + pixel_temp[j] |= (SANE_Word) resample_buffer[i + 2]; + j++; + } + + k = 0; + for (i = 0; i < j; i += chip->soft_resample * 2) + { + data[k] = (SANE_Byte) (pixel_temp[i] & 0x00ff); + k++; + data[k] = (SANE_Byte) ((pixel_temp[i] & 0x0f00) >> 4); + data[k] |= (SANE_Byte) ((pixel_temp[i + 2] & 0x0f00) >> 8); + k++; + data[k] = (SANE_Byte) (pixel_temp[i + 2] & 0x00ff); + k++; + } + free (pixel_temp); + } + else /* fixme? */ + { + for (i = 0; i < chip->byte_width; i += chip->soft_resample) + *(data++) = resample_buffer[i]; + } + chip->lines_left--; + *lines_left = chip->lines_left; + } + DBG (7, "usb_low_get_row_resample: exit\n"); + return SANE_STATUS_GOOD; +} + +SANE_Status +usb_low_wait_rowing (ma1017 * chip) +{ + SANE_Byte read_byte; + size_t n; + SANE_Status status; + + DBG (7, "usb_low_wait_rowing: start\n"); + + if (!chip->is_opened) + { + DBG (3, "usb_low_wait_rowing: open first\n"); + return SANE_STATUS_INVAL; + } + if (!chip->is_rowing) + { + DBG (3, "usb_low_wait_rowing: not rowing\n"); + return SANE_STATUS_INVAL; + } + n = 1; + status = sanei_usb_read_bulk (chip->fd, (SANE_Byte *) & read_byte, &n); + if (status != SANE_STATUS_GOOD || n != 1) + { + DBG (3, "usb_low_wait_rowing: couldn't read: %s\n", + sane_strstatus (status)); + return SANE_STATUS_IO_ERROR; + } + chip->total_read_urbs++; + chip->is_rowing = SANE_FALSE; + DBG (7, "usb_low_wait_rowing: exit\n"); + return SANE_STATUS_GOOD; +} + +SANE_Status +usb_low_read_rows (ma1017 * chip, SANE_Byte * data, SANE_Word byte_count) +{ + size_t n, bytes_total; + SANE_Status status; + + DBG (7, "usb_low_read_rows: start\n"); + if (!(chip->is_opened)) + { + DBG (3, "usb_low_read_rows: is_opened==SANE_FALSE\n"); + return SANE_STATUS_INVAL; + } + if (!(chip->is_rowing)) + { + DBG (3, "usb_low_read_rows: is_rowing==SANE_FALSE\n"); + return SANE_STATUS_INVAL; + } + + n = MIN (byte_count, chip->max_block_size); + bytes_total = 0; + + while ((SANE_Word) bytes_total < byte_count) + { + status = + sanei_usb_read_bulk (chip->fd, (SANE_Byte *) (data + bytes_total), + &n); + if (status != SANE_STATUS_GOOD) + { + DBG (7, "usb_low_read_rows: problems during read: %s -- exiting\n", + sane_strstatus (status)); + return status; + } + /* Count the number of URBs. This is a bit tricky, as we are reading + bigger chunks here but the scanner can only handle 64 bytes at once. */ + chip->total_read_urbs += ((n + 63) / 64); + bytes_total += n; + if ((SANE_Word) bytes_total != byte_count) + { + DBG (7, "usb_low_read_rows: wanted %d, got %d " + "bytes (%d in total) -- retrying\n", byte_count, (SANE_Word) n, + (SANE_Word) bytes_total); + } + n = MIN ((byte_count - (SANE_Word) bytes_total), chip->max_block_size); + } + + DBG (7, "usb_low_read_rows: exit, read %d bytes\n", + (SANE_Word) bytes_total); + return SANE_STATUS_GOOD; +} + + +SANE_Status +usb_low_write_reg (ma1017 * chip, SANE_Byte reg_no, SANE_Byte data) +{ + size_t n; + SANE_Status status; + SANE_Byte data_field[2]; + + data_field[0] = data; + data_field[1] = reg_no; + + if (!chip->is_opened) + { + DBG (3, "usb_low_write_reg: open first\n"); + return SANE_STATUS_INVAL; + } + if (chip->is_rowing) + { + DBG (3, "usb_low_write_reg: rowing, stop first\n"); + return SANE_STATUS_INVAL; + } + if (reg_no > 0x20) + { + DBG (3, "usb_low_write_reg: reg_no out of range\n"); + return SANE_STATUS_INVAL; + } + n = 2; + status = sanei_usb_write_bulk (chip->fd, data_field, &n); + if (status != SANE_STATUS_GOOD || n != 2) + { + DBG (3, "usb_low_write_reg: couldn't write, tried to write %d, " + "wrote %lu: %s\n", 2, (unsigned long int) n, + sane_strstatus (status)); + return SANE_STATUS_IO_ERROR; + } + chip->total_write_urbs++; + DBG (7, "usb_low_write_reg: reg: 0x%02x, value: 0x%02x\n", reg_no, data); + return SANE_STATUS_GOOD; +} + +SANE_Status +usb_low_read_reg (ma1017 * chip, SANE_Byte reg_no, SANE_Byte * data) +{ + SANE_Byte data_field[2]; + SANE_Byte read_byte; + size_t n; + SANE_Status status; + + data_field[0] = 0x00; + data_field[1] = reg_no | 0x20; + + if (!chip->is_opened) + { + DBG (3, "usb_low_read_reg: open first\n"); + return SANE_STATUS_INVAL; + } + if (chip->is_rowing) + { + DBG (3, "usb_low_read_reg: rowing, stop first\n"); + return SANE_STATUS_INVAL; + } + if (reg_no > 0x20) + { + DBG (3, "usb_low_read_reg: reg_no out of range\n"); + return SANE_STATUS_INVAL; + } + n = 2; + DBG (5, "usb_low_read_reg: trying to write %lu bytes\n", (unsigned long int) n); + + status = sanei_usb_write_bulk (chip->fd, data_field, &n); + if (status != SANE_STATUS_GOOD || n != 2) + { + DBG (3, "usb_low_read_reg: couldn't write, tried to write %d, " + "wrote %lu: %s\n", 2, (unsigned long int) n, + sane_strstatus (status)); + return SANE_STATUS_IO_ERROR; + } + chip->total_write_urbs++; + n = 1; + DBG (5, "usb_low_read_reg: trying to read %lu bytes\n", (unsigned long int) n); + status = sanei_usb_read_bulk (chip->fd, (SANE_Byte *) & read_byte, &n); + if (status != SANE_STATUS_GOOD || n != 1) + { + DBG (3, "usb_low_read_reg: couldn't read, tried to read %lu, " + "read %lu: %s\n", (unsigned long int) 1, + (unsigned long int) n, sane_strstatus (status)); + return SANE_STATUS_IO_ERROR; + } + chip->total_read_urbs++; + if (data) + *data = read_byte; + DBG (7, "usb_low_read_reg: Reg: 0x%02x, Value: 0x%02x\n", + reg_no, read_byte); + return SANE_STATUS_GOOD; +} + +SANE_Status +usb_low_identify_scanner (SANE_Int fd, Mustek_Type * scanner_type) +{ + SANE_Status status; + SANE_Word devvendor, devproduct; + Mustek_Type devtype; + + DBG (7, "usb_low_identify_scanner: start\n"); + + status = sanei_usb_get_vendor_product (fd, &devvendor, &devproduct); + devtype = MT_UNKNOWN; + if (status == SANE_STATUS_GOOD) + { + if (devvendor == 0x055f) + { + switch (devproduct) + { + case 0x0001: + devtype = MT_1200CU; + break; + case 0x0002: + devtype = MT_600CU; + break; + case 0x0003: + devtype = MT_1200USB; + break; + case 0x0006: + devtype = MT_1200UB; + break; + case 0x0008: + devtype = MT_1200CU_PLUS; + break; + case 0x0873: + devtype = MT_600USB; + break; + default: + if (scanner_type) + *scanner_type = devtype; + DBG (3, "usb_low_identify_scanner: unknown product id: " + "0x%04x\n", devproduct); + return SANE_STATUS_INVAL; + break; + } + } + else + { + if (scanner_type) + *scanner_type = devtype; + DBG (3, "usb_low_identify_scanner: unknown vendor id: 0x%04d\n", + devvendor); + return SANE_STATUS_INVAL; + } + } + if (scanner_type) + *scanner_type = devtype; + DBG (7, "usb_low_identify_scanner: exit\n"); + return SANE_STATUS_GOOD; +} + +SANE_Status +usb_low_open (ma1017 * chip, SANE_String_Const devname) +{ + SANE_Status status; + Mustek_Type scanner_type; + + DBG (7, "usb_low_open: start: chip = %p\n", (void *) chip); + + if (chip->is_rowing) + { + DBG (3, "usb_low_open: already rowing\n"); + return SANE_STATUS_INVAL; + } + if (chip->is_opened) + { + DBG (3, "usb_low_open: already opened\n"); + return SANE_STATUS_INVAL; + } + + status = sanei_usb_open ((SANE_String_Const) devname, &chip->fd); + + if (status == SANE_STATUS_GOOD) + { + DBG (7, "usb_low_open: device %s successfully opened\n", devname); + chip->is_opened = SANE_TRUE; + /* Try to get vendor and device ids */ + DBG (7, "usb_low_open: trying to identify device `%s'\n", devname); + status = usb_low_identify_scanner (chip->fd, &scanner_type); + if (status != SANE_STATUS_GOOD) + { + DBG (3, "usb_low_open: device `%s' doesn't look like a supported " + "scanner\n", devname); + sanei_usb_close (chip->fd); + return status; + } + else + { + if (scanner_type == MT_UNKNOWN) + { + DBG (3, "usb_low_open: device `%s' can't be identified\n", + devname); + } + else if (scanner_type != chip->scanner_type) + { + DBG (3, "usb_low_open: device `%s' is supported but" + "it's not the same as at the start\n", devname); + return SANE_STATUS_INVAL; + } + } + } + else + { + DBG (1, "usb_low_open: device %s couldn't be opened: %s\n", + devname, sane_strstatus (status)); + return status; + } + + chip->is_opened = SANE_TRUE; + + RIE (usb_low_read_all_registers (chip)); + + DBG (7, "usb_low_open: exit, type is %d\n", scanner_type); + return SANE_STATUS_GOOD; +} + +SANE_Status +usb_low_close (ma1017 * chip) +{ + DBG (7, "usb_low_close: start, chip=%p\n", (void *) chip); + if (!chip->is_opened) + { + DBG (3, "usb_low_close: already close or never opened\n"); + return SANE_STATUS_INVAL; + } + + if (chip->fd >= 0) + { + SANE_Byte dummy; + + if (chip->is_rowing) + usb_low_stop_rowing (chip); + /* Now make sure that both the number of written and + read URBs is even. Use some dummy writes/reads. That's to avoid + a nasty bug in the MA 1017 chipset that causes timeouts when + the number of URBs is odd (toggle bug). */ + if ((chip->total_read_urbs % 2) == 1) + usb_low_get_a4 (chip, &dummy); + if ((chip->total_write_urbs % 2) == 1) + usb_low_set_fix_pattern (chip, SANE_FALSE); + sanei_usb_close (chip->fd); + chip->fd = -1; + } + chip->is_opened = SANE_FALSE; + chip->is_rowing = SANE_FALSE; + + DBG (7, "usb_low_close: exit\n"); + return SANE_STATUS_GOOD; +} |