1141cc406Sopenharmony_ci/* SANE - Scanner Access Now Easy. 2141cc406Sopenharmony_ci 3141cc406Sopenharmony_ci Copyright (C) 2011-2020 Rolf Bensch <rolf at bensch hyphen online dot de> 4141cc406Sopenharmony_ci Copyright (C) 2007-2009 Nicolas Martin, <nicols-guest at alioth dot debian dot org> 5141cc406Sopenharmony_ci Copyright (C) 2006-2007 Wittawat Yamwong <wittawat@web.de> 6141cc406Sopenharmony_ci 7141cc406Sopenharmony_ci This file is part of the SANE package. 8141cc406Sopenharmony_ci 9141cc406Sopenharmony_ci This program is free software; you can redistribute it and/or 10141cc406Sopenharmony_ci modify it under the terms of the GNU General Public License as 11141cc406Sopenharmony_ci published by the Free Software Foundation; either version 2 of the 12141cc406Sopenharmony_ci License, or (at your option) any later version. 13141cc406Sopenharmony_ci 14141cc406Sopenharmony_ci This program is distributed in the hope that it will be useful, but 15141cc406Sopenharmony_ci WITHOUT ANY WARRANTY; without even the implied warranty of 16141cc406Sopenharmony_ci MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 17141cc406Sopenharmony_ci General Public License for more details. 18141cc406Sopenharmony_ci 19141cc406Sopenharmony_ci You should have received a copy of the GNU General Public License 20141cc406Sopenharmony_ci along with this program. If not, see <https://www.gnu.org/licenses/>. 21141cc406Sopenharmony_ci 22141cc406Sopenharmony_ci As a special exception, the authors of SANE give permission for 23141cc406Sopenharmony_ci additional uses of the libraries contained in this release of SANE. 24141cc406Sopenharmony_ci 25141cc406Sopenharmony_ci The exception is that, if you link a SANE library with other files 26141cc406Sopenharmony_ci to produce an executable, this does not by itself cause the 27141cc406Sopenharmony_ci resulting executable to be covered by the GNU General Public 28141cc406Sopenharmony_ci License. Your use of that executable is in no way restricted on 29141cc406Sopenharmony_ci account of linking the SANE library code into it. 30141cc406Sopenharmony_ci 31141cc406Sopenharmony_ci This exception does not, however, invalidate any other reasons why 32141cc406Sopenharmony_ci the executable file might be covered by the GNU General Public 33141cc406Sopenharmony_ci License. 34141cc406Sopenharmony_ci 35141cc406Sopenharmony_ci If you submit changes to SANE to the maintainers to be included in 36141cc406Sopenharmony_ci a subsequent release, you agree by submitting the changes that 37141cc406Sopenharmony_ci those changes may be distributed with this exception intact. 38141cc406Sopenharmony_ci 39141cc406Sopenharmony_ci If you write modifications of your own for SANE, it is your choice 40141cc406Sopenharmony_ci whether to permit this exception to apply to your modifications. 41141cc406Sopenharmony_ci If you do not wish that, delete this exception notice. 42141cc406Sopenharmony_ci */ 43141cc406Sopenharmony_ci/* test cases 44141cc406Sopenharmony_ci 1. short USB packet (must be no -ETIMEDOUT) 45141cc406Sopenharmony_ci 2. cancel using button on the printer (look for abort command) 46141cc406Sopenharmony_ci 3. start scan while busy (status 0x1414) 47141cc406Sopenharmony_ci 4. cancel using ctrl-c (must send abort command) 48141cc406Sopenharmony_ci */ 49141cc406Sopenharmony_ci 50141cc406Sopenharmony_ci#define TPU_48 /* uncomment to activate TPU scan at 48 bits */ 51141cc406Sopenharmony_ci/*#define DEBUG_TPU_48*//* uncomment to debug 48 bits TPU on a non TPU device */ 52141cc406Sopenharmony_ci/*#define DEBUG_TPU_24*//* uncomment to debug 24 bits TPU on a non TPU device */ 53141cc406Sopenharmony_ci 54141cc406Sopenharmony_ci/*#define TPUIR_USE_RGB*/ /* uncomment to use RGB channels and convert them to gray; otherwise use R channel only */ 55141cc406Sopenharmony_ci 56141cc406Sopenharmony_ci#include "../include/sane/config.h" 57141cc406Sopenharmony_ci 58141cc406Sopenharmony_ci#include <stdio.h> 59141cc406Sopenharmony_ci#include <stdlib.h> 60141cc406Sopenharmony_ci#include <string.h> 61141cc406Sopenharmony_ci#include <time.h> /* localtime(C90) */ 62141cc406Sopenharmony_ci 63141cc406Sopenharmony_ci#include "pixma_rename.h" 64141cc406Sopenharmony_ci#include "pixma_common.h" 65141cc406Sopenharmony_ci#include "pixma_io.h" 66141cc406Sopenharmony_ci 67141cc406Sopenharmony_ci/* Some macro code to enhance readability */ 68141cc406Sopenharmony_ci#define RET_IF_ERR(x) do { \ 69141cc406Sopenharmony_ci if ((error = (x)) < 0) \ 70141cc406Sopenharmony_ci return error; \ 71141cc406Sopenharmony_ci } while(0) 72141cc406Sopenharmony_ci 73141cc406Sopenharmony_ci#define WAIT_INTERRUPT(x) do { \ 74141cc406Sopenharmony_ci error = handle_interrupt (s, x); \ 75141cc406Sopenharmony_ci if (s->cancel) \ 76141cc406Sopenharmony_ci return PIXMA_ECANCELED; \ 77141cc406Sopenharmony_ci if (error != PIXMA_ECANCELED && error < 0) \ 78141cc406Sopenharmony_ci return error; \ 79141cc406Sopenharmony_ci } while(0) 80141cc406Sopenharmony_ci 81141cc406Sopenharmony_ci#ifdef __GNUC__ 82141cc406Sopenharmony_ci# define UNUSED(v) (void) v 83141cc406Sopenharmony_ci#else 84141cc406Sopenharmony_ci# define UNUSED(v) 85141cc406Sopenharmony_ci#endif 86141cc406Sopenharmony_ci 87141cc406Sopenharmony_ci/* Size of the command buffer should be multiple of wMaxPacketLength and 88141cc406Sopenharmony_ci greater than 4096+24. 89141cc406Sopenharmony_ci 4096 = size of gamma table. 24 = header + checksum */ 90141cc406Sopenharmony_ci#define IMAGE_BLOCK_SIZE (512*1024) 91141cc406Sopenharmony_ci#define CMDBUF_SIZE (4096 + 24) 92141cc406Sopenharmony_ci#define UNKNOWN_PID 0xffff 93141cc406Sopenharmony_ci 94141cc406Sopenharmony_ci#define CANON_VID 0x04a9 95141cc406Sopenharmony_ci 96141cc406Sopenharmony_ci/* Generation 1 */ 97141cc406Sopenharmony_ci#define MP800_PID 0x170d 98141cc406Sopenharmony_ci#define MP800R_PID 0x170e 99141cc406Sopenharmony_ci#define MP830_PID 0x1713 100141cc406Sopenharmony_ci 101141cc406Sopenharmony_ci/* Generation 2 */ 102141cc406Sopenharmony_ci#define MP810_PID 0x171a 103141cc406Sopenharmony_ci#define MP960_PID 0x171b 104141cc406Sopenharmony_ci 105141cc406Sopenharmony_ci/* Generation 3 */ 106141cc406Sopenharmony_ci/* PIXMA 2007 vintage */ 107141cc406Sopenharmony_ci#define MP970_PID 0x1726 108141cc406Sopenharmony_ci 109141cc406Sopenharmony_ci/* Flatbed scanner CCD (2007) */ 110141cc406Sopenharmony_ci#define CS8800F_PID 0x1901 111141cc406Sopenharmony_ci 112141cc406Sopenharmony_ci/* PIXMA 2008 vintage */ 113141cc406Sopenharmony_ci#define MP980_PID 0x172d 114141cc406Sopenharmony_ci 115141cc406Sopenharmony_ci/* Generation 4 */ 116141cc406Sopenharmony_ci#define MP990_PID 0x1740 117141cc406Sopenharmony_ci 118141cc406Sopenharmony_ci/* Flatbed scanner CCD (2010) */ 119141cc406Sopenharmony_ci#define CS9000F_PID 0x1908 120141cc406Sopenharmony_ci 121141cc406Sopenharmony_ci/* 2010 new device (untested) */ 122141cc406Sopenharmony_ci#define MG8100_PID 0x174b /* CCD */ 123141cc406Sopenharmony_ci 124141cc406Sopenharmony_ci/* 2011 new device (untested) */ 125141cc406Sopenharmony_ci#define MG8200_PID 0x1756 /* CCD */ 126141cc406Sopenharmony_ci 127141cc406Sopenharmony_ci/* 2013 new device */ 128141cc406Sopenharmony_ci#define CS9000F_MII_PID 0x190d 129141cc406Sopenharmony_ci 130141cc406Sopenharmony_ci/* Generation 4 XML messages that encapsulates the Pixma protocol messages */ 131141cc406Sopenharmony_ci#define XML_START_1 \ 132141cc406Sopenharmony_ci"<?xml version=\"1.0\" encoding=\"utf-8\" ?>\ 133141cc406Sopenharmony_ci<cmd xmlns:ivec=\"http://www.canon.com/ns/cmd/2008/07/common/\">\ 134141cc406Sopenharmony_ci<ivec:contents><ivec:operation>StartJob</ivec:operation>\ 135141cc406Sopenharmony_ci<ivec:param_set servicetype=\"scan\"><ivec:jobID>00000001</ivec:jobID>\ 136141cc406Sopenharmony_ci<ivec:bidi>1</ivec:bidi></ivec:param_set></ivec:contents></cmd>" 137141cc406Sopenharmony_ci 138141cc406Sopenharmony_ci#define XML_START_2 \ 139141cc406Sopenharmony_ci"<?xml version=\"1.0\" encoding=\"utf-8\" ?>\ 140141cc406Sopenharmony_ci<cmd xmlns:ivec=\"http://www.canon.com/ns/cmd/2008/07/common/\" xmlns:vcn=\"http://www.canon.com/ns/cmd/2008/07/canon/\">\ 141141cc406Sopenharmony_ci<ivec:contents><ivec:operation>VendorCmd</ivec:operation>\ 142141cc406Sopenharmony_ci<ivec:param_set servicetype=\"scan\"><ivec:jobID>00000001</ivec:jobID>\ 143141cc406Sopenharmony_ci<vcn:ijoperation>ModeShift</vcn:ijoperation><vcn:ijmode>1</vcn:ijmode>\ 144141cc406Sopenharmony_ci</ivec:param_set></ivec:contents></cmd>" 145141cc406Sopenharmony_ci 146141cc406Sopenharmony_ci#define XML_END \ 147141cc406Sopenharmony_ci"<?xml version=\"1.0\" encoding=\"utf-8\" ?>\ 148141cc406Sopenharmony_ci<cmd xmlns:ivec=\"http://www.canon.com/ns/cmd/2008/07/common/\">\ 149141cc406Sopenharmony_ci<ivec:contents><ivec:operation>EndJob</ivec:operation>\ 150141cc406Sopenharmony_ci<ivec:param_set servicetype=\"scan\"><ivec:jobID>00000001</ivec:jobID>\ 151141cc406Sopenharmony_ci</ivec:param_set></ivec:contents></cmd>" 152141cc406Sopenharmony_ci 153141cc406Sopenharmony_ci#if !defined(HAVE_LIBXML2) 154141cc406Sopenharmony_ci#define XML_OK "<ivec:response>OK</ivec:response>" 155141cc406Sopenharmony_ci#endif 156141cc406Sopenharmony_ci 157141cc406Sopenharmony_cienum mp810_state_t 158141cc406Sopenharmony_ci{ 159141cc406Sopenharmony_ci state_idle, 160141cc406Sopenharmony_ci state_warmup, 161141cc406Sopenharmony_ci state_scanning, 162141cc406Sopenharmony_ci state_transfering, 163141cc406Sopenharmony_ci state_finished 164141cc406Sopenharmony_ci}; 165141cc406Sopenharmony_ci 166141cc406Sopenharmony_cienum mp810_cmd_t 167141cc406Sopenharmony_ci{ 168141cc406Sopenharmony_ci cmd_start_session = 0xdb20, 169141cc406Sopenharmony_ci cmd_select_source = 0xdd20, 170141cc406Sopenharmony_ci cmd_gamma = 0xee20, 171141cc406Sopenharmony_ci cmd_scan_param = 0xde20, 172141cc406Sopenharmony_ci cmd_status = 0xf320, 173141cc406Sopenharmony_ci cmd_abort_session = 0xef20, 174141cc406Sopenharmony_ci cmd_time = 0xeb80, 175141cc406Sopenharmony_ci cmd_read_image = 0xd420, 176141cc406Sopenharmony_ci cmd_error_info = 0xff20, 177141cc406Sopenharmony_ci 178141cc406Sopenharmony_ci cmd_start_calibrate_ccd_3 = 0xd520, 179141cc406Sopenharmony_ci cmd_end_calibrate_ccd_3 = 0xd720, 180141cc406Sopenharmony_ci cmd_scan_param_3 = 0xd820, 181141cc406Sopenharmony_ci cmd_scan_start_3 = 0xd920, 182141cc406Sopenharmony_ci cmd_status_3 = 0xda20, 183141cc406Sopenharmony_ci cmd_get_tpu_info_3 = 0xf520, 184141cc406Sopenharmony_ci cmd_set_tpu_info_3 = 0xea20, 185141cc406Sopenharmony_ci 186141cc406Sopenharmony_ci cmd_e920 = 0xe920 /* seen in MP800 */ 187141cc406Sopenharmony_ci}; 188141cc406Sopenharmony_ci 189141cc406Sopenharmony_citypedef struct mp810_t 190141cc406Sopenharmony_ci{ 191141cc406Sopenharmony_ci enum mp810_state_t state; 192141cc406Sopenharmony_ci pixma_cmdbuf_t cb; 193141cc406Sopenharmony_ci uint8_t *imgbuf; 194141cc406Sopenharmony_ci uint8_t current_status[16]; 195141cc406Sopenharmony_ci unsigned last_block; 196141cc406Sopenharmony_ci uint8_t generation; 197141cc406Sopenharmony_ci /* for Generation 3 and CCD shift */ 198141cc406Sopenharmony_ci uint8_t *linebuf; 199141cc406Sopenharmony_ci uint8_t *data_left_ofs; 200141cc406Sopenharmony_ci unsigned data_left_len; 201141cc406Sopenharmony_ci int shift[3]; 202141cc406Sopenharmony_ci unsigned color_shift; 203141cc406Sopenharmony_ci unsigned stripe_shift; 204141cc406Sopenharmony_ci unsigned stripe_shift2; /* added for MP810, MP960 at 4800dpi & 9000F at 9600dpi */ 205141cc406Sopenharmony_ci unsigned jumplines; /* added for MP810, MP960 at 4800dpi & 9000F at 9600dpi */ 206141cc406Sopenharmony_ci uint8_t tpu_datalen; 207141cc406Sopenharmony_ci uint8_t tpu_data[0x40]; 208141cc406Sopenharmony_ci} mp810_t; 209141cc406Sopenharmony_ci 210141cc406Sopenharmony_ci/* 211141cc406Sopenharmony_ci STAT: 0x0606 = ok, 212141cc406Sopenharmony_ci 0x1515 = failed (PIXMA_ECANCELED), 213141cc406Sopenharmony_ci 0x1414 = busy (PIXMA_EBUSY) 214141cc406Sopenharmony_ci 215141cc406Sopenharmony_ci Transaction scheme 216141cc406Sopenharmony_ci 1. command_header/data | result_header 217141cc406Sopenharmony_ci 2. command_header | result_header/data 218141cc406Sopenharmony_ci 3. command_header | result_header/image_data 219141cc406Sopenharmony_ci 220141cc406Sopenharmony_ci - data has checksum in the last byte. 221141cc406Sopenharmony_ci - image_data has no checksum. 222141cc406Sopenharmony_ci - data and image_data begins in the same USB packet as 223141cc406Sopenharmony_ci command_header or result_header. 224141cc406Sopenharmony_ci 225141cc406Sopenharmony_ci command format #1: 226141cc406Sopenharmony_ci u16be cmd 227141cc406Sopenharmony_ci u8[6] 0 228141cc406Sopenharmony_ci u8[4] 0 229141cc406Sopenharmony_ci u32be PLEN parameter length 230141cc406Sopenharmony_ci u8[PLEN-1] parameter 231141cc406Sopenharmony_ci u8 parameter check sum 232141cc406Sopenharmony_ci result: 233141cc406Sopenharmony_ci u16be STAT 234141cc406Sopenharmony_ci u8 0 235141cc406Sopenharmony_ci u8 0 or 0x21 if STAT == 0x1414 236141cc406Sopenharmony_ci u8[4] 0 237141cc406Sopenharmony_ci 238141cc406Sopenharmony_ci command format #2: 239141cc406Sopenharmony_ci u16be cmd 240141cc406Sopenharmony_ci u8[6] 0 241141cc406Sopenharmony_ci u8[4] 0 242141cc406Sopenharmony_ci u32be RLEN result length 243141cc406Sopenharmony_ci result: 244141cc406Sopenharmony_ci u16be STAT 245141cc406Sopenharmony_ci u8[6] 0 246141cc406Sopenharmony_ci u8[RLEN-1] result 247141cc406Sopenharmony_ci u8 result check sum 248141cc406Sopenharmony_ci 249141cc406Sopenharmony_ci command format #3: (only used by read_image_block) 250141cc406Sopenharmony_ci u16be 0xd420 251141cc406Sopenharmony_ci u8[6] 0 252141cc406Sopenharmony_ci u8[4] 0 253141cc406Sopenharmony_ci u32be max. block size + 8 254141cc406Sopenharmony_ci result: 255141cc406Sopenharmony_ci u16be STAT 256141cc406Sopenharmony_ci u8[6] 0 257141cc406Sopenharmony_ci u8 block info bitfield: 0x8 = end of scan, 0x10 = no more paper, 0x20 = no more data 258141cc406Sopenharmony_ci u8[3] 0 259141cc406Sopenharmony_ci u32be ILEN image data size 260141cc406Sopenharmony_ci u8[ILEN] image data 261141cc406Sopenharmony_ci */ 262141cc406Sopenharmony_ci 263141cc406Sopenharmony_cistatic void mp810_finish_scan (pixma_t * s); 264141cc406Sopenharmony_ci 265141cc406Sopenharmony_cistatic int is_scanning_from_adf (pixma_t * s) 266141cc406Sopenharmony_ci{ 267141cc406Sopenharmony_ci return (s->param->source == PIXMA_SOURCE_ADF 268141cc406Sopenharmony_ci || s->param->source == PIXMA_SOURCE_ADFDUP); 269141cc406Sopenharmony_ci} 270141cc406Sopenharmony_ci 271141cc406Sopenharmony_cistatic int is_scanning_from_adfdup (pixma_t * s) 272141cc406Sopenharmony_ci{ 273141cc406Sopenharmony_ci return (s->param->source == PIXMA_SOURCE_ADFDUP); 274141cc406Sopenharmony_ci} 275141cc406Sopenharmony_ci 276141cc406Sopenharmony_cistatic int is_scanning_from_tpu (pixma_t * s) 277141cc406Sopenharmony_ci{ 278141cc406Sopenharmony_ci return (s->param->source == PIXMA_SOURCE_TPU); 279141cc406Sopenharmony_ci} 280141cc406Sopenharmony_ci 281141cc406Sopenharmony_cistatic int send_xml_dialog (pixma_t * s, const char * xml_message) 282141cc406Sopenharmony_ci{ 283141cc406Sopenharmony_ci mp810_t *mp = (mp810_t *) s->subdriver; 284141cc406Sopenharmony_ci int datalen; 285141cc406Sopenharmony_ci 286141cc406Sopenharmony_ci datalen = pixma_cmd_transaction (s, xml_message, strlen (xml_message), 287141cc406Sopenharmony_ci mp->cb.buf, 1024); 288141cc406Sopenharmony_ci if (datalen < 0) 289141cc406Sopenharmony_ci return datalen; 290141cc406Sopenharmony_ci 291141cc406Sopenharmony_ci mp->cb.buf[datalen] = 0; 292141cc406Sopenharmony_ci 293141cc406Sopenharmony_ci PDBG(pixma_dbg (10, "XML message sent to scanner:\n%s\n", xml_message)); 294141cc406Sopenharmony_ci PDBG(pixma_dbg (10, "XML response back from scanner:\n%s\n", mp->cb.buf)); 295141cc406Sopenharmony_ci 296141cc406Sopenharmony_ci#if defined(HAVE_LIBXML2) 297141cc406Sopenharmony_ci return pixma_parse_xml_response((const char*)mp->cb.buf) == PIXMA_STATUS_OK; 298141cc406Sopenharmony_ci#else 299141cc406Sopenharmony_ci return (strcasestr ((const char *) mp->cb.buf, XML_OK) != NULL); 300141cc406Sopenharmony_ci#endif 301141cc406Sopenharmony_ci} 302141cc406Sopenharmony_ci 303141cc406Sopenharmony_cistatic void new_cmd_tpu_msg (pixma_t *s, pixma_cmdbuf_t * cb, uint16_t cmd) 304141cc406Sopenharmony_ci{ 305141cc406Sopenharmony_ci pixma_newcmd (cb, cmd, 0, 0); 306141cc406Sopenharmony_ci cb->buf[3] = (is_scanning_from_tpu (s)) ? 0x01 : 0x00; 307141cc406Sopenharmony_ci} 308141cc406Sopenharmony_ci 309141cc406Sopenharmony_cistatic int start_session (pixma_t * s) 310141cc406Sopenharmony_ci{ 311141cc406Sopenharmony_ci mp810_t *mp = (mp810_t *) s->subdriver; 312141cc406Sopenharmony_ci 313141cc406Sopenharmony_ci new_cmd_tpu_msg (s, &mp->cb, cmd_start_session); 314141cc406Sopenharmony_ci return pixma_exec (s, &mp->cb); 315141cc406Sopenharmony_ci} 316141cc406Sopenharmony_ci 317141cc406Sopenharmony_cistatic int start_scan_3 (pixma_t * s) 318141cc406Sopenharmony_ci{ 319141cc406Sopenharmony_ci mp810_t *mp = (mp810_t *) s->subdriver; 320141cc406Sopenharmony_ci 321141cc406Sopenharmony_ci new_cmd_tpu_msg (s, &mp->cb, cmd_scan_start_3); 322141cc406Sopenharmony_ci return pixma_exec (s, &mp->cb); 323141cc406Sopenharmony_ci} 324141cc406Sopenharmony_ci 325141cc406Sopenharmony_cistatic int send_cmd_start_calibrate_ccd_3 (pixma_t * s) 326141cc406Sopenharmony_ci{ 327141cc406Sopenharmony_ci mp810_t *mp = (mp810_t *) s->subdriver; 328141cc406Sopenharmony_ci 329141cc406Sopenharmony_ci pixma_newcmd (&mp->cb, cmd_start_calibrate_ccd_3, 0, 0); 330141cc406Sopenharmony_ci mp->cb.buf[3] = 0x01; 331141cc406Sopenharmony_ci return pixma_exec (s, &mp->cb); 332141cc406Sopenharmony_ci} 333141cc406Sopenharmony_ci 334141cc406Sopenharmony_cistatic int is_calibrated (pixma_t * s) 335141cc406Sopenharmony_ci{ 336141cc406Sopenharmony_ci mp810_t *mp = (mp810_t *) s->subdriver; 337141cc406Sopenharmony_ci if (mp->generation >= 3) 338141cc406Sopenharmony_ci { 339141cc406Sopenharmony_ci return ((mp->current_status[0] & 0x01) == 1); 340141cc406Sopenharmony_ci } 341141cc406Sopenharmony_ci if (mp->generation == 1) 342141cc406Sopenharmony_ci { 343141cc406Sopenharmony_ci return (mp->current_status[8] == 1); 344141cc406Sopenharmony_ci } 345141cc406Sopenharmony_ci else 346141cc406Sopenharmony_ci { 347141cc406Sopenharmony_ci return (mp->current_status[9] == 1); 348141cc406Sopenharmony_ci } 349141cc406Sopenharmony_ci} 350141cc406Sopenharmony_ci 351141cc406Sopenharmony_cistatic int has_paper (pixma_t * s) 352141cc406Sopenharmony_ci{ 353141cc406Sopenharmony_ci mp810_t *mp = (mp810_t *) s->subdriver; 354141cc406Sopenharmony_ci 355141cc406Sopenharmony_ci if (is_scanning_from_adfdup (s)) 356141cc406Sopenharmony_ci return (mp->current_status[1] == 0 || mp->current_status[2] == 0); 357141cc406Sopenharmony_ci else 358141cc406Sopenharmony_ci return (mp->current_status[1] == 0); 359141cc406Sopenharmony_ci} 360141cc406Sopenharmony_ci 361141cc406Sopenharmony_cistatic void drain_bulk_in (pixma_t * s) 362141cc406Sopenharmony_ci{ 363141cc406Sopenharmony_ci mp810_t *mp = (mp810_t *) s->subdriver; 364141cc406Sopenharmony_ci while (pixma_read (s->io, mp->imgbuf, IMAGE_BLOCK_SIZE) >= 0) 365141cc406Sopenharmony_ci ; 366141cc406Sopenharmony_ci} 367141cc406Sopenharmony_ci 368141cc406Sopenharmony_cistatic int abort_session (pixma_t * s) 369141cc406Sopenharmony_ci{ 370141cc406Sopenharmony_ci mp810_t *mp = (mp810_t *) s->subdriver; 371141cc406Sopenharmony_ci return pixma_exec_short_cmd (s, &mp->cb, cmd_abort_session); 372141cc406Sopenharmony_ci} 373141cc406Sopenharmony_ci 374141cc406Sopenharmony_cistatic int send_cmd_e920 (pixma_t * s) 375141cc406Sopenharmony_ci{ 376141cc406Sopenharmony_ci mp810_t *mp = (mp810_t *) s->subdriver; 377141cc406Sopenharmony_ci return pixma_exec_short_cmd (s, &mp->cb, cmd_e920); 378141cc406Sopenharmony_ci} 379141cc406Sopenharmony_ci 380141cc406Sopenharmony_cistatic int select_source (pixma_t * s) 381141cc406Sopenharmony_ci{ 382141cc406Sopenharmony_ci mp810_t *mp = (mp810_t *) s->subdriver; 383141cc406Sopenharmony_ci uint8_t *data; 384141cc406Sopenharmony_ci 385141cc406Sopenharmony_ci data = pixma_newcmd (&mp->cb, cmd_select_source, 12, 0); 386141cc406Sopenharmony_ci data[5] = ((mp->generation == 2) ? 1 : 0); 387141cc406Sopenharmony_ci switch (s->param->source) 388141cc406Sopenharmony_ci { 389141cc406Sopenharmony_ci case PIXMA_SOURCE_FLATBED: 390141cc406Sopenharmony_ci data[0] = 1; 391141cc406Sopenharmony_ci data[1] = 1; 392141cc406Sopenharmony_ci break; 393141cc406Sopenharmony_ci 394141cc406Sopenharmony_ci case PIXMA_SOURCE_ADF: 395141cc406Sopenharmony_ci data[0] = 2; 396141cc406Sopenharmony_ci data[5] = 1; 397141cc406Sopenharmony_ci data[6] = 1; 398141cc406Sopenharmony_ci break; 399141cc406Sopenharmony_ci 400141cc406Sopenharmony_ci case PIXMA_SOURCE_ADFDUP: 401141cc406Sopenharmony_ci data[0] = 2; 402141cc406Sopenharmony_ci data[5] = 3; 403141cc406Sopenharmony_ci data[6] = 3; 404141cc406Sopenharmony_ci break; 405141cc406Sopenharmony_ci 406141cc406Sopenharmony_ci case PIXMA_SOURCE_TPU: 407141cc406Sopenharmony_ci data[0] = 4; 408141cc406Sopenharmony_ci data[1] = 2; 409141cc406Sopenharmony_ci break; 410141cc406Sopenharmony_ci 411141cc406Sopenharmony_ci case PIXMA_SOURCE_NONE: 412141cc406Sopenharmony_ci /* this source can not be selected */ 413141cc406Sopenharmony_ci break; 414141cc406Sopenharmony_ci } 415141cc406Sopenharmony_ci return pixma_exec (s, &mp->cb); 416141cc406Sopenharmony_ci} 417141cc406Sopenharmony_ci 418141cc406Sopenharmony_cistatic int send_get_tpu_info_3 (pixma_t * s) 419141cc406Sopenharmony_ci{ 420141cc406Sopenharmony_ci mp810_t *mp = (mp810_t *) s->subdriver; 421141cc406Sopenharmony_ci uint8_t *data; 422141cc406Sopenharmony_ci int error; 423141cc406Sopenharmony_ci 424141cc406Sopenharmony_ci data = pixma_newcmd (&mp->cb, cmd_get_tpu_info_3, 0, 0x34); 425141cc406Sopenharmony_ci RET_IF_ERR(pixma_exec (s, &mp->cb)); 426141cc406Sopenharmony_ci memcpy (mp->tpu_data, data, 0x34); 427141cc406Sopenharmony_ci return error; 428141cc406Sopenharmony_ci} 429141cc406Sopenharmony_ci 430141cc406Sopenharmony_cistatic int send_set_tpu_info (pixma_t * s) 431141cc406Sopenharmony_ci{ 432141cc406Sopenharmony_ci mp810_t *mp = (mp810_t *) s->subdriver; 433141cc406Sopenharmony_ci uint8_t *data; 434141cc406Sopenharmony_ci 435141cc406Sopenharmony_ci if (mp->tpu_datalen == 0) 436141cc406Sopenharmony_ci return 0; 437141cc406Sopenharmony_ci data = pixma_newcmd (&mp->cb, cmd_set_tpu_info_3, 0x34, 0); 438141cc406Sopenharmony_ci memcpy (data, mp->tpu_data, 0x34); 439141cc406Sopenharmony_ci return pixma_exec (s, &mp->cb); 440141cc406Sopenharmony_ci} 441141cc406Sopenharmony_ci 442141cc406Sopenharmony_cistatic int send_gamma_table (pixma_t * s) 443141cc406Sopenharmony_ci{ 444141cc406Sopenharmony_ci mp810_t *mp = (mp810_t *) s->subdriver; 445141cc406Sopenharmony_ci const uint8_t *lut = s->param->gamma_table; 446141cc406Sopenharmony_ci uint8_t *data; 447141cc406Sopenharmony_ci 448141cc406Sopenharmony_ci if (s->cfg->cap & PIXMA_CAP_GT_4096) 449141cc406Sopenharmony_ci { 450141cc406Sopenharmony_ci data = pixma_newcmd (&mp->cb, cmd_gamma, 4096 + 8, 0); 451141cc406Sopenharmony_ci data[0] = (s->param->channels == 3) ? 0x10 : 0x01; 452141cc406Sopenharmony_ci pixma_set_be16 (0x1004, data + 2); 453141cc406Sopenharmony_ci if (lut) 454141cc406Sopenharmony_ci { 455141cc406Sopenharmony_ci /* PDBG (pixma_dbg (4, "*send_gamma_table***** Use 4096 bytes from LUT ***** \n")); */ 456141cc406Sopenharmony_ci /* PDBG (pixma_hexdump (4, lut, 4096)); */ 457141cc406Sopenharmony_ci memcpy (data + 4, lut, 4096); 458141cc406Sopenharmony_ci } 459141cc406Sopenharmony_ci else 460141cc406Sopenharmony_ci { 461141cc406Sopenharmony_ci /* fallback: we should never see this */ 462141cc406Sopenharmony_ci PDBG (pixma_dbg (4, "*send_gamma_table***** Generate 4096 bytes Table with %f ***** \n", 463141cc406Sopenharmony_ci s->param->gamma)); 464141cc406Sopenharmony_ci pixma_fill_gamma_table (s->param->gamma, data + 4, 4096); 465141cc406Sopenharmony_ci /* PDBG (pixma_hexdump (4, data + 4, 4096)); */ 466141cc406Sopenharmony_ci } 467141cc406Sopenharmony_ci } 468141cc406Sopenharmony_ci else 469141cc406Sopenharmony_ci { 470141cc406Sopenharmony_ci /* Gamma table for 2nd+ generation: 1024 * uint16_le */ 471141cc406Sopenharmony_ci data = pixma_newcmd (&mp->cb, cmd_gamma, 1024 * 2 + 8, 0); 472141cc406Sopenharmony_ci data[0] = 0x10; 473141cc406Sopenharmony_ci pixma_set_be16 (0x0804, data + 2); 474141cc406Sopenharmony_ci if (lut) 475141cc406Sopenharmony_ci { 476141cc406Sopenharmony_ci /* PDBG (pixma_dbg (4, "*send_gamma_table***** Use 1024 * 2 bytes from LUT ***** \n")); */ 477141cc406Sopenharmony_ci /* PDBG (pixma_hexdump (4, lut, 1024 * 2)); */ 478141cc406Sopenharmony_ci memcpy (data + 4, lut, 1024 * 2); 479141cc406Sopenharmony_ci } 480141cc406Sopenharmony_ci else 481141cc406Sopenharmony_ci { 482141cc406Sopenharmony_ci /* fallback: we should never see this */ 483141cc406Sopenharmony_ci PDBG (pixma_dbg (4, "*send_gamma_table***** Generate 1024 * 2 bytes Table with %f ***** \n", 484141cc406Sopenharmony_ci s->param->gamma)); 485141cc406Sopenharmony_ci pixma_fill_gamma_table (s->param->gamma, data + 4, 1024); 486141cc406Sopenharmony_ci /* PDBG (pixma_hexdump (4, data + 4, 1024 * 2)); */ 487141cc406Sopenharmony_ci } 488141cc406Sopenharmony_ci } 489141cc406Sopenharmony_ci return pixma_exec (s, &mp->cb); 490141cc406Sopenharmony_ci} 491141cc406Sopenharmony_ci 492141cc406Sopenharmony_cistatic unsigned calc_raw_width (const mp810_t * mp, 493141cc406Sopenharmony_ci const pixma_scan_param_t * param) 494141cc406Sopenharmony_ci{ 495141cc406Sopenharmony_ci unsigned raw_width; 496141cc406Sopenharmony_ci /* NOTE: Actually, we can send arbitrary width to MP810. Lines returned 497141cc406Sopenharmony_ci are always padded to multiple of 4 or 12 pixels. Is this valid for 498141cc406Sopenharmony_ci other models, too? */ 499141cc406Sopenharmony_ci if (mp->generation >= 2) 500141cc406Sopenharmony_ci { 501141cc406Sopenharmony_ci raw_width = ALIGN_SUP (param->w + param->xs, 32); 502141cc406Sopenharmony_ci /* PDBG (pixma_dbg (4, "*calc_raw_width***** width %u extended by %u and rounded to %u *****\n", param->w, param->xs, raw_width)); */ 503141cc406Sopenharmony_ci } 504141cc406Sopenharmony_ci else if (param->channels == 1) 505141cc406Sopenharmony_ci { 506141cc406Sopenharmony_ci raw_width = ALIGN_SUP (param->w + param->xs, 12); 507141cc406Sopenharmony_ci } 508141cc406Sopenharmony_ci else 509141cc406Sopenharmony_ci { 510141cc406Sopenharmony_ci raw_width = ALIGN_SUP (param->w + param->xs, 4); 511141cc406Sopenharmony_ci } 512141cc406Sopenharmony_ci return raw_width; 513141cc406Sopenharmony_ci} 514141cc406Sopenharmony_ci 515141cc406Sopenharmony_cistatic int has_ccd_sensor (pixma_t * s) 516141cc406Sopenharmony_ci{ 517141cc406Sopenharmony_ci return ((s->cfg->cap & PIXMA_CAP_CCD) != 0); 518141cc406Sopenharmony_ci} 519141cc406Sopenharmony_ci 520141cc406Sopenharmony_ci#if 0 521141cc406Sopenharmony_cistatic int is_color (pixma_t * s) 522141cc406Sopenharmony_ci{ 523141cc406Sopenharmony_ci return (s->param->mode == PIXMA_SCAN_MODE_COLOR); 524141cc406Sopenharmony_ci} 525141cc406Sopenharmony_ci 526141cc406Sopenharmony_cistatic int is_color_48 (pixma_t * s) 527141cc406Sopenharmony_ci{ 528141cc406Sopenharmony_ci return (s->param->mode == PIXMA_SCAN_MODE_COLOR_48); 529141cc406Sopenharmony_ci} 530141cc406Sopenharmony_ci 531141cc406Sopenharmony_cistatic int is_color_negative (pixma_t * s) 532141cc406Sopenharmony_ci{ 533141cc406Sopenharmony_ci return (s->param->mode == PIXMA_SCAN_MODE_NEGATIVE_COLOR); 534141cc406Sopenharmony_ci} 535141cc406Sopenharmony_ci 536141cc406Sopenharmony_cistatic int is_color_all (pixma_t * s) 537141cc406Sopenharmony_ci{ 538141cc406Sopenharmony_ci return (is_color (s) || is_color_48 (s) || is_color_negative (s)); 539141cc406Sopenharmony_ci} 540141cc406Sopenharmony_ci#endif 541141cc406Sopenharmony_ci 542141cc406Sopenharmony_cistatic int is_gray (pixma_t * s) 543141cc406Sopenharmony_ci{ 544141cc406Sopenharmony_ci return (s->param->mode == PIXMA_SCAN_MODE_GRAY); 545141cc406Sopenharmony_ci} 546141cc406Sopenharmony_ci 547141cc406Sopenharmony_cistatic int is_gray_16 (pixma_t * s) 548141cc406Sopenharmony_ci{ 549141cc406Sopenharmony_ci return (s->param->mode == PIXMA_SCAN_MODE_GRAY_16); 550141cc406Sopenharmony_ci} 551141cc406Sopenharmony_ci 552141cc406Sopenharmony_cistatic int is_gray_negative (pixma_t * s) 553141cc406Sopenharmony_ci{ 554141cc406Sopenharmony_ci return (s->param->mode == PIXMA_SCAN_MODE_NEGATIVE_GRAY); 555141cc406Sopenharmony_ci} 556141cc406Sopenharmony_ci 557141cc406Sopenharmony_cistatic int is_gray_all (pixma_t * s) 558141cc406Sopenharmony_ci{ 559141cc406Sopenharmony_ci return (is_gray (s) || is_gray_16 (s) || is_gray_negative (s)); 560141cc406Sopenharmony_ci} 561141cc406Sopenharmony_ci 562141cc406Sopenharmony_cistatic int is_lineart (pixma_t * s) 563141cc406Sopenharmony_ci{ 564141cc406Sopenharmony_ci return (s->param->mode == PIXMA_SCAN_MODE_LINEART); 565141cc406Sopenharmony_ci} 566141cc406Sopenharmony_ci 567141cc406Sopenharmony_cistatic int is_tpuir (pixma_t * s) 568141cc406Sopenharmony_ci{ 569141cc406Sopenharmony_ci return (s->param->mode == PIXMA_SCAN_MODE_TPUIR); 570141cc406Sopenharmony_ci} 571141cc406Sopenharmony_ci 572141cc406Sopenharmony_ci/* CCD sensors don't have neither a Grayscale mode nor a Lineart mode, 573141cc406Sopenharmony_ci * but use color mode instead */ 574141cc406Sopenharmony_cistatic unsigned get_cis_ccd_line_size (pixma_t * s) 575141cc406Sopenharmony_ci{ 576141cc406Sopenharmony_ci return (( 577141cc406Sopenharmony_ci s->param->wx ? s->param->line_size / s->param->w * s->param->wx 578141cc406Sopenharmony_ci : s->param->line_size) 579141cc406Sopenharmony_ci * ((is_tpuir (s) || is_gray_all (s) || is_lineart (s)) ? 3 : 1)); 580141cc406Sopenharmony_ci} 581141cc406Sopenharmony_ci 582141cc406Sopenharmony_cistatic unsigned calc_shifting (pixma_t * s) 583141cc406Sopenharmony_ci{ 584141cc406Sopenharmony_ci mp810_t *mp = (mp810_t *) s->subdriver; 585141cc406Sopenharmony_ci 586141cc406Sopenharmony_ci /* If stripes shift needed (CCD devices), how many pixels shift */ 587141cc406Sopenharmony_ci mp->stripe_shift = 0; 588141cc406Sopenharmony_ci mp->stripe_shift2 = 0; 589141cc406Sopenharmony_ci mp->jumplines = 0; 590141cc406Sopenharmony_ci 591141cc406Sopenharmony_ci switch (s->cfg->pid) 592141cc406Sopenharmony_ci { 593141cc406Sopenharmony_ci case MP800_PID: 594141cc406Sopenharmony_ci case MP800R_PID: 595141cc406Sopenharmony_ci case MP830_PID: 596141cc406Sopenharmony_ci if (s->param->xdpi == 2400) 597141cc406Sopenharmony_ci { 598141cc406Sopenharmony_ci if (is_scanning_from_tpu(s)) 599141cc406Sopenharmony_ci mp->stripe_shift = 6; 600141cc406Sopenharmony_ci else 601141cc406Sopenharmony_ci mp->stripe_shift = 3; 602141cc406Sopenharmony_ci } 603141cc406Sopenharmony_ci if (s->param->ydpi > 75) 604141cc406Sopenharmony_ci { 605141cc406Sopenharmony_ci mp->color_shift = s->param->ydpi / ((s->param->ydpi < 1200) ? 150 : 75); 606141cc406Sopenharmony_ci 607141cc406Sopenharmony_ci if (is_scanning_from_tpu (s)) 608141cc406Sopenharmony_ci mp->color_shift = s->param->ydpi / 75; 609141cc406Sopenharmony_ci 610141cc406Sopenharmony_ci /* If you're trying to decipher this color-shifting code, 611141cc406Sopenharmony_ci the following line is where the magic is revealed. */ 612141cc406Sopenharmony_ci mp->shift[1] = mp->color_shift * get_cis_ccd_line_size (s); 613141cc406Sopenharmony_ci if (is_scanning_from_adf (s)) 614141cc406Sopenharmony_ci { /* ADF */ 615141cc406Sopenharmony_ci mp->shift[0] = 0; 616141cc406Sopenharmony_ci mp->shift[2] = 2 * mp->shift[1]; 617141cc406Sopenharmony_ci } 618141cc406Sopenharmony_ci else 619141cc406Sopenharmony_ci { /* Flatbed or TPU */ 620141cc406Sopenharmony_ci mp->shift[0] = 2 * mp->shift[1]; 621141cc406Sopenharmony_ci mp->shift[2] = 0; 622141cc406Sopenharmony_ci } 623141cc406Sopenharmony_ci } 624141cc406Sopenharmony_ci break; 625141cc406Sopenharmony_ci 626141cc406Sopenharmony_ci case MP970_PID: /* MP970 at 4800 dpi */ 627141cc406Sopenharmony_ci case CS8800F_PID: /* CanoScan 8800F at 4800 dpi */ 628141cc406Sopenharmony_ci if (s->param->xdpi == 4800) 629141cc406Sopenharmony_ci { 630141cc406Sopenharmony_ci if (is_scanning_from_tpu (s)) 631141cc406Sopenharmony_ci mp->stripe_shift = 6; 632141cc406Sopenharmony_ci else 633141cc406Sopenharmony_ci mp->stripe_shift = 3; 634141cc406Sopenharmony_ci } 635141cc406Sopenharmony_ci break; 636141cc406Sopenharmony_ci 637141cc406Sopenharmony_ci case CS9000F_PID: /* CanoScan 9000F at 4800 dpi */ 638141cc406Sopenharmony_ci case CS9000F_MII_PID: 639141cc406Sopenharmony_ci if (s->param->xdpi == 4800) 640141cc406Sopenharmony_ci { 641141cc406Sopenharmony_ci if (is_scanning_from_tpu (s)) 642141cc406Sopenharmony_ci mp->stripe_shift = 6; /* should work for CS9000F same as manual */ 643141cc406Sopenharmony_ci else 644141cc406Sopenharmony_ci mp->stripe_shift = 3; 645141cc406Sopenharmony_ci } 646141cc406Sopenharmony_ci if (s->param->xdpi == 9600) 647141cc406Sopenharmony_ci { 648141cc406Sopenharmony_ci if (is_scanning_from_tpu (s)) 649141cc406Sopenharmony_ci { 650141cc406Sopenharmony_ci /* need to double up for TPU */ 651141cc406Sopenharmony_ci mp->stripe_shift = 6; /* for 1st set of 4 images */ 652141cc406Sopenharmony_ci /* unfortunately there are 2 stripe shifts */ 653141cc406Sopenharmony_ci mp->stripe_shift2 = 6; /* for 2nd set of 4 images */ 654141cc406Sopenharmony_ci mp->jumplines = 32; /* try 33 or 34 */ 655141cc406Sopenharmony_ci } 656141cc406Sopenharmony_ci /* there is no 9600dpi support in flatbed mode */ 657141cc406Sopenharmony_ci } 658141cc406Sopenharmony_ci break; 659141cc406Sopenharmony_ci 660141cc406Sopenharmony_ci case MP960_PID: 661141cc406Sopenharmony_ci if (s->param->xdpi == 2400) 662141cc406Sopenharmony_ci { 663141cc406Sopenharmony_ci if (is_scanning_from_tpu (s)) 664141cc406Sopenharmony_ci mp->stripe_shift = 6; 665141cc406Sopenharmony_ci else 666141cc406Sopenharmony_ci mp->stripe_shift = 3; 667141cc406Sopenharmony_ci } 668141cc406Sopenharmony_ci if (s->param->xdpi == 4800) 669141cc406Sopenharmony_ci { 670141cc406Sopenharmony_ci if (is_scanning_from_tpu (s)) 671141cc406Sopenharmony_ci { 672141cc406Sopenharmony_ci mp->stripe_shift = 6; 673141cc406Sopenharmony_ci mp->stripe_shift2 = 6; 674141cc406Sopenharmony_ci } 675141cc406Sopenharmony_ci else 676141cc406Sopenharmony_ci { 677141cc406Sopenharmony_ci mp->stripe_shift = 3; 678141cc406Sopenharmony_ci mp->stripe_shift2 = 3; 679141cc406Sopenharmony_ci } 680141cc406Sopenharmony_ci mp->jumplines = 33; /* better than 32 or 34 : applies to flatbed & TPU */ 681141cc406Sopenharmony_ci } 682141cc406Sopenharmony_ci break; 683141cc406Sopenharmony_ci 684141cc406Sopenharmony_ci case MP810_PID: 685141cc406Sopenharmony_ci if (s->param->xdpi == 2400) 686141cc406Sopenharmony_ci { 687141cc406Sopenharmony_ci if (is_scanning_from_tpu (s)) 688141cc406Sopenharmony_ci mp->stripe_shift = 6; 689141cc406Sopenharmony_ci else 690141cc406Sopenharmony_ci mp->stripe_shift = 3; 691141cc406Sopenharmony_ci } 692141cc406Sopenharmony_ci if (s->param->xdpi == 4800) 693141cc406Sopenharmony_ci { 694141cc406Sopenharmony_ci if (is_scanning_from_tpu (s)) 695141cc406Sopenharmony_ci { 696141cc406Sopenharmony_ci mp->stripe_shift = 6; 697141cc406Sopenharmony_ci mp->stripe_shift2 = 6; 698141cc406Sopenharmony_ci } 699141cc406Sopenharmony_ci else 700141cc406Sopenharmony_ci { 701141cc406Sopenharmony_ci mp->stripe_shift = 3; 702141cc406Sopenharmony_ci mp->stripe_shift2 = 3; 703141cc406Sopenharmony_ci } 704141cc406Sopenharmony_ci mp->jumplines = 33; /* better than 32 or 34 : applies to flatbed & TPU */ 705141cc406Sopenharmony_ci } 706141cc406Sopenharmony_ci break; 707141cc406Sopenharmony_ci 708141cc406Sopenharmony_ci case MP990_PID: 709141cc406Sopenharmony_ci if (s->param->xdpi == 4800) 710141cc406Sopenharmony_ci { 711141cc406Sopenharmony_ci if (is_scanning_from_tpu (s)) 712141cc406Sopenharmony_ci { 713141cc406Sopenharmony_ci mp->stripe_shift = 6; 714141cc406Sopenharmony_ci mp->stripe_shift2 = 6; 715141cc406Sopenharmony_ci } 716141cc406Sopenharmony_ci else 717141cc406Sopenharmony_ci { 718141cc406Sopenharmony_ci mp->stripe_shift = 3; 719141cc406Sopenharmony_ci mp->stripe_shift2 = 3; 720141cc406Sopenharmony_ci } 721141cc406Sopenharmony_ci mp->jumplines = 34; /* better than 32 or 34 : applies to flatbed & TPU */ 722141cc406Sopenharmony_ci } 723141cc406Sopenharmony_ci break; 724141cc406Sopenharmony_ci 725141cc406Sopenharmony_ci default: /* Default, and all CIS devices */ 726141cc406Sopenharmony_ci break; 727141cc406Sopenharmony_ci } 728141cc406Sopenharmony_ci /* If color plane shift (CCD devices), how many pixels shift */ 729141cc406Sopenharmony_ci mp->color_shift = mp->shift[0] = mp->shift[1] = mp->shift[2] = 0; 730141cc406Sopenharmony_ci if (s->param->ydpi > 75) 731141cc406Sopenharmony_ci { 732141cc406Sopenharmony_ci switch (s->cfg->pid) 733141cc406Sopenharmony_ci { 734141cc406Sopenharmony_ci case MP970_PID: 735141cc406Sopenharmony_ci case CS8800F_PID: /* CanoScan 8800F */ 736141cc406Sopenharmony_ci mp->color_shift = s->param->ydpi / 50; 737141cc406Sopenharmony_ci mp->shift[1] = mp->color_shift * get_cis_ccd_line_size (s); 738141cc406Sopenharmony_ci mp->shift[0] = 0; 739141cc406Sopenharmony_ci mp->shift[2] = 2 * mp->shift[1]; 740141cc406Sopenharmony_ci break; 741141cc406Sopenharmony_ci 742141cc406Sopenharmony_ci case CS9000F_PID: /* CanoScan 9000F */ 743141cc406Sopenharmony_ci case CS9000F_MII_PID: 744141cc406Sopenharmony_ci mp->color_shift = s->param->ydpi / 30; 745141cc406Sopenharmony_ci mp->shift[1] = mp->color_shift * get_cis_ccd_line_size (s); 746141cc406Sopenharmony_ci mp->shift[0] = 0; 747141cc406Sopenharmony_ci mp->shift[2] = 2 * mp->shift[1]; 748141cc406Sopenharmony_ci break; 749141cc406Sopenharmony_ci 750141cc406Sopenharmony_ci case MP980_PID: 751141cc406Sopenharmony_ci case MP990_PID: 752141cc406Sopenharmony_ci case MG8200_PID: 753141cc406Sopenharmony_ci if (s->param->ydpi > 150) 754141cc406Sopenharmony_ci { 755141cc406Sopenharmony_ci mp->color_shift = s->param->ydpi / 75; 756141cc406Sopenharmony_ci mp->shift[1] = mp->color_shift * get_cis_ccd_line_size (s); 757141cc406Sopenharmony_ci mp->shift[0] = 0; 758141cc406Sopenharmony_ci mp->shift[2] = 2 * mp->shift[1]; 759141cc406Sopenharmony_ci } 760141cc406Sopenharmony_ci break; 761141cc406Sopenharmony_ci 762141cc406Sopenharmony_ci case MP810_PID: 763141cc406Sopenharmony_ci case MP960_PID: 764141cc406Sopenharmony_ci mp->color_shift = s->param->ydpi / 50; 765141cc406Sopenharmony_ci if (is_scanning_from_tpu (s)) 766141cc406Sopenharmony_ci mp->color_shift = s->param->ydpi / 50; 767141cc406Sopenharmony_ci mp->shift[1] = mp->color_shift * get_cis_ccd_line_size (s); 768141cc406Sopenharmony_ci mp->shift[0] = 2 * mp->shift[1]; 769141cc406Sopenharmony_ci mp->shift[2] = 0; 770141cc406Sopenharmony_ci break; 771141cc406Sopenharmony_ci 772141cc406Sopenharmony_ci default: 773141cc406Sopenharmony_ci break; 774141cc406Sopenharmony_ci } 775141cc406Sopenharmony_ci } 776141cc406Sopenharmony_ci /* special settings for 16 bit flatbed mode @ 75 dpi 777141cc406Sopenharmony_ci * minimum of 150 dpi is used yet */ 778141cc406Sopenharmony_ci /* else if (!is_scanning_from_tpu (s)) 779141cc406Sopenharmony_ci { 780141cc406Sopenharmony_ci switch (s->cfg->pid) 781141cc406Sopenharmony_ci { 782141cc406Sopenharmony_ci case CS9000F_PID: 783141cc406Sopenharmony_ci case CS9000F_MII_PID: 784141cc406Sopenharmony_ci if (is_color_48 (s) || is_gray_16 (s)) 785141cc406Sopenharmony_ci { 786141cc406Sopenharmony_ci mp->color_shift = 5; 787141cc406Sopenharmony_ci mp->shift[1] = 0; 788141cc406Sopenharmony_ci mp->shift[0] = 0; 789141cc406Sopenharmony_ci mp->shift[2] = 0; 790141cc406Sopenharmony_ci } 791141cc406Sopenharmony_ci break; 792141cc406Sopenharmony_ci } 793141cc406Sopenharmony_ci } */ 794141cc406Sopenharmony_ci /* PDBG (pixma_dbg (4, "*calc_shifing***** color_shift = %u, stripe_shift = %u, jumplines = %u *****\n", 795141cc406Sopenharmony_ci mp->color_shift, mp->stripe_shift, mp->jumplines)); */ 796141cc406Sopenharmony_ci return (2 * mp->color_shift + mp->stripe_shift + mp->jumplines); /* note impact of stripe shift2 later if needed! */ 797141cc406Sopenharmony_ci} 798141cc406Sopenharmony_ci 799141cc406Sopenharmony_cistatic int send_scan_param (pixma_t * s) 800141cc406Sopenharmony_ci{ 801141cc406Sopenharmony_ci mp810_t *mp = (mp810_t *) s->subdriver; 802141cc406Sopenharmony_ci uint8_t *data; 803141cc406Sopenharmony_ci unsigned raw_width = calc_raw_width (mp, s->param); 804141cc406Sopenharmony_ci unsigned h, h1, h2, shifting; 805141cc406Sopenharmony_ci 806141cc406Sopenharmony_ci /* TPU scan does not support lineart */ 807141cc406Sopenharmony_ci if (is_scanning_from_tpu (s) && is_lineart (s)) 808141cc406Sopenharmony_ci { 809141cc406Sopenharmony_ci return PIXMA_ENOTSUP; 810141cc406Sopenharmony_ci } 811141cc406Sopenharmony_ci 812141cc406Sopenharmony_ci shifting = calc_shifting (s); 813141cc406Sopenharmony_ci h1 = s->param->h + shifting; /* add lines for color shifting */ 814141cc406Sopenharmony_ci /* PDBG (pixma_dbg (4, "* send_scan_param: height calc (choose lesser) 1 %u \n", h1 )); */ 815141cc406Sopenharmony_ci if (mp->generation >= 4) /* use most global condition */ 816141cc406Sopenharmony_ci { 817141cc406Sopenharmony_ci /* tested for MP960, 9000F */ 818141cc406Sopenharmony_ci /* add lines for color shifting */ 819141cc406Sopenharmony_ci /* otherwise you cannot scan all lines defined for flatbed mode */ 820141cc406Sopenharmony_ci /* this shouldn't affect TPU mode */ 821141cc406Sopenharmony_ci h2 = s->cfg->height * s->param->ydpi / 75 + shifting; 822141cc406Sopenharmony_ci /* PDBG (pixma_dbg (4, "* send_scan_param: height calc (choose lesser) 2 %u = %u max. lines for scanner + %u lines for color shifting \n", h2, s->cfg->height * s->param->ydpi / 75, shifting )); */ 823141cc406Sopenharmony_ci } 824141cc406Sopenharmony_ci else 825141cc406Sopenharmony_ci { 826141cc406Sopenharmony_ci /* TODO: Check for other scanners. */ 827141cc406Sopenharmony_ci h2 = s->cfg->height * s->param->ydpi / 75; /* this might be causing problems for generation 1 devices */ 828141cc406Sopenharmony_ci /* PDBG (pixma_dbg (4, "* send_scan_param: height calc (choose lesser) 2 %u \n", h2 )); */ 829141cc406Sopenharmony_ci } 830141cc406Sopenharmony_ci h = MIN (h1, h2); 831141cc406Sopenharmony_ci 832141cc406Sopenharmony_ci if (mp->generation <= 2) 833141cc406Sopenharmony_ci { 834141cc406Sopenharmony_ci data = pixma_newcmd (&mp->cb, cmd_scan_param, 0x30, 0); 835141cc406Sopenharmony_ci pixma_set_be16 (s->param->xdpi | 0x8000, data + 0x04); 836141cc406Sopenharmony_ci pixma_set_be16 (s->param->ydpi | 0x8000, data + 0x06); 837141cc406Sopenharmony_ci pixma_set_be32 (s->param->x, data + 0x08); 838141cc406Sopenharmony_ci if (mp->generation == 2) 839141cc406Sopenharmony_ci pixma_set_be32 (s->param->x - s->param->xs, data + 0x08); 840141cc406Sopenharmony_ci pixma_set_be32 (s->param->y, data + 0x0c); 841141cc406Sopenharmony_ci pixma_set_be32 (raw_width, data + 0x10); 842141cc406Sopenharmony_ci pixma_set_be32 (h, data + 0x14); 843141cc406Sopenharmony_ci data[0x18] = 844141cc406Sopenharmony_ci ((s->param->channels != 1) || is_gray_all (s) || is_lineart (s)) ? 845141cc406Sopenharmony_ci 0x08 : 0x04; 846141cc406Sopenharmony_ci data[0x19] = ((s->param->software_lineart) ? 8 : s->param->depth) 847141cc406Sopenharmony_ci * ((is_gray_all (s) || is_lineart (s)) ? 3 : s->param->channels); /* bits per pixel */ 848141cc406Sopenharmony_ci data[0x1a] = (is_scanning_from_tpu (s) ? 1 : 0); 849141cc406Sopenharmony_ci data[0x20] = 0xff; 850141cc406Sopenharmony_ci data[0x23] = 0x81; 851141cc406Sopenharmony_ci data[0x26] = 0x02; 852141cc406Sopenharmony_ci data[0x27] = 0x01; 853141cc406Sopenharmony_ci } 854141cc406Sopenharmony_ci else 855141cc406Sopenharmony_ci { 856141cc406Sopenharmony_ci /* scan parameters: 857141cc406Sopenharmony_ci * ================ 858141cc406Sopenharmony_ci * 859141cc406Sopenharmony_ci * byte | # of | mode | value / description 860141cc406Sopenharmony_ci * | bytes | | 861141cc406Sopenharmony_ci * -----+-------+---------+--------------------------- 862141cc406Sopenharmony_ci * 0x00 | 1 | default | 0x01 863141cc406Sopenharmony_ci * | | adf | 0x02 864141cc406Sopenharmony_ci * | | tpu | 0x04 865141cc406Sopenharmony_ci * | | tpuir | cs9000f: 0x03 866141cc406Sopenharmony_ci * -----+-------+---------+--------------------------- 867141cc406Sopenharmony_ci * 0x01 | 1 | default | 0x00 868141cc406Sopenharmony_ci * | | tpu | 0x02 869141cc406Sopenharmony_ci * -----+-------+---------+--------------------------- 870141cc406Sopenharmony_ci * 0x02 | 1 | default | 0x01 871141cc406Sopenharmony_ci * | | adfdup | 0x03 872141cc406Sopenharmony_ci * -----+-------+---------+--------------------------- 873141cc406Sopenharmony_ci * 0x03 | 1 | default | 0x00 874141cc406Sopenharmony_ci * | | adfdup | 0x03 875141cc406Sopenharmony_ci * -----+-------+---------+--------------------------- 876141cc406Sopenharmony_ci * 0x04 | 1 | all | 0x00 877141cc406Sopenharmony_ci * -----+-------+---------+--------------------------- 878141cc406Sopenharmony_ci * 0x05 | 1 | all | 0x01: This one also seen at 0. Don't know yet what's used for. 879141cc406Sopenharmony_ci * -----+-------+---------+--------------------------- 880141cc406Sopenharmony_ci * ... | 1 | all | 0x00 881141cc406Sopenharmony_ci * -----+-------+---------+--------------------------- 882141cc406Sopenharmony_ci * 0x08 | 2 | all | xdpi | 0x8000 883141cc406Sopenharmony_ci * -----+-------+---------+--------------------------- 884141cc406Sopenharmony_ci * 0x0a | 2 | all | ydpi | 0x8000: Must be the same as xdpi. 885141cc406Sopenharmony_ci * -----+-------+---------+--------------------------- 886141cc406Sopenharmony_ci * 0x0c | 4 | all | x position of start pixel 887141cc406Sopenharmony_ci * -----+-------+---------+--------------------------- 888141cc406Sopenharmony_ci * 0x10 | 4 | all | y position of start pixel 889141cc406Sopenharmony_ci * -----+-------+---------+--------------------------- 890141cc406Sopenharmony_ci * 0x14 | 4 | all | # of pixels in 1 line 891141cc406Sopenharmony_ci * -----+-------+---------+--------------------------- 892141cc406Sopenharmony_ci * 0x18 | 4 | all | # of scan lines 893141cc406Sopenharmony_ci * -----+-------+---------+--------------------------- 894141cc406Sopenharmony_ci * 0x1c | 1 | all | 0x08 895141cc406Sopenharmony_ci * | | | 0x04 = relict from cis scanners? 896141cc406Sopenharmony_ci * -----+-------+---------+--------------------------- 897141cc406Sopenharmony_ci * 0x1d | 1 | all | # of bits per pixel 898141cc406Sopenharmony_ci * -----+-------+---------+--------------------------- 899141cc406Sopenharmony_ci * 0x1e | 1 | default | 0x00: paper 900141cc406Sopenharmony_ci * | | tpu | 0x01: positives 901141cc406Sopenharmony_ci * | | tpu | 0x02: negatives 902141cc406Sopenharmony_ci * | | tpuir | 0x01: positives 903141cc406Sopenharmony_ci * -----+-------+---------+--------------------------- 904141cc406Sopenharmony_ci * 0x1f | 1 | all | 0x01 905141cc406Sopenharmony_ci * | | | cs9000f: 0x00: Not sure if that is because of positives. 906141cc406Sopenharmony_ci * -----+-------+---------+--------------------------- 907141cc406Sopenharmony_ci * 0x20 | 1 | all | 0xff 908141cc406Sopenharmony_ci * -----+-------+---------+--------------------------- 909141cc406Sopenharmony_ci * 0x21 | 1 | all | 0x81 910141cc406Sopenharmony_ci * -----+-------+---------+--------------------------- 911141cc406Sopenharmony_ci * 0x22 | 1 | all | 0x00 912141cc406Sopenharmony_ci * -----+-------+---------+--------------------------- 913141cc406Sopenharmony_ci * 0x23 | 1 | all | 0x02 914141cc406Sopenharmony_ci * -----+-------+---------+--------------------------- 915141cc406Sopenharmony_ci * 0x24 | 1 | all | 0x01 916141cc406Sopenharmony_ci * -----+-------+---------+--------------------------- 917141cc406Sopenharmony_ci * 0x25 | 1 | default | 0x00; cs8800f: 0x01 918141cc406Sopenharmony_ci * | | tpu | 0x00; cs9000f, mg8200, mp990: 0x01 919141cc406Sopenharmony_ci * | | tpuir | cs9000f: 0x00 920141cc406Sopenharmony_ci * -----+-------+---------+--------------------------- 921141cc406Sopenharmony_ci * ... | 1 | all | 0x00 922141cc406Sopenharmony_ci * -----+-------+---------+--------------------------- 923141cc406Sopenharmony_ci * 0x30 | 1 | all | 0x01 924141cc406Sopenharmony_ci * 925141cc406Sopenharmony_ci */ 926141cc406Sopenharmony_ci 927141cc406Sopenharmony_ci data = pixma_newcmd (&mp->cb, cmd_scan_param_3, 0x38, 0); 928141cc406Sopenharmony_ci data[0x00] = is_scanning_from_adf (s) ? 0x02 : 0x01; 929141cc406Sopenharmony_ci data[0x01] = 0x01; 930141cc406Sopenharmony_ci if (is_scanning_from_tpu (s)) 931141cc406Sopenharmony_ci { 932141cc406Sopenharmony_ci data[0x00] = is_tpuir (s) ? 0x03 : 0x04; 933141cc406Sopenharmony_ci data[0x01] = 0x02; 934141cc406Sopenharmony_ci data[0x1e] = 0x02; /* NB: CanoScan 8800F: 0x02->negatives, 0x01->positives, paper->0x00 */ 935141cc406Sopenharmony_ci } 936141cc406Sopenharmony_ci data[0x02] = 0x01; 937141cc406Sopenharmony_ci if (is_scanning_from_adfdup (s)) 938141cc406Sopenharmony_ci { 939141cc406Sopenharmony_ci data[0x02] = 0x03; 940141cc406Sopenharmony_ci data[0x03] = 0x03; 941141cc406Sopenharmony_ci } 942141cc406Sopenharmony_ci data[0x05] = pixma_calc_calibrate (s); 943141cc406Sopenharmony_ci /* the scanner controls the scan */ 944141cc406Sopenharmony_ci /* no software control needed */ 945141cc406Sopenharmony_ci pixma_set_be16 (s->param->xdpi | 0x8000, data + 0x08); 946141cc406Sopenharmony_ci pixma_set_be16 (s->param->ydpi | 0x8000, data + 0x0a); 947141cc406Sopenharmony_ci /*PDBG (pixma_dbg (4, "*send_scan_param***** Setting: xdpi=%hi ydpi=%hi x=%u y=%u w=%u h=%u ***** \n", 948141cc406Sopenharmony_ci s->param->xdpi,s->param->ydpi,(s->param->x)-(s->param->xs),s->param->y,raw_width,h));*/ 949141cc406Sopenharmony_ci pixma_set_be32 (s->param->x - s->param->xs, data + 0x0c); 950141cc406Sopenharmony_ci pixma_set_be32 (s->param->y, data + 0x10); 951141cc406Sopenharmony_ci pixma_set_be32 (raw_width, data + 0x14); 952141cc406Sopenharmony_ci pixma_set_be32 (h, data + 0x18); 953141cc406Sopenharmony_ci data[0x1c] = ((s->param->channels != 1) || is_tpuir (s) || is_gray_all (s) || is_lineart (s)) ? 0x08 : 0x04; 954141cc406Sopenharmony_ci 955141cc406Sopenharmony_ci#ifdef DEBUG_TPU_48 956141cc406Sopenharmony_ci data[0x1d] = 24; 957141cc406Sopenharmony_ci#else 958141cc406Sopenharmony_ci data[0x1d] = (is_scanning_from_tpu (s)) ? 48 959141cc406Sopenharmony_ci : (((s->param->software_lineart) ? 8 : s->param->depth) 960141cc406Sopenharmony_ci * ((is_tpuir (s) || is_gray_all (s) || is_lineart (s)) ? 3 : s->param->channels)); /* bits per pixel */ 961141cc406Sopenharmony_ci#endif 962141cc406Sopenharmony_ci 963141cc406Sopenharmony_ci data[0x1f] = 0x01; /* for 9000F this appears to be 0x00, not sure if that is because of positives */ 964141cc406Sopenharmony_ci 965141cc406Sopenharmony_ci if (s->cfg->pid == CS9000F_PID || s->cfg->pid == CS9000F_MII_PID || s->cfg->pid == MG8200_PID) 966141cc406Sopenharmony_ci { 967141cc406Sopenharmony_ci data[0x1f] = 0x00; 968141cc406Sopenharmony_ci } 969141cc406Sopenharmony_ci 970141cc406Sopenharmony_ci data[0x20] = 0xff; 971141cc406Sopenharmony_ci data[0x21] = 0x81; 972141cc406Sopenharmony_ci data[0x23] = 0x02; 973141cc406Sopenharmony_ci data[0x24] = 0x01; 974141cc406Sopenharmony_ci 975141cc406Sopenharmony_ci /* MG8200 & MP990 addition */ 976141cc406Sopenharmony_ci if (s->cfg->pid == MG8200_PID || s->cfg->pid == MP990_PID) 977141cc406Sopenharmony_ci { 978141cc406Sopenharmony_ci if (is_scanning_from_tpu (s)) 979141cc406Sopenharmony_ci { 980141cc406Sopenharmony_ci data[0x25] = 0x01; 981141cc406Sopenharmony_ci } 982141cc406Sopenharmony_ci } 983141cc406Sopenharmony_ci 984141cc406Sopenharmony_ci /* CS8800F & CS9000F addition */ 985141cc406Sopenharmony_ci if (s->cfg->pid == CS8800F_PID || s->cfg->pid == CS9000F_PID || s->cfg->pid == CS9000F_MII_PID) 986141cc406Sopenharmony_ci { 987141cc406Sopenharmony_ci if (is_scanning_from_tpu (s)) 988141cc406Sopenharmony_ci { /* TPU */ 989141cc406Sopenharmony_ci /* 0x02->negatives, 0x01->positives, paper->0x00 990141cc406Sopenharmony_ci * no paper in TPU mode */ 991141cc406Sopenharmony_ci if (s->param->mode == PIXMA_SCAN_MODE_NEGATIVE_COLOR 992141cc406Sopenharmony_ci || s->param->mode == PIXMA_SCAN_MODE_NEGATIVE_GRAY) 993141cc406Sopenharmony_ci { 994141cc406Sopenharmony_ci PDBG( 995141cc406Sopenharmony_ci pixma_dbg (4, "*send_scan_param***** TPU scan negatives *****\n")); 996141cc406Sopenharmony_ci data[0x1e] = 0x02; 997141cc406Sopenharmony_ci } 998141cc406Sopenharmony_ci else 999141cc406Sopenharmony_ci { 1000141cc406Sopenharmony_ci PDBG( 1001141cc406Sopenharmony_ci pixma_dbg (4, "*send_scan_param***** TPU scan positives *****\n")); 1002141cc406Sopenharmony_ci data[0x1e] = 0x01; 1003141cc406Sopenharmony_ci } 1004141cc406Sopenharmony_ci /* CS8800F: 0x00 for TPU color management */ 1005141cc406Sopenharmony_ci if (s->cfg->pid == CS8800F_PID) 1006141cc406Sopenharmony_ci data[0x25] = 0x00; 1007141cc406Sopenharmony_ci /* CS9000F: 0x01 for TPU */ 1008141cc406Sopenharmony_ci if (s->cfg->pid == CS9000F_PID || s->cfg->pid == CS9000F_MII_PID) 1009141cc406Sopenharmony_ci data[0x25] = 0x01; 1010141cc406Sopenharmony_ci if (s->param->mode == PIXMA_SCAN_MODE_TPUIR) 1011141cc406Sopenharmony_ci data[0x25] = 0x00; 1012141cc406Sopenharmony_ci } 1013141cc406Sopenharmony_ci else 1014141cc406Sopenharmony_ci { /* flatbed and ADF */ 1015141cc406Sopenharmony_ci /* paper->0x00 */ 1016141cc406Sopenharmony_ci data[0x1e] = 0x00; 1017141cc406Sopenharmony_ci /* CS8800F: 0x01 normally */ 1018141cc406Sopenharmony_ci if (s->cfg->pid == CS8800F_PID) 1019141cc406Sopenharmony_ci data[0x25] = 0x01; 1020141cc406Sopenharmony_ci /* CS9000F: 0x00 normally */ 1021141cc406Sopenharmony_ci if (s->cfg->pid == CS9000F_PID || s->cfg->pid == CS9000F_MII_PID) 1022141cc406Sopenharmony_ci data[0x25] = 0x00; 1023141cc406Sopenharmony_ci } 1024141cc406Sopenharmony_ci } 1025141cc406Sopenharmony_ci 1026141cc406Sopenharmony_ci data[0x30] = 0x01; 1027141cc406Sopenharmony_ci } 1028141cc406Sopenharmony_ci return pixma_exec (s, &mp->cb); 1029141cc406Sopenharmony_ci} 1030141cc406Sopenharmony_ci 1031141cc406Sopenharmony_cistatic int query_status_3 (pixma_t * s) 1032141cc406Sopenharmony_ci{ 1033141cc406Sopenharmony_ci mp810_t *mp = (mp810_t *) s->subdriver; 1034141cc406Sopenharmony_ci uint8_t *data; 1035141cc406Sopenharmony_ci int error, status_len; 1036141cc406Sopenharmony_ci 1037141cc406Sopenharmony_ci status_len = 8; 1038141cc406Sopenharmony_ci data = pixma_newcmd (&mp->cb, cmd_status_3, 0, status_len); 1039141cc406Sopenharmony_ci RET_IF_ERR(pixma_exec (s, &mp->cb)); 1040141cc406Sopenharmony_ci memcpy (mp->current_status, data, status_len); 1041141cc406Sopenharmony_ci return error; 1042141cc406Sopenharmony_ci} 1043141cc406Sopenharmony_ci 1044141cc406Sopenharmony_cistatic int query_status (pixma_t * s) 1045141cc406Sopenharmony_ci{ 1046141cc406Sopenharmony_ci mp810_t *mp = (mp810_t *) s->subdriver; 1047141cc406Sopenharmony_ci uint8_t *data; 1048141cc406Sopenharmony_ci int error, status_len; 1049141cc406Sopenharmony_ci 1050141cc406Sopenharmony_ci status_len = (mp->generation == 1) ? 12 : 16; 1051141cc406Sopenharmony_ci data = pixma_newcmd (&mp->cb, cmd_status, 0, status_len); 1052141cc406Sopenharmony_ci RET_IF_ERR(pixma_exec (s, &mp->cb)); 1053141cc406Sopenharmony_ci memcpy (mp->current_status, data, status_len); 1054141cc406Sopenharmony_ci PDBG( 1055141cc406Sopenharmony_ci pixma_dbg (3, "Current status: paper=%u cal=%u lamp=%u busy=%u\n", data[1], data[8], data[7], data[9])); 1056141cc406Sopenharmony_ci return error; 1057141cc406Sopenharmony_ci} 1058141cc406Sopenharmony_ci 1059141cc406Sopenharmony_ci#if 0 1060141cc406Sopenharmony_cistatic int send_time (pixma_t * s) 1061141cc406Sopenharmony_ci{ 1062141cc406Sopenharmony_ci /* Why does a scanner need a time? */ 1063141cc406Sopenharmony_ci time_t now; 1064141cc406Sopenharmony_ci struct tm *t; 1065141cc406Sopenharmony_ci uint8_t *data; 1066141cc406Sopenharmony_ci mp810_t *mp = (mp810_t *) s->subdriver; 1067141cc406Sopenharmony_ci 1068141cc406Sopenharmony_ci data = pixma_newcmd (&mp->cb, cmd_time, 20, 0); 1069141cc406Sopenharmony_ci pixma_get_time (&now, NULL); 1070141cc406Sopenharmony_ci t = localtime (&now); 1071141cc406Sopenharmony_ci strftime ((char *) data, 16, "%y/%m/%d %H:%M", t); 1072141cc406Sopenharmony_ci PDBG(pixma_dbg (3, "Sending time: '%s'\n", (char *) data)); 1073141cc406Sopenharmony_ci return pixma_exec (s, &mp->cb); 1074141cc406Sopenharmony_ci} 1075141cc406Sopenharmony_ci#endif 1076141cc406Sopenharmony_ci 1077141cc406Sopenharmony_ci/* TODO: Simplify this function. Read the whole data packet in one shot. */ 1078141cc406Sopenharmony_cistatic int read_image_block (pixma_t * s, uint8_t * header, uint8_t * data) 1079141cc406Sopenharmony_ci{ 1080141cc406Sopenharmony_ci uint8_t cmd[16]; 1081141cc406Sopenharmony_ci mp810_t *mp = (mp810_t *) s->subdriver; 1082141cc406Sopenharmony_ci const int hlen = 8 + 8; 1083141cc406Sopenharmony_ci int error, datalen; 1084141cc406Sopenharmony_ci 1085141cc406Sopenharmony_ci memset (cmd, 0, sizeof(cmd)); 1086141cc406Sopenharmony_ci /* PDBG (pixma_dbg (4, "* read_image_block: last_block\n", mp->last_block)); */ 1087141cc406Sopenharmony_ci pixma_set_be16 (cmd_read_image, cmd); 1088141cc406Sopenharmony_ci if ((mp->last_block & 0x20) == 0) 1089141cc406Sopenharmony_ci pixma_set_be32 ((IMAGE_BLOCK_SIZE / 65536) * 65536 + 8, cmd + 0xc); 1090141cc406Sopenharmony_ci else 1091141cc406Sopenharmony_ci pixma_set_be32 (32 + 8, cmd + 0xc); 1092141cc406Sopenharmony_ci 1093141cc406Sopenharmony_ci mp->state = state_transfering; 1094141cc406Sopenharmony_ci mp->cb.reslen = pixma_cmd_transaction (s, cmd, sizeof(cmd), mp->cb.buf, 512); /* read 1st 512 bytes of image block */ 1095141cc406Sopenharmony_ci datalen = mp->cb.reslen; 1096141cc406Sopenharmony_ci if (datalen < 0) 1097141cc406Sopenharmony_ci return datalen; 1098141cc406Sopenharmony_ci 1099141cc406Sopenharmony_ci memcpy (header, mp->cb.buf, hlen); 1100141cc406Sopenharmony_ci /* PDBG (pixma_dbg (4, "* read_image_block: datalen %i\n", datalen)); */ 1101141cc406Sopenharmony_ci /* PDBG (pixma_dbg (4, "* read_image_block: hlen %i\n", hlen)); */ 1102141cc406Sopenharmony_ci if (datalen >= hlen) 1103141cc406Sopenharmony_ci { 1104141cc406Sopenharmony_ci datalen -= hlen; 1105141cc406Sopenharmony_ci memcpy (data, mp->cb.buf + hlen, datalen); 1106141cc406Sopenharmony_ci data += datalen; 1107141cc406Sopenharmony_ci if (mp->cb.reslen == 512) 1108141cc406Sopenharmony_ci { /* read the rest of the image block */ 1109141cc406Sopenharmony_ci error = pixma_read (s->io, data, IMAGE_BLOCK_SIZE - 512 + hlen); 1110141cc406Sopenharmony_ci RET_IF_ERR(error); 1111141cc406Sopenharmony_ci datalen += error; 1112141cc406Sopenharmony_ci } 1113141cc406Sopenharmony_ci } 1114141cc406Sopenharmony_ci 1115141cc406Sopenharmony_ci mp->state = state_scanning; 1116141cc406Sopenharmony_ci mp->cb.expected_reslen = 0; 1117141cc406Sopenharmony_ci RET_IF_ERR(pixma_check_result (&mp->cb)); 1118141cc406Sopenharmony_ci if (mp->cb.reslen < hlen) 1119141cc406Sopenharmony_ci return PIXMA_EPROTO; 1120141cc406Sopenharmony_ci return datalen; 1121141cc406Sopenharmony_ci} 1122141cc406Sopenharmony_ci 1123141cc406Sopenharmony_cistatic int read_error_info (pixma_t * s, void *buf, unsigned size) 1124141cc406Sopenharmony_ci{ 1125141cc406Sopenharmony_ci unsigned len = 16; 1126141cc406Sopenharmony_ci mp810_t *mp = (mp810_t *) s->subdriver; 1127141cc406Sopenharmony_ci uint8_t *data; 1128141cc406Sopenharmony_ci int error; 1129141cc406Sopenharmony_ci 1130141cc406Sopenharmony_ci data = pixma_newcmd (&mp->cb, cmd_error_info, 0, len); 1131141cc406Sopenharmony_ci RET_IF_ERR(pixma_exec (s, &mp->cb)); 1132141cc406Sopenharmony_ci if (buf && len < size) 1133141cc406Sopenharmony_ci { 1134141cc406Sopenharmony_ci size = len; 1135141cc406Sopenharmony_ci /* NOTE: I've absolutely no idea what the returned data mean. */ 1136141cc406Sopenharmony_ci memcpy (buf, data, size); 1137141cc406Sopenharmony_ci error = len; 1138141cc406Sopenharmony_ci } 1139141cc406Sopenharmony_ci return error; 1140141cc406Sopenharmony_ci} 1141141cc406Sopenharmony_ci 1142141cc406Sopenharmony_ci/* 1143141cc406Sopenharmony_ci handle_interrupt() waits until it receives an interrupt packet or times out. 1144141cc406Sopenharmony_ci It calls send_time() and query_status() if necessary. Therefore, make sure 1145141cc406Sopenharmony_ci that handle_interrupt() is only called from a safe context for send_time() 1146141cc406Sopenharmony_ci and query_status(). 1147141cc406Sopenharmony_ci 1148141cc406Sopenharmony_ci Returns: 1149141cc406Sopenharmony_ci 0 timed out 1150141cc406Sopenharmony_ci 1 an interrupt packet received 1151141cc406Sopenharmony_ci PIXMA_ECANCELED interrupted by signal 1152141cc406Sopenharmony_ci <0 error 1153141cc406Sopenharmony_ci */ 1154141cc406Sopenharmony_cistatic int handle_interrupt (pixma_t * s, int timeout) 1155141cc406Sopenharmony_ci{ 1156141cc406Sopenharmony_ci uint8_t buf[64]; /* check max. packet size with 'lsusb -v' for "EP 9 IN" */ 1157141cc406Sopenharmony_ci int len; 1158141cc406Sopenharmony_ci 1159141cc406Sopenharmony_ci len = pixma_wait_interrupt (s->io, buf, sizeof(buf), timeout); 1160141cc406Sopenharmony_ci if (len == PIXMA_ETIMEDOUT) 1161141cc406Sopenharmony_ci return 0; 1162141cc406Sopenharmony_ci if (len < 0) 1163141cc406Sopenharmony_ci return len; 1164141cc406Sopenharmony_ci if (len%16) /* len must be a multiple of 16 bytes */ 1165141cc406Sopenharmony_ci { 1166141cc406Sopenharmony_ci PDBG(pixma_dbg (1, "WARNING:unexpected interrupt packet length %d\n", len)); 1167141cc406Sopenharmony_ci return PIXMA_EPROTO; 1168141cc406Sopenharmony_ci } 1169141cc406Sopenharmony_ci 1170141cc406Sopenharmony_ci /* s->event = 0x0brroott 1171141cc406Sopenharmony_ci * b: button 1172141cc406Sopenharmony_ci * oo: original 1173141cc406Sopenharmony_ci * tt: target 1174141cc406Sopenharmony_ci * rr: scan resolution 1175141cc406Sopenharmony_ci * poll event with 'scanimage -A' */ 1176141cc406Sopenharmony_ci if (s->cfg->pid == MG8200_PID) 1177141cc406Sopenharmony_ci /* button no. in buf[7] 1178141cc406Sopenharmony_ci * size in buf[10] 01=A4; 02=Letter; 08=10x15; 09=13x18; 0b=auto 1179141cc406Sopenharmony_ci * format in buf[11] 01=JPEG; 02=TIFF; 03=PDF; 04=Kompakt-PDF 1180141cc406Sopenharmony_ci * dpi in buf[12] 01=75; 02=150; 03=300; 04=600 1181141cc406Sopenharmony_ci * target = format; original = size; scan-resolution = dpi */ 1182141cc406Sopenharmony_ci { 1183141cc406Sopenharmony_ci if (buf[7] & 1) 1184141cc406Sopenharmony_ci { 1185141cc406Sopenharmony_ci /* color scan */ 1186141cc406Sopenharmony_ci s->events = PIXMA_EV_BUTTON1 | (buf[11] & 0x0f) | (buf[10] & 0x0f) << 8 1187141cc406Sopenharmony_ci | (buf[12] & 0x0f) << 16; 1188141cc406Sopenharmony_ci } 1189141cc406Sopenharmony_ci if (buf[7] & 2) 1190141cc406Sopenharmony_ci { 1191141cc406Sopenharmony_ci /* b/w scan */ 1192141cc406Sopenharmony_ci s->events = PIXMA_EV_BUTTON2 | (buf[11] & 0x0f) | (buf[10] & 0x0f) << 8 1193141cc406Sopenharmony_ci | (buf[12] & 0x0f) << 16; 1194141cc406Sopenharmony_ci } 1195141cc406Sopenharmony_ci } 1196141cc406Sopenharmony_ci else if (s->cfg->pid == CS8800F_PID 1197141cc406Sopenharmony_ci || s->cfg->pid == CS9000F_PID 1198141cc406Sopenharmony_ci || s->cfg->pid == CS9000F_MII_PID) 1199141cc406Sopenharmony_ci /* button no. in buf[1] 1200141cc406Sopenharmony_ci * target = button no. 1201141cc406Sopenharmony_ci * "Finish PDF" is Button-2, all others are Button-1 */ 1202141cc406Sopenharmony_ci { 1203141cc406Sopenharmony_ci if ((s->cfg->pid == CS8800F_PID && buf[1] == 0x70) 1204141cc406Sopenharmony_ci || (s->cfg->pid != CS8800F_PID && buf[1] == 0x50)) 1205141cc406Sopenharmony_ci { 1206141cc406Sopenharmony_ci /* button 2 = cancel / end scan */ 1207141cc406Sopenharmony_ci s->events = PIXMA_EV_BUTTON2 | buf[1] >> 4; 1208141cc406Sopenharmony_ci } 1209141cc406Sopenharmony_ci else 1210141cc406Sopenharmony_ci { 1211141cc406Sopenharmony_ci /* button 1 = start scan */ 1212141cc406Sopenharmony_ci s->events = PIXMA_EV_BUTTON1 | buf[1] >> 4; 1213141cc406Sopenharmony_ci } 1214141cc406Sopenharmony_ci } 1215141cc406Sopenharmony_ci else 1216141cc406Sopenharmony_ci /* button no. in buf[0] 1217141cc406Sopenharmony_ci * original in buf[0] 1218141cc406Sopenharmony_ci * target in buf[1] */ 1219141cc406Sopenharmony_ci { 1220141cc406Sopenharmony_ci /* More than one event can be reported at the same time. */ 1221141cc406Sopenharmony_ci if (buf[3] & 1) 1222141cc406Sopenharmony_ci /* FIXME: This function makes trouble with a lot of scanners 1223141cc406Sopenharmony_ci send_time (s); 1224141cc406Sopenharmony_ci */ 1225141cc406Sopenharmony_ci PDBG (pixma_dbg (1, "WARNING:send_time() disabled!\n")); 1226141cc406Sopenharmony_ci if (buf[9] & 2) 1227141cc406Sopenharmony_ci query_status (s); 1228141cc406Sopenharmony_ci 1229141cc406Sopenharmony_ci if (buf[0] & 2) 1230141cc406Sopenharmony_ci { 1231141cc406Sopenharmony_ci /* b/w scan */ 1232141cc406Sopenharmony_ci s->events = PIXMA_EV_BUTTON2 | (buf[1] & 0x0f) | (buf[0] & 0xf0) << 4; 1233141cc406Sopenharmony_ci } 1234141cc406Sopenharmony_ci if (buf[0] & 1) 1235141cc406Sopenharmony_ci { 1236141cc406Sopenharmony_ci /* color scan */ 1237141cc406Sopenharmony_ci s->events = PIXMA_EV_BUTTON1 | (buf[1] & 0x0f) | (buf[0] & 0xf0) << 4; 1238141cc406Sopenharmony_ci } 1239141cc406Sopenharmony_ci } 1240141cc406Sopenharmony_ci return 1; 1241141cc406Sopenharmony_ci} 1242141cc406Sopenharmony_ci 1243141cc406Sopenharmony_cistatic int init_ccd_lamp_3 (pixma_t * s) 1244141cc406Sopenharmony_ci{ 1245141cc406Sopenharmony_ci mp810_t *mp = (mp810_t *) s->subdriver; 1246141cc406Sopenharmony_ci uint8_t *data; 1247141cc406Sopenharmony_ci int error, status_len, tmo; 1248141cc406Sopenharmony_ci 1249141cc406Sopenharmony_ci status_len = 8; 1250141cc406Sopenharmony_ci RET_IF_ERR(query_status (s)); 1251141cc406Sopenharmony_ci RET_IF_ERR(query_status (s)); 1252141cc406Sopenharmony_ci RET_IF_ERR(send_cmd_start_calibrate_ccd_3 (s)); 1253141cc406Sopenharmony_ci RET_IF_ERR(query_status (s)); 1254141cc406Sopenharmony_ci tmo = 20; /* like Windows driver, CCD lamp adjustment */ 1255141cc406Sopenharmony_ci while (--tmo >= 0) 1256141cc406Sopenharmony_ci { 1257141cc406Sopenharmony_ci data = pixma_newcmd (&mp->cb, cmd_end_calibrate_ccd_3, 0, status_len); 1258141cc406Sopenharmony_ci RET_IF_ERR(pixma_exec (s, &mp->cb)); 1259141cc406Sopenharmony_ci memcpy (mp->current_status, data, status_len); 1260141cc406Sopenharmony_ci PDBG(pixma_dbg (3, "Lamp status: %u , timeout in: %u\n", data[0], tmo)); 1261141cc406Sopenharmony_ci if (mp->current_status[0] == 3 || !is_scanning_from_tpu (s)) 1262141cc406Sopenharmony_ci break; 1263141cc406Sopenharmony_ci WAIT_INTERRUPT(1000); 1264141cc406Sopenharmony_ci } 1265141cc406Sopenharmony_ci return error; 1266141cc406Sopenharmony_ci} 1267141cc406Sopenharmony_ci 1268141cc406Sopenharmony_cistatic int wait_until_ready (pixma_t * s) 1269141cc406Sopenharmony_ci{ 1270141cc406Sopenharmony_ci mp810_t *mp = (mp810_t *) s->subdriver; 1271141cc406Sopenharmony_ci int error, tmo = 60; 1272141cc406Sopenharmony_ci 1273141cc406Sopenharmony_ci RET_IF_ERR((mp->generation >= 3) ? query_status_3 (s) : query_status (s)); 1274141cc406Sopenharmony_ci while (!is_calibrated (s)) 1275141cc406Sopenharmony_ci { 1276141cc406Sopenharmony_ci WAIT_INTERRUPT(1000); 1277141cc406Sopenharmony_ci if (mp->generation >= 3) 1278141cc406Sopenharmony_ci RET_IF_ERR(query_status_3 (s)); 1279141cc406Sopenharmony_ci else if (s->cfg->pid == MP800R_PID) 1280141cc406Sopenharmony_ci RET_IF_ERR (query_status (s)); 1281141cc406Sopenharmony_ci if (--tmo == 0) 1282141cc406Sopenharmony_ci { 1283141cc406Sopenharmony_ci PDBG(pixma_dbg (1, "WARNING: Timed out in wait_until_ready()\n")); 1284141cc406Sopenharmony_ci PDBG(query_status (s)); 1285141cc406Sopenharmony_ci return PIXMA_ETIMEDOUT; 1286141cc406Sopenharmony_ci } 1287141cc406Sopenharmony_ci } 1288141cc406Sopenharmony_ci return 0; 1289141cc406Sopenharmony_ci} 1290141cc406Sopenharmony_ci 1291141cc406Sopenharmony_ci/* the RGB images are shifted by # of lines */ 1292141cc406Sopenharmony_ci/* the R image is shifted by colshift[0] */ 1293141cc406Sopenharmony_ci/* the G image is shifted by colshift[1] */ 1294141cc406Sopenharmony_ci/* the B image is shifted by colshift[2] */ 1295141cc406Sopenharmony_ci/* usually one of the RGB images must not be shifted */ 1296141cc406Sopenharmony_ci/* which one depends on the scanner */ 1297141cc406Sopenharmony_ci/* some scanners have an additional stripe shift */ 1298141cc406Sopenharmony_ci/* e.g. colshift[0]=0, colshift[1]=1, colshift[2]=2 */ 1299141cc406Sopenharmony_ci/* R image is OK: RGBRGBRGB... */ 1300141cc406Sopenharmony_ci/* ^^ ^^ ^^ */ 1301141cc406Sopenharmony_ci/* || || || */ 1302141cc406Sopenharmony_ci/* shift G image: RG|RG|RG|... */ 1303141cc406Sopenharmony_ci/* | | | */ 1304141cc406Sopenharmony_ci/* shift B image: RGBRGBRGB... */ 1305141cc406Sopenharmony_ci/* this doesn't affect the G and B images */ 1306141cc406Sopenharmony_ci/* G image will become the R image in the next run */ 1307141cc406Sopenharmony_ci/* B image will become the G image in the next run */ 1308141cc406Sopenharmony_ci/* the next line will become the B image in the next run */ 1309141cc406Sopenharmony_cistatic uint8_t * 1310141cc406Sopenharmony_cishift_colors (uint8_t * dptr, uint8_t * sptr, unsigned w, unsigned dpi, 1311141cc406Sopenharmony_ci unsigned pid, unsigned c, int * colshft, unsigned strshft) 1312141cc406Sopenharmony_ci{ 1313141cc406Sopenharmony_ci unsigned i, sr, sg, sb, st; 1314141cc406Sopenharmony_ci UNUSED(dpi); 1315141cc406Sopenharmony_ci UNUSED(pid); 1316141cc406Sopenharmony_ci sr = colshft[0]; 1317141cc406Sopenharmony_ci sg = colshft[1]; 1318141cc406Sopenharmony_ci sb = colshft[2]; 1319141cc406Sopenharmony_ci 1320141cc406Sopenharmony_ci /* PDBG (pixma_dbg (4, "*shift_colors***** c=%u, w=%i, sr=%u, sg=%u, sb=%u, strshft=%u ***** \n", 1321141cc406Sopenharmony_ci c, w, sr, sg, sb, strshft)); */ 1322141cc406Sopenharmony_ci 1323141cc406Sopenharmony_ci for (i = 0; i < w; i++) 1324141cc406Sopenharmony_ci { 1325141cc406Sopenharmony_ci /* stripes shift for MP970 at 4800 dpi, MP810 at 2400 dpi */ 1326141cc406Sopenharmony_ci st = (i % 2 == 0) ? strshft : 0; 1327141cc406Sopenharmony_ci 1328141cc406Sopenharmony_ci *sptr++ = *(dptr++ + sr + st); 1329141cc406Sopenharmony_ci if (c == 6) 1330141cc406Sopenharmony_ci *sptr++ = *(dptr++ + sr + st); 1331141cc406Sopenharmony_ci *sptr++ = *(dptr++ + sg + st); 1332141cc406Sopenharmony_ci if (c == 6) 1333141cc406Sopenharmony_ci *sptr++ = *(dptr++ + sg + st); 1334141cc406Sopenharmony_ci *sptr++ = *(dptr++ + sb + st); 1335141cc406Sopenharmony_ci if (c == 6) 1336141cc406Sopenharmony_ci *sptr++ = *(dptr++ + sb + st); 1337141cc406Sopenharmony_ci } 1338141cc406Sopenharmony_ci 1339141cc406Sopenharmony_ci return dptr; 1340141cc406Sopenharmony_ci} 1341141cc406Sopenharmony_ci 1342141cc406Sopenharmony_cistatic uint8_t * 1343141cc406Sopenharmony_cishift_colorsCS9000 (uint8_t * dptr, uint8_t * sptr, unsigned w, unsigned dpi, 1344141cc406Sopenharmony_ci unsigned pid, unsigned c, int * colshft, unsigned strshft, 1345141cc406Sopenharmony_ci unsigned strshft2, unsigned jump) 1346141cc406Sopenharmony_ci 1347141cc406Sopenharmony_ci{ 1348141cc406Sopenharmony_ci unsigned i, sr, sg, sb, st, st2; 1349141cc406Sopenharmony_ci UNUSED(dpi); 1350141cc406Sopenharmony_ci UNUSED(pid); 1351141cc406Sopenharmony_ci sr = colshft[0]; 1352141cc406Sopenharmony_ci sg = colshft[1]; 1353141cc406Sopenharmony_ci sb = colshft[2]; 1354141cc406Sopenharmony_ci 1355141cc406Sopenharmony_ci for (i = 0; i < w; i++) 1356141cc406Sopenharmony_ci { 1357141cc406Sopenharmony_ci if (i < (w / 2)) 1358141cc406Sopenharmony_ci { 1359141cc406Sopenharmony_ci /* stripes shift for 1st 4 images for Canoscan 9000F at 9600dpi */ 1360141cc406Sopenharmony_ci st = (i % 2 == 0) ? strshft : 0; 1361141cc406Sopenharmony_ci *sptr++ = *(dptr++ + sr + st); 1362141cc406Sopenharmony_ci if (c == 6) 1363141cc406Sopenharmony_ci *sptr++ = *(dptr++ + sr + st); 1364141cc406Sopenharmony_ci *sptr++ = *(dptr++ + sg + st); 1365141cc406Sopenharmony_ci if (c == 6) 1366141cc406Sopenharmony_ci *sptr++ = *(dptr++ + sg + st); 1367141cc406Sopenharmony_ci *sptr++ = *(dptr++ + sb + st); 1368141cc406Sopenharmony_ci if (c == 6) 1369141cc406Sopenharmony_ci *sptr++ = *(dptr++ + sb + st); 1370141cc406Sopenharmony_ci } 1371141cc406Sopenharmony_ci if (i >= (w / 2)) 1372141cc406Sopenharmony_ci { 1373141cc406Sopenharmony_ci /* stripes shift for 2nd 4 images for Canoscan 9000F at 9600dpi */ 1374141cc406Sopenharmony_ci st2 = (i % 2 == 0) ? strshft2 : 0; 1375141cc406Sopenharmony_ci *sptr++ = *(dptr++ + sr + jump + st2); 1376141cc406Sopenharmony_ci if (c == 6) 1377141cc406Sopenharmony_ci *sptr++ = *(dptr++ + sr + jump + st2); 1378141cc406Sopenharmony_ci *sptr++ = *(dptr++ + sg + jump + st2); 1379141cc406Sopenharmony_ci if (c == 6) 1380141cc406Sopenharmony_ci *sptr++ = *(dptr++ + sg + jump + st2); 1381141cc406Sopenharmony_ci *sptr++ = *(dptr++ + sb + jump + st2); 1382141cc406Sopenharmony_ci if (c == 6) 1383141cc406Sopenharmony_ci *sptr++ = *(dptr++ + sb + jump + st2); 1384141cc406Sopenharmony_ci } 1385141cc406Sopenharmony_ci } 1386141cc406Sopenharmony_ci return dptr; 1387141cc406Sopenharmony_ci} 1388141cc406Sopenharmony_ci 1389141cc406Sopenharmony_cistatic uint8_t * 1390141cc406Sopenharmony_cishift_colorsCS9000_4800 (uint8_t * dptr, uint8_t * sptr, unsigned w, 1391141cc406Sopenharmony_ci unsigned dpi, unsigned pid, unsigned c, int * colshft, 1392141cc406Sopenharmony_ci unsigned strshft, unsigned strshft2, unsigned jump) 1393141cc406Sopenharmony_ci 1394141cc406Sopenharmony_ci{ 1395141cc406Sopenharmony_ci unsigned i, sr, sg, sb, st2; 1396141cc406Sopenharmony_ci UNUSED(dpi); 1397141cc406Sopenharmony_ci UNUSED(pid); 1398141cc406Sopenharmony_ci UNUSED(strshft); 1399141cc406Sopenharmony_ci sr = colshft[0]; 1400141cc406Sopenharmony_ci sg = colshft[1]; 1401141cc406Sopenharmony_ci sb = colshft[2]; 1402141cc406Sopenharmony_ci 1403141cc406Sopenharmony_ci for (i = 0; i < w; i++) 1404141cc406Sopenharmony_ci { 1405141cc406Sopenharmony_ci /* stripes shift for 2nd 4 images 1406141cc406Sopenharmony_ci * for Canoscan 9000F with 16 bit flatbed scans at 4800dpi */ 1407141cc406Sopenharmony_ci st2 = (i % 2 == 0) ? strshft2 : 0; 1408141cc406Sopenharmony_ci *sptr++ = *(dptr++ + sr + jump + st2); 1409141cc406Sopenharmony_ci if (c == 6) 1410141cc406Sopenharmony_ci *sptr++ = *(dptr++ + sr + jump + st2); 1411141cc406Sopenharmony_ci *sptr++ = *(dptr++ + sg + jump + st2); 1412141cc406Sopenharmony_ci if (c == 6) 1413141cc406Sopenharmony_ci *sptr++ = *(dptr++ + sg + jump + st2); 1414141cc406Sopenharmony_ci *sptr++ = *(dptr++ + sb + jump + st2); 1415141cc406Sopenharmony_ci if (c == 6) 1416141cc406Sopenharmony_ci *sptr++ = *(dptr++ + sb + jump + st2); 1417141cc406Sopenharmony_ci } 1418141cc406Sopenharmony_ci return dptr; 1419141cc406Sopenharmony_ci} 1420141cc406Sopenharmony_ci 1421141cc406Sopenharmony_ci/* under some conditions some scanners have sub images in one line */ 1422141cc406Sopenharmony_ci/* e.g. doubled image, line size = 8 */ 1423141cc406Sopenharmony_ci/* line before reordering: px1 px3 px5 px7 px2 px4 px6 px8 */ 1424141cc406Sopenharmony_ci/* line after reordering: px1 px2 px3 px4 px5 px6 px7 px8 */ 1425141cc406Sopenharmony_cistatic void reorder_pixels (uint8_t * linebuf, uint8_t * sptr, unsigned c, 1426141cc406Sopenharmony_ci unsigned n, unsigned m, unsigned w, 1427141cc406Sopenharmony_ci unsigned line_size) 1428141cc406Sopenharmony_ci{ 1429141cc406Sopenharmony_ci unsigned i; 1430141cc406Sopenharmony_ci 1431141cc406Sopenharmony_ci for (i = 0; i < w; i++) 1432141cc406Sopenharmony_ci { /* process complete line */ 1433141cc406Sopenharmony_ci memcpy (linebuf + c * (n * (i % m) + i / m), sptr + c * i, c); 1434141cc406Sopenharmony_ci } 1435141cc406Sopenharmony_ci memcpy (sptr, linebuf, line_size); 1436141cc406Sopenharmony_ci} 1437141cc406Sopenharmony_ci 1438141cc406Sopenharmony_ci/* special reorder matrix for mp960 */ 1439141cc406Sopenharmony_cistatic void mp960_reorder_pixels (uint8_t * linebuf, uint8_t * sptr, unsigned c, 1440141cc406Sopenharmony_ci unsigned n, unsigned m, unsigned w, 1441141cc406Sopenharmony_ci unsigned line_size) 1442141cc406Sopenharmony_ci{ 1443141cc406Sopenharmony_ci unsigned i, i2; 1444141cc406Sopenharmony_ci 1445141cc406Sopenharmony_ci /* try and copy 2 px at once */ 1446141cc406Sopenharmony_ci for (i = 0; i < w; i++) 1447141cc406Sopenharmony_ci { /* process complete line */ 1448141cc406Sopenharmony_ci i2 = i % 2; 1449141cc406Sopenharmony_ci if (i < w / 2) 1450141cc406Sopenharmony_ci { 1451141cc406Sopenharmony_ci if (i2 == 0) 1452141cc406Sopenharmony_ci memcpy (linebuf + c * (n * ((i) % m) + ((i) / m)), sptr + c * i, c); 1453141cc406Sopenharmony_ci else 1454141cc406Sopenharmony_ci memcpy (linebuf + c * (n * ((i - 1) % m) + 1 + ((i) / m)), sptr + c * i, c); 1455141cc406Sopenharmony_ci } 1456141cc406Sopenharmony_ci else 1457141cc406Sopenharmony_ci { 1458141cc406Sopenharmony_ci if (i2 == 0) 1459141cc406Sopenharmony_ci memcpy (linebuf + c * (n * ((i) % m) + ((i) / m) + 1), sptr + c * i, c); 1460141cc406Sopenharmony_ci else 1461141cc406Sopenharmony_ci memcpy (linebuf + c * (n * ((i - 1) % m) + 1 + ((i) / m) + 1), sptr + c * i, c); 1462141cc406Sopenharmony_ci } 1463141cc406Sopenharmony_ci } 1464141cc406Sopenharmony_ci 1465141cc406Sopenharmony_ci memcpy (sptr, linebuf, line_size); 1466141cc406Sopenharmony_ci} 1467141cc406Sopenharmony_ci 1468141cc406Sopenharmony_ci/* special reorder matrix for mp970 */ 1469141cc406Sopenharmony_cistatic void mp970_reorder_pixels (uint8_t * linebuf, uint8_t * sptr, unsigned c, 1470141cc406Sopenharmony_ci unsigned w, unsigned line_size) 1471141cc406Sopenharmony_ci{ 1472141cc406Sopenharmony_ci unsigned i, i8; 1473141cc406Sopenharmony_ci 1474141cc406Sopenharmony_ci for (i = 0; i < w; i++) 1475141cc406Sopenharmony_ci { /* process complete line */ 1476141cc406Sopenharmony_ci i8 = i % 8; 1477141cc406Sopenharmony_ci memcpy (linebuf + c * (i + i8 - ((i8 > 3) ? 7 : 0)), sptr + c * i, c); 1478141cc406Sopenharmony_ci } 1479141cc406Sopenharmony_ci memcpy (sptr, linebuf, line_size); 1480141cc406Sopenharmony_ci} 1481141cc406Sopenharmony_ci 1482141cc406Sopenharmony_ci/* special reorder matrix for CS9000F */ 1483141cc406Sopenharmony_cistatic void cs9000f_initial_reorder_pixels (uint8_t * linebuf, uint8_t * sptr, 1484141cc406Sopenharmony_ci unsigned c, unsigned n, unsigned m, 1485141cc406Sopenharmony_ci unsigned w, unsigned line_size) 1486141cc406Sopenharmony_ci{ 1487141cc406Sopenharmony_ci unsigned i, i2; 1488141cc406Sopenharmony_ci 1489141cc406Sopenharmony_ci /* try and copy 2 px at once */ 1490141cc406Sopenharmony_ci for (i = 0; i < w; i++) 1491141cc406Sopenharmony_ci { /* process complete line */ 1492141cc406Sopenharmony_ci i2 = i % 2; 1493141cc406Sopenharmony_ci if (i < w / 8) 1494141cc406Sopenharmony_ci { 1495141cc406Sopenharmony_ci if (i2 == 0) 1496141cc406Sopenharmony_ci memcpy (linebuf + c * (n * ((i) % m) + ((i) / m)), sptr + c * i, c); 1497141cc406Sopenharmony_ci else 1498141cc406Sopenharmony_ci memcpy (linebuf + c * (n * ((i - 1) % m) + 1 + ((i) / m)), sptr + c * i, c); 1499141cc406Sopenharmony_ci } 1500141cc406Sopenharmony_ci else if (i >= w / 8 && i < w / 4) 1501141cc406Sopenharmony_ci { 1502141cc406Sopenharmony_ci if (i2 == 0) 1503141cc406Sopenharmony_ci memcpy (linebuf + c * (n * ((i) % m) + ((i) / m) + 1), sptr + c * i, c); 1504141cc406Sopenharmony_ci else 1505141cc406Sopenharmony_ci memcpy (linebuf + c * (n * ((i - 1) % m) + 1 + ((i) / m) + 1), sptr + c * i, c); 1506141cc406Sopenharmony_ci } 1507141cc406Sopenharmony_ci else if (i >= w / 4 && i < 3 * w / 8) 1508141cc406Sopenharmony_ci { 1509141cc406Sopenharmony_ci if (i2 == 0) 1510141cc406Sopenharmony_ci memcpy (linebuf + c * (n * ((i) % m) + ((i) / m) + 2), sptr + c * i, c); 1511141cc406Sopenharmony_ci else 1512141cc406Sopenharmony_ci memcpy (linebuf + c * (n * ((i - 1) % m) + 1 + ((i) / m) + 2), sptr + c * i, c); 1513141cc406Sopenharmony_ci } 1514141cc406Sopenharmony_ci else if (i >= 3 * w / 8 && i < w / 2) 1515141cc406Sopenharmony_ci { 1516141cc406Sopenharmony_ci if (i2 == 0) 1517141cc406Sopenharmony_ci memcpy (linebuf + c * (n * ((i) % m) + ((i) / m) + 3), sptr + c * i, c); 1518141cc406Sopenharmony_ci else 1519141cc406Sopenharmony_ci memcpy (linebuf + c * (n * ((i - 1) % m) + 1 + ((i) / m) + 3), sptr + c * i, c); 1520141cc406Sopenharmony_ci } 1521141cc406Sopenharmony_ci else if (i >= w / 2 && i < 5 * w / 8) 1522141cc406Sopenharmony_ci { 1523141cc406Sopenharmony_ci if (i2 == 0) 1524141cc406Sopenharmony_ci memcpy (linebuf + c * (n * ((i) % m) + ((i) / m) + 4), sptr + c * i, c); 1525141cc406Sopenharmony_ci else 1526141cc406Sopenharmony_ci memcpy (linebuf + c * (n * ((i - 1) % m) + 1 + ((i) / m) + 4), sptr + c * i, c); 1527141cc406Sopenharmony_ci } 1528141cc406Sopenharmony_ci else if (i >= 5 * w / 8 && i < 3 * w / 4) 1529141cc406Sopenharmony_ci { 1530141cc406Sopenharmony_ci if (i2 == 0) 1531141cc406Sopenharmony_ci memcpy (linebuf + c * (n * ((i) % m) + ((i) / m) + 5), sptr + c * i, c); 1532141cc406Sopenharmony_ci else 1533141cc406Sopenharmony_ci memcpy (linebuf + c * (n * ((i - 1) % m) + 1 + ((i) / m) + 5), sptr + c * i, c); 1534141cc406Sopenharmony_ci } 1535141cc406Sopenharmony_ci else if (i >= 3 * w / 4 && i < 7 * w / 8) 1536141cc406Sopenharmony_ci { 1537141cc406Sopenharmony_ci if (i2 == 0) 1538141cc406Sopenharmony_ci memcpy (linebuf + c * (n * ((i) % m) + ((i) / m) + 6), sptr + c * i, c); 1539141cc406Sopenharmony_ci else 1540141cc406Sopenharmony_ci memcpy (linebuf + c * (n * ((i - 1) % m) + 1 + ((i) / m) + 6), sptr + c * i, c); 1541141cc406Sopenharmony_ci } 1542141cc406Sopenharmony_ci else 1543141cc406Sopenharmony_ci { 1544141cc406Sopenharmony_ci if (i2 == 0) 1545141cc406Sopenharmony_ci memcpy (linebuf + c * (n * ((i) % m) + ((i) / m) + 7), sptr + c * i, c); 1546141cc406Sopenharmony_ci else 1547141cc406Sopenharmony_ci memcpy (linebuf + c * (n * ((i - 1) % m) + 1 + ((i) / m) + 7), sptr + c * i, c); 1548141cc406Sopenharmony_ci } 1549141cc406Sopenharmony_ci } 1550141cc406Sopenharmony_ci 1551141cc406Sopenharmony_ci memcpy (sptr, linebuf, line_size); 1552141cc406Sopenharmony_ci} 1553141cc406Sopenharmony_ci 1554141cc406Sopenharmony_ci/* CS9000F 9600dpi reorder: actually 4800dpi since each pixel is doubled */ 1555141cc406Sopenharmony_ci/* need to rearrange each sequence of 16 pairs of pixels as follows: */ 1556141cc406Sopenharmony_ci/* start px : 0 2 4 6 8 10 12 14 16 18 20 22 24 26 28 30 */ 1557141cc406Sopenharmony_ci/* before : p1a p1b p1c p1d p2a p2b p2c p2d p3a p3b p3c p3d p4a p4b p4c p4d */ 1558141cc406Sopenharmony_ci/* after : p1a p3a p1b p3b p1c p3c p1d p3d p2a p4a p2b p4b p2c p4c p2d p4d */ 1559141cc406Sopenharmony_ci/* start px : 0 16 2 18 4 20 6 22 8 24 10 26 12 28 14 30 */ 1560141cc406Sopenharmony_ci/* change : * * * * * * * * * * * * * * */ 1561141cc406Sopenharmony_ci/* no change: * * */ 1562141cc406Sopenharmony_ci/* so the 1st and the 3rd set are interleaved, followed by the 2nd and 4th sets interleaved */ 1563141cc406Sopenharmony_cistatic void cs9000f_second_reorder_pixels (uint8_t * linebuf, uint8_t * sptr, 1564141cc406Sopenharmony_ci unsigned c, unsigned w, 1565141cc406Sopenharmony_ci unsigned line_size) 1566141cc406Sopenharmony_ci{ 1567141cc406Sopenharmony_ci unsigned i, i8; 1568141cc406Sopenharmony_ci static const int shifts[8] = 1569141cc406Sopenharmony_ci { 2, 4, 6, 8, -8, -6, -4, -2 }; 1570141cc406Sopenharmony_ci 1571141cc406Sopenharmony_ci for (i = 0; i < w; i += 2) 1572141cc406Sopenharmony_ci { /* process complete line */ 1573141cc406Sopenharmony_ci i8 = (i >> 1) & 0x7; 1574141cc406Sopenharmony_ci /* Copy 2 pixels at once */ 1575141cc406Sopenharmony_ci memcpy (linebuf + c * (i + shifts[i8]), sptr + c * i, c * 2); 1576141cc406Sopenharmony_ci } 1577141cc406Sopenharmony_ci 1578141cc406Sopenharmony_ci memcpy (sptr, linebuf, line_size); 1579141cc406Sopenharmony_ci} 1580141cc406Sopenharmony_ci 1581141cc406Sopenharmony_ci#ifndef TPU_48 1582141cc406Sopenharmony_cistatic unsigned 1583141cc406Sopenharmony_cipack_48_24_bpc (uint8_t * sptr, unsigned n) 1584141cc406Sopenharmony_ci{ 1585141cc406Sopenharmony_ci unsigned i; 1586141cc406Sopenharmony_ci uint8_t *cptr, lsb; 1587141cc406Sopenharmony_ci static uint8_t offset = 0; 1588141cc406Sopenharmony_ci 1589141cc406Sopenharmony_ci cptr = sptr; 1590141cc406Sopenharmony_ci if (n % 2 != 0) 1591141cc406Sopenharmony_ci PDBG (pixma_dbg (3, "WARNING: misaligned image.\n")); 1592141cc406Sopenharmony_ci for (i = 0; i < n; i += 2) 1593141cc406Sopenharmony_ci { 1594141cc406Sopenharmony_ci /* offset = 1 + (offset % 3); */ 1595141cc406Sopenharmony_ci lsb = *sptr++; 1596141cc406Sopenharmony_ci *cptr++ = ((*sptr++) << offset) | lsb >> (8 - offset); 1597141cc406Sopenharmony_ci } 1598141cc406Sopenharmony_ci return (n / 2); 1599141cc406Sopenharmony_ci} 1600141cc406Sopenharmony_ci#endif 1601141cc406Sopenharmony_ci 1602141cc406Sopenharmony_ci/* This function deals both with PIXMA CCD sensors producing shifted color 1603141cc406Sopenharmony_ci * planes images, Grayscale CCD scan and Generation >= 3 high dpi images. 1604141cc406Sopenharmony_ci * Each complete line in mp->imgbuf is processed for shifting CCD sensor 1605141cc406Sopenharmony_ci * color planes, reordering pixels above 600 dpi for Generation >= 3, and 1606141cc406Sopenharmony_ci * converting to Grayscale for CCD sensors. */ 1607141cc406Sopenharmony_cistatic unsigned post_process_image_data (pixma_t * s, pixma_imagebuf_t * ib) 1608141cc406Sopenharmony_ci{ 1609141cc406Sopenharmony_ci mp810_t *mp = (mp810_t *) s->subdriver; 1610141cc406Sopenharmony_ci unsigned c, lines, line_size, n, m, cw, cx, reducelines; 1611141cc406Sopenharmony_ci uint8_t *sptr, *dptr, *gptr, *cptr; 1612141cc406Sopenharmony_ci unsigned /*color_shift, stripe_shift, stripe_shift2,*/ jumplines /*, height*/; 1613141cc406Sopenharmony_ci int test; 1614141cc406Sopenharmony_ci 1615141cc406Sopenharmony_ci /* For testers: */ 1616141cc406Sopenharmony_ci /* set this to 1 in order to get unprocessed images next to one another at 9600dpi */ 1617141cc406Sopenharmony_ci /* other resolutions should not be affected */ 1618141cc406Sopenharmony_ci /* set this to 2 if you want to see the same with jumplines=0 */ 1619141cc406Sopenharmony_ci test = 0; 1620141cc406Sopenharmony_ci jumplines = 0; 1621141cc406Sopenharmony_ci 1622141cc406Sopenharmony_ci c = ((is_tpuir (s) || is_gray_all (s) || is_lineart (s)) ? 3 : s->param->channels) 1623141cc406Sopenharmony_ci * ((s->param->software_lineart) ? 8 : s->param->depth) / 8; 1624141cc406Sopenharmony_ci cw = c * s->param->w; 1625141cc406Sopenharmony_ci cx = c * s->param->xs; 1626141cc406Sopenharmony_ci 1627141cc406Sopenharmony_ci /* PDBG (pixma_dbg (4, "*post_process_image_data***** c = %u, cw = %u, cx = %u *****\n", c, cw, cx)); */ 1628141cc406Sopenharmony_ci 1629141cc406Sopenharmony_ci if (mp->generation >= 3) 1630141cc406Sopenharmony_ci n = s->param->xdpi / 600; 1631141cc406Sopenharmony_ci else 1632141cc406Sopenharmony_ci /* FIXME: maybe need different values for CIS and CCD sensors */ 1633141cc406Sopenharmony_ci n = s->param->xdpi / 2400; 1634141cc406Sopenharmony_ci 1635141cc406Sopenharmony_ci /* Some exceptions to global rules here */ 1636141cc406Sopenharmony_ci if (s->cfg->pid == MP970_PID || s->cfg->pid == MP990_PID || s->cfg->pid == MG8200_PID 1637141cc406Sopenharmony_ci || s->cfg->pid == CS8800F_PID || s->cfg->pid == CS9000F_PID || s->cfg->pid == CS9000F_MII_PID) 1638141cc406Sopenharmony_ci n = MIN (n, 4); 1639141cc406Sopenharmony_ci 1640141cc406Sopenharmony_ci /* exception for 9600dpi on Canoscan 9000F */ 1641141cc406Sopenharmony_ci if ((s->cfg->pid == CS9000F_PID || s->cfg->pid == CS9000F_MII_PID) && (s->param->xdpi == 9600)) 1642141cc406Sopenharmony_ci { 1643141cc406Sopenharmony_ci n = 8; 1644141cc406Sopenharmony_ci if (test > 0) 1645141cc406Sopenharmony_ci n = 1; /* test if 8 images are next to one another */ 1646141cc406Sopenharmony_ci } 1647141cc406Sopenharmony_ci 1648141cc406Sopenharmony_ci /* test if 2 images are next to one another */ 1649141cc406Sopenharmony_ci if ((s->cfg->pid == MP960_PID) && (s->param->xdpi == 4800) && (test > 0)) 1650141cc406Sopenharmony_ci { 1651141cc406Sopenharmony_ci n = 1; 1652141cc406Sopenharmony_ci } 1653141cc406Sopenharmony_ci 1654141cc406Sopenharmony_ci m = (n > 0) ? s->param->wx / n : 1; 1655141cc406Sopenharmony_ci 1656141cc406Sopenharmony_ci sptr = dptr = gptr = cptr = mp->imgbuf; 1657141cc406Sopenharmony_ci line_size = get_cis_ccd_line_size (s); 1658141cc406Sopenharmony_ci /* PDBG (pixma_dbg (4, "*post_process_image_data***** ----- Set n=%u, m=%u, line_size=%u ----- ***** \n", n, m, line_size)); */ 1659141cc406Sopenharmony_ci /* PDBG (pixma_dbg (4, "*post_process_image_data***** ----- spr=dpr=%u, linebuf=%u ----- ***** \n", sptr, mp->linebuf)); */ 1660141cc406Sopenharmony_ci 1661141cc406Sopenharmony_ci lines = (mp->data_left_ofs - mp->imgbuf) / line_size; 1662141cc406Sopenharmony_ci /* PDBG (pixma_dbg (4, "*post_process_image_data***** lines = %i > 2 * mp->color_shift + mp->stripe_shift = %i ***** \n", 1663141cc406Sopenharmony_ci lines, 2 * mp->color_shift + mp->stripe_shift)); */ 1664141cc406Sopenharmony_ci /* PDBG (pixma_dbg (4, "*post_process_image_data***** mp->color_shift = %u, mp->stripe_shift = %u, , mp->stripe_shift2 = %u ***** \n", 1665141cc406Sopenharmony_ci mp->color_shift, mp->stripe_shift, mp->stripe_shift2)); */ 1666141cc406Sopenharmony_ci 1667141cc406Sopenharmony_ci /*color_shift = mp->color_shift;*/ 1668141cc406Sopenharmony_ci /*stripe_shift = mp->stripe_shift;*/ 1669141cc406Sopenharmony_ci /*stripe_shift2 = mp->stripe_shift2;*/ 1670141cc406Sopenharmony_ci jumplines = mp->jumplines; 1671141cc406Sopenharmony_ci 1672141cc406Sopenharmony_ci /* height not needed here! */ 1673141cc406Sopenharmony_ci /* removed to avoid confusion */ 1674141cc406Sopenharmony_ci /* height = MIN (s->param->h + calc_shifting (s), 1675141cc406Sopenharmony_ci s->cfg->height * s->param->ydpi / 75); */ 1676141cc406Sopenharmony_ci 1677141cc406Sopenharmony_ci /* have to test if rounding down is OK or not -- currently 0.5 lines is rounded down */ 1678141cc406Sopenharmony_ci /* note stripe shifts doubled already in definitions */ 1679141cc406Sopenharmony_ci if ((s->cfg->pid == CS9000F_PID || s->cfg->pid == CS9000F_MII_PID) && (s->param->xdpi == 9600) && (test > 0)) 1680141cc406Sopenharmony_ci { 1681141cc406Sopenharmony_ci /* using test==2 you can check in GIMP the required offset, and 1682141cc406Sopenharmony_ci use the below line (uncommented) and replace XXX with that 1683141cc406Sopenharmony_ci number, and then compile again with test set to 1. */ 1684141cc406Sopenharmony_ci 1685141cc406Sopenharmony_ci jumplines = 32; 1686141cc406Sopenharmony_ci if (test == 2) 1687141cc406Sopenharmony_ci jumplines = 0; 1688141cc406Sopenharmony_ci } 1689141cc406Sopenharmony_ci 1690141cc406Sopenharmony_ci /* mp960 test */ 1691141cc406Sopenharmony_ci if ((s->cfg->pid == MP960_PID) && (s->param->xdpi == 4800) && (test > 0)) 1692141cc406Sopenharmony_ci { 1693141cc406Sopenharmony_ci jumplines = 32; 1694141cc406Sopenharmony_ci if (test == 2) 1695141cc406Sopenharmony_ci jumplines = 0; 1696141cc406Sopenharmony_ci } 1697141cc406Sopenharmony_ci 1698141cc406Sopenharmony_ci reducelines = ((2 * mp->color_shift + mp->stripe_shift) + jumplines); 1699141cc406Sopenharmony_ci /* PDBG (pixma_dbg (4, "*post_process_image_data: lines %u, reducelines %u \n", lines, reducelines)); */ 1700141cc406Sopenharmony_ci if (lines > reducelines) 1701141cc406Sopenharmony_ci { /* (line - reducelines) of image lines can be converted */ 1702141cc406Sopenharmony_ci unsigned i; 1703141cc406Sopenharmony_ci 1704141cc406Sopenharmony_ci lines -= reducelines; 1705141cc406Sopenharmony_ci 1706141cc406Sopenharmony_ci for (i = 0; i < lines; i++, sptr += line_size) 1707141cc406Sopenharmony_ci { /* convert only full image lines */ 1708141cc406Sopenharmony_ci /* Color plane and stripes shift needed by e.g. CCD */ 1709141cc406Sopenharmony_ci /* PDBG (pixma_dbg (4, "*post_process_image_data***** Processing with c=%u, n=%u, m=%u, w=%i, line_size=%u ***** \n", 1710141cc406Sopenharmony_ci c, n, m, s->param->wx, line_size)); */ 1711141cc406Sopenharmony_ci if (c >= 3) 1712141cc406Sopenharmony_ci { 1713141cc406Sopenharmony_ci if (((s->cfg->pid == CS9000F_PID || s->cfg->pid == CS9000F_MII_PID) && (s->param->xdpi == 9600)) 1714141cc406Sopenharmony_ci || ((s->cfg->pid == MP960_PID) && (s->param->xdpi == 4800)) 1715141cc406Sopenharmony_ci || ((s->cfg->pid == MP810_PID) && (s->param->xdpi == 4800))) 1716141cc406Sopenharmony_ci { 1717141cc406Sopenharmony_ci dptr = shift_colorsCS9000 (dptr, sptr, s->param->wx, s->param->xdpi, 1718141cc406Sopenharmony_ci s->cfg->pid, c, mp->shift, 1719141cc406Sopenharmony_ci mp->stripe_shift, mp->stripe_shift2, 1720141cc406Sopenharmony_ci jumplines * line_size); 1721141cc406Sopenharmony_ci } 1722141cc406Sopenharmony_ci 1723141cc406Sopenharmony_ci else if ((s->cfg->pid == CS9000F_PID || s->cfg->pid == CS9000F_MII_PID) /* 9000F: 16 bit flatbed scan at 4800dpi */ 1724141cc406Sopenharmony_ci && ((s->param->mode == PIXMA_SCAN_MODE_COLOR_48) 1725141cc406Sopenharmony_ci || (s->param->mode == PIXMA_SCAN_MODE_GRAY_16)) 1726141cc406Sopenharmony_ci && (s->param->xdpi == 4800) 1727141cc406Sopenharmony_ci && (s->param->source == PIXMA_SOURCE_FLATBED)) 1728141cc406Sopenharmony_ci dptr = shift_colorsCS9000_4800 (dptr, sptr, s->param->wx, 1729141cc406Sopenharmony_ci s->param->xdpi, s->cfg->pid, c, 1730141cc406Sopenharmony_ci mp->shift, mp->stripe_shift, 1731141cc406Sopenharmony_ci mp->stripe_shift2, 1732141cc406Sopenharmony_ci jumplines * line_size); 1733141cc406Sopenharmony_ci 1734141cc406Sopenharmony_ci else 1735141cc406Sopenharmony_ci /* all except 9000F at 9600dpi */ 1736141cc406Sopenharmony_ci dptr = shift_colors (dptr, sptr, s->param->wx, s->param->xdpi, 1737141cc406Sopenharmony_ci s->cfg->pid, c, mp->shift, mp->stripe_shift); 1738141cc406Sopenharmony_ci } 1739141cc406Sopenharmony_ci 1740141cc406Sopenharmony_ci /*PDBG (pixma_dbg (4, "*post_process_image_data***** test = %i *****\n", test)); */ 1741141cc406Sopenharmony_ci 1742141cc406Sopenharmony_ci /*--comment out all between this line and the one below for 9000F tests at 9600dpi or MP960 at 4800dpi ------*/ 1743141cc406Sopenharmony_ci /* if ( 0 ) */ 1744141cc406Sopenharmony_ci if ((((s->cfg->pid != CS9000F_PID && s->cfg->pid != CS9000F_MII_PID) || (s->param->xdpi < 9600)) 1745141cc406Sopenharmony_ci && ((s->cfg->pid != MP960_PID) || (s->param->xdpi < 4800)) 1746141cc406Sopenharmony_ci && ((s->cfg->pid != MP810_PID) || (s->param->xdpi < 4800))) 1747141cc406Sopenharmony_ci || (test == 0)) 1748141cc406Sopenharmony_ci { 1749141cc406Sopenharmony_ci /* PDBG (pixma_dbg (4, "*post_process_image_data***** MUST GET HERE WHEN TEST == 0 *****\n")); */ 1750141cc406Sopenharmony_ci 1751141cc406Sopenharmony_ci if (!((s->cfg->pid == MP810_PID) && (s->param->xdpi == 4800)) 1752141cc406Sopenharmony_ci && !((s->cfg->pid == MP960_PID) && (s->param->xdpi == 4800)) 1753141cc406Sopenharmony_ci && !((s->cfg->pid == CS9000F_PID || s->cfg->pid == CS9000F_MII_PID) && (s->param->xdpi == 9600))) 1754141cc406Sopenharmony_ci { /* for both flatbed & TPU */ 1755141cc406Sopenharmony_ci /* PDBG (pixma_dbg (4, "*post_process_image_data***** reordering pixels normal n = %i *****\n", n)); */ 1756141cc406Sopenharmony_ci reorder_pixels (mp->linebuf, sptr, c, n, m, s->param->wx, line_size); 1757141cc406Sopenharmony_ci } 1758141cc406Sopenharmony_ci 1759141cc406Sopenharmony_ci if ((s->cfg->pid == CS9000F_PID || s->cfg->pid == CS9000F_MII_PID) && (s->param->xdpi == 9600)) 1760141cc406Sopenharmony_ci { 1761141cc406Sopenharmony_ci /* PDBG (pixma_dbg (4, "*post_process_image_data***** cs900f_initial_reorder_pixels n = %i *****\n", n)); */ 1762141cc406Sopenharmony_ci /* this combines pixels from 8 images 2px at a time from left to right: 1122334455667788... */ 1763141cc406Sopenharmony_ci cs9000f_initial_reorder_pixels (mp->linebuf, sptr, c, n, m, 1764141cc406Sopenharmony_ci s->param->wx, line_size); 1765141cc406Sopenharmony_ci /* final interleaving */ 1766141cc406Sopenharmony_ci cs9000f_second_reorder_pixels (mp->linebuf, sptr, c, s->param->wx, 1767141cc406Sopenharmony_ci line_size); 1768141cc406Sopenharmony_ci } 1769141cc406Sopenharmony_ci 1770141cc406Sopenharmony_ci /* comment: special image format for MP960 in flatbed mode 1771141cc406Sopenharmony_ci at 4800dpi. It is actually 2400dpi, with each pixel 1772141cc406Sopenharmony_ci doubled. The TPU mode has proper pixel ordering */ 1773141cc406Sopenharmony_ci if ((((s->cfg->pid == MP960_PID) || (s->cfg->pid == MP810_PID)) && (s->param->xdpi == 4800)) 1774141cc406Sopenharmony_ci && (n > 0)) 1775141cc406Sopenharmony_ci { 1776141cc406Sopenharmony_ci /* for both flatbed & TPU */ 1777141cc406Sopenharmony_ci /* PDBG (pixma_dbg (4, "*post_process_image_data***** flatbed mp960_reordering pixels n = %i *****\n", n)); */ 1778141cc406Sopenharmony_ci mp960_reorder_pixels (mp->linebuf, sptr, c, n, m, s->param->wx, 1779141cc406Sopenharmony_ci line_size); 1780141cc406Sopenharmony_ci } 1781141cc406Sopenharmony_ci 1782141cc406Sopenharmony_ci /* comment: MP970, CS8800F, CS9000F specific reordering for 4800 dpi */ 1783141cc406Sopenharmony_ci if ((s->cfg->pid == MP970_PID || s->cfg->pid == CS8800F_PID 1784141cc406Sopenharmony_ci || s->cfg->pid == CS9000F_PID || s->cfg->pid == CS9000F_MII_PID 1785141cc406Sopenharmony_ci || s->cfg->pid == MP990_PID) && (s->param->xdpi == 4800)) 1786141cc406Sopenharmony_ci { 1787141cc406Sopenharmony_ci /*PDBG (pixma_dbg (4, "*post_process_image_data***** mp970_reordering pixels n = %i *****\n", n)); */ 1788141cc406Sopenharmony_ci mp970_reorder_pixels (mp->linebuf, sptr, c, s->param->wx, line_size); 1789141cc406Sopenharmony_ci } 1790141cc406Sopenharmony_ci 1791141cc406Sopenharmony_ci } 1792141cc406Sopenharmony_ci /*-------------------------------------------------------*/ 1793141cc406Sopenharmony_ci 1794141cc406Sopenharmony_ci /* PDBG (pixma_dbg (4, "*post_process_image_data: sptr=%u, dptr=%u \n", sptr, dptr)); */ 1795141cc406Sopenharmony_ci 1796141cc406Sopenharmony_ci /* Crop line to selected borders */ 1797141cc406Sopenharmony_ci memmove (cptr, sptr + cx, cw); 1798141cc406Sopenharmony_ci /* PDBG (pixma_dbg (4, "*post_process_image_data***** crop line: cx=%u, cw=%u ***** \n", cx, cw)); */ 1799141cc406Sopenharmony_ci 1800141cc406Sopenharmony_ci /* Color to Lineart convert for CCD sensor */ 1801141cc406Sopenharmony_ci if (is_lineart (s)) 1802141cc406Sopenharmony_ci cptr = gptr = pixma_binarize_line (s->param, gptr, cptr, s->param->w, c); 1803141cc406Sopenharmony_ci#ifndef TPUIR_USE_RGB 1804141cc406Sopenharmony_ci /* save IR only for CCD sensor */ 1805141cc406Sopenharmony_ci else if (is_tpuir (s)) 1806141cc406Sopenharmony_ci cptr = gptr = pixma_r_to_ir (gptr, cptr, s->param->w, c); 1807141cc406Sopenharmony_ci /* Color to Grayscale convert for CCD sensor */ 1808141cc406Sopenharmony_ci else if (is_gray_all (s)) 1809141cc406Sopenharmony_ci#else 1810141cc406Sopenharmony_ci /* IR *and* Color to Grayscale convert for CCD sensor */ 1811141cc406Sopenharmony_ci else if (is_tpuir (s) || is_gray_all (s)) 1812141cc406Sopenharmony_ci#endif 1813141cc406Sopenharmony_ci cptr = gptr = pixma_rgb_to_gray (gptr, cptr, s->param->w, c); 1814141cc406Sopenharmony_ci else 1815141cc406Sopenharmony_ci cptr += cw; 1816141cc406Sopenharmony_ci } 1817141cc406Sopenharmony_ci /* PDBG (pixma_dbg (4, "*post_process_image_data: sptr=%u, dptr=%u \n", sptr, dptr)); */ 1818141cc406Sopenharmony_ci } 1819141cc406Sopenharmony_ci ib->rptr = mp->imgbuf; 1820141cc406Sopenharmony_ci ib->rend = cptr; 1821141cc406Sopenharmony_ci return mp->data_left_ofs - sptr; /* # of non processed bytes */ 1822141cc406Sopenharmony_ci /* contains shift color data for new lines */ 1823141cc406Sopenharmony_ci /* and already received data for the next line */ 1824141cc406Sopenharmony_ci} 1825141cc406Sopenharmony_ci 1826141cc406Sopenharmony_cistatic int mp810_open (pixma_t * s) 1827141cc406Sopenharmony_ci{ 1828141cc406Sopenharmony_ci mp810_t *mp; 1829141cc406Sopenharmony_ci uint8_t *buf; 1830141cc406Sopenharmony_ci 1831141cc406Sopenharmony_ci mp = (mp810_t *) calloc (1, sizeof(*mp)); 1832141cc406Sopenharmony_ci if (!mp) 1833141cc406Sopenharmony_ci return PIXMA_ENOMEM; 1834141cc406Sopenharmony_ci 1835141cc406Sopenharmony_ci buf = (uint8_t *) malloc (CMDBUF_SIZE + IMAGE_BLOCK_SIZE); 1836141cc406Sopenharmony_ci if (!buf) 1837141cc406Sopenharmony_ci { 1838141cc406Sopenharmony_ci free (mp); 1839141cc406Sopenharmony_ci return PIXMA_ENOMEM; 1840141cc406Sopenharmony_ci } 1841141cc406Sopenharmony_ci 1842141cc406Sopenharmony_ci s->subdriver = mp; 1843141cc406Sopenharmony_ci mp->state = state_idle; 1844141cc406Sopenharmony_ci 1845141cc406Sopenharmony_ci mp->cb.buf = buf; 1846141cc406Sopenharmony_ci mp->cb.size = CMDBUF_SIZE; 1847141cc406Sopenharmony_ci mp->cb.res_header_len = 8; 1848141cc406Sopenharmony_ci mp->cb.cmd_header_len = 16; 1849141cc406Sopenharmony_ci mp->cb.cmd_len_field_ofs = 14; 1850141cc406Sopenharmony_ci 1851141cc406Sopenharmony_ci mp->imgbuf = buf + CMDBUF_SIZE; 1852141cc406Sopenharmony_ci 1853141cc406Sopenharmony_ci /* General rules for setting Pixma protocol generation # */ 1854141cc406Sopenharmony_ci mp->generation = (s->cfg->pid >= MP810_PID) ? 2 : 1; 1855141cc406Sopenharmony_ci 1856141cc406Sopenharmony_ci if (s->cfg->pid >= MP970_PID) 1857141cc406Sopenharmony_ci mp->generation = 3; 1858141cc406Sopenharmony_ci 1859141cc406Sopenharmony_ci if (s->cfg->pid >= MP990_PID) 1860141cc406Sopenharmony_ci mp->generation = 4; 1861141cc406Sopenharmony_ci 1862141cc406Sopenharmony_ci /* And exceptions to be added here */ 1863141cc406Sopenharmony_ci if (s->cfg->pid == CS8800F_PID) 1864141cc406Sopenharmony_ci mp->generation = 3; 1865141cc406Sopenharmony_ci 1866141cc406Sopenharmony_ci if (s->cfg->pid == CS9000F_PID || s->cfg->pid == CS9000F_MII_PID) 1867141cc406Sopenharmony_ci mp->generation = 4; 1868141cc406Sopenharmony_ci 1869141cc406Sopenharmony_ci /* TPU info data setup */ 1870141cc406Sopenharmony_ci mp->tpu_datalen = 0; 1871141cc406Sopenharmony_ci 1872141cc406Sopenharmony_ci if (mp->generation < 4) 1873141cc406Sopenharmony_ci { 1874141cc406Sopenharmony_ci /* Canoscan 8800F ignores commands if not initialized */ 1875141cc406Sopenharmony_ci if (s->cfg->pid == CS8800F_PID) 1876141cc406Sopenharmony_ci abort_session (s); 1877141cc406Sopenharmony_ci else 1878141cc406Sopenharmony_ci { 1879141cc406Sopenharmony_ci query_status (s); 1880141cc406Sopenharmony_ci handle_interrupt (s, 200); 1881141cc406Sopenharmony_ci if (mp->generation == 3 && has_ccd_sensor (s)) 1882141cc406Sopenharmony_ci send_cmd_start_calibrate_ccd_3 (s); 1883141cc406Sopenharmony_ci } 1884141cc406Sopenharmony_ci } 1885141cc406Sopenharmony_ci return 0; 1886141cc406Sopenharmony_ci} 1887141cc406Sopenharmony_ci 1888141cc406Sopenharmony_cistatic void mp810_close (pixma_t * s) 1889141cc406Sopenharmony_ci{ 1890141cc406Sopenharmony_ci mp810_t *mp = (mp810_t *) s->subdriver; 1891141cc406Sopenharmony_ci 1892141cc406Sopenharmony_ci mp810_finish_scan (s); 1893141cc406Sopenharmony_ci free (mp->cb.buf); 1894141cc406Sopenharmony_ci free (mp); 1895141cc406Sopenharmony_ci s->subdriver = NULL; 1896141cc406Sopenharmony_ci} 1897141cc406Sopenharmony_ci 1898141cc406Sopenharmony_cistatic int mp810_check_param (pixma_t * s, pixma_scan_param_t * sp) 1899141cc406Sopenharmony_ci{ 1900141cc406Sopenharmony_ci mp810_t *mp = (mp810_t *) s->subdriver; 1901141cc406Sopenharmony_ci unsigned w_max; 1902141cc406Sopenharmony_ci 1903141cc406Sopenharmony_ci /* PDBG (pixma_dbg (4, "*mp810_check_param***** Initially: channels=%u, depth=%u, x=%u, y=%u, w=%u, h=%u, xs=%u, wx=%u, gamma=%f *****\n", 1904141cc406Sopenharmony_ci sp->channels, sp->depth, sp->x, sp->y, sp->w, sp->h, sp->xs, sp->wx, sp->gamma)); */ 1905141cc406Sopenharmony_ci 1906141cc406Sopenharmony_ci sp->channels = 3; 1907141cc406Sopenharmony_ci sp->software_lineart = 0; 1908141cc406Sopenharmony_ci switch (sp->mode) 1909141cc406Sopenharmony_ci { 1910141cc406Sopenharmony_ci /* standard scan modes 1911141cc406Sopenharmony_ci * 8 bit per channel in color and grayscale mode 1912141cc406Sopenharmony_ci * 16 bit per channel with TPU */ 1913141cc406Sopenharmony_ci case PIXMA_SCAN_MODE_GRAY: 1914141cc406Sopenharmony_ci case PIXMA_SCAN_MODE_NEGATIVE_GRAY: 1915141cc406Sopenharmony_ci case PIXMA_SCAN_MODE_TPUIR: 1916141cc406Sopenharmony_ci sp->channels = 1; 1917141cc406Sopenharmony_ci /* fall through */ 1918141cc406Sopenharmony_ci case PIXMA_SCAN_MODE_COLOR: 1919141cc406Sopenharmony_ci case PIXMA_SCAN_MODE_NEGATIVE_COLOR: 1920141cc406Sopenharmony_ci sp->depth = 8; 1921141cc406Sopenharmony_ci#ifdef TPU_48 1922141cc406Sopenharmony_ci#ifndef DEBUG_TPU_48 1923141cc406Sopenharmony_ci if (sp->source == PIXMA_SOURCE_TPU) 1924141cc406Sopenharmony_ci#endif 1925141cc406Sopenharmony_ci sp->depth = 16; /* TPU in 16 bits mode */ 1926141cc406Sopenharmony_ci#endif 1927141cc406Sopenharmony_ci break; 1928141cc406Sopenharmony_ci /* extended scan modes for 48 bit flatbed scanners 1929141cc406Sopenharmony_ci * 16 bit per channel in color and grayscale mode */ 1930141cc406Sopenharmony_ci case PIXMA_SCAN_MODE_GRAY_16: 1931141cc406Sopenharmony_ci sp->channels = 1; 1932141cc406Sopenharmony_ci sp->depth = 16; 1933141cc406Sopenharmony_ci break; 1934141cc406Sopenharmony_ci case PIXMA_SCAN_MODE_COLOR_48: 1935141cc406Sopenharmony_ci sp->channels = 3; 1936141cc406Sopenharmony_ci sp->depth = 16; 1937141cc406Sopenharmony_ci break; 1938141cc406Sopenharmony_ci /* software lineart 1939141cc406Sopenharmony_ci * 1 bit per channel */ 1940141cc406Sopenharmony_ci case PIXMA_SCAN_MODE_LINEART: 1941141cc406Sopenharmony_ci sp->software_lineart = 1; 1942141cc406Sopenharmony_ci sp->channels = 1; 1943141cc406Sopenharmony_ci sp->depth = 1; 1944141cc406Sopenharmony_ci break; 1945141cc406Sopenharmony_ci } 1946141cc406Sopenharmony_ci 1947141cc406Sopenharmony_ci /* for software lineart w must be a multiple of 8 1948141cc406Sopenharmony_ci * I don't know why is_lineart(s) doesn't work here */ 1949141cc406Sopenharmony_ci if (sp->software_lineart == 1 && sp->w % 8) 1950141cc406Sopenharmony_ci { 1951141cc406Sopenharmony_ci sp->w += 8 - (sp->w % 8); 1952141cc406Sopenharmony_ci 1953141cc406Sopenharmony_ci /* do not exceed the scanner capability */ 1954141cc406Sopenharmony_ci w_max = s->cfg->width * s->cfg->xdpi / 75; 1955141cc406Sopenharmony_ci w_max -= w_max % 8; 1956141cc406Sopenharmony_ci if (sp->w > w_max) 1957141cc406Sopenharmony_ci sp->w = w_max; 1958141cc406Sopenharmony_ci } 1959141cc406Sopenharmony_ci 1960141cc406Sopenharmony_ci if (sp->source == PIXMA_SOURCE_TPU && !sp->tpu_offset_added) 1961141cc406Sopenharmony_ci { 1962141cc406Sopenharmony_ci unsigned fixed_offset_y; /* TPU offsets for CanoScan 8800F, or other CCD at 300dpi. */ 1963141cc406Sopenharmony_ci unsigned max_y; /* max TPU height for CS9000F at 75 dpi */ 1964141cc406Sopenharmony_ci 1965141cc406Sopenharmony_ci /* CanoScan 8800F and others adding an offset depending on resolution */ 1966141cc406Sopenharmony_ci /* CS9000F and others maximum TPU height */ 1967141cc406Sopenharmony_ci switch (s->cfg->pid) 1968141cc406Sopenharmony_ci { 1969141cc406Sopenharmony_ci case CS8800F_PID: 1970141cc406Sopenharmony_ci fixed_offset_y = 140; 1971141cc406Sopenharmony_ci max_y = MIN (740, s->cfg->height); 1972141cc406Sopenharmony_ci break; 1973141cc406Sopenharmony_ci case CS9000F_PID: 1974141cc406Sopenharmony_ci case CS9000F_MII_PID: 1975141cc406Sopenharmony_ci fixed_offset_y = 146; 1976141cc406Sopenharmony_ci max_y = MIN (740, s->cfg->height); 1977141cc406Sopenharmony_ci break; 1978141cc406Sopenharmony_ci default: 1979141cc406Sopenharmony_ci fixed_offset_y = 0; 1980141cc406Sopenharmony_ci max_y = s->cfg->height; 1981141cc406Sopenharmony_ci break; 1982141cc406Sopenharmony_ci } 1983141cc406Sopenharmony_ci 1984141cc406Sopenharmony_ci /* cropping y and h to scanable area */ 1985141cc406Sopenharmony_ci max_y *= (sp->ydpi) / 75; 1986141cc406Sopenharmony_ci sp->y = MIN(sp->y, max_y); 1987141cc406Sopenharmony_ci sp->h = MIN(sp->h, max_y - sp->y); 1988141cc406Sopenharmony_ci /* PDBG (pixma_dbg (4, "*mp810_check_param***** Cropping: y=%u, h=%u *****\n", 1989141cc406Sopenharmony_ci sp->y, sp->h)); */ 1990141cc406Sopenharmony_ci if (!sp->h) 1991141cc406Sopenharmony_ci return SANE_STATUS_INVAL; /* no lines */ 1992141cc406Sopenharmony_ci 1993141cc406Sopenharmony_ci /* Convert the offsets from 300dpi to actual resolution */ 1994141cc406Sopenharmony_ci fixed_offset_y = fixed_offset_y * (sp->xdpi) / 300; 1995141cc406Sopenharmony_ci 1996141cc406Sopenharmony_ci /* In TPU mode, the CS9000F appears to always subtract 146 from the 1997141cc406Sopenharmony_ci vertical starting position, but clamps its at 0. Therefore vertical 1998141cc406Sopenharmony_ci offsets 0 through 146 (@300 dpi) get all mapped onto the same 1999141cc406Sopenharmony_ci physical starting position: line 0. Then, starting from 147, the 2000141cc406Sopenharmony_ci offsets get mapped onto successive physical lines: 2001141cc406Sopenharmony_ci y line 2002141cc406Sopenharmony_ci 0 -> 0 2003141cc406Sopenharmony_ci 1 -> 0 2004141cc406Sopenharmony_ci 2 -> 0 2005141cc406Sopenharmony_ci ... 2006141cc406Sopenharmony_ci 146 -> 0 2007141cc406Sopenharmony_ci 147 -> 1 2008141cc406Sopenharmony_ci 148 -> 2 2009141cc406Sopenharmony_ci ... 2010141cc406Sopenharmony_ci Since a preview scan is typically made starting from y = 0, but 2011141cc406Sopenharmony_ci partial image scans usually start at y >> 147, this results in a 2012141cc406Sopenharmony_ci discontinuity in the y to line mapping, resulting in wrong offsets. 2013141cc406Sopenharmony_ci To prevent this, we must always add (at least) 146 to the y 2014141cc406Sopenharmony_ci offset before it is sent to the scanner. The scanner will then 2015141cc406Sopenharmony_ci map y = 0 (146) to the first line, y = 1 (147) to the second line, 2016141cc406Sopenharmony_ci and so on. Any distance that is then measured on the preview scan, 2017141cc406Sopenharmony_ci can be translated without any discontinuity. 2018141cc406Sopenharmony_ci 2019141cc406Sopenharmony_ci However, there is one complication: during a preview scan, which 2020141cc406Sopenharmony_ci normally covers the whole scan area of the scanner, we should _not_ 2021141cc406Sopenharmony_ci add the offset because it will result in a reduced number of lines 2022141cc406Sopenharmony_ci being returned (the scan height is clamped in 2023141cc406Sopenharmony_ci pixma_check_scan_param()). Since the frontend has no way of telling 2024141cc406Sopenharmony_ci that the scan area has been reduced, it would derive an incorrect 2025141cc406Sopenharmony_ci effective scan resolution, and any position calculations based on 2026141cc406Sopenharmony_ci this would therefore be inaccurate. 2027141cc406Sopenharmony_ci 2028141cc406Sopenharmony_ci To prevent this, we don't add the offset in case y = 0, which is 2029141cc406Sopenharmony_ci typically the case during a preview scan (the scanner effectively 2030141cc406Sopenharmony_ci adds the offset for us, see above). In that way we keep the 2031141cc406Sopenharmony_ci linearity and we don't affect the scan area during previews. 2032141cc406Sopenharmony_ci */ 2033141cc406Sopenharmony_ci 2034141cc406Sopenharmony_ci if (sp->y > 0) 2035141cc406Sopenharmony_ci sp->y += fixed_offset_y; 2036141cc406Sopenharmony_ci 2037141cc406Sopenharmony_ci /* Prevent repeated corrections as check_param may be called multiple times */ 2038141cc406Sopenharmony_ci sp->tpu_offset_added = 1; 2039141cc406Sopenharmony_ci } 2040141cc406Sopenharmony_ci 2041141cc406Sopenharmony_ci if (mp->generation >= 2) 2042141cc406Sopenharmony_ci { 2043141cc406Sopenharmony_ci /* mod 32 and expansion of the X scan limits */ 2044141cc406Sopenharmony_ci /* PDBG (pixma_dbg (4, "*mp810_check_param***** (gen>=2) xs=mod32 ----- Initially: x=%u, y=%u, w=%u, h=%u *****\n", sp->x, sp->y, sp->w, sp->h)); */ 2045141cc406Sopenharmony_ci sp->xs = (sp->x) % 32; 2046141cc406Sopenharmony_ci } 2047141cc406Sopenharmony_ci else 2048141cc406Sopenharmony_ci { 2049141cc406Sopenharmony_ci sp->xs = 0; 2050141cc406Sopenharmony_ci /* PDBG (pixma_dbg (4, "*mp810_check_param***** (else) xs=0 Selected origin, origin shift: %u, %u *****\n", sp->x, sp->xs)); */ 2051141cc406Sopenharmony_ci } 2052141cc406Sopenharmony_ci sp->wx = calc_raw_width (mp, sp); 2053141cc406Sopenharmony_ci sp->line_size = sp->w * sp->channels * (((sp->software_lineart) ? 8 : sp->depth) / 8); /* bytes per line per color after cropping */ 2054141cc406Sopenharmony_ci /* PDBG (pixma_dbg (4, "*mp810_check_param***** (else) Final scan width and line-size: %u, %"PRIu64" *****\n", sp->wx, sp->line_size)); */ 2055141cc406Sopenharmony_ci 2056141cc406Sopenharmony_ci /* highest res is 600, 2400, 4800 or 9600 dpi */ 2057141cc406Sopenharmony_ci { 2058141cc406Sopenharmony_ci uint8_t k; 2059141cc406Sopenharmony_ci 2060141cc406Sopenharmony_ci if ((sp->source == PIXMA_SOURCE_ADF || sp->source == PIXMA_SOURCE_ADFDUP) 2061141cc406Sopenharmony_ci && mp->generation >= 4) 2062141cc406Sopenharmony_ci /* ADF/ADF duplex mode: max scan res is 600 dpi, at least for generation 4 */ 2063141cc406Sopenharmony_ci k = sp->xdpi / MIN (sp->xdpi, 600); 2064141cc406Sopenharmony_ci else if (sp->source == PIXMA_SOURCE_TPU && sp->mode == PIXMA_SCAN_MODE_TPUIR) 2065141cc406Sopenharmony_ci /* TPUIR mode: max scan res is 2400 dpi */ 2066141cc406Sopenharmony_ci k = sp->xdpi / MIN (sp->xdpi, 2400); 2067141cc406Sopenharmony_ci else if (sp->source == PIXMA_SOURCE_TPU && (s->cfg->pid == CS9000F_PID || s->cfg->pid == CS9000F_MII_PID)) 2068141cc406Sopenharmony_ci /* CS9000F in TPU mode */ 2069141cc406Sopenharmony_ci k = sp->xdpi / MIN (sp->xdpi, 9600); 2070141cc406Sopenharmony_ci else 2071141cc406Sopenharmony_ci /* default */ 2072141cc406Sopenharmony_ci k = sp->xdpi / MIN (sp->xdpi, 4800); 2073141cc406Sopenharmony_ci 2074141cc406Sopenharmony_ci sp->x /= k; 2075141cc406Sopenharmony_ci sp->xs /= k; 2076141cc406Sopenharmony_ci sp->y /= k; 2077141cc406Sopenharmony_ci sp->w /= k; 2078141cc406Sopenharmony_ci sp->wx /= k; 2079141cc406Sopenharmony_ci sp->h /= k; 2080141cc406Sopenharmony_ci sp->xdpi /= k; 2081141cc406Sopenharmony_ci sp->ydpi = sp->xdpi; 2082141cc406Sopenharmony_ci } 2083141cc406Sopenharmony_ci 2084141cc406Sopenharmony_ci /* lowest res is 75, 150, 300 or 600 dpi */ 2085141cc406Sopenharmony_ci { 2086141cc406Sopenharmony_ci uint8_t k; 2087141cc406Sopenharmony_ci 2088141cc406Sopenharmony_ci if (sp->source == PIXMA_SOURCE_TPU && sp->mode == PIXMA_SCAN_MODE_TPUIR) 2089141cc406Sopenharmony_ci /* TPUIR mode */ 2090141cc406Sopenharmony_ci k = MAX (sp->xdpi, 600) / sp->xdpi; 2091141cc406Sopenharmony_ci else if (sp->source == PIXMA_SOURCE_TPU 2092141cc406Sopenharmony_ci && ((mp->generation >= 3) || (s->cfg->pid == MP810_PID) || (s->cfg->pid == MP960_PID))) 2093141cc406Sopenharmony_ci /* TPU mode for generation 3+ scanners 2094141cc406Sopenharmony_ci * MP810, MP960 appear to have a 200dpi mode for low-res scans, not 150 dpi */ 2095141cc406Sopenharmony_ci k = MAX (sp->xdpi, 300) / sp->xdpi; 2096141cc406Sopenharmony_ci else if (sp->source == PIXMA_SOURCE_TPU 2097141cc406Sopenharmony_ci || sp->mode == PIXMA_SCAN_MODE_COLOR_48 || sp->mode == PIXMA_SCAN_MODE_GRAY_16) 2098141cc406Sopenharmony_ci /* TPU mode and 16 bit flatbed scans */ 2099141cc406Sopenharmony_ci k = MAX (sp->xdpi, 150) / sp->xdpi; 2100141cc406Sopenharmony_ci else 2101141cc406Sopenharmony_ci /* default */ 2102141cc406Sopenharmony_ci k = MAX (sp->xdpi, 75) / sp->xdpi; 2103141cc406Sopenharmony_ci 2104141cc406Sopenharmony_ci sp->x *= k; 2105141cc406Sopenharmony_ci sp->xs *= k; 2106141cc406Sopenharmony_ci sp->y *= k; 2107141cc406Sopenharmony_ci sp->w *= k; 2108141cc406Sopenharmony_ci sp->wx *= k; 2109141cc406Sopenharmony_ci sp->h *= k; 2110141cc406Sopenharmony_ci sp->xdpi *= k; 2111141cc406Sopenharmony_ci sp->ydpi = sp->xdpi; 2112141cc406Sopenharmony_ci } 2113141cc406Sopenharmony_ci 2114141cc406Sopenharmony_ci /* PDBG (pixma_dbg (4, "*mp810_check_param***** Finally: channels=%u, depth=%u, x=%u, y=%u, w=%u, h=%u, xs=%u, wx=%u *****\n", 2115141cc406Sopenharmony_ci sp->channels, sp->depth, sp->x, sp->y, sp->w, sp->h, sp->xs, sp->wx)); */ 2116141cc406Sopenharmony_ci 2117141cc406Sopenharmony_ci return 0; 2118141cc406Sopenharmony_ci} 2119141cc406Sopenharmony_ci 2120141cc406Sopenharmony_cistatic int mp810_scan (pixma_t * s) 2121141cc406Sopenharmony_ci{ 2122141cc406Sopenharmony_ci int error = 0, tmo; 2123141cc406Sopenharmony_ci mp810_t *mp = (mp810_t *) s->subdriver; 2124141cc406Sopenharmony_ci 2125141cc406Sopenharmony_ci if (mp->state != state_idle) 2126141cc406Sopenharmony_ci return PIXMA_EBUSY; 2127141cc406Sopenharmony_ci 2128141cc406Sopenharmony_ci /* Generation 4: send XML dialog */ 2129141cc406Sopenharmony_ci if (mp->generation == 4 && s->param->adf_pageid == 0) 2130141cc406Sopenharmony_ci { 2131141cc406Sopenharmony_ci if (!send_xml_dialog (s, XML_START_1)) 2132141cc406Sopenharmony_ci return PIXMA_EPROTO; 2133141cc406Sopenharmony_ci if (!send_xml_dialog (s, XML_START_2)) 2134141cc406Sopenharmony_ci return PIXMA_EPROTO; 2135141cc406Sopenharmony_ci } 2136141cc406Sopenharmony_ci 2137141cc406Sopenharmony_ci /* clear interrupt packets buffer */ 2138141cc406Sopenharmony_ci while (handle_interrupt (s, 0) > 0) 2139141cc406Sopenharmony_ci { 2140141cc406Sopenharmony_ci } 2141141cc406Sopenharmony_ci 2142141cc406Sopenharmony_ci /* FIXME: Duplex ADF: check paper status only before odd pages (1,3,5,...). */ 2143141cc406Sopenharmony_ci if (is_scanning_from_adf (s)) 2144141cc406Sopenharmony_ci { 2145141cc406Sopenharmony_ci if ((error = query_status (s)) < 0) 2146141cc406Sopenharmony_ci return error; 2147141cc406Sopenharmony_ci tmo = 10; 2148141cc406Sopenharmony_ci while (!has_paper (s) && --tmo >= 0) 2149141cc406Sopenharmony_ci { 2150141cc406Sopenharmony_ci WAIT_INTERRUPT(1000); 2151141cc406Sopenharmony_ci PDBG(pixma_dbg (2, "No paper in ADF. Timed out in %d sec.\n", tmo)); 2152141cc406Sopenharmony_ci } 2153141cc406Sopenharmony_ci if (!has_paper (s)) 2154141cc406Sopenharmony_ci return PIXMA_ENO_PAPER; 2155141cc406Sopenharmony_ci } 2156141cc406Sopenharmony_ci 2157141cc406Sopenharmony_ci if (has_ccd_sensor (s) && (mp->generation <= 2)) 2158141cc406Sopenharmony_ci { 2159141cc406Sopenharmony_ci error = send_cmd_e920 (s); 2160141cc406Sopenharmony_ci switch (error) 2161141cc406Sopenharmony_ci { 2162141cc406Sopenharmony_ci case PIXMA_ECANCELED: 2163141cc406Sopenharmony_ci case PIXMA_EBUSY: 2164141cc406Sopenharmony_ci PDBG(pixma_dbg (2, "cmd e920 or d520 returned %s\n", pixma_strerror (error))); 2165141cc406Sopenharmony_ci /* fall through */ 2166141cc406Sopenharmony_ci case 0: 2167141cc406Sopenharmony_ci query_status (s); 2168141cc406Sopenharmony_ci break; 2169141cc406Sopenharmony_ci default: 2170141cc406Sopenharmony_ci PDBG(pixma_dbg (1, "WARNING: cmd e920 or d520 failed %s\n", pixma_strerror (error))); 2171141cc406Sopenharmony_ci return error; 2172141cc406Sopenharmony_ci } 2173141cc406Sopenharmony_ci tmo = 3; /* like Windows driver, CCD calibration ? */ 2174141cc406Sopenharmony_ci while (--tmo >= 0) 2175141cc406Sopenharmony_ci { 2176141cc406Sopenharmony_ci WAIT_INTERRUPT(1000); 2177141cc406Sopenharmony_ci PDBG(pixma_dbg (2, "CCD Calibration ends in %d sec.\n", tmo)); 2178141cc406Sopenharmony_ci } 2179141cc406Sopenharmony_ci /* pixma_sleep(2000000); */ 2180141cc406Sopenharmony_ci } 2181141cc406Sopenharmony_ci 2182141cc406Sopenharmony_ci tmo = 10; 2183141cc406Sopenharmony_ci if (s->param->adf_pageid == 0 || mp->generation <= 2) 2184141cc406Sopenharmony_ci { 2185141cc406Sopenharmony_ci error = start_session (s); 2186141cc406Sopenharmony_ci while (error == PIXMA_EBUSY && --tmo >= 0) 2187141cc406Sopenharmony_ci { 2188141cc406Sopenharmony_ci if (s->cancel) 2189141cc406Sopenharmony_ci { 2190141cc406Sopenharmony_ci error = PIXMA_ECANCELED; 2191141cc406Sopenharmony_ci break; 2192141cc406Sopenharmony_ci } 2193141cc406Sopenharmony_ci PDBG(pixma_dbg (2, "Scanner is busy. Timed out in %d sec.\n", tmo + 1)); 2194141cc406Sopenharmony_ci pixma_sleep (1000000); 2195141cc406Sopenharmony_ci error = start_session (s); 2196141cc406Sopenharmony_ci } 2197141cc406Sopenharmony_ci if (error == PIXMA_EBUSY || error == PIXMA_ETIMEDOUT) 2198141cc406Sopenharmony_ci { 2199141cc406Sopenharmony_ci /* The scanner maybe hangs. We try to empty output buffer of the 2200141cc406Sopenharmony_ci * scanner and issue the cancel command. */ 2201141cc406Sopenharmony_ci PDBG(pixma_dbg (2, "Scanner hangs? Sending abort_session command.\n")); 2202141cc406Sopenharmony_ci drain_bulk_in (s); 2203141cc406Sopenharmony_ci abort_session (s); 2204141cc406Sopenharmony_ci pixma_sleep (500000); 2205141cc406Sopenharmony_ci error = start_session (s); 2206141cc406Sopenharmony_ci } 2207141cc406Sopenharmony_ci if ((error >= 0) || (mp->generation >= 3)) 2208141cc406Sopenharmony_ci mp->state = state_warmup; 2209141cc406Sopenharmony_ci if ((error >= 0) && (mp->generation <= 2)) 2210141cc406Sopenharmony_ci error = select_source (s); 2211141cc406Sopenharmony_ci if ((error >= 0) && (mp->generation >= 3) && has_ccd_sensor (s)) 2212141cc406Sopenharmony_ci error = init_ccd_lamp_3 (s); 2213141cc406Sopenharmony_ci if ((error >= 0) && !is_scanning_from_tpu (s)) 2214141cc406Sopenharmony_ci { 2215141cc406Sopenharmony_ci int i; 2216141cc406Sopenharmony_ci /* FIXME: 48 bit flatbed scans don't need gamma tables 2217141cc406Sopenharmony_ci * the code below doesn't run */ 2218141cc406Sopenharmony_ci /*if (is_color_48 (s) || is_gray_16 (s)) 2219141cc406Sopenharmony_ci error = 0; 2220141cc406Sopenharmony_ci else*/ 2221141cc406Sopenharmony_ci for (i = (mp->generation >= 3) ? 3 : 1; i > 0 && error >= 0; i--) 2222141cc406Sopenharmony_ci error = send_gamma_table (s); 2223141cc406Sopenharmony_ci } 2224141cc406Sopenharmony_ci else if (error >= 0) /* in TPU mode, for gen 1, 2, and 3 */ 2225141cc406Sopenharmony_ci error = send_set_tpu_info (s); 2226141cc406Sopenharmony_ci } 2227141cc406Sopenharmony_ci else 2228141cc406Sopenharmony_ci /* ADF pageid != 0 and gen3 or above */ 2229141cc406Sopenharmony_ci pixma_sleep (1000000); 2230141cc406Sopenharmony_ci 2231141cc406Sopenharmony_ci if ((error >= 0) || (mp->generation >= 3)) 2232141cc406Sopenharmony_ci mp->state = state_warmup; 2233141cc406Sopenharmony_ci if (error >= 0) 2234141cc406Sopenharmony_ci error = send_scan_param (s); 2235141cc406Sopenharmony_ci if ((error >= 0) && (mp->generation >= 3)) 2236141cc406Sopenharmony_ci error = start_scan_3 (s); 2237141cc406Sopenharmony_ci if (error < 0) 2238141cc406Sopenharmony_ci { 2239141cc406Sopenharmony_ci mp->last_block = 0x38; /* Force abort session if ADF scan */ 2240141cc406Sopenharmony_ci mp810_finish_scan (s); 2241141cc406Sopenharmony_ci return error; 2242141cc406Sopenharmony_ci } 2243141cc406Sopenharmony_ci return 0; 2244141cc406Sopenharmony_ci} 2245141cc406Sopenharmony_ci 2246141cc406Sopenharmony_cistatic int mp810_fill_buffer (pixma_t * s, pixma_imagebuf_t * ib) 2247141cc406Sopenharmony_ci{ 2248141cc406Sopenharmony_ci int error; 2249141cc406Sopenharmony_ci mp810_t *mp = (mp810_t *) s->subdriver; 2250141cc406Sopenharmony_ci unsigned block_size, bytes_received, proc_buf_size, line_size; 2251141cc406Sopenharmony_ci uint8_t header[16]; 2252141cc406Sopenharmony_ci 2253141cc406Sopenharmony_ci if (mp->state == state_warmup) 2254141cc406Sopenharmony_ci { /* prepare read image data */ 2255141cc406Sopenharmony_ci /* PDBG (pixma_dbg (4, "**mp810_fill_buffer***** warmup *****\n")); */ 2256141cc406Sopenharmony_ci 2257141cc406Sopenharmony_ci RET_IF_ERR(wait_until_ready (s)); 2258141cc406Sopenharmony_ci pixma_sleep (1000000); /* No need to sleep, actually, but Window's driver 2259141cc406Sopenharmony_ci * sleep 1.5 sec. */ 2260141cc406Sopenharmony_ci mp->state = state_scanning; 2261141cc406Sopenharmony_ci mp->last_block = 0; 2262141cc406Sopenharmony_ci 2263141cc406Sopenharmony_ci line_size = get_cis_ccd_line_size (s); 2264141cc406Sopenharmony_ci proc_buf_size = (2 * calc_shifting (s) + 2) * line_size; 2265141cc406Sopenharmony_ci mp->cb.buf = realloc (mp->cb.buf, CMDBUF_SIZE + IMAGE_BLOCK_SIZE + proc_buf_size); 2266141cc406Sopenharmony_ci if (!mp->cb.buf) 2267141cc406Sopenharmony_ci return PIXMA_ENOMEM; 2268141cc406Sopenharmony_ci mp->linebuf = mp->cb.buf + CMDBUF_SIZE; 2269141cc406Sopenharmony_ci mp->imgbuf = mp->data_left_ofs = mp->linebuf + line_size; 2270141cc406Sopenharmony_ci mp->data_left_len = 0; 2271141cc406Sopenharmony_ci } 2272141cc406Sopenharmony_ci 2273141cc406Sopenharmony_ci do 2274141cc406Sopenharmony_ci { /* read complete image data from the scanner */ 2275141cc406Sopenharmony_ci if (s->cancel) 2276141cc406Sopenharmony_ci return PIXMA_ECANCELED; 2277141cc406Sopenharmony_ci if ((mp->last_block & 0x28) == 0x28) 2278141cc406Sopenharmony_ci { /* end of image */ 2279141cc406Sopenharmony_ci mp->state = state_finished; 2280141cc406Sopenharmony_ci /* PDBG (pixma_dbg (4, "**mp810_fill_buffer***** end of image *****\n")); */ 2281141cc406Sopenharmony_ci return 0; 2282141cc406Sopenharmony_ci } 2283141cc406Sopenharmony_ci /* PDBG (pixma_dbg (4, "*mp810_fill_buffer***** moving %u bytes into buffer *****\n", mp->data_left_len)); */ 2284141cc406Sopenharmony_ci memmove (mp->imgbuf, mp->data_left_ofs, mp->data_left_len); 2285141cc406Sopenharmony_ci error = read_image_block (s, header, mp->imgbuf + mp->data_left_len); 2286141cc406Sopenharmony_ci if (error < 0) 2287141cc406Sopenharmony_ci { 2288141cc406Sopenharmony_ci if (error == PIXMA_ECANCELED) 2289141cc406Sopenharmony_ci { 2290141cc406Sopenharmony_ci /* NOTE: I see this in traffic logs but I don't know its meaning. */ 2291141cc406Sopenharmony_ci read_error_info (s, NULL, 0); 2292141cc406Sopenharmony_ci } 2293141cc406Sopenharmony_ci return error; 2294141cc406Sopenharmony_ci } 2295141cc406Sopenharmony_ci 2296141cc406Sopenharmony_ci bytes_received = error; 2297141cc406Sopenharmony_ci /*PDBG (pixma_dbg (4, "*mp810_fill_buffer***** %u bytes received by read_image_block *****\n", bytes_received));*/ 2298141cc406Sopenharmony_ci block_size = pixma_get_be32 (header + 12); 2299141cc406Sopenharmony_ci mp->last_block = header[8] & 0x38; 2300141cc406Sopenharmony_ci if ((header[8] & ~0x38) != 0) 2301141cc406Sopenharmony_ci { 2302141cc406Sopenharmony_ci PDBG(pixma_dbg (1, "WARNING: Unexpected result header\n")); 2303141cc406Sopenharmony_ci PDBG(pixma_hexdump (1, header, 16)); 2304141cc406Sopenharmony_ci } 2305141cc406Sopenharmony_ci PASSERT(bytes_received == block_size); 2306141cc406Sopenharmony_ci 2307141cc406Sopenharmony_ci if (block_size == 0) 2308141cc406Sopenharmony_ci { /* no image data at this moment. */ 2309141cc406Sopenharmony_ci pixma_sleep (10000); 2310141cc406Sopenharmony_ci } 2311141cc406Sopenharmony_ci /* For TPU at 48 bits/pixel to output at 24 bits/pixel */ 2312141cc406Sopenharmony_ci#ifndef DEBUG_TPU_48 2313141cc406Sopenharmony_ci#ifndef TPU_48 2314141cc406Sopenharmony_ci PDBG (pixma_dbg (1, "WARNING: 9000F using 24 instead of 48 bit processing \n")); 2315141cc406Sopenharmony_ci#ifndef DEBUG_TPU_24 2316141cc406Sopenharmony_ci if (is_scanning_from_tpu (s)) 2317141cc406Sopenharmony_ci#endif 2318141cc406Sopenharmony_ci bytes_received = pack_48_24_bpc (mp->imgbuf + mp->data_left_len, bytes_received); 2319141cc406Sopenharmony_ci#endif 2320141cc406Sopenharmony_ci#endif 2321141cc406Sopenharmony_ci /* Post-process the image data */ 2322141cc406Sopenharmony_ci mp->data_left_ofs = mp->imgbuf + mp->data_left_len + bytes_received; 2323141cc406Sopenharmony_ci mp->data_left_len = post_process_image_data (s, ib); 2324141cc406Sopenharmony_ci mp->data_left_ofs -= mp->data_left_len; 2325141cc406Sopenharmony_ci /* PDBG (pixma_dbg (4, "* mp810_fill_buffer: data_left_len %u \n", mp->data_left_len)); */ 2326141cc406Sopenharmony_ci /* PDBG (pixma_dbg (4, "* mp810_fill_buffer: data_left_ofs %u \n", mp->data_left_ofs)); */ 2327141cc406Sopenharmony_ci } 2328141cc406Sopenharmony_ci while (ib->rend == ib->rptr); 2329141cc406Sopenharmony_ci 2330141cc406Sopenharmony_ci return ib->rend - ib->rptr; 2331141cc406Sopenharmony_ci} 2332141cc406Sopenharmony_ci 2333141cc406Sopenharmony_cistatic void mp810_finish_scan (pixma_t * s) 2334141cc406Sopenharmony_ci{ 2335141cc406Sopenharmony_ci int error; 2336141cc406Sopenharmony_ci mp810_t *mp = (mp810_t *) s->subdriver; 2337141cc406Sopenharmony_ci 2338141cc406Sopenharmony_ci switch (mp->state) 2339141cc406Sopenharmony_ci { 2340141cc406Sopenharmony_ci case state_transfering: 2341141cc406Sopenharmony_ci drain_bulk_in (s); 2342141cc406Sopenharmony_ci /* fall through */ 2343141cc406Sopenharmony_ci case state_scanning: 2344141cc406Sopenharmony_ci case state_warmup: 2345141cc406Sopenharmony_ci case state_finished: 2346141cc406Sopenharmony_ci /* Send the get TPU info message */ 2347141cc406Sopenharmony_ci if (is_scanning_from_tpu (s) && mp->tpu_datalen == 0) 2348141cc406Sopenharmony_ci send_get_tpu_info_3 (s); 2349141cc406Sopenharmony_ci /* FIXME: to process several pages ADF scan, must not send 2350141cc406Sopenharmony_ci * abort_session and start_session between pages (last_block=0x28) */ 2351141cc406Sopenharmony_ci if (mp->generation <= 2 || !is_scanning_from_adf (s) 2352141cc406Sopenharmony_ci || mp->last_block == 0x38) 2353141cc406Sopenharmony_ci { 2354141cc406Sopenharmony_ci error = abort_session (s); /* FIXME: it probably doesn't work in duplex mode! */ 2355141cc406Sopenharmony_ci if (error < 0) 2356141cc406Sopenharmony_ci PDBG(pixma_dbg (1, "WARNING:abort_session() failed %d\n", error)); 2357141cc406Sopenharmony_ci 2358141cc406Sopenharmony_ci /* Generation 4: send XML end of scan dialog */ 2359141cc406Sopenharmony_ci if (mp->generation == 4) 2360141cc406Sopenharmony_ci { 2361141cc406Sopenharmony_ci if (!send_xml_dialog (s, XML_END)) 2362141cc406Sopenharmony_ci PDBG(pixma_dbg (1, "WARNING:XML_END dialog failed \n")); 2363141cc406Sopenharmony_ci } 2364141cc406Sopenharmony_ci } 2365141cc406Sopenharmony_ci mp->state = state_idle; 2366141cc406Sopenharmony_ci /* fall through */ 2367141cc406Sopenharmony_ci case state_idle: 2368141cc406Sopenharmony_ci break; 2369141cc406Sopenharmony_ci } 2370141cc406Sopenharmony_ci} 2371141cc406Sopenharmony_ci 2372141cc406Sopenharmony_cistatic void mp810_wait_event (pixma_t * s, int timeout) 2373141cc406Sopenharmony_ci{ 2374141cc406Sopenharmony_ci /* FIXME: timeout is not correct. See usbGetCompleteUrbNoIntr() for 2375141cc406Sopenharmony_ci * instance. */ 2376141cc406Sopenharmony_ci while (s->events == 0 && handle_interrupt (s, timeout) > 0) 2377141cc406Sopenharmony_ci { 2378141cc406Sopenharmony_ci } 2379141cc406Sopenharmony_ci} 2380141cc406Sopenharmony_ci 2381141cc406Sopenharmony_cistatic int mp810_get_status (pixma_t * s, pixma_device_status_t * status) 2382141cc406Sopenharmony_ci{ 2383141cc406Sopenharmony_ci int error; 2384141cc406Sopenharmony_ci 2385141cc406Sopenharmony_ci RET_IF_ERR(query_status (s)); 2386141cc406Sopenharmony_ci status->hardware = PIXMA_HARDWARE_OK; 2387141cc406Sopenharmony_ci status->adf = (has_paper (s)) ? PIXMA_ADF_OK : PIXMA_ADF_NO_PAPER; 2388141cc406Sopenharmony_ci status->cal = 2389141cc406Sopenharmony_ci (is_calibrated (s)) ? PIXMA_CALIBRATION_OK : PIXMA_CALIBRATION_OFF; 2390141cc406Sopenharmony_ci return 0; 2391141cc406Sopenharmony_ci} 2392141cc406Sopenharmony_ci 2393141cc406Sopenharmony_cistatic const pixma_scan_ops_t pixma_mp800_ops = 2394141cc406Sopenharmony_ci{ 2395141cc406Sopenharmony_ci mp810_open, 2396141cc406Sopenharmony_ci mp810_close, 2397141cc406Sopenharmony_ci mp810_scan, 2398141cc406Sopenharmony_ci mp810_fill_buffer, 2399141cc406Sopenharmony_ci mp810_finish_scan, 2400141cc406Sopenharmony_ci mp810_wait_event, 2401141cc406Sopenharmony_ci mp810_check_param, 2402141cc406Sopenharmony_ci mp810_get_status 2403141cc406Sopenharmony_ci}; 2404141cc406Sopenharmony_ci 2405141cc406Sopenharmony_ci#define DEVICE(name, model, pid, min_dpi_16, dpi, adftpu_min_dpi, adftpu_max_dpi, tpuir_min_dpi, tpuir_max_dpi, w, h, cap) { \ 2406141cc406Sopenharmony_ci name, /* name */ \ 2407141cc406Sopenharmony_ci model, /* model */ \ 2408141cc406Sopenharmony_ci CANON_VID, pid, /* vid pid */ \ 2409141cc406Sopenharmony_ci 0, /* iface */ \ 2410141cc406Sopenharmony_ci &pixma_mp800_ops, /* ops */ \ 2411141cc406Sopenharmony_ci 0, /* min_xdpi not used in this subdriver */ \ 2412141cc406Sopenharmony_ci min_dpi_16, /* min_xdpi_16 */ \ 2413141cc406Sopenharmony_ci dpi, 2*(dpi), /* xdpi, ydpi */ \ 2414141cc406Sopenharmony_ci adftpu_min_dpi, adftpu_max_dpi, /* adftpu_min_dpi, adftpu_max_dpi */ \ 2415141cc406Sopenharmony_ci tpuir_min_dpi, tpuir_max_dpi, /* tpuir_min_dpi, tpuir_max_dpi */ \ 2416141cc406Sopenharmony_ci w, h, /* width, height */ \ 2417141cc406Sopenharmony_ci PIXMA_CAP_CCD| /* all scanners with CCD*/ \ 2418141cc406Sopenharmony_ci PIXMA_CAP_EASY_RGB| \ 2419141cc406Sopenharmony_ci PIXMA_CAP_GRAY| /* all scanners with software grayscale */ \ 2420141cc406Sopenharmony_ci PIXMA_CAP_LINEART| /* all scanners with software lineart */ \ 2421141cc406Sopenharmony_ci PIXMA_CAP_GAMMA_TABLE|PIXMA_CAP_EVENTS|cap \ 2422141cc406Sopenharmony_ci} 2423141cc406Sopenharmony_ci 2424141cc406Sopenharmony_ci#define END_OF_DEVICE_LIST DEVICE(NULL, NULL, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0) 2425141cc406Sopenharmony_ci 2426141cc406Sopenharmony_ciconst pixma_config_t pixma_mp800_devices[] = 2427141cc406Sopenharmony_ci{ 2428141cc406Sopenharmony_ci /* Generation 1: CCD */ 2429141cc406Sopenharmony_ci DEVICE ("Canon PIXMA MP800", "MP800", MP800_PID, 0, 2400, 150, 0, 0, 0, 638, 877, PIXMA_CAP_TPU | PIXMA_CAP_GT_4096), 2430141cc406Sopenharmony_ci DEVICE ("Canon PIXMA MP800R", "MP800R", MP800R_PID, 0, 2400, 150, 0, 0, 0, 638, 877, PIXMA_CAP_TPU | PIXMA_CAP_GT_4096), 2431141cc406Sopenharmony_ci DEVICE ("Canon PIXMA MP830", "MP830", MP830_PID, 0, 2400, 150, 0, 0, 0, 638, 877, PIXMA_CAP_ADFDUP | PIXMA_CAP_GT_4096), 2432141cc406Sopenharmony_ci 2433141cc406Sopenharmony_ci /* Generation 2: CCD */ 2434141cc406Sopenharmony_ci DEVICE ("Canon PIXMA MP810", "MP810", MP810_PID, 0, 4800, 300, 0, 0, 0, 638, 877, PIXMA_CAP_TPU), 2435141cc406Sopenharmony_ci DEVICE ("Canon PIXMA MP960", "MP960", MP960_PID, 0, 4800, 300, 0, 0, 0, 638, 877, PIXMA_CAP_TPU), 2436141cc406Sopenharmony_ci 2437141cc406Sopenharmony_ci /* Generation 3 CCD not managed as Generation 2 */ 2438141cc406Sopenharmony_ci DEVICE ("Canon Pixma MP970", "MP970", MP970_PID, 0, 4800, 300, 0, 0, 0, 638, 877, PIXMA_CAP_TPU), 2439141cc406Sopenharmony_ci 2440141cc406Sopenharmony_ci /* Flatbed scanner CCD (2007) */ 2441141cc406Sopenharmony_ci DEVICE ("Canoscan 8800F", "8800F", CS8800F_PID, 150, 4800, 300, 0, 0, 0, 638, 877, PIXMA_CAP_TPU /*| PIXMA_CAP_NEGATIVE*/ | PIXMA_CAP_48BIT), 2442141cc406Sopenharmony_ci 2443141cc406Sopenharmony_ci /* PIXMA 2008 vintage CCD */ 2444141cc406Sopenharmony_ci DEVICE ("Canon MP980 series", "MP980", MP980_PID, 0, 4800, 300, 0, 0, 0, 638, 877, PIXMA_CAP_TPU), 2445141cc406Sopenharmony_ci 2446141cc406Sopenharmony_ci /* Generation 4 CCD */ 2447141cc406Sopenharmony_ci DEVICE ("Canon MP990 series", "MP990", MP990_PID, 0, 4800, 300, 0, 0, 0, 638, 877, PIXMA_CAP_TPU), 2448141cc406Sopenharmony_ci 2449141cc406Sopenharmony_ci /* Flatbed scanner (2010) */ 2450141cc406Sopenharmony_ci DEVICE ("Canoscan 9000F", "9000F", CS9000F_PID, 150, 4800, 300, 9600, 600, 2400, 638, 877, PIXMA_CAP_TPUIR /*| PIXMA_CAP_NEGATIVE*/ | PIXMA_CAP_48BIT), 2451141cc406Sopenharmony_ci 2452141cc406Sopenharmony_ci /* Latest devices (2010) Generation 4 CCD untested */ 2453141cc406Sopenharmony_ci DEVICE ("Canon PIXMA MG8100", "MG8100", MG8100_PID, 0, 4800, 300, 0, 0, 0, 638, 877, PIXMA_CAP_TPU), 2454141cc406Sopenharmony_ci 2455141cc406Sopenharmony_ci /* Latest devices (2011) Generation 4 CCD untested */ 2456141cc406Sopenharmony_ci DEVICE ("Canon PIXMA MG8200", "MG8200", MG8200_PID, 0, 4800, 300, 0, 0, 0, 638, 877, PIXMA_CAP_TPU), 2457141cc406Sopenharmony_ci 2458141cc406Sopenharmony_ci /* Flatbed scanner (2013) */ 2459141cc406Sopenharmony_ci DEVICE ("Canoscan 9000F Mark II", "9000FMarkII", CS9000F_MII_PID, 150, 4800, 300, 9600, 600, 2400, 638, 877, PIXMA_CAP_TPUIR | PIXMA_CAP_48BIT), 2460141cc406Sopenharmony_ci 2461141cc406Sopenharmony_ci END_OF_DEVICE_LIST 2462141cc406Sopenharmony_ci}; 2463