1/* sane - Scanner Access Now Easy. 2 (C) Marian Matthias Eichholz 2001 3 4 This file is part of the SANE package. 5 6 This program is free software; you can redistribute it and/or 7 modify it under the terms of the GNU General Public License as 8 published by the Free Software Foundation; either version 2 of the 9 License, or (at your option) any later version. 10 11 This program is distributed in the hope that it will be useful, but 12 WITHOUT ANY WARRANTY; without even the implied warranty of 13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 General Public License for more details. 15 16 You should have received a copy of the GNU General Public License 17 along with this program. If not, see <https://www.gnu.org/licenses/>. 18 19 As a special exception, the authors of SANE give permission for 20 additional uses of the libraries contained in this release of SANE. 21 22 The exception is that, if you link a SANE library with other files 23 to produce an executable, this does not by itself cause the 24 resulting executable to be covered by the GNU General Public 25 License. Your use of that executable is in no way restricted on 26 account of linking the SANE library code into it. 27 28 This exception does not, however, invalidate any other reasons why 29 the executable file might be covered by the GNU General Public 30 License. 31 32 If you submit changes to SANE to the maintainers to be included in 33 a subsequent release, you agree by submitting the changes that 34 those changes may be distributed with this exception intact. 35 36 If you write modifications of your own for SANE, it is your choice 37 whether to permit this exception to apply to your modifications. 38 If you do not wish that, delete this exception notice. 39 40 This file implements SANE backend for Microtek scanners with M011 USB 41 chip like the Microtek ScanMaker 3600, 3700 and 3750. */ 42 43 44/* ====================================================================== 45 46sm3600.c 47 48SANE backend master module 49 50(C) Marian Matthias Eichholz 2001 51 52Start: 2.4.2001 53 54====================================================================== */ 55 56#include "../include/sane/config.h" 57#include <stdlib.h> 58#include <string.h> 59#include <errno.h> 60 61#define BUILD 6 62 63#ifndef BACKEND_NAME 64#define BACKEND_NAME sm3600 65#endif 66 67#include "../include/sane/sane.h" 68#include "../include/sane/sanei.h" 69#include "../include/sane/sanei_backend.h" 70#include "../include/sane/sanei_config.h" 71#include "../include/sane/saneopts.h" 72#include "../include/sane/sanei_usb.h" 73 74#undef HAVE_LIBUSB_LEGACY 75 76/* prevent inclusion of scantool.h */ 77#define SCANTOOL_H 78/* make no real function export, since we include the modules */ 79#define __SM3600EXPORT__ static 80 81/* if defined, *before* sm3600.h inclusion */ 82#define SM3600_SUPPORT_EXPOSURE 83 84#include "sm3600.h" 85 86static unsigned long ulDebugMask; 87 88static int num_devices; 89static TDevice *pdevFirst; 90static TInstance *pinstFirst; 91 92/* ====================================================================== */ 93 94#include "sm3600-scanutil.c" 95#include "sm3600-scanusb.c" 96#include "sm3600-scanmtek.c" 97#include "sm3600-homerun.c" 98#include "sm3600-gray.c" 99#include "sm3600-color.c" 100 101/* ====================================================================== 102 103Initialise SANE options 104 105====================================================================== */ 106 107typedef enum { optCount, 108 optGroupMode, optMode, optResolution, 109#ifdef SM3600_SUPPORT_EXPOSURE 110 optBrightness, optContrast, 111#endif 112 optPreview, optGrayPreview, 113 optGroupGeometry,optTLX, optTLY, optBRX, optBRY, 114 optGroupEnhancement, 115 optGammaY, optGammaR,optGammaG,optGammaB, 116 optLast } TOptionIndex; 117 118static const SANE_String_Const aScanModes[]= { "color", "gray", "lineart", 119 "halftone", NULL }; 120 121static const SANE_Range rangeXmm = { 122 SANE_FIX(0), 123 SANE_FIX(220), 124 SANE_FIX(0.1) }; 125 126static const SANE_Range rangeYmm = { 127 SANE_FIX(0), 128 SANE_FIX(300), 129 SANE_FIX(0.1) }; 130 131#ifdef SM3600_SUPPORT_EXPOSURE 132static const SANE_Range rangeLumi = { 133 SANE_FIX(-100.0), 134 SANE_FIX(100.0), 135 SANE_FIX(1.0) }; 136#endif 137 138static const SANE_Range rangeGamma = { 0, 4095, 1 }; 139 140static const SANE_Int setResolutions[] = { 5, 75,100,200,300,600 }; 141 142static 143SANE_Status 144InitOptions(TInstance *this) 145{ 146 TOptionIndex iOpt; 147 if (optLast!=NUM_OPTIONS) 148 { 149 DBG(1,"NUM_OPTIONS does not fit!"); 150 return SANE_STATUS_INVAL; 151 } 152 memset(this->aoptDesc,0,sizeof(this->aoptDesc)); 153 memset(this->aoptVal,0,sizeof(this->aoptVal)); 154 InitGammaTables(this,0,0); 155 for (iOpt=optCount; iOpt!=optLast; iOpt++) 156 { 157 static char *achNamesXY[]= { 158 SANE_NAME_SCAN_TL_X, SANE_NAME_SCAN_TL_Y, 159 SANE_NAME_SCAN_BR_X, SANE_NAME_SCAN_BR_Y }; 160 static char *achTitlesXY[]= { 161 SANE_TITLE_SCAN_TL_X, SANE_TITLE_SCAN_TL_Y, 162 SANE_TITLE_SCAN_BR_X, SANE_TITLE_SCAN_BR_Y }; 163 static char *achDescXY[]= { 164 SANE_DESC_SCAN_TL_X, SANE_DESC_SCAN_TL_Y, 165 SANE_DESC_SCAN_BR_X, SANE_DESC_SCAN_BR_Y }; 166 static double afFullBed[] = { 22.0,30.0, 50.0, 80.0 }; /* TODO: calculate exactly! */ 167 static const SANE_Range *aRangesXY[] = { &rangeXmm,&rangeYmm,&rangeXmm,&rangeYmm }; 168 SANE_Option_Descriptor *pdesc; 169 Option_Value *pval; 170 /* shorthands */ 171 pdesc=this->aoptDesc+iOpt; 172 pval=this->aoptVal+iOpt; 173 /* default */ 174 pdesc->size=sizeof(SANE_Word); 175 pdesc->cap=SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT; 176 177 /* 178 Some hints: 179 *every* field needs a constraint, elseway there will be a warning. 180 */ 181 182 switch (iOpt) 183 { 184 case optCount: 185 pdesc->title =SANE_TITLE_NUM_OPTIONS; 186 pdesc->desc =SANE_DESC_NUM_OPTIONS; 187 pdesc->type =SANE_TYPE_INT; 188 pdesc->cap =SANE_CAP_SOFT_DETECT; 189 pval->w =(SANE_Word)optLast; 190 break; 191 case optGroupMode: 192 pdesc->title="Mode"; 193 pdesc->desc =""; 194 pdesc->type = SANE_TYPE_GROUP; 195 pdesc->cap = SANE_CAP_ADVANCED; 196 break; 197 case optMode: 198 pdesc->name =SANE_NAME_SCAN_MODE; 199 pdesc->title =SANE_TITLE_SCAN_MODE; 200 pdesc->desc ="Select the scan mode"; 201 pdesc->type =SANE_TYPE_STRING; 202 pdesc->size =20; 203 pdesc->constraint_type = SANE_CONSTRAINT_STRING_LIST; 204 pdesc->constraint.string_list = aScanModes; 205 pval->s = strdup(aScanModes[color]); 206 break; 207 case optResolution: 208 pdesc->name =SANE_NAME_SCAN_RESOLUTION; 209 pdesc->title =SANE_TITLE_SCAN_RESOLUTION; 210 pdesc->desc =SANE_DESC_SCAN_RESOLUTION; 211 pdesc->type =SANE_TYPE_INT; 212 pdesc->unit =SANE_UNIT_DPI; 213 pdesc->constraint_type = SANE_CONSTRAINT_WORD_LIST; 214 pdesc->constraint.word_list = setResolutions; 215 pval->w =75; 216 break; 217#ifdef SM3600_SUPPORT_EXPOSURE 218 case optBrightness: 219 pdesc->name =SANE_NAME_BRIGHTNESS; 220 pdesc->title =SANE_TITLE_BRIGHTNESS; 221 pdesc->desc =SANE_DESC_BRIGHTNESS; 222 pdesc->type =SANE_TYPE_FIXED; 223 pdesc->unit =SANE_UNIT_PERCENT; 224 pdesc->constraint_type =SANE_CONSTRAINT_RANGE; 225 pdesc->constraint.range=&rangeLumi; 226 pval->w =SANE_FIX(0); 227 break; 228 case optContrast: 229 pdesc->name =SANE_NAME_CONTRAST; 230 pdesc->title =SANE_TITLE_CONTRAST; 231 pdesc->desc =SANE_DESC_CONTRAST; 232 pdesc->type =SANE_TYPE_FIXED; 233 pdesc->unit =SANE_UNIT_PERCENT; 234 pdesc->constraint_type =SANE_CONSTRAINT_RANGE; 235 pdesc->constraint.range=&rangeLumi; 236 pval->w =SANE_FIX(0); 237 break; 238#endif 239 case optPreview: 240 pdesc->name =SANE_NAME_PREVIEW; 241 pdesc->title =SANE_TITLE_PREVIEW; 242 pdesc->desc =SANE_DESC_PREVIEW; 243 pdesc->type =SANE_TYPE_BOOL; 244 pval->w =SANE_FALSE; 245 break; 246 case optGrayPreview: 247 pdesc->name =SANE_NAME_GRAY_PREVIEW; 248 pdesc->title =SANE_TITLE_GRAY_PREVIEW; 249 pdesc->desc =SANE_DESC_GRAY_PREVIEW; 250 pdesc->type =SANE_TYPE_BOOL; 251 pval->w =SANE_FALSE; 252 break; 253 case optGroupGeometry: 254 pdesc->title="Geometry"; 255 pdesc->desc =""; 256 pdesc->type = SANE_TYPE_GROUP; 257 pdesc->constraint_type=SANE_CONSTRAINT_NONE; 258 pdesc->cap = SANE_CAP_ADVANCED; 259 break; 260 case optTLX: case optTLY: case optBRX: case optBRY: 261 pdesc->name =achNamesXY[iOpt-optTLX]; 262 pdesc->title =achTitlesXY[iOpt-optTLX]; 263 pdesc->desc =achDescXY[iOpt-optTLX]; 264 pdesc->type =SANE_TYPE_FIXED; 265 pdesc->unit =SANE_UNIT_MM; /* arghh */ 266 pdesc->constraint_type =SANE_CONSTRAINT_RANGE; 267 pdesc->constraint.range=aRangesXY[iOpt-optTLX]; 268 pval->w =SANE_FIX(afFullBed[iOpt-optTLX]); 269 break; 270 case optGroupEnhancement: 271 pdesc->title="Enhancement"; 272 pdesc->desc =""; 273 pdesc->type = SANE_TYPE_GROUP; 274 pdesc->constraint_type=SANE_CONSTRAINT_NONE; 275 pdesc->cap = SANE_CAP_ADVANCED; 276 break; 277 case optGammaY: 278 pdesc->name = SANE_NAME_GAMMA_VECTOR; 279 pdesc->title = SANE_TITLE_GAMMA_VECTOR; 280 pdesc->desc = SANE_DESC_GAMMA_VECTOR; 281 pdesc->type = SANE_TYPE_INT; 282 pdesc->unit = SANE_UNIT_NONE; 283 pdesc->size = 4096*sizeof(SANE_Int); 284 pdesc->constraint_type = SANE_CONSTRAINT_RANGE; 285 pdesc->constraint.range = &rangeGamma; 286 pval->wa = this->agammaY; 287 break; 288 case optGammaR: 289 pdesc->name = SANE_NAME_GAMMA_VECTOR_R; 290 pdesc->title = SANE_TITLE_GAMMA_VECTOR_R; 291 pdesc->desc = SANE_DESC_GAMMA_VECTOR_R; 292 pdesc->type = SANE_TYPE_INT; 293 pdesc->unit = SANE_UNIT_NONE; 294 pdesc->size = 4096*sizeof(SANE_Int); 295 pdesc->constraint_type = SANE_CONSTRAINT_RANGE; 296 pdesc->constraint.range = &rangeGamma; 297 pval->wa = this->agammaR; 298 break; 299 case optGammaG: 300 pdesc->name = SANE_NAME_GAMMA_VECTOR_G; 301 pdesc->title = SANE_TITLE_GAMMA_VECTOR_G; 302 pdesc->desc = SANE_DESC_GAMMA_VECTOR_G; 303 pdesc->type = SANE_TYPE_INT; 304 pdesc->unit = SANE_UNIT_NONE; 305 pdesc->size = 4096*sizeof(SANE_Int); 306 pdesc->constraint_type = SANE_CONSTRAINT_RANGE; 307 pdesc->constraint.range = &rangeGamma; 308 pval->wa = this->agammaG; 309 break; 310 case optGammaB: 311 pdesc->name = SANE_NAME_GAMMA_VECTOR_B; 312 pdesc->title = SANE_TITLE_GAMMA_VECTOR_B; 313 pdesc->desc = SANE_DESC_GAMMA_VECTOR_B; 314 pdesc->type = SANE_TYPE_INT; 315 pdesc->unit = SANE_UNIT_NONE; 316 pdesc->size = 4096*sizeof(SANE_Int); 317 pdesc->constraint_type = SANE_CONSTRAINT_RANGE; 318 pdesc->constraint.range = &rangeGamma; 319 pval->wa = this->agammaB; 320 break; 321 case optLast: /* not reached */ 322 break; 323 } 324 } 325 return SANE_STATUS_GOOD; 326} 327 328static SANE_Status 329RegisterSaneDev (TModel model, SANE_String_Const szName) 330{ 331 TDevice * q; 332 333 errno = 0; 334 335 q = malloc (sizeof (*q)); 336 if (!q) 337 return SANE_STATUS_NO_MEM; 338 339 memset (q, 0, sizeof (*q)); /* clear every field */ 340 q->szSaneName = strdup (szName); 341 q->sane.name = (SANE_String_Const) q->szSaneName; 342 q->sane.vendor = "Microtek"; 343 q->sane.model = "ScanMaker 3600"; 344 q->sane.type = "flatbed scanner"; 345 346 q->model=model; 347 348 ++num_devices; 349 q->pNext = pdevFirst; /* link backwards */ 350 pdevFirst = q; 351 352 return SANE_STATUS_GOOD; 353} 354 355static SANE_Status 356sm_usb_attach (SANE_String_Const dev_name) 357{ 358 int fd; 359 SANE_Status err; 360 SANE_Word v, p; 361 TModel model; 362 363 err = sanei_usb_open(dev_name, &fd); 364 if (err) 365 return err; 366 err = sanei_usb_get_vendor_product (fd, &v, &p); 367 if (err) 368 { 369 sanei_usb_close (fd); 370 return err; 371 } 372 DBG (DEBUG_JUNK, "found dev %04X/%04X, %s\n", v, p, dev_name); 373 model = GetScannerModel (v, p); 374 if (model != unknown) 375 RegisterSaneDev (model, dev_name); 376 377 sanei_usb_close(fd); 378 return SANE_STATUS_GOOD; 379} 380 381SANE_Status 382sane_init (SANE_Int *version_code, SANE_Auth_Callback authCB) 383{ 384 int i; 385 386 DBG_INIT(); 387 388 (void) authCB; /* compiler */ 389 390 DBG(DEBUG_VERBOSE,"SM3600 init\n"); 391 if (version_code) 392 { 393 *version_code = SANE_VERSION_CODE (SANE_CURRENT_MAJOR, SANE_CURRENT_MINOR, BUILD); 394 DBG(DEBUG_VERBOSE,"SM3600 version: %x\n", 395 SANE_VERSION_CODE(SANE_CURRENT_MAJOR, SANE_CURRENT_MINOR, BUILD)); 396 } 397 398 pdevFirst=NULL; 399 400 sanei_usb_init(); 401 for (i = 0; aScanners[i].idProduct; i++) 402 { 403 sanei_usb_find_devices(SCANNER_VENDOR, aScanners[i].idProduct, sm_usb_attach); 404 } 405 return SANE_STATUS_GOOD; 406} 407 408static const SANE_Device ** devlist = 0; /* only pseudo-statical */ 409 410void 411sane_exit (void) 412{ 413 TDevice *dev, *pNext; 414 415 /* free all bound resources and instances */ 416 while (pinstFirst) 417 sane_close((SANE_Handle)pinstFirst); /* free all resources */ 418 419 /* free all device descriptors */ 420 for (dev = pdevFirst; dev; dev = pNext) 421 { 422 pNext = dev->pNext; 423 free (dev->szSaneName); 424 free (dev); 425 } 426 if (devlist) free(devlist); 427 devlist=NULL; 428} 429 430SANE_Status 431sane_get_devices (const SANE_Device *** device_list, 432 SANE_Bool __sane_unused__ local_only) 433{ 434 TDevice *dev; 435 int i; 436 437 if (devlist) free (devlist); 438 439 devlist = malloc ((num_devices + 1) * sizeof (devlist[0])); 440 if (!devlist) 441 return SANE_STATUS_NO_MEM; 442 443 i = 0; 444 for (dev = pdevFirst; i < num_devices; dev = dev->pNext) 445 devlist[i++] = &dev->sane; 446 devlist[i++] = 0; 447 448 *device_list = devlist; 449 return SANE_STATUS_GOOD; 450} 451 452SANE_Status 453sane_open (SANE_String_Const devicename, SANE_Handle *handle) 454{ 455 TDevice *pdev; 456 TInstance *this; 457 DBG(DEBUG_VERBOSE,"opening %s\n",devicename); 458 if (devicename[0]) /* selected */ 459 { 460 for (pdev=pdevFirst; pdev; pdev=pdev->pNext) 461{ 462DBG(DEBUG_VERBOSE,"%s<>%s\n",devicename, pdev->sane.name); 463 if (!strcmp(devicename,pdev->sane.name)) 464 break; 465} 466 /* no dynamic post-registration */ 467 } 468 else 469 pdev=pdevFirst; 470 if (!pdev) 471 return SANE_STATUS_INVAL; 472 this = (TInstance*) calloc(1,sizeof(TInstance)); 473 if (!this) return SANE_STATUS_NO_MEM; 474 475 *handle = (SANE_Handle)this; 476 477 ResetCalibration(this); /* do not release memory */ 478 this->pNext=pinstFirst; /* register open handle */ 479 pinstFirst=this; 480 this->model=pdev->model; /* memorize model */ 481 /* open and prepare USB scanner handle */ 482 483 if (sanei_usb_open (devicename, &this->hScanner) != SANE_STATUS_GOOD) 484 return SetError (this, SANE_STATUS_IO_ERROR, "cannot open scanner device"); 485 486 this->quality=fast; 487 return InitOptions(this); 488} 489 490void 491sane_close (SANE_Handle handle) 492{ 493 TInstance *this,*pParent,*p; 494 this=(TInstance*)handle; 495 DBG(DEBUG_VERBOSE,"closing scanner\n"); 496 if (this->hScanner) 497 { 498 if (this->state.bScanning) 499 EndScan(this); 500 501 sanei_usb_close(this->hScanner); 502 this->hScanner=-1; 503 } 504 ResetCalibration(this); /* release calibration data */ 505 /* unlink active device entry */ 506 pParent=NULL; 507 for (p=pinstFirst; p; p=p->pNext) 508 { 509 if (p==this) break; 510 pParent=p; 511 } 512 513 if (!p) 514 { 515 DBG(1,"invalid handle in close()\n"); 516 return; 517 } 518 /* delete instance from instance list */ 519 if (pParent) 520 pParent->pNext=this->pNext; 521 else 522 pinstFirst=this->pNext; /* NULL with last entry */ 523 /* free resources */ 524 if (this->pchPageBuffer) 525 free(this->pchPageBuffer); 526 if (this->szErrorReason) 527 { 528 DBG(DEBUG_VERBOSE,"Error status: %d, %s", 529 this->nErrorState, this->szErrorReason); 530 free(this->szErrorReason); 531 } 532 free(this); 533} 534 535const SANE_Option_Descriptor * 536sane_get_option_descriptor (SANE_Handle handle, SANE_Int iOpt) 537{ 538 TInstance *this=(TInstance*)handle; 539 if (iOpt<NUM_OPTIONS) 540 return this->aoptDesc+iOpt; 541 return NULL; 542} 543 544SANE_Status 545sane_control_option (SANE_Handle handle, SANE_Int iOpt, 546 SANE_Action action, void *pVal, 547 SANE_Int *pnInfo) 548{ 549 SANE_Word cap; 550 SANE_Status rc; 551 TInstance *this; 552 this=(TInstance*)handle; 553 rc=SANE_STATUS_GOOD; 554 if (pnInfo) 555 *pnInfo=0; 556 557 if (this->state.bScanning) 558 return SANE_STATUS_DEVICE_BUSY; 559 if (iOpt>=NUM_OPTIONS) 560 return SANE_STATUS_INVAL; 561 562 cap=this->aoptDesc[iOpt].cap; 563 564 switch (action) 565 { 566 567 /* ------------------------------------------------------------ */ 568 569 case SANE_ACTION_GET_VALUE: 570 switch ((TOptionIndex)iOpt) 571 { 572 case optCount: 573 case optPreview: 574 case optGrayPreview: 575 case optResolution: 576#ifdef SM3600_SUPPORT_EXPOSURE 577 case optBrightness: 578 case optContrast: 579#endif 580 case optTLX: case optTLY: case optBRX: case optBRY: 581 *(SANE_Word*)pVal = this->aoptVal[iOpt].w; 582 break; 583 case optMode: 584 strcpy(pVal,this->aoptVal[iOpt].s); 585 break; 586 case optGammaY: 587 case optGammaR: 588 case optGammaG: 589 case optGammaB: 590 DBG(DEBUG_INFO,"getting gamma\n"); 591 memcpy(pVal,this->aoptVal[iOpt].wa, this->aoptDesc[iOpt].size); 592 break; 593 default: 594 return SANE_STATUS_INVAL; 595 } 596 break; 597 598 /* ------------------------------------------------------------ */ 599 600 case SANE_ACTION_SET_VALUE: 601 if (!SANE_OPTION_IS_SETTABLE(cap)) 602 return SANE_STATUS_INVAL; 603 rc=sanei_constrain_value(this->aoptDesc+iOpt,pVal,pnInfo); 604 if (rc!=SANE_STATUS_GOOD) 605 return rc; 606 switch ((TOptionIndex)iOpt) 607 { 608 case optResolution: 609 case optTLX: case optTLY: case optBRX: case optBRY: 610 if (pnInfo) (*pnInfo) |= SANE_INFO_RELOAD_PARAMS; 611 // fall through 612 case optPreview: 613 case optGrayPreview: 614#ifdef SM3600_SUPPORT_EXPOSURE 615 case optBrightness: 616 case optContrast: 617#endif 618 this->aoptVal[iOpt].w = *(SANE_Word*)pVal; 619 break; 620 case optMode: 621 if (pnInfo) 622 (*pnInfo) |= SANE_INFO_RELOAD_PARAMS 623 | SANE_INFO_RELOAD_OPTIONS; 624 strcpy(this->aoptVal[iOpt].s,pVal); 625 break; 626 case optGammaY: 627 case optGammaR: case optGammaG: case optGammaB: 628 DBG(DEBUG_INFO,"setting gamma #%d\n",iOpt); 629 memcpy(this->aoptVal[iOpt].wa, pVal, this->aoptDesc[iOpt].size); 630 break; 631 default: 632 return SANE_STATUS_INVAL; 633 } 634 break; 635 case SANE_ACTION_SET_AUTO: 636 return SANE_STATUS_UNSUPPORTED; 637 } /* switch action */ 638 return rc; /* normally GOOD */ 639} 640 641static SANE_Status 642SetupInternalParameters(TInstance *this) 643{ 644 int i; 645 this->param.res=(int)this->aoptVal[optResolution].w; 646#ifdef SM3600_SUPPORT_EXPOSURE 647 this->param.nBrightness=(int)(this->aoptVal[optBrightness].w>>SANE_FIXED_SCALE_SHIFT); 648 this->param.nContrast=(int)(this->aoptVal[optContrast].w>>SANE_FIXED_SCALE_SHIFT); 649#else 650 this->param.nBrightness=0; 651 this->param.nContrast=0; 652#endif 653 this->param.x=(int)(SANE_UNFIX(this->aoptVal[optTLX].w)*1200.0/25.4); 654 this->param.y=(int)(SANE_UNFIX(this->aoptVal[optTLY].w)*1200.0/25.4); 655 this->param.cx=(int)(SANE_UNFIX(this->aoptVal[optBRX].w-this->aoptVal[optTLX].w)*1200.0/25.4)+1; 656 this->param.cy=(int)(SANE_UNFIX(this->aoptVal[optBRY].w-this->aoptVal[optTLY].w)*1200.0/25.4)+1; 657 for (i=0; aScanModes[i]; i++) 658 if (!strcasecmp(this->aoptVal[optMode].s,aScanModes[i])) 659 { 660 this->mode=(TMode)i; 661 break; 662 } 663 DBG(DEBUG_INFO,"mode=%d, res=%d, BC=[%d,%d], xywh=[%d,%d,%d,%d]\n", 664 this->mode, this->param.res, 665 this->param.nBrightness, this->param.nContrast, 666 this->param.x,this->param.y,this->param.cx,this->param.cy); 667 return SANE_STATUS_GOOD; 668} 669 670SANE_Status 671sane_get_parameters (SANE_Handle handle, SANE_Parameters *p) 672{ 673 /* extremely important for xscanimage */ 674 TInstance *this; 675 this=(TInstance*)handle; 676 SetupInternalParameters(this); 677 GetAreaSize(this); 678 p->pixels_per_line=this->state.cxPixel; 679 /* TODO: we need a more stable cyPixel prediction */ 680 p->lines=this->state.cyPixel; 681 p->last_frame=SANE_TRUE; 682 switch (this->mode) 683 { 684 case color: 685 p->format=SANE_FRAME_RGB; 686 p->depth=8; 687 p->bytes_per_line=p->pixels_per_line*3; 688 break; 689 case gray: 690 p->format=SANE_FRAME_GRAY; 691 p->depth=8; 692 p->bytes_per_line=p->pixels_per_line; 693 break; 694 case halftone: 695 case line: 696 p->format=SANE_FRAME_GRAY; 697 p->depth=1; 698 p->bytes_per_line=(p->pixels_per_line+7)/8; 699 break; 700 } 701 DBG(DEBUG_INFO,"getting parameters (%d,%d)...\n",p->bytes_per_line,p->lines); 702 return SANE_STATUS_GOOD; 703} 704 705SANE_Status 706sane_start (SANE_Handle handle) 707{ 708 TInstance *this; 709 SANE_Status rc; 710 this=(TInstance*)handle; 711 DBG(DEBUG_VERBOSE,"starting scan...\n"); 712 if (this->state.bScanning) return SANE_STATUS_DEVICE_BUSY; 713 rc=SetupInternalParameters(this); 714 this->state.bCanceled=false; 715 if (!rc) rc=DoInit(this); /* oopsi, we should initialise :-) */ 716 if (!rc && !this->bOptSkipOriginate) rc=DoOriginate(this,true); 717 if (!rc) rc=DoJog(this,this->calibration.yMargin); 718 if (rc) return rc; 719 this->state.bEOF=false; 720 switch (this->mode) 721 { 722 case color: rc=StartScanColor(this); break; 723 default: rc=StartScanGray(this); break; 724 } 725 if (this->state.bCanceled) return SANE_STATUS_CANCELLED; 726 return rc; 727} 728 729SANE_Status 730sane_read (SANE_Handle handle, SANE_Byte *puchBuffer, 731 SANE_Int cchMax, 732 SANE_Int *pcchRead) 733{ 734 SANE_Status rc; 735 TInstance *this; 736 this=(TInstance*)handle; 737 DBG(DEBUG_INFO,"reading chunk %d...\n",(int)cchMax); 738 *pcchRead=0; 739 if (this->state.bEOF) 740 return SANE_STATUS_EOF; 741 rc=ReadChunk(this,puchBuffer,cchMax,pcchRead); 742 DBG(DEBUG_INFO,"... line %d (%d/%d)...\n",this->state.iLine,*pcchRead,rc); 743 switch (rc) 744 { 745 case SANE_STATUS_EOF: 746 this->state.bEOF=true; /* flag EOF on next read() */ 747 rc=SANE_STATUS_GOOD; /* we do not flag THIS block! */ 748 break; 749 case SANE_STATUS_GOOD: 750 if (!*pcchRead) rc=SANE_STATUS_EOF; 751 break; 752 default: 753 break; 754 } 755 return rc; 756} 757 758void 759sane_cancel (SANE_Handle handle) 760{ 761 TInstance *this; 762 this=(TInstance*)handle; 763 DBG(DEBUG_VERBOSE,"cancel called...\n"); 764 if (this->state.bScanning) 765 { 766 this->state.bCanceled=true; 767 if (this->state.bEOF) /* regular (fast) cancel */ 768 { 769 DBG(DEBUG_INFO,"regular end cancel\n"); 770 EndScan(this); 771 DoJog(this,-this->calibration.yMargin); 772 } 773 else 774 { 775 /* since Xsane does not continue scanning, 776 we cannot defer cancellation */ 777 DBG(DEBUG_INFO,"hard cancel called...\n"); 778 CancelScan(this); 779 } 780 } 781} 782 783SANE_Status 784sane_set_io_mode(SANE_Handle h, SANE_Bool m) 785{ 786 (void) h; 787 if (m==SANE_TRUE) /* no non-blocking-mode */ 788 return SANE_STATUS_UNSUPPORTED; 789 return SANE_STATUS_GOOD; 790} 791 792SANE_Status 793sane_get_select_fd(SANE_Handle handle, SANE_Int *fd) 794{ 795 (void) handle; (void) fd; 796 return SANE_STATUS_UNSUPPORTED; /* we have no file IO */ 797} 798