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) 2006-2007 Wittawat Yamwong <wittawat@web.de> 5141cc406Sopenharmony_ci 6141cc406Sopenharmony_ci This file is part of the SANE package. 7141cc406Sopenharmony_ci 8141cc406Sopenharmony_ci This program is free software; you can redistribute it and/or 9141cc406Sopenharmony_ci modify it under the terms of the GNU General Public License as 10141cc406Sopenharmony_ci published by the Free Software Foundation; either version 2 of the 11141cc406Sopenharmony_ci License, or (at your option) any later version. 12141cc406Sopenharmony_ci 13141cc406Sopenharmony_ci This program is distributed in the hope that it will be useful, but 14141cc406Sopenharmony_ci WITHOUT ANY WARRANTY; without even the implied warranty of 15141cc406Sopenharmony_ci MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 16141cc406Sopenharmony_ci General Public License for more details. 17141cc406Sopenharmony_ci 18141cc406Sopenharmony_ci You should have received a copy of the GNU General Public License 19141cc406Sopenharmony_ci along with this program. If not, see <https://www.gnu.org/licenses/>. 20141cc406Sopenharmony_ci 21141cc406Sopenharmony_ci As a special exception, the authors of SANE give permission for 22141cc406Sopenharmony_ci additional uses of the libraries contained in this release of SANE. 23141cc406Sopenharmony_ci 24141cc406Sopenharmony_ci The exception is that, if you link a SANE library with other files 25141cc406Sopenharmony_ci to produce an executable, this does not by itself cause the 26141cc406Sopenharmony_ci resulting executable to be covered by the GNU General Public 27141cc406Sopenharmony_ci License. Your use of that executable is in no way restricted on 28141cc406Sopenharmony_ci account of linking the SANE library code into it. 29141cc406Sopenharmony_ci 30141cc406Sopenharmony_ci This exception does not, however, invalidate any other reasons why 31141cc406Sopenharmony_ci the executable file might be covered by the GNU General Public 32141cc406Sopenharmony_ci License. 33141cc406Sopenharmony_ci 34141cc406Sopenharmony_ci If you submit changes to SANE to the maintainers to be included in 35141cc406Sopenharmony_ci a subsequent release, you agree by submitting the changes that 36141cc406Sopenharmony_ci those changes may be distributed with this exception intact. 37141cc406Sopenharmony_ci 38141cc406Sopenharmony_ci If you write modifications of your own for SANE, it is your choice 39141cc406Sopenharmony_ci whether to permit this exception to apply to your modifications. 40141cc406Sopenharmony_ci If you do not wish that, delete this exception notice. 41141cc406Sopenharmony_ci */ 42141cc406Sopenharmony_ci 43141cc406Sopenharmony_ci/**************************************************************************** 44141cc406Sopenharmony_ci * Credits should go to Martin Schewe (http://pixma.schewe.com) who analysed 45141cc406Sopenharmony_ci * the protocol of MP750. 46141cc406Sopenharmony_ci ****************************************************************************/ 47141cc406Sopenharmony_ci 48141cc406Sopenharmony_ci#include "../include/sane/config.h" 49141cc406Sopenharmony_ci 50141cc406Sopenharmony_ci#include <stdlib.h> 51141cc406Sopenharmony_ci#include <string.h> 52141cc406Sopenharmony_ci 53141cc406Sopenharmony_ci#include "pixma_rename.h" 54141cc406Sopenharmony_ci#include "pixma_common.h" 55141cc406Sopenharmony_ci#include "pixma_io.h" 56141cc406Sopenharmony_ci 57141cc406Sopenharmony_ci/* TODO: remove lines marked with SIM. They are inserted so that I can test 58141cc406Sopenharmony_ci the subdriver with the simulator. WY */ 59141cc406Sopenharmony_ci 60141cc406Sopenharmony_ci#ifdef __GNUC__ 61141cc406Sopenharmony_ci# define UNUSED(v) (void) v 62141cc406Sopenharmony_ci#else 63141cc406Sopenharmony_ci# define UNUSED(v) 64141cc406Sopenharmony_ci#endif 65141cc406Sopenharmony_ci 66141cc406Sopenharmony_ci#define IMAGE_BLOCK_SIZE 0xc000 67141cc406Sopenharmony_ci#define CMDBUF_SIZE 512 68141cc406Sopenharmony_ci#define HAS_PAPER(s) (s[1] == 0) 69141cc406Sopenharmony_ci#define IS_WARMING_UP(s) (s[7] != 3) 70141cc406Sopenharmony_ci#define IS_CALIBRATED(s) (s[8] == 0xf) 71141cc406Sopenharmony_ci 72141cc406Sopenharmony_ci#define MP750_PID 0x1706 73141cc406Sopenharmony_ci#define MP760_PID 0x1708 74141cc406Sopenharmony_ci#define MP780_PID 0x1707 75141cc406Sopenharmony_ci 76141cc406Sopenharmony_ci 77141cc406Sopenharmony_cienum mp750_state_t 78141cc406Sopenharmony_ci{ 79141cc406Sopenharmony_ci state_idle, 80141cc406Sopenharmony_ci state_warmup, 81141cc406Sopenharmony_ci state_scanning, 82141cc406Sopenharmony_ci state_transfering, 83141cc406Sopenharmony_ci state_finished 84141cc406Sopenharmony_ci}; 85141cc406Sopenharmony_ci 86141cc406Sopenharmony_cienum mp750_cmd_t 87141cc406Sopenharmony_ci{ 88141cc406Sopenharmony_ci cmd_start_session = 0xdb20, 89141cc406Sopenharmony_ci cmd_select_source = 0xdd20, 90141cc406Sopenharmony_ci cmd_scan_param = 0xde20, 91141cc406Sopenharmony_ci cmd_status = 0xf320, 92141cc406Sopenharmony_ci cmd_abort_session = 0xef20, 93141cc406Sopenharmony_ci cmd_time = 0xeb80, 94141cc406Sopenharmony_ci cmd_read_image = 0xd420, 95141cc406Sopenharmony_ci 96141cc406Sopenharmony_ci cmd_activate = 0xcf60, 97141cc406Sopenharmony_ci cmd_calibrate = 0xe920, 98141cc406Sopenharmony_ci cmd_error_info = 0xff20 99141cc406Sopenharmony_ci}; 100141cc406Sopenharmony_ci 101141cc406Sopenharmony_citypedef struct mp750_t 102141cc406Sopenharmony_ci{ 103141cc406Sopenharmony_ci enum mp750_state_t state; 104141cc406Sopenharmony_ci pixma_cmdbuf_t cb; 105141cc406Sopenharmony_ci unsigned raw_width, raw_height; 106141cc406Sopenharmony_ci uint8_t current_status[12]; 107141cc406Sopenharmony_ci 108141cc406Sopenharmony_ci uint8_t *buf, *rawimg, *img; 109141cc406Sopenharmony_ci /* make new buffer for rgb_to_gray to act on */ 110141cc406Sopenharmony_ci uint8_t *imgcol; 111141cc406Sopenharmony_ci unsigned line_size; /* need in 2 functions */ 112141cc406Sopenharmony_ci 113141cc406Sopenharmony_ci unsigned rawimg_left, imgbuf_len, last_block_size, imgbuf_ofs; 114141cc406Sopenharmony_ci int shifted_bytes; 115141cc406Sopenharmony_ci int stripe_shift; /* for 2400dpi */ 116141cc406Sopenharmony_ci unsigned last_block; 117141cc406Sopenharmony_ci 118141cc406Sopenharmony_ci unsigned monochrome:1; 119141cc406Sopenharmony_ci unsigned needs_abort:1; 120141cc406Sopenharmony_ci} mp750_t; 121141cc406Sopenharmony_ci 122141cc406Sopenharmony_ci 123141cc406Sopenharmony_ci 124141cc406Sopenharmony_cistatic void mp750_finish_scan (pixma_t * s); 125141cc406Sopenharmony_cistatic void check_status (pixma_t * s); 126141cc406Sopenharmony_ci 127141cc406Sopenharmony_cistatic int 128141cc406Sopenharmony_cihas_paper (pixma_t * s) 129141cc406Sopenharmony_ci{ 130141cc406Sopenharmony_ci mp750_t *mp = (mp750_t *) s->subdriver; 131141cc406Sopenharmony_ci return HAS_PAPER (mp->current_status); 132141cc406Sopenharmony_ci} 133141cc406Sopenharmony_ci 134141cc406Sopenharmony_cistatic int 135141cc406Sopenharmony_ciis_warming_up (pixma_t * s) 136141cc406Sopenharmony_ci{ 137141cc406Sopenharmony_ci mp750_t *mp = (mp750_t *) s->subdriver; 138141cc406Sopenharmony_ci return IS_WARMING_UP (mp->current_status); 139141cc406Sopenharmony_ci} 140141cc406Sopenharmony_ci 141141cc406Sopenharmony_cistatic int 142141cc406Sopenharmony_ciis_calibrated (pixma_t * s) 143141cc406Sopenharmony_ci{ 144141cc406Sopenharmony_ci mp750_t *mp = (mp750_t *) s->subdriver; 145141cc406Sopenharmony_ci return IS_CALIBRATED (mp->current_status); 146141cc406Sopenharmony_ci} 147141cc406Sopenharmony_ci 148141cc406Sopenharmony_cistatic void 149141cc406Sopenharmony_cidrain_bulk_in (pixma_t * s) 150141cc406Sopenharmony_ci{ 151141cc406Sopenharmony_ci mp750_t *mp = (mp750_t *) s->subdriver; 152141cc406Sopenharmony_ci while (pixma_read (s->io, mp->buf, IMAGE_BLOCK_SIZE) >= 0); 153141cc406Sopenharmony_ci} 154141cc406Sopenharmony_ci 155141cc406Sopenharmony_cistatic int 156141cc406Sopenharmony_ciabort_session (pixma_t * s) 157141cc406Sopenharmony_ci{ 158141cc406Sopenharmony_ci mp750_t *mp = (mp750_t *) s->subdriver; 159141cc406Sopenharmony_ci return pixma_exec_short_cmd (s, &mp->cb, cmd_abort_session); 160141cc406Sopenharmony_ci} 161141cc406Sopenharmony_ci 162141cc406Sopenharmony_cistatic int 163141cc406Sopenharmony_ciquery_status (pixma_t * s) 164141cc406Sopenharmony_ci{ 165141cc406Sopenharmony_ci mp750_t *mp = (mp750_t *) s->subdriver; 166141cc406Sopenharmony_ci uint8_t *data; 167141cc406Sopenharmony_ci int error; 168141cc406Sopenharmony_ci 169141cc406Sopenharmony_ci data = pixma_newcmd (&mp->cb, cmd_status, 0, 12); 170141cc406Sopenharmony_ci error = pixma_exec (s, &mp->cb); 171141cc406Sopenharmony_ci if (error >= 0) 172141cc406Sopenharmony_ci { 173141cc406Sopenharmony_ci memcpy (mp->current_status, data, 12); 174141cc406Sopenharmony_ci PDBG (pixma_dbg (3, "Current status: paper=%u cal=%u lamp=%u\n", 175141cc406Sopenharmony_ci data[1], data[8], data[7])); 176141cc406Sopenharmony_ci } 177141cc406Sopenharmony_ci return error; 178141cc406Sopenharmony_ci} 179141cc406Sopenharmony_ci 180141cc406Sopenharmony_cistatic int 181141cc406Sopenharmony_ciactivate (pixma_t * s, uint8_t x) 182141cc406Sopenharmony_ci{ 183141cc406Sopenharmony_ci mp750_t *mp = (mp750_t *) s->subdriver; 184141cc406Sopenharmony_ci uint8_t *data = pixma_newcmd (&mp->cb, cmd_activate, 10, 0); 185141cc406Sopenharmony_ci data[0] = 1; 186141cc406Sopenharmony_ci data[3] = x; 187141cc406Sopenharmony_ci return pixma_exec (s, &mp->cb); 188141cc406Sopenharmony_ci} 189141cc406Sopenharmony_ci 190141cc406Sopenharmony_cistatic int 191141cc406Sopenharmony_ciactivate_cs (pixma_t * s, uint8_t x) 192141cc406Sopenharmony_ci{ 193141cc406Sopenharmony_ci /*SIM*/ check_status (s); 194141cc406Sopenharmony_ci return activate (s, x); 195141cc406Sopenharmony_ci} 196141cc406Sopenharmony_ci 197141cc406Sopenharmony_cistatic int 198141cc406Sopenharmony_cistart_session (pixma_t * s) 199141cc406Sopenharmony_ci{ 200141cc406Sopenharmony_ci mp750_t *mp = (mp750_t *) s->subdriver; 201141cc406Sopenharmony_ci return pixma_exec_short_cmd (s, &mp->cb, cmd_start_session); 202141cc406Sopenharmony_ci} 203141cc406Sopenharmony_ci 204141cc406Sopenharmony_cistatic int 205141cc406Sopenharmony_ciselect_source (pixma_t * s) 206141cc406Sopenharmony_ci{ 207141cc406Sopenharmony_ci mp750_t *mp = (mp750_t *) s->subdriver; 208141cc406Sopenharmony_ci uint8_t *data = pixma_newcmd (&mp->cb, cmd_select_source, 10, 0); 209141cc406Sopenharmony_ci data[0] = (s->param->source == PIXMA_SOURCE_ADF) ? 2 : 1; 210141cc406Sopenharmony_ci data[1] = 1; 211141cc406Sopenharmony_ci return pixma_exec (s, &mp->cb); 212141cc406Sopenharmony_ci} 213141cc406Sopenharmony_ci 214141cc406Sopenharmony_cistatic int 215141cc406Sopenharmony_cihas_ccd_sensor (pixma_t * s) 216141cc406Sopenharmony_ci{ 217141cc406Sopenharmony_ci return ((s->cfg->cap & PIXMA_CAP_CCD) != 0); 218141cc406Sopenharmony_ci} 219141cc406Sopenharmony_ci 220141cc406Sopenharmony_cistatic int 221141cc406Sopenharmony_ciis_ccd_grayscale (pixma_t * s) 222141cc406Sopenharmony_ci{ 223141cc406Sopenharmony_ci return (has_ccd_sensor (s) && (s->param->channels == 1)); 224141cc406Sopenharmony_ci} 225141cc406Sopenharmony_ci 226141cc406Sopenharmony_ci/* CCD sensors don't have a Grayscale mode, but use color mode instead */ 227141cc406Sopenharmony_cistatic unsigned 228141cc406Sopenharmony_ciget_cis_ccd_line_size (pixma_t * s) 229141cc406Sopenharmony_ci{ 230141cc406Sopenharmony_ci return (s->param->wx ? s->param->line_size / s->param->w * s->param->wx 231141cc406Sopenharmony_ci : s->param->line_size) * ((is_ccd_grayscale (s)) ? 3 : 1); 232141cc406Sopenharmony_ci} 233141cc406Sopenharmony_ci 234141cc406Sopenharmony_cistatic int 235141cc406Sopenharmony_cisend_scan_param (pixma_t * s) 236141cc406Sopenharmony_ci{ 237141cc406Sopenharmony_ci mp750_t *mp = (mp750_t *) s->subdriver; 238141cc406Sopenharmony_ci uint8_t *data; 239141cc406Sopenharmony_ci 240141cc406Sopenharmony_ci data = pixma_newcmd (&mp->cb, cmd_scan_param, 0x2e, 0); 241141cc406Sopenharmony_ci pixma_set_be16 (s->param->xdpi | 0x8000, data + 0x04); 242141cc406Sopenharmony_ci pixma_set_be16 (s->param->ydpi | 0x8000, data + 0x06); 243141cc406Sopenharmony_ci pixma_set_be32 (s->param->x, data + 0x08); 244141cc406Sopenharmony_ci pixma_set_be32 (s->param->y, data + 0x0c); 245141cc406Sopenharmony_ci pixma_set_be32 (mp->raw_width, data + 0x10); 246141cc406Sopenharmony_ci pixma_set_be32 (mp->raw_height, data + 0x14); 247141cc406Sopenharmony_ci data[0x18] = 8; /* 8 = color, 4 = grayscale(?) */ 248141cc406Sopenharmony_ci /* GH: No, there is no grayscale for CCD devices, Windows shows same */ 249141cc406Sopenharmony_ci data[0x19] = s->param->depth * ((is_ccd_grayscale (s)) ? 3 : s->param->channels); /* bits per pixel */ 250141cc406Sopenharmony_ci data[0x20] = 0xff; 251141cc406Sopenharmony_ci data[0x23] = 0x81; 252141cc406Sopenharmony_ci data[0x26] = 0x02; 253141cc406Sopenharmony_ci data[0x27] = 0x01; 254141cc406Sopenharmony_ci data[0x29] = mp->monochrome ? 0 : 1; 255141cc406Sopenharmony_ci 256141cc406Sopenharmony_ci return pixma_exec (s, &mp->cb); 257141cc406Sopenharmony_ci} 258141cc406Sopenharmony_ci 259141cc406Sopenharmony_cistatic int 260141cc406Sopenharmony_cicalibrate (pixma_t * s) 261141cc406Sopenharmony_ci{ 262141cc406Sopenharmony_ci mp750_t *mp = (mp750_t *) s->subdriver; 263141cc406Sopenharmony_ci return pixma_exec_short_cmd (s, &mp->cb, cmd_calibrate); 264141cc406Sopenharmony_ci} 265141cc406Sopenharmony_ci 266141cc406Sopenharmony_cistatic int 267141cc406Sopenharmony_cicalibrate_cs (pixma_t * s) 268141cc406Sopenharmony_ci{ 269141cc406Sopenharmony_ci /*SIM*/ check_status (s); 270141cc406Sopenharmony_ci return calibrate (s); 271141cc406Sopenharmony_ci} 272141cc406Sopenharmony_ci 273141cc406Sopenharmony_cistatic int 274141cc406Sopenharmony_cirequest_image_block_ex (pixma_t * s, unsigned *size, uint8_t * info, 275141cc406Sopenharmony_ci unsigned flag) 276141cc406Sopenharmony_ci{ 277141cc406Sopenharmony_ci mp750_t *mp = (mp750_t *) s->subdriver; 278141cc406Sopenharmony_ci int error; 279141cc406Sopenharmony_ci 280141cc406Sopenharmony_ci memset (mp->cb.buf, 0, 10); 281141cc406Sopenharmony_ci pixma_set_be16 (cmd_read_image, mp->cb.buf); 282141cc406Sopenharmony_ci mp->cb.buf[7] = *size >> 8; 283141cc406Sopenharmony_ci mp->cb.buf[8] = 4 | flag; 284141cc406Sopenharmony_ci mp->cb.reslen = pixma_cmd_transaction (s, mp->cb.buf, 10, mp->cb.buf, 6); 285141cc406Sopenharmony_ci mp->cb.expected_reslen = 0; 286141cc406Sopenharmony_ci error = pixma_check_result (&mp->cb); 287141cc406Sopenharmony_ci if (error >= 0) 288141cc406Sopenharmony_ci { 289141cc406Sopenharmony_ci if (mp->cb.reslen == 6) 290141cc406Sopenharmony_ci { 291141cc406Sopenharmony_ci *info = mp->cb.buf[2]; 292141cc406Sopenharmony_ci *size = pixma_get_be16 (mp->cb.buf + 4); 293141cc406Sopenharmony_ci } 294141cc406Sopenharmony_ci else 295141cc406Sopenharmony_ci { 296141cc406Sopenharmony_ci error = PIXMA_EPROTO; 297141cc406Sopenharmony_ci } 298141cc406Sopenharmony_ci } 299141cc406Sopenharmony_ci return error; 300141cc406Sopenharmony_ci} 301141cc406Sopenharmony_ci 302141cc406Sopenharmony_cistatic int 303141cc406Sopenharmony_cirequest_image_block (pixma_t * s, unsigned *size, uint8_t * info) 304141cc406Sopenharmony_ci{ 305141cc406Sopenharmony_ci return request_image_block_ex (s, size, info, 0); 306141cc406Sopenharmony_ci} 307141cc406Sopenharmony_ci 308141cc406Sopenharmony_cistatic int 309141cc406Sopenharmony_cirequest_image_block2 (pixma_t * s, uint8_t * info) 310141cc406Sopenharmony_ci{ 311141cc406Sopenharmony_ci unsigned temp = 0; 312141cc406Sopenharmony_ci return request_image_block_ex (s, &temp, info, 0x20); 313141cc406Sopenharmony_ci} 314141cc406Sopenharmony_ci 315141cc406Sopenharmony_cistatic int 316141cc406Sopenharmony_ciread_image_block (pixma_t * s, uint8_t * data) 317141cc406Sopenharmony_ci{ 318141cc406Sopenharmony_ci int count, temp; 319141cc406Sopenharmony_ci 320141cc406Sopenharmony_ci count = pixma_read (s->io, data, IMAGE_BLOCK_SIZE); 321141cc406Sopenharmony_ci if (count < 0) 322141cc406Sopenharmony_ci return count; 323141cc406Sopenharmony_ci if (count == IMAGE_BLOCK_SIZE) 324141cc406Sopenharmony_ci { 325141cc406Sopenharmony_ci int error = pixma_read (s->io, &temp, 0); 326141cc406Sopenharmony_ci if (error < 0) 327141cc406Sopenharmony_ci { 328141cc406Sopenharmony_ci PDBG (pixma_dbg 329141cc406Sopenharmony_ci (1, "WARNING: reading zero-length packet failed %d\n", error)); 330141cc406Sopenharmony_ci } 331141cc406Sopenharmony_ci } 332141cc406Sopenharmony_ci return count; 333141cc406Sopenharmony_ci} 334141cc406Sopenharmony_ci 335141cc406Sopenharmony_cistatic int 336141cc406Sopenharmony_ciread_error_info (pixma_t * s, void *buf, unsigned size) 337141cc406Sopenharmony_ci{ 338141cc406Sopenharmony_ci unsigned len = 16; 339141cc406Sopenharmony_ci mp750_t *mp = (mp750_t *) s->subdriver; 340141cc406Sopenharmony_ci uint8_t *data; 341141cc406Sopenharmony_ci int error; 342141cc406Sopenharmony_ci 343141cc406Sopenharmony_ci data = pixma_newcmd (&mp->cb, cmd_error_info, 0, len); 344141cc406Sopenharmony_ci error = pixma_exec (s, &mp->cb); 345141cc406Sopenharmony_ci if (error >= 0 && buf) 346141cc406Sopenharmony_ci { 347141cc406Sopenharmony_ci if (len < size) 348141cc406Sopenharmony_ci size = len; 349141cc406Sopenharmony_ci /* NOTE: I've absolutely no idea what the returned data mean. */ 350141cc406Sopenharmony_ci memcpy (buf, data, size); 351141cc406Sopenharmony_ci error = len; 352141cc406Sopenharmony_ci } 353141cc406Sopenharmony_ci return error; 354141cc406Sopenharmony_ci} 355141cc406Sopenharmony_ci 356141cc406Sopenharmony_cistatic int 357141cc406Sopenharmony_cisend_time (pixma_t * s) 358141cc406Sopenharmony_ci{ 359141cc406Sopenharmony_ci /* TODO: implement send_time() */ 360141cc406Sopenharmony_ci UNUSED (s); 361141cc406Sopenharmony_ci PDBG (pixma_dbg (3, "send_time() is not yet implemented.\n")); 362141cc406Sopenharmony_ci return 0; 363141cc406Sopenharmony_ci} 364141cc406Sopenharmony_ci 365141cc406Sopenharmony_cistatic int 366141cc406Sopenharmony_cihandle_interrupt (pixma_t * s, int timeout) 367141cc406Sopenharmony_ci{ 368141cc406Sopenharmony_ci int error; 369141cc406Sopenharmony_ci uint8_t intr[16]; 370141cc406Sopenharmony_ci 371141cc406Sopenharmony_ci error = pixma_wait_interrupt (s->io, intr, sizeof (intr), timeout); 372141cc406Sopenharmony_ci if (error == PIXMA_ETIMEDOUT) 373141cc406Sopenharmony_ci return 0; 374141cc406Sopenharmony_ci if (error < 0) 375141cc406Sopenharmony_ci return error; 376141cc406Sopenharmony_ci if (error != 16) 377141cc406Sopenharmony_ci { 378141cc406Sopenharmony_ci PDBG (pixma_dbg (1, "WARNING: unexpected interrupt packet length %d\n", 379141cc406Sopenharmony_ci error)); 380141cc406Sopenharmony_ci return PIXMA_EPROTO; 381141cc406Sopenharmony_ci } 382141cc406Sopenharmony_ci 383141cc406Sopenharmony_ci if (intr[10] & 0x40) 384141cc406Sopenharmony_ci send_time (s); 385141cc406Sopenharmony_ci if (intr[12] & 0x40) 386141cc406Sopenharmony_ci query_status (s); 387141cc406Sopenharmony_ci if (intr[15] & 1) 388141cc406Sopenharmony_ci s->events = PIXMA_EV_BUTTON2; /* b/w scan */ 389141cc406Sopenharmony_ci if (intr[15] & 2) 390141cc406Sopenharmony_ci s->events = PIXMA_EV_BUTTON1; /* color scan */ 391141cc406Sopenharmony_ci return 1; 392141cc406Sopenharmony_ci} 393141cc406Sopenharmony_ci 394141cc406Sopenharmony_cistatic void 395141cc406Sopenharmony_cicheck_status (pixma_t * s) 396141cc406Sopenharmony_ci{ 397141cc406Sopenharmony_ci while (handle_interrupt (s, 0) > 0); 398141cc406Sopenharmony_ci} 399141cc406Sopenharmony_ci 400141cc406Sopenharmony_cistatic int 401141cc406Sopenharmony_cistep1 (pixma_t * s) 402141cc406Sopenharmony_ci{ 403141cc406Sopenharmony_ci int error, tmo; 404141cc406Sopenharmony_ci 405141cc406Sopenharmony_ci error = activate (s, 0); 406141cc406Sopenharmony_ci if (error < 0) 407141cc406Sopenharmony_ci return error; 408141cc406Sopenharmony_ci error = query_status (s); 409141cc406Sopenharmony_ci if (error < 0) 410141cc406Sopenharmony_ci return error; 411141cc406Sopenharmony_ci if (s->param->source == PIXMA_SOURCE_ADF && !has_paper (s)) 412141cc406Sopenharmony_ci return PIXMA_ENO_PAPER; 413141cc406Sopenharmony_ci error = activate_cs (s, 0); 414141cc406Sopenharmony_ci /*SIM*/ if (error < 0) 415141cc406Sopenharmony_ci return error; 416141cc406Sopenharmony_ci error = activate_cs (s, 0x20); 417141cc406Sopenharmony_ci if (error < 0) 418141cc406Sopenharmony_ci return error; 419141cc406Sopenharmony_ci 420141cc406Sopenharmony_ci tmo = 60; 421141cc406Sopenharmony_ci error = calibrate_cs (s); 422141cc406Sopenharmony_ci while (error == PIXMA_EBUSY && --tmo >= 0) 423141cc406Sopenharmony_ci { 424141cc406Sopenharmony_ci if (s->cancel) 425141cc406Sopenharmony_ci return PIXMA_ECANCELED; 426141cc406Sopenharmony_ci PDBG (pixma_dbg 427141cc406Sopenharmony_ci (2, "Scanner is busy. Timed out in %d sec.\n", tmo + 1)); 428141cc406Sopenharmony_ci pixma_sleep (1000000); 429141cc406Sopenharmony_ci error = calibrate_cs (s); 430141cc406Sopenharmony_ci } 431141cc406Sopenharmony_ci return error; 432141cc406Sopenharmony_ci} 433141cc406Sopenharmony_ci 434141cc406Sopenharmony_cistatic void 435141cc406Sopenharmony_cishift_rgb (const uint8_t * src, unsigned pixels, 436141cc406Sopenharmony_ci int sr, int sg, int sb, int stripe_shift, 437141cc406Sopenharmony_ci int line_size, uint8_t * dst) 438141cc406Sopenharmony_ci{ 439141cc406Sopenharmony_ci unsigned st; 440141cc406Sopenharmony_ci 441141cc406Sopenharmony_ci for (; pixels != 0; pixels--) 442141cc406Sopenharmony_ci { 443141cc406Sopenharmony_ci st = (pixels % 2 == 0) ? -2 * stripe_shift * line_size : 0; 444141cc406Sopenharmony_ci *(dst++ + sr + st) = *src++; 445141cc406Sopenharmony_ci *(dst++ + sg + st) = *src++; 446141cc406Sopenharmony_ci *(dst++ + sb + st) = *src++; 447141cc406Sopenharmony_ci } 448141cc406Sopenharmony_ci} 449141cc406Sopenharmony_ci 450141cc406Sopenharmony_cistatic uint8_t * 451141cc406Sopenharmony_cirgb_to_gray (uint8_t * gptr, const uint8_t * cptr, unsigned pixels, unsigned c) 452141cc406Sopenharmony_ci{ 453141cc406Sopenharmony_ci unsigned i, j, g; 454141cc406Sopenharmony_ci 455141cc406Sopenharmony_ci /* gptr: destination gray scale buffer */ 456141cc406Sopenharmony_ci /* cptr: source color scale buffer */ 457141cc406Sopenharmony_ci /* c: 3 for 3-channel single-byte data, 6 for double-byte data */ 458141cc406Sopenharmony_ci 459141cc406Sopenharmony_ci for (i=0; i < pixels; i++) 460141cc406Sopenharmony_ci { 461141cc406Sopenharmony_ci for (j = 0, g = 0; j < 3; j++) 462141cc406Sopenharmony_ci { 463141cc406Sopenharmony_ci g += *cptr++; 464141cc406Sopenharmony_ci if (c == 6) g += (*cptr++ << 8); 465141cc406Sopenharmony_ci } 466141cc406Sopenharmony_ci g /= 3; 467141cc406Sopenharmony_ci *gptr++ = g; 468141cc406Sopenharmony_ci if (c == 6) *gptr++ = (g >> 8); 469141cc406Sopenharmony_ci } 470141cc406Sopenharmony_ci return gptr; 471141cc406Sopenharmony_ci} 472141cc406Sopenharmony_ci 473141cc406Sopenharmony_cistatic int 474141cc406Sopenharmony_cicalc_component_shifting (pixma_t * s) 475141cc406Sopenharmony_ci{ 476141cc406Sopenharmony_ci switch (s->cfg->pid) 477141cc406Sopenharmony_ci { 478141cc406Sopenharmony_ci case MP760_PID: 479141cc406Sopenharmony_ci switch (s->param->ydpi) 480141cc406Sopenharmony_ci { 481141cc406Sopenharmony_ci case 300: 482141cc406Sopenharmony_ci return 3; 483141cc406Sopenharmony_ci case 600: 484141cc406Sopenharmony_ci return 6; 485141cc406Sopenharmony_ci default: 486141cc406Sopenharmony_ci return s->param->ydpi / 75; 487141cc406Sopenharmony_ci } 488141cc406Sopenharmony_ci /* never reached */ 489141cc406Sopenharmony_ci break; 490141cc406Sopenharmony_ci 491141cc406Sopenharmony_ci case MP750_PID: 492141cc406Sopenharmony_ci case MP780_PID: 493141cc406Sopenharmony_ci default: 494141cc406Sopenharmony_ci return 2 * s->param->ydpi / 75; 495141cc406Sopenharmony_ci } 496141cc406Sopenharmony_ci} 497141cc406Sopenharmony_ci 498141cc406Sopenharmony_cistatic void 499141cc406Sopenharmony_ciworkaround_first_command (pixma_t * s) 500141cc406Sopenharmony_ci{ 501141cc406Sopenharmony_ci /* FIXME: Send a dummy command because the device doesn't response to the 502141cc406Sopenharmony_ci first command that is sent directly after the USB interface has been 503141cc406Sopenharmony_ci set up. Why? USB isn't set up properly? */ 504141cc406Sopenharmony_ci uint8_t cmd[10]; 505141cc406Sopenharmony_ci int error; 506141cc406Sopenharmony_ci 507141cc406Sopenharmony_ci if (s->cfg->pid == MP750_PID) 508141cc406Sopenharmony_ci return; /* MP750 doesn't have this problem(?) */ 509141cc406Sopenharmony_ci 510141cc406Sopenharmony_ci PDBG (pixma_dbg 511141cc406Sopenharmony_ci (1, 512141cc406Sopenharmony_ci "Work-around for the problem: device doesn't response to the first command.\n")); 513141cc406Sopenharmony_ci memset (cmd, 0, sizeof (cmd)); 514141cc406Sopenharmony_ci pixma_set_be16 (cmd_calibrate, cmd); 515141cc406Sopenharmony_ci error = pixma_write (s->io, cmd, 10); 516141cc406Sopenharmony_ci if (error != 10) 517141cc406Sopenharmony_ci { 518141cc406Sopenharmony_ci if (error < 0) 519141cc406Sopenharmony_ci { 520141cc406Sopenharmony_ci PDBG (pixma_dbg 521141cc406Sopenharmony_ci (1, " Sending a dummy command failed: %s\n", 522141cc406Sopenharmony_ci pixma_strerror (error))); 523141cc406Sopenharmony_ci } 524141cc406Sopenharmony_ci else 525141cc406Sopenharmony_ci { 526141cc406Sopenharmony_ci PDBG (pixma_dbg 527141cc406Sopenharmony_ci (1, " Sending a dummy command failed: count = %d\n", error)); 528141cc406Sopenharmony_ci } 529141cc406Sopenharmony_ci return; 530141cc406Sopenharmony_ci } 531141cc406Sopenharmony_ci error = pixma_read (s->io, cmd, sizeof (cmd)); 532141cc406Sopenharmony_ci if (error >= 0) 533141cc406Sopenharmony_ci { 534141cc406Sopenharmony_ci PDBG (pixma_dbg 535141cc406Sopenharmony_ci (1, " Got %d bytes response from a dummy command.\n", error)); 536141cc406Sopenharmony_ci } 537141cc406Sopenharmony_ci else 538141cc406Sopenharmony_ci { 539141cc406Sopenharmony_ci PDBG (pixma_dbg 540141cc406Sopenharmony_ci (1, " Reading response of a dummy command failed: %s\n", 541141cc406Sopenharmony_ci pixma_strerror (error))); 542141cc406Sopenharmony_ci } 543141cc406Sopenharmony_ci} 544141cc406Sopenharmony_ci 545141cc406Sopenharmony_cistatic int 546141cc406Sopenharmony_cimp750_open (pixma_t * s) 547141cc406Sopenharmony_ci{ 548141cc406Sopenharmony_ci mp750_t *mp; 549141cc406Sopenharmony_ci uint8_t *buf; 550141cc406Sopenharmony_ci 551141cc406Sopenharmony_ci mp = (mp750_t *) calloc (1, sizeof (*mp)); 552141cc406Sopenharmony_ci if (!mp) 553141cc406Sopenharmony_ci return PIXMA_ENOMEM; 554141cc406Sopenharmony_ci 555141cc406Sopenharmony_ci buf = (uint8_t *) malloc (CMDBUF_SIZE); 556141cc406Sopenharmony_ci if (!buf) 557141cc406Sopenharmony_ci { 558141cc406Sopenharmony_ci free (mp); 559141cc406Sopenharmony_ci return PIXMA_ENOMEM; 560141cc406Sopenharmony_ci } 561141cc406Sopenharmony_ci 562141cc406Sopenharmony_ci s->subdriver = mp; 563141cc406Sopenharmony_ci mp->state = state_idle; 564141cc406Sopenharmony_ci 565141cc406Sopenharmony_ci /* ofs: 0 1 2 3 4 5 6 7 8 9 566141cc406Sopenharmony_ci cmd: cmd1 cmd2 00 00 00 00 00 00 00 00 567141cc406Sopenharmony_ci data length-^^^^^ => cmd_len_field_ofs 568141cc406Sopenharmony_ci |--------- cmd_header_len --------| 569141cc406Sopenharmony_ci 570141cc406Sopenharmony_ci res: res1 res2 571141cc406Sopenharmony_ci |---------| res_header_len 572141cc406Sopenharmony_ci */ 573141cc406Sopenharmony_ci mp->cb.buf = buf; 574141cc406Sopenharmony_ci mp->cb.size = CMDBUF_SIZE; 575141cc406Sopenharmony_ci mp->cb.res_header_len = 2; 576141cc406Sopenharmony_ci mp->cb.cmd_header_len = 10; 577141cc406Sopenharmony_ci mp->cb.cmd_len_field_ofs = 7; 578141cc406Sopenharmony_ci 579141cc406Sopenharmony_ci handle_interrupt (s, 200); 580141cc406Sopenharmony_ci workaround_first_command (s); 581141cc406Sopenharmony_ci return 0; 582141cc406Sopenharmony_ci} 583141cc406Sopenharmony_ci 584141cc406Sopenharmony_cistatic void 585141cc406Sopenharmony_cimp750_close (pixma_t * s) 586141cc406Sopenharmony_ci{ 587141cc406Sopenharmony_ci mp750_t *mp = (mp750_t *) s->subdriver; 588141cc406Sopenharmony_ci 589141cc406Sopenharmony_ci mp750_finish_scan (s); 590141cc406Sopenharmony_ci free (mp->cb.buf); 591141cc406Sopenharmony_ci free (mp); 592141cc406Sopenharmony_ci s->subdriver = NULL; 593141cc406Sopenharmony_ci} 594141cc406Sopenharmony_ci 595141cc406Sopenharmony_cistatic int 596141cc406Sopenharmony_cimp750_check_param (pixma_t * s, pixma_scan_param_t * sp) 597141cc406Sopenharmony_ci{ 598141cc406Sopenharmony_ci unsigned raw_width; 599141cc406Sopenharmony_ci 600141cc406Sopenharmony_ci UNUSED (s); 601141cc406Sopenharmony_ci 602141cc406Sopenharmony_ci sp->depth = 8; /* FIXME: Does MP750 supports other depth? */ 603141cc406Sopenharmony_ci 604141cc406Sopenharmony_ci /* GH: my implementation */ 605141cc406Sopenharmony_ci /* if ((sp->channels == 3) || (is_ccd_grayscale (s))) 606141cc406Sopenharmony_ci raw_width = ALIGN_SUP (sp->w, 4); 607141cc406Sopenharmony_ci else 608141cc406Sopenharmony_ci raw_width = ALIGN_SUP (sp->w, 12);*/ 609141cc406Sopenharmony_ci 610141cc406Sopenharmony_ci /* the above code gives segmentation fault?!? why... it seems to work in the mp750_scan function */ 611141cc406Sopenharmony_ci raw_width = ALIGN_SUP (sp->w, 4); 612141cc406Sopenharmony_ci 613141cc406Sopenharmony_ci /*sp->line_size = raw_width * sp->channels;*/ 614141cc406Sopenharmony_ci sp->line_size = raw_width * sp->channels * (sp->depth / 8); /* no cropping? */ 615141cc406Sopenharmony_ci return 0; 616141cc406Sopenharmony_ci} 617141cc406Sopenharmony_ci 618141cc406Sopenharmony_cistatic int 619141cc406Sopenharmony_cimp750_scan (pixma_t * s) 620141cc406Sopenharmony_ci{ 621141cc406Sopenharmony_ci mp750_t *mp = (mp750_t *) s->subdriver; 622141cc406Sopenharmony_ci int error; 623141cc406Sopenharmony_ci uint8_t *buf; 624141cc406Sopenharmony_ci unsigned size, dpi, spare; 625141cc406Sopenharmony_ci 626141cc406Sopenharmony_ci dpi = s->param->ydpi; 627141cc406Sopenharmony_ci /* add a stripe shift for 2400dpi */ 628141cc406Sopenharmony_ci mp->stripe_shift = (dpi == 2400) ? 4 : 0; 629141cc406Sopenharmony_ci 630141cc406Sopenharmony_ci if (mp->state != state_idle) 631141cc406Sopenharmony_ci return PIXMA_EBUSY; 632141cc406Sopenharmony_ci 633141cc406Sopenharmony_ci /* clear interrupt packets buffer */ 634141cc406Sopenharmony_ci while (handle_interrupt (s, 0) > 0) 635141cc406Sopenharmony_ci { 636141cc406Sopenharmony_ci } 637141cc406Sopenharmony_ci 638141cc406Sopenharmony_ci /* if (s->param->channels == 1) 639141cc406Sopenharmony_ci mp->raw_width = ALIGN_SUP (s->param->w, 12); 640141cc406Sopenharmony_ci else 641141cc406Sopenharmony_ci mp->raw_width = ALIGN_SUP (s->param->w, 4);*/ 642141cc406Sopenharmony_ci 643141cc406Sopenharmony_ci /* change to use CCD grayscale mode --- why does this give segmentation error at runtime in mp750_check_param? */ 644141cc406Sopenharmony_ci if ((s->param->channels == 3) || (is_ccd_grayscale (s))) 645141cc406Sopenharmony_ci mp->raw_width = ALIGN_SUP (s->param->w, 4); 646141cc406Sopenharmony_ci else 647141cc406Sopenharmony_ci mp->raw_width = ALIGN_SUP (s->param->w, 12); 648141cc406Sopenharmony_ci /* not sure about MP750, but there is no need for aligning at 12 for the MP760/770, MP780/790 since always use CCD color mode */ 649141cc406Sopenharmony_ci 650141cc406Sopenharmony_ci /* modify for stripe shift */ 651141cc406Sopenharmony_ci spare = 2 * calc_component_shifting (s) + 2 * mp->stripe_shift; /* FIXME: or maybe (2*... + 1)? */ 652141cc406Sopenharmony_ci mp->raw_height = s->param->h + spare; 653141cc406Sopenharmony_ci PDBG (pixma_dbg (3, "raw_width=%u raw_height=%u dpi=%u\n", 654141cc406Sopenharmony_ci mp->raw_width, mp->raw_height, dpi)); 655141cc406Sopenharmony_ci 656141cc406Sopenharmony_ci /* PDBG (pixma_dbg (4, "line_size=%"PRIu64"\n",s->param->line_size)); */ 657141cc406Sopenharmony_ci 658141cc406Sopenharmony_ci mp->line_size = get_cis_ccd_line_size (s); /* scanner hardware line_size multiplied by 3 for CCD grayscale */ 659141cc406Sopenharmony_ci 660141cc406Sopenharmony_ci size = 8 + 2 * IMAGE_BLOCK_SIZE + spare * mp->line_size; 661141cc406Sopenharmony_ci buf = (uint8_t *) malloc (size); 662141cc406Sopenharmony_ci if (!buf) 663141cc406Sopenharmony_ci return PIXMA_ENOMEM; 664141cc406Sopenharmony_ci mp->buf = buf; 665141cc406Sopenharmony_ci mp->rawimg = buf; 666141cc406Sopenharmony_ci mp->imgbuf_ofs = spare * mp->line_size; 667141cc406Sopenharmony_ci mp->imgcol = mp->rawimg + IMAGE_BLOCK_SIZE + 8; /* added to make rgb->gray */ 668141cc406Sopenharmony_ci mp->img = mp->rawimg + IMAGE_BLOCK_SIZE + 8; 669141cc406Sopenharmony_ci mp->imgbuf_len = IMAGE_BLOCK_SIZE + mp->imgbuf_ofs; 670141cc406Sopenharmony_ci mp->rawimg_left = 0; 671141cc406Sopenharmony_ci mp->last_block_size = 0; 672141cc406Sopenharmony_ci mp->shifted_bytes = -(int) mp->imgbuf_ofs; 673141cc406Sopenharmony_ci 674141cc406Sopenharmony_ci error = step1 (s); 675141cc406Sopenharmony_ci if (error >= 0) 676141cc406Sopenharmony_ci error = start_session (s); 677141cc406Sopenharmony_ci if (error >= 0) 678141cc406Sopenharmony_ci mp->state = state_warmup; 679141cc406Sopenharmony_ci if (error >= 0) 680141cc406Sopenharmony_ci error = select_source (s); 681141cc406Sopenharmony_ci if (error >= 0) 682141cc406Sopenharmony_ci error = send_scan_param (s); 683141cc406Sopenharmony_ci if (error < 0) 684141cc406Sopenharmony_ci { 685141cc406Sopenharmony_ci mp750_finish_scan (s); 686141cc406Sopenharmony_ci return error; 687141cc406Sopenharmony_ci } 688141cc406Sopenharmony_ci return 0; 689141cc406Sopenharmony_ci} 690141cc406Sopenharmony_ci 691141cc406Sopenharmony_ci 692141cc406Sopenharmony_cistatic int 693141cc406Sopenharmony_cimp750_fill_buffer (pixma_t * s, pixma_imagebuf_t * ib) 694141cc406Sopenharmony_ci{ 695141cc406Sopenharmony_ci mp750_t *mp = (mp750_t *) s->subdriver; 696141cc406Sopenharmony_ci int error; 697141cc406Sopenharmony_ci uint8_t info; 698141cc406Sopenharmony_ci unsigned block_size, bytes_received, n; 699141cc406Sopenharmony_ci int shift[3], base_shift; 700141cc406Sopenharmony_ci int c; 701141cc406Sopenharmony_ci 702141cc406Sopenharmony_ci c = ((is_ccd_grayscale (s)) ? 3 : s->param->channels) * s->param->depth / 8; /* single-byte or double-byte data */ 703141cc406Sopenharmony_ci 704141cc406Sopenharmony_ci if (mp->state == state_warmup) 705141cc406Sopenharmony_ci { 706141cc406Sopenharmony_ci int tmo = 60; 707141cc406Sopenharmony_ci 708141cc406Sopenharmony_ci query_status (s); 709141cc406Sopenharmony_ci check_status (s); 710141cc406Sopenharmony_ci /*SIM*/ while (!is_calibrated (s) && --tmo >= 0) 711141cc406Sopenharmony_ci { 712141cc406Sopenharmony_ci if (s->cancel) 713141cc406Sopenharmony_ci return PIXMA_ECANCELED; 714141cc406Sopenharmony_ci if (handle_interrupt (s, 1000) > 0) 715141cc406Sopenharmony_ci { 716141cc406Sopenharmony_ci block_size = 0; 717141cc406Sopenharmony_ci error = request_image_block (s, &block_size, &info); 718141cc406Sopenharmony_ci /*SIM*/ if (error < 0) 719141cc406Sopenharmony_ci return error; 720141cc406Sopenharmony_ci } 721141cc406Sopenharmony_ci } 722141cc406Sopenharmony_ci if (tmo < 0) 723141cc406Sopenharmony_ci { 724141cc406Sopenharmony_ci PDBG (pixma_dbg (1, "WARNING: Timed out waiting for calibration\n")); 725141cc406Sopenharmony_ci return PIXMA_ETIMEDOUT; 726141cc406Sopenharmony_ci } 727141cc406Sopenharmony_ci pixma_sleep (100000); 728141cc406Sopenharmony_ci query_status (s); 729141cc406Sopenharmony_ci if (is_warming_up (s) || !is_calibrated (s)) 730141cc406Sopenharmony_ci { 731141cc406Sopenharmony_ci PDBG (pixma_dbg (1, "WARNING: Wrong status: wup=%d cal=%d\n", 732141cc406Sopenharmony_ci is_warming_up (s), is_calibrated (s))); 733141cc406Sopenharmony_ci return PIXMA_EPROTO; 734141cc406Sopenharmony_ci } 735141cc406Sopenharmony_ci block_size = 0; 736141cc406Sopenharmony_ci request_image_block (s, &block_size, &info); 737141cc406Sopenharmony_ci /*SIM*/ mp->state = state_scanning; 738141cc406Sopenharmony_ci mp->last_block = 0; 739141cc406Sopenharmony_ci } 740141cc406Sopenharmony_ci 741141cc406Sopenharmony_ci /* TODO: Move to other place, values are constant. */ 742141cc406Sopenharmony_ci base_shift = calc_component_shifting (s) * mp->line_size; 743141cc406Sopenharmony_ci if (s->param->source == PIXMA_SOURCE_ADF) 744141cc406Sopenharmony_ci { 745141cc406Sopenharmony_ci shift[0] = 0; 746141cc406Sopenharmony_ci shift[1] = -base_shift; 747141cc406Sopenharmony_ci shift[2] = -2 * base_shift; 748141cc406Sopenharmony_ci } 749141cc406Sopenharmony_ci else 750141cc406Sopenharmony_ci { 751141cc406Sopenharmony_ci shift[0] = -2 * base_shift; 752141cc406Sopenharmony_ci shift[1] = -base_shift; 753141cc406Sopenharmony_ci shift[2] = 0; 754141cc406Sopenharmony_ci } 755141cc406Sopenharmony_ci 756141cc406Sopenharmony_ci do 757141cc406Sopenharmony_ci { 758141cc406Sopenharmony_ci if (mp->last_block_size > 0) 759141cc406Sopenharmony_ci { 760141cc406Sopenharmony_ci block_size = mp->imgbuf_len - mp->last_block_size; 761141cc406Sopenharmony_ci memcpy (mp->img, mp->img + mp->last_block_size, block_size); 762141cc406Sopenharmony_ci } 763141cc406Sopenharmony_ci 764141cc406Sopenharmony_ci do 765141cc406Sopenharmony_ci { 766141cc406Sopenharmony_ci if (s->cancel) 767141cc406Sopenharmony_ci return PIXMA_ECANCELED; 768141cc406Sopenharmony_ci if (mp->last_block) 769141cc406Sopenharmony_ci { 770141cc406Sopenharmony_ci /* end of image */ 771141cc406Sopenharmony_ci info = mp->last_block; 772141cc406Sopenharmony_ci if (info != 0x38) 773141cc406Sopenharmony_ci { 774141cc406Sopenharmony_ci query_status (s); 775141cc406Sopenharmony_ci /*SIM*/ while ((info & 0x28) != 0x28) 776141cc406Sopenharmony_ci { 777141cc406Sopenharmony_ci pixma_sleep (10000); 778141cc406Sopenharmony_ci error = request_image_block2 (s, &info); 779141cc406Sopenharmony_ci if (s->cancel) 780141cc406Sopenharmony_ci return PIXMA_ECANCELED; /* FIXME: Is it safe to cancel here? */ 781141cc406Sopenharmony_ci if (error < 0) 782141cc406Sopenharmony_ci return error; 783141cc406Sopenharmony_ci } 784141cc406Sopenharmony_ci } 785141cc406Sopenharmony_ci mp->needs_abort = (info != 0x38); 786141cc406Sopenharmony_ci mp->last_block = info; 787141cc406Sopenharmony_ci mp->state = state_finished; 788141cc406Sopenharmony_ci return 0; 789141cc406Sopenharmony_ci } 790141cc406Sopenharmony_ci 791141cc406Sopenharmony_ci check_status (s); 792141cc406Sopenharmony_ci /*SIM*/ while (handle_interrupt (s, 1) > 0); 793141cc406Sopenharmony_ci /*SIM*/ block_size = IMAGE_BLOCK_SIZE; 794141cc406Sopenharmony_ci error = request_image_block (s, &block_size, &info); 795141cc406Sopenharmony_ci if (error < 0) 796141cc406Sopenharmony_ci { 797141cc406Sopenharmony_ci if (error == PIXMA_ECANCELED) 798141cc406Sopenharmony_ci read_error_info (s, NULL, 0); 799141cc406Sopenharmony_ci return error; 800141cc406Sopenharmony_ci } 801141cc406Sopenharmony_ci mp->last_block = info; 802141cc406Sopenharmony_ci if ((info & ~0x38) != 0) 803141cc406Sopenharmony_ci { 804141cc406Sopenharmony_ci PDBG (pixma_dbg (1, "WARNING: Unknown info byte %x\n", info)); 805141cc406Sopenharmony_ci } 806141cc406Sopenharmony_ci if (block_size == 0) 807141cc406Sopenharmony_ci { 808141cc406Sopenharmony_ci /* no image data at this moment. */ 809141cc406Sopenharmony_ci pixma_sleep (10000); 810141cc406Sopenharmony_ci } 811141cc406Sopenharmony_ci } 812141cc406Sopenharmony_ci while (block_size == 0); 813141cc406Sopenharmony_ci 814141cc406Sopenharmony_ci error = read_image_block (s, mp->rawimg + mp->rawimg_left); 815141cc406Sopenharmony_ci if (error < 0) 816141cc406Sopenharmony_ci { 817141cc406Sopenharmony_ci mp->state = state_transfering; 818141cc406Sopenharmony_ci return error; 819141cc406Sopenharmony_ci } 820141cc406Sopenharmony_ci bytes_received = error; 821141cc406Sopenharmony_ci PASSERT (bytes_received == block_size); 822141cc406Sopenharmony_ci 823141cc406Sopenharmony_ci /* TODO: simplify! */ 824141cc406Sopenharmony_ci mp->rawimg_left += bytes_received; 825141cc406Sopenharmony_ci n = mp->rawimg_left / 3; 826141cc406Sopenharmony_ci /* n = number of pixels in the buffer? */ 827141cc406Sopenharmony_ci 828141cc406Sopenharmony_ci /* Color to Grayscale conversion for CCD sensor */ 829141cc406Sopenharmony_ci if (is_ccd_grayscale (s)) { 830141cc406Sopenharmony_ci shift_rgb (mp->rawimg, n, shift[0], shift[1], shift[2], mp->stripe_shift, mp->line_size, 831141cc406Sopenharmony_ci mp->imgcol + mp->imgbuf_ofs); 832141cc406Sopenharmony_ci /* dst: img, src: imgcol */ 833141cc406Sopenharmony_ci rgb_to_gray (mp->img, mp->imgcol, n, c); /* cropping occurs later? */ 834141cc406Sopenharmony_ci PDBG (pixma_dbg (4, "*fill_buffer: did grayscale conversion \n")); 835141cc406Sopenharmony_ci } 836141cc406Sopenharmony_ci /* Color image processing */ 837141cc406Sopenharmony_ci else { 838141cc406Sopenharmony_ci shift_rgb (mp->rawimg, n, shift[0], shift[1], shift[2], mp->stripe_shift, mp->line_size, 839141cc406Sopenharmony_ci mp->img + mp->imgbuf_ofs); 840141cc406Sopenharmony_ci PDBG (pixma_dbg (4, "*fill_buffer: no grayscale conversion---keep color \n")); 841141cc406Sopenharmony_ci } 842141cc406Sopenharmony_ci 843141cc406Sopenharmony_ci /* entering remaining unprocessed bytes after last complete pixel into mp->rawimg buffer -- no influence on mp->img */ 844141cc406Sopenharmony_ci n *= 3; 845141cc406Sopenharmony_ci mp->shifted_bytes += n; 846141cc406Sopenharmony_ci mp->rawimg_left -= n; /* rawimg_left = 0, 1 or 2 bytes left in the buffer. */ 847141cc406Sopenharmony_ci mp->last_block_size = n; 848141cc406Sopenharmony_ci memcpy (mp->rawimg, mp->rawimg + n, mp->rawimg_left); 849141cc406Sopenharmony_ci 850141cc406Sopenharmony_ci } 851141cc406Sopenharmony_ci while (mp->shifted_bytes <= 0); 852141cc406Sopenharmony_ci 853141cc406Sopenharmony_ci if ((unsigned) mp->shifted_bytes < mp->last_block_size) 854141cc406Sopenharmony_ci { 855141cc406Sopenharmony_ci if (is_ccd_grayscale (s)) 856141cc406Sopenharmony_ci ib->rptr = mp->img + mp->last_block_size/3 - mp->shifted_bytes/3; /* testing---works OK */ 857141cc406Sopenharmony_ci else 858141cc406Sopenharmony_ci ib->rptr = mp->img + mp->last_block_size - mp->shifted_bytes; 859141cc406Sopenharmony_ci } 860141cc406Sopenharmony_ci else 861141cc406Sopenharmony_ci ib->rptr = mp->img; 862141cc406Sopenharmony_ci if (is_ccd_grayscale (s)) 863141cc406Sopenharmony_ci ib->rend = mp->img + mp->last_block_size/3; /* testing---works OK */ 864141cc406Sopenharmony_ci else 865141cc406Sopenharmony_ci ib->rend = mp->img + mp->last_block_size; 866141cc406Sopenharmony_ci return ib->rend - ib->rptr; 867141cc406Sopenharmony_ci} 868141cc406Sopenharmony_ci 869141cc406Sopenharmony_cistatic void 870141cc406Sopenharmony_cimp750_finish_scan (pixma_t * s) 871141cc406Sopenharmony_ci{ 872141cc406Sopenharmony_ci int error; 873141cc406Sopenharmony_ci mp750_t *mp = (mp750_t *) s->subdriver; 874141cc406Sopenharmony_ci 875141cc406Sopenharmony_ci switch (mp->state) 876141cc406Sopenharmony_ci { 877141cc406Sopenharmony_ci case state_transfering: 878141cc406Sopenharmony_ci drain_bulk_in (s); 879141cc406Sopenharmony_ci /* fall through */ 880141cc406Sopenharmony_ci case state_scanning: 881141cc406Sopenharmony_ci case state_warmup: 882141cc406Sopenharmony_ci error = abort_session (s); 883141cc406Sopenharmony_ci if (error == PIXMA_ECANCELED) 884141cc406Sopenharmony_ci read_error_info (s, NULL, 0); 885141cc406Sopenharmony_ci /* fall through */ 886141cc406Sopenharmony_ci case state_finished: 887141cc406Sopenharmony_ci if (s->param->source == PIXMA_SOURCE_FLATBED) 888141cc406Sopenharmony_ci { 889141cc406Sopenharmony_ci /*SIM*/ query_status (s); 890141cc406Sopenharmony_ci if (abort_session (s) == PIXMA_ECANCELED) 891141cc406Sopenharmony_ci { 892141cc406Sopenharmony_ci read_error_info (s, NULL, 0); 893141cc406Sopenharmony_ci query_status (s); 894141cc406Sopenharmony_ci } 895141cc406Sopenharmony_ci } 896141cc406Sopenharmony_ci query_status (s); 897141cc406Sopenharmony_ci /*SIM*/ activate (s, 0); 898141cc406Sopenharmony_ci if (mp->needs_abort) 899141cc406Sopenharmony_ci { 900141cc406Sopenharmony_ci mp->needs_abort = 0; 901141cc406Sopenharmony_ci abort_session (s); 902141cc406Sopenharmony_ci } 903141cc406Sopenharmony_ci free (mp->buf); 904141cc406Sopenharmony_ci mp->buf = mp->rawimg = NULL; 905141cc406Sopenharmony_ci mp->state = state_idle; 906141cc406Sopenharmony_ci /* fall through */ 907141cc406Sopenharmony_ci case state_idle: 908141cc406Sopenharmony_ci break; 909141cc406Sopenharmony_ci } 910141cc406Sopenharmony_ci} 911141cc406Sopenharmony_ci 912141cc406Sopenharmony_cistatic void 913141cc406Sopenharmony_cimp750_wait_event (pixma_t * s, int timeout) 914141cc406Sopenharmony_ci{ 915141cc406Sopenharmony_ci /* FIXME: timeout is not correct. See usbGetCompleteUrbNoIntr() for 916141cc406Sopenharmony_ci * instance. */ 917141cc406Sopenharmony_ci while (s->events == 0 && handle_interrupt (s, timeout) > 0) 918141cc406Sopenharmony_ci { 919141cc406Sopenharmony_ci } 920141cc406Sopenharmony_ci} 921141cc406Sopenharmony_ci 922141cc406Sopenharmony_cistatic int 923141cc406Sopenharmony_cimp750_get_status (pixma_t * s, pixma_device_status_t * status) 924141cc406Sopenharmony_ci{ 925141cc406Sopenharmony_ci int error; 926141cc406Sopenharmony_ci 927141cc406Sopenharmony_ci error = query_status (s); 928141cc406Sopenharmony_ci if (error < 0) 929141cc406Sopenharmony_ci return error; 930141cc406Sopenharmony_ci status->hardware = PIXMA_HARDWARE_OK; 931141cc406Sopenharmony_ci status->adf = (has_paper (s)) ? PIXMA_ADF_OK : PIXMA_ADF_NO_PAPER; 932141cc406Sopenharmony_ci status->cal = 933141cc406Sopenharmony_ci (is_calibrated (s)) ? PIXMA_CALIBRATION_OK : PIXMA_CALIBRATION_OFF; 934141cc406Sopenharmony_ci status->lamp = (is_warming_up (s)) ? PIXMA_LAMP_WARMING_UP : PIXMA_LAMP_OK; 935141cc406Sopenharmony_ci return 0; 936141cc406Sopenharmony_ci} 937141cc406Sopenharmony_ci 938141cc406Sopenharmony_ci 939141cc406Sopenharmony_cistatic const pixma_scan_ops_t pixma_mp750_ops = { 940141cc406Sopenharmony_ci mp750_open, 941141cc406Sopenharmony_ci mp750_close, 942141cc406Sopenharmony_ci mp750_scan, 943141cc406Sopenharmony_ci mp750_fill_buffer, 944141cc406Sopenharmony_ci mp750_finish_scan, 945141cc406Sopenharmony_ci mp750_wait_event, 946141cc406Sopenharmony_ci mp750_check_param, 947141cc406Sopenharmony_ci mp750_get_status 948141cc406Sopenharmony_ci}; 949141cc406Sopenharmony_ci 950141cc406Sopenharmony_ci#define DEVICE(name, model, pid, dpi, cap) { \ 951141cc406Sopenharmony_ci name, /* name */ \ 952141cc406Sopenharmony_ci model, /* model */ \ 953141cc406Sopenharmony_ci 0x04a9, pid, /* vid pid */ \ 954141cc406Sopenharmony_ci 0, /* iface */ \ 955141cc406Sopenharmony_ci &pixma_mp750_ops, /* ops */ \ 956141cc406Sopenharmony_ci 0, 0, /* min_xdpi & min_xdpi_16 not used in this subdriver */ \ 957141cc406Sopenharmony_ci dpi, 2*(dpi), /* xdpi, ydpi */ \ 958141cc406Sopenharmony_ci 0, 0, /* adftpu_min_dpi & adftpu_max_dpi not used in this subdriver */ \ 959141cc406Sopenharmony_ci 0, 0, /* tpuir_min_dpi & tpuir_max_dpi not used in this subdriver */ \ 960141cc406Sopenharmony_ci 637, 877, /* width, height */ \ 961141cc406Sopenharmony_ci PIXMA_CAP_CCD| /* all scanners with CCD */ \ 962141cc406Sopenharmony_ci PIXMA_CAP_GRAY|PIXMA_CAP_EVENTS|cap \ 963141cc406Sopenharmony_ci} 964141cc406Sopenharmony_ci 965141cc406Sopenharmony_ciconst pixma_config_t pixma_mp750_devices[] = { 966141cc406Sopenharmony_ci DEVICE ("Canon PIXMA MP750", "MP750", MP750_PID, 2400, PIXMA_CAP_ADF), 967141cc406Sopenharmony_ci DEVICE ("Canon PIXMA MP760/770", "MP760/770", MP760_PID, 2400, PIXMA_CAP_TPU), 968141cc406Sopenharmony_ci DEVICE ("Canon PIXMA MP780/790", "MP780/790", MP780_PID, 2400, PIXMA_CAP_ADF), 969141cc406Sopenharmony_ci DEVICE (NULL, NULL, 0, 0, 0) 970141cc406Sopenharmony_ci}; 971