diff -ruN sane-backends-1.0.12/backend/Makefile.in sane-backends-1.0.12-patched/backend/Makefile.in --- sane-backends-1.0.12/backend/Makefile.in 2003-05-13 04:39:50.000000000 -0500 +++ sane-backends-1.0.12-patched/backend/Makefile.in 2003-06-19 11:02:15.000000000 -0500 @@ -62,7 +62,7 @@ @SET_MAKE@ -PRELOADABLE_BACKENDS = abaton agfafocus apple artec as6e avision bh canon \ +PRELOADABLE_BACKENDS = niash abaton agfafocus apple artec as6e avision bh canon \ canon630u @CANON_PP@ coolscan coolscan2 dc25 @DC210@ @DC240@ dmc \ epson fujitsu @GPHOTO2@ gt68xx hp @HPSJ5S@ leo matsushita microtek \ microtek2 mustek mustek_pp mustek_usb nec @NET@ pie @PINT@ plustek \ @@ -70,7 +70,7 @@ sp15c st400 tamarack test teco1 teco2 teco3 umax umax_pp umax1220u \ @V4L@ artec_eplus48u ma1509 ibm hp5400 ifneq (@SELECTED_BACKENDS@,) -PRELOADABLE_BACKENDS = @SELECTED_BACKENDS@ +PRELOADABLE_BACKENDS = niash @SELECTED_BACKENDS@ endif ALL_BACKENDS = $(PRELOADABLE_BACKENDS) dll @@ -266,7 +266,10 @@ libsane-abaton.la: ../sanei/sanei_config2.lo libsane-abaton.la: ../sanei/sanei_constrain_value.lo -libsane-abaton.la: ../sanei/sanei_scsi.lo +libsane-abaton.la: ../sanei/sanei_scsi.lo +libsane-niash.la: ../sanei/sanei_config2.lo +libsane-niash.la: ../sanei/sanei_constrain_value.lo +libsane-niash.la: ../sanei/sanei_usb.lo libsane-agfafocus.la: ../sanei/sanei_config2.lo libsane-agfafocus.la: ../sanei/sanei_constrain_value.lo libsane-agfafocus.la: ../sanei/sanei_scsi.lo diff -ruN sane-backends-1.0.12/backend/dll.conf sane-backends-1.0.12-patched/backend/dll.conf --- sane-backends-1.0.12/backend/dll.conf 2003-04-17 04:19:42.000000000 -0500 +++ sane-backends-1.0.12-patched/backend/dll.conf 2003-06-19 11:02:15.000000000 -0500 @@ -64,3 +64,4 @@ # HP OfficeJet backend homepage: http://hpoj.sf.net/ # Uncomment the following line if hpoj is installed: #hpoj +niash diff -ruN sane-backends-1.0.12/backend/hp3300c.c sane-backends-1.0.12-patched/backend/hp3300c.c --- sane-backends-1.0.12/backend/hp3300c.c 1969-12-31 18:00:00.000000000 -0600 +++ sane-backends-1.0.12-patched/backend/hp3300c.c 2003-06-19 11:02:15.000000000 -0500 @@ -0,0 +1,1077 @@ +/* + Copyright (C) 2001 Bertrik Sikken (bertrik@zonnet.nl) + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License + as published by the Free Software Foundation; either version 2 + of the License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + + $Id: hp3300c.c,v 1.52 2003/03/24 19:14:46 bertrik Exp $ +*/ + +/* + Core HP3300c functions. +*/ + +#include /* fopen, fread, fwrite, fclose etc */ +#include /* va_list for vfprintf */ +#include /* memcpy, memset */ +#include /* unlink */ +#include /* malloc, free */ +#include /* exp, pow */ + +#include "mytypes.h" +#include "hp3300c_xfer.h" + +#include "hp3300c.h" + + +#ifndef MIN +#define MIN(a,b) (((a) < (b)) ? (a) : (b)) +#endif + +#ifndef MAX +#define MAX(a,b) (((a) > (b)) ? (a) : (b)) +#endif + + +#define XFER_BUF_SIZE 0xF000 + + +/* HP3400 firmware data */ +static byte abData0000[] = { + 0xfe, 0x9f, 0x58, 0x1b, 0x00, 0x03, 0xa4, 0x02, 0x63, 0x02, 0x33, 0x02, 0x0d, 0x02, 0xf0, 0x01, + 0xd8, 0x01, 0xc5, 0x01, 0xb5, 0x01, 0xa8, 0x01, 0x9d, 0x01, 0x93, 0x01, 0x8b, 0x01, 0x84, 0x01, + 0x7e, 0x01, 0x79, 0x01, 0x74, 0x01, 0x70, 0x01, 0x6d, 0x01, 0x69, 0x01, 0x67, 0x01, 0x64, 0x01, + 0x62, 0x01, 0x60, 0x01, 0x5f, 0x01, 0x5d, 0x01, 0x5c, 0x01, 0x5b, 0x01, 0x5a, 0x01, 0x59, 0x01, + 0x58, 0x01, 0x57, 0x01, 0x57, 0x01, 0x56, 0x01, 0x56, 0x01, 0x55, 0x01, 0x55, 0x01, 0x54, 0x01, + 0x54, 0x01, 0x54, 0x01, 0x54, 0x01, 0x53, 0x01, 0x53, 0x01, 0x53, 0x01, 0x53, 0x01, 0x52, 0x81 }; +/* 1st word : 0x9ffe = 40958, strip 15th bit: 0x1ffe = 8190 + 2nd word : 0x1b58 = 7000 -> coincidence ? + other words: formula: y = 676 / (2 - exp(0.113 * (1-x)) ), where x = 0 for first entry +*/ + +/* more HP3400 firmware data */ +static byte abData0400[] = { + 0xa4, 0x82, 0x00, 0x80, 0xa4, 0x82, 0xaa, 0x02, 0xc0, 0x02, 0xe8, 0x02, 0x3e, 0x03, 0xc8, 0x03, + 0x58, 0x1b, 0xfe, 0x9f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00 }; + + + +/* utility function to show a hexdump of a buffer */ +void DumpHex(byte *pabData, int iLen, int iWidth) +{ + int i; + for (i = 0; i < iLen; i++) { + if ((i % iWidth) == 0) { + printf("\n%04X", i); + } + printf(" %02X", pabData[i]); + } + printf("\n"); +} + + +static void _ConvertMotorTable(byte *pabOld, byte *pabNew, int iSize, int iLpi) +{ + int iData, i, iBit15; + + for (i = 0; i < (iSize / 2); i++) { + iData = pabOld[2*i + 0] + (pabOld[2*i + 1] << 8); + iBit15 = (iData & 0x8000); + iData = (iData & 0x7FFF); + if (iData <= 0x400) { + iData = iData * iLpi / 300; + } + if (iBit15 != 0) { + iData |= 0x8000; + } + pabNew[2*i + 0] = iData & 255; + pabNew[2*i + 1] = (iData >> 8) & 255; + } +} + + +/************************************************************************* + _ProbeRegisters + =============== + Tries to determine certain hardware properties. + + This is done by checking the writeability of some scanner registers. + We cannot rely simply on the scanner model to contain a specific + chip. The HP3300c for example uses one of at least three slightly + different scanner ASICs (NIASH00012, NIASH00013 and NIASH00014). + + OUT pHWParams Hardware parameters, updated fields: + fGamma16 TRUE if 16 bit gamma tables can be used + fReg07 TRUE if reg07 is writeable + iBufferSize Size of scanner's internal buffer + + Returns TRUE if a NIASH chipset was found. +*************************************************************************/ +static bool _ProbeRegisters(THWParams *pHWParams) +{ + byte bData1, bData2; + int iHandle; + + iHandle = pHWParams->iXferHandle; + + DBG(DBG_MSG, "Probing scanner...\n"); + + /* check register 0x04 */ + Hp3300cRegWrite (iHandle, 0x04, 0x55); + Hp3300cRegRead (iHandle, 0x04, &bData1); + Hp3300cRegWrite (iHandle, 0x04, 0xAA); + Hp3300cRegRead (iHandle, 0x04, &bData2); + Hp3300cRegWrite (iHandle, 0x04, 0x07); + if ((bData1 != 0x55) || (bData2 != 0xAA)) { + DBG(DBG_ERR, " No NIASH chipset found!\n"); + return FALSE; + } + + /* check writeability of register 3 bit 1 */ + Hp3300cRegRead (iHandle, 0x03, &bData1); + Hp3300cRegWrite (iHandle, 0x03, bData1 | 0x02); + Hp3300cRegRead (iHandle, 0x03, &bData2); + Hp3300cRegWrite (iHandle, 0x03, bData1); + pHWParams->fGamma16 = ((bData2 & 0x02) != 0); + DBG(DBG_MSG, " Gamma table entries are %d bit\n", pHWParams->fGamma16 ? 16 : 8); + + /* check register 0x07 */ + Hp3300cRegRead (iHandle, 0x07, &bData1); + Hp3300cRegWrite (iHandle, 0x07, 0x1C); + Hp3300cRegRead (iHandle, 0x07, &bData2); + Hp3300cRegWrite (iHandle, 0x07, bData1); + pHWParams->fReg07 = (bData2 == 0x1C); + + if (!pHWParams->fGamma16) { + /* internal scan buffer size is an educated guess, but seems to correlate + well with the size calculated from several windows driver log files + size = 128kB - 44088 bytes (space required for gamma/calibration table) + */ + pHWParams->iBufferSize = 86984L; + DBG(DBG_MSG, " NIASH version < 00014\n"); + } + else { + pHWParams->iBufferSize = 0x60000L; + if (!pHWParams->fReg07) { + DBG(DBG_MSG, " NIASH version = 00014\n"); + } + else { + DBG(DBG_MSG, " NIASH version > 00014\n"); + } + } + + return TRUE; +} + + +/* returns 0 on success, < 0 otherwise */ +int Hp3300cOpen(THWParams *pHWParams, char *pszName) +{ + int iXferHandle; + + iXferHandle = Hp3300cXferOpen(pszName, &pHWParams->eModel); + if (iXferHandle < 0) { + DBG(DBG_ERR, "Hp3300cXferOpen failed for '%s'\n", pszName); + return -1; + } + + pHWParams->iXferHandle = iXferHandle; + + Hp3300cWakeup(pHWParams->iXferHandle); + + /* default HW params */ + pHWParams->iSensorSkew = 8; + pHWParams->iTopLeftX = 0; + pHWParams->iTopLeftY = 3; + pHWParams->fReg07 = FALSE; + pHWParams->iSkipLines = 0; + pHWParams->iExpTime = 5408; + pHWParams->iReversedHead = TRUE; + + switch (pHWParams->eModel) { + + case eHp3300c: + DBG(DBG_MSG, "Setting params for Hp3300\n"); + pHWParams->iTopLeftX = 4; + pHWParams->iTopLeftY = 11; + pHWParams->iSkipLines = 14; + break; + + case eHp3400c: case eHp4300c: + DBG(DBG_MSG, "Setting params for Hp3400c/Hp4300c\n"); + pHWParams->iTopLeftX = 2; + pHWParams->iTopLeftY = 13; + pHWParams->fReg07 = TRUE; + break; + + case eAgfaTouch: + DBG(DBG_MSG, "Setting params for AgfaTouch\n"); + pHWParams->iReversedHead = FALSE; /* head not reversed on Agfa Touch */ + pHWParams->iTopLeftX = 3; + pHWParams->iTopLeftY = 10; + pHWParams->iSkipLines = 7; + break; + + case eUnknownModel: + DBG(DBG_MSG, "Setting params for UnknownModel\n"); + break; + + default: + DBG(DBG_ERR, "ERROR: internal error! (%d)\n", (int)pHWParams->eModel); + return -1; + } + + /* autodetect some hardware properties */ + if (!_ProbeRegisters(pHWParams)) { + DBG(DBG_ERR, "_ProbeRegisters failed!\n"); + return -1; + } + + return 0; +} + + +void Hp3300cClose(THWParams *pHWPar) +{ + Hp3300cXferClose(pHWPar->iXferHandle); + pHWPar->iXferHandle = 0; +} + + +static void WriteRegWord(int iHandle, byte bReg, word wData) +{ + Hp3300cRegWrite(iHandle, bReg, wData & 0xFF); + Hp3300cRegWrite(iHandle, bReg + 1, (wData >> 8) & 0xFF); +} + + +/* calculate a 4096 byte gamma table */ +void CalcGamma(byte *pabTable, double Gamma) +{ + int i, iData; + + /* fill gamma table */ + for (i = 0; i < 4096; i++) { + iData = floor(256.0 * pow(((double)i / 4096.0), 1.0 / Gamma)); + pabTable[i] = iData; + } +} + + +/* + Hp3400WriteFw + ============= + Writes data to scanners with a NIASH00019 chipset, e.g. + gamma, calibration and motor control data. + + IN pabData pointer to firmware data + iLen Size of firmware date (bytes) + iAddr Scanner address to write to +*/ +static void Hp3400cWriteFW(int iXferHandle, byte *pabData, int iLen, int iAddr) +{ + iAddr--; + Hp3300cRegWrite(iXferHandle, 0x21, iAddr & 0xFF); + Hp3300cRegWrite(iXferHandle, 0x22, (iAddr >> 8) & 0xFF); + Hp3300cRegWrite(iXferHandle, 0x23, (iAddr >> 16) & 0xFF); + Hp3300cBulkWrite(iXferHandle, pabData, iLen); +} + + +/* Writes the gamma and offset/gain tables to the scanner. + In case a calibration file exist, it will be used for offset/gain */ +void WriteGammaCalibTable(byte *pabGammaR, byte *pabGammaG, byte *pabGammaB, + byte *pabCalibTable, int iGain, int iOffset, THWParams *pHWPar) +{ + int i, j, k; + static byte abGamma[60000]; + int iData; + int iHandle; + + iHandle = pHWPar->iXferHandle; + + j = 0; + /* fill gamma table for red component */ + /* pad entries with 0 for 16-bit gamma table */ + for (i = 0; i < 4096; i++) { + if (pHWPar->fGamma16) { + abGamma[j++] = 0; + } + abGamma[j++] = pabGammaR[i]; + } + /* fill gamma table for green component */ + for (i = 0; i < 4096; i++) { + if (pHWPar->fGamma16) { + abGamma[j++] = 0; + } + abGamma[j++] = pabGammaG[i]; + } + /* fill gamma table for blue component */ + for (i = 0; i < 4096; i++) { + if (pHWPar->fGamma16) { + abGamma[j++] = 0; + } + abGamma[j++] = pabGammaB[i]; + } + + if (pabCalibTable == NULL) { + iData = (iGain << 6) + iOffset; + for (i = 0; i < HW_PIXELS; i++) { + for (k = 0; k < 3; k++) { + abGamma[j++] = (iData) & 255; + abGamma[j++] = (iData >> 8) & 255; + } + } + } + else { + memcpy(&abGamma[j], pabCalibTable, HW_PIXELS * 6); + j += HW_PIXELS * 6; + } + + Hp3300cRegWrite(iHandle, 0x02, 0x80); + Hp3300cRegWrite(iHandle, 0x03, 0x01); + Hp3300cRegWrite(iHandle, 0x03, 0x11); + Hp3300cRegWrite(iHandle, 0x02, 0x84); + + if (pHWPar->fReg07) { + Hp3400cWriteFW(iHandle, abGamma, j, 0x2000); + } + else { + Hp3300cBulkWrite(iHandle, abGamma, j); + } + + Hp3300cRegWrite(iHandle, 0x02, 0x80); +} + + +static void WriteAFEReg(int iHandle, int iReg, int iData) +{ + Hp3300cRegWrite(iHandle, 0x25, iReg); + Hp3300cRegWrite(iHandle, 0x26, iData); +} + + +/* setup the analog front-end -> coarse calibration */ +static void WriteAFE(int iHandle) +{ + /* see WM8143 datasheet */ + + WriteAFEReg(iHandle, 0x04, 0x00); + WriteAFEReg(iHandle, 0x03, 0x12); + WriteAFEReg(iHandle, 0x02, 0x04); + WriteAFEReg(iHandle, 0x05, 0x10); + WriteAFEReg(iHandle, 0x01, 0x03); + + WriteAFEReg(iHandle, 0x20, 0xc0);/*c8*/ /* red offset */ + WriteAFEReg(iHandle, 0x21, 0xc0);/*c8*/ /* green offset */ + WriteAFEReg(iHandle, 0x22, 0xc0);/*d0*/ /* blue offset */ + + WriteAFEReg(iHandle, 0x28, 0x05);/*5*/ /* red gain */ + WriteAFEReg(iHandle, 0x29, 0x03);/*3*/ /* green gain */ + WriteAFEReg(iHandle, 0x2A, 0x04);/*4*/ /* blue gain */ +} + + +/* wait for the carriage to return */ +static void WaitReadyBit(int iHandle) +{ + byte bData; + + do { + Hp3300cRegRead(iHandle, 0x03, &bData); + } while ((bData & 8) == 0); +} + + +/* + Initialisation specific for NIASH00014 and lower chips +*/ +static void InitNiash00014(TScanParams *pParams, THWParams *pHWParams) +{ + int iHandle, iLpiCode; + + iHandle = pHWParams->iXferHandle; + + /* exposure time (in units 24/Fcrystal)? */ + WriteRegWord(iHandle, 0x08, pHWParams->iExpTime - 1); + + /* width in pixels */ + WriteRegWord(iHandle, 0x12, pParams->iWidth - 1); + + /* top */ + WriteRegWord (iHandle, 0x17, pParams->iTop); + WriteRegWord (iHandle, 0x19, pParams->iTop); + + /* time between stepper motor steps (in units of 24/Fcrystal)? */ + iLpiCode = pParams->iLpi * pHWParams->iExpTime / 1200L; + + if (!pHWParams->fGamma16) { + /* NIASH 00012 / 00013 init */ + + /* LPI specific settings */ + if (pParams->iLpi < 600) { + /* set halfres bit */ + Hp3300cRegWrite(iHandle, 0x06, 0x01); + /* double lpi code because of halfres bit */ + iLpiCode *= 2; + } + else { + /* clear halfres bit */ + Hp3300cRegWrite(iHandle, 0x06, 0x00); + /* add exptime to make it scan slower */ + iLpiCode += pHWParams->iExpTime; + } + + /* unknown setting */ + WriteRegWord (iHandle, 0x27, 0x7FD2); + WriteRegWord (iHandle, 0x29, 0x6421); + + } + else { + /* NIASH 00014 init */ + + /* halfres bit always cleared */ + Hp3300cRegWrite(iHandle, 0x06, 0x00); + + /* LPI specific settings */ + if (pParams->iLpi >= 600) { + /* add exptime to make it scan slower */ + iLpiCode += pHWParams->iExpTime; + } + + /* unknown setting */ + WriteRegWord (iHandle, 0x27, 0xc862);/*c862 */ + WriteRegWord (iHandle, 0x29, 0xb853);/*b853 */ + } + + /* LPI code */ + WriteRegWord(iHandle, 0x0A, iLpiCode - 1); + + /* backtrack reversing speed */ + Hp3300cRegWrite(iHandle, 0x1E, (iLpiCode - 1) / 32); +} + + +/* + Initialisation specific for NIASH00019 chips +*/ +static void InitNiash00019(TScanParams *pParams, THWParams *pHWParams) +{ + int iHandle, iLpiCode; + static byte abMotor[512]; + + + iHandle = pHWParams->iXferHandle; + + /* exposure time (in units 24/Fcrystal)? */ + WriteRegWord (iHandle, 0x08, pHWParams->iExpTime); + + /* width in pixels */ + WriteRegWord (iHandle, 0x12, pParams->iWidth); + + /* ? */ + WriteRegWord (iHandle, 0x27, 0xc862);/*c862 */ + WriteRegWord (iHandle, 0x29, 0xb853);/*b853 */ + + /* specific handling of 150 dpi resolution */ + if (pParams->iLpi == 150) { + /* use 300 LPI but skip every other line */ + pParams->iLpi = 300; + Hp3300cRegWrite(iHandle, 0x06, 0x01); + } + else { + Hp3300cRegWrite(iHandle, 0x06, 0x00); + } + + /* DPI and position table */ + Hp3300cRegWrite (iHandle, 0x07, 0x02); + _ConvertMotorTable(abData0000, abMotor, sizeof(abData0000), pParams->iLpi); + Hp3400cWriteFW(iHandle, abMotor, sizeof(abData0000), 0x000); + _ConvertMotorTable(abData0400, abMotor, sizeof(abData0400), pParams->iLpi); + Hp3400cWriteFW(iHandle, abMotor, sizeof(abData0400), 0x400); + + /* backtrack reversing speed */ + iLpiCode = pParams->iLpi * pHWParams->iExpTime / 1200L; + Hp3300cRegWrite(iHandle, 0x1E, (iLpiCode - 1) / 32); +} + + +/* + Scanner initialisation common to all NIASH chips +*/ +static void InitNiashCommon(TScanParams *pParams, THWParams *pHWParams) +{ + int iWidthHW, iHandle, iMaxLevel; + + + iHandle = pHWParams->iXferHandle; + + Hp3300cRegWrite (iHandle, 0x02, 0x80); + Hp3300cRegWrite (iHandle, 0x03, 0x11); + Hp3300cRegWrite (iHandle, 0x01, 0x8B); + Hp3300cRegWrite (iHandle, 0x05, 0x01); + + /* dpi */ + WriteRegWord (iHandle, 0x0C, pParams->iDpi); + + /* calculate width in units of HW resolution */ + iWidthHW = pParams->iWidth * (HW_DPI / pParams->iDpi); + + /* set left and right limits */ + if ( pHWParams->iReversedHead ) { + /* head is reversed */ + /* right */ + WriteRegWord (iHandle, 0x0E, 3 * (HW_PIXELS - (pParams->iLeft + iWidthHW)) ); + + /* left */ + WriteRegWord (iHandle, 0x10, 3 * (HW_PIXELS - pParams->iLeft) - 1); + } else { + /* head is not reversed */ + /*left */ + WriteRegWord (iHandle, 0x0E, 3 * pParams->iLeft); + + /* right */ + WriteRegWord (iHandle, 0x10, 3 * (pParams->iLeft + iWidthHW) - 1); + } + + /* bottom */ + WriteRegWord (iHandle, 0x1B, pParams->iBottom); /* 0x393C); */ + + /* forward jogging speed */ + Hp3300cRegWrite (iHandle, 0x1D, 0x60); + + /* backtrack reversing speed? */ + Hp3300cRegWrite (iHandle, 0x2B, 0x15); + + /* backtrack distance */ + if (pParams->iLpi < 600) { + Hp3300cRegWrite(iHandle, 0x1F, 0x30); + } + else { + Hp3300cRegWrite(iHandle, 0x1F, 0x18); + } + + /* max buffer level before backtrace */ + iMaxLevel = MIN(pHWParams->iBufferSize / pParams->iWidth, 250); + Hp3300cRegWrite (iHandle, 0x14, iMaxLevel - 1); + + /* lamp PWM, max = 0x1ff? */ + WriteRegWord (iHandle, 0x2C, 0x01FF); + + /* not needed? */ + Hp3300cRegWrite (iHandle, 0x15, 0x90);/* 90 */ + Hp3300cRegWrite (iHandle, 0x16, 0x70);/* 70 */ + + WriteAFE(iHandle); + + WaitReadyBit(iHandle); + + Hp3300cRegWrite (iHandle, 0x03, 0x05); + + Hp3300cRegWrite(iHandle, 0x02, pParams->fCalib ? 0x88 : 0xA8); +} + + +/* write registers */ +bool InitScan(TScanParams *pParams, THWParams *pHWParams) +{ + int iHeight; + int iExpTime; + TScanParams Params; + int iHandle; + + iHandle = pHWParams->iXferHandle; + + /* check validity of scanparameters */ + switch (pParams->iDpi) { + case 150: case 300: case 600: + break; + default: + DBG(DBG_ERR, "Invalid dpi (%d)\n", pParams->iDpi); + return FALSE; + } + + iHeight = (pParams->iBottom - pParams->iTop + 1); + if (iHeight <= 0) { + DBG(DBG_ERR, "Invalid height (%d)\n", iHeight); + return FALSE; + } + + if (pParams->iWidth <= 0) { + DBG(DBG_ERR, "Invalid width (%d)\n", pParams->iWidth); + return FALSE; + } + + switch (pParams->iLpi) { + case 150: case 300: case 600: + break; + default: + DBG(DBG_ERR, "Invalid lpi (%d)\n", pParams->iLpi); + return FALSE; + } + + /* exposure time (in units of 24/Fcrystal?), must be divisible by 8 !!! */ + iExpTime = 5408; + if ((iExpTime % 8) != 0) { + DBG(DBG_ERR, "Invalid exposure time (%d)\n", iExpTime); + return FALSE; + } + + /* + *** Done checking scan parameters validity *** + */ + + /* + copy the parameters locally and make pParams point to the local copy + */ + memcpy(&Params, pParams, sizeof(Params)); + pParams = &Params; + + if (!pHWParams->fReg07) { + /* init NIASH00014 and lower */ + InitNiash00014(pParams, pHWParams); + } + else { + /* init NIASH00019 */ + InitNiash00019(pParams, pHWParams); + } + + /* common NIASH init */ + InitNiashCommon(pParams, pHWParams); + + return TRUE; +} + + +/************************************************************************/ + +static void XferBufferGetLine(int iHandle, TDataPipe *p, byte *pabLine) +{ + byte bData; + + /* time for a fresh read? */ + if (p->iCurLine == 0) { + /* DBG(DBG_MSG, "Reading buffer %d bytes\n", _iLinesPerXferBuf + * _iBytesPerLine); */ + Hp3300cRegRead(iHandle, 0x20, &bData); + DBG(DBG_MSG, "buffer level = %3d, , ", + (int)bData, p->iLinesPerXferBuf * p->iBytesPerLine); + Hp3300cBulkRead(iHandle, p->pabXferBuf, p->iLinesPerXferBuf * p->iBytesPerLine); + Hp3300cRegRead(iHandle, 0x20, &bData); + DBG(DBG_MSG, "buffer level = %3d\r", bData); + fflush(stdout); + } + /* copy one line */ + if (pabLine != NULL) { + memcpy(pabLine, &p->pabXferBuf[p->iCurLine * p->iBytesPerLine], p->iBytesPerLine); + } + /* advance pointer */ + p->iCurLine = (p->iCurLine + 1) % p->iLinesPerXferBuf; +} + + +static void XferBufferInit(int iHandle, TDataPipe *p) +{ + int i; + + p->pabXferBuf = (byte *)malloc(XFER_BUF_SIZE); + p->iCurLine = 0; + + /* skip garbage lines */ + for (i = 0; i < p->iSkipLines; i++) { + XferBufferGetLine(iHandle, p, NULL); + } +} + + +static void XferBufferExit(TDataPipe *p) +{ + if (p->pabXferBuf != NULL) { + free(p->pabXferBuf); + p->pabXferBuf = NULL; + } + else { + DBG(DBG_ERR, "XferBufExit: Xfer buffer not initialised!\n"); + } +} + + +/* unscrambles a line: + - combining the proper R, G and B lines and converting them to interpixel RGB + - mirroring left to right +*/ +static void _UnscrambleLine(byte *pabLine, + byte *pabRed, byte *pabGrn, byte *pabBlu, int iWidth, bool iReversedHead) +{ + int i, j; + if (iReversedHead) { + /* reversed */ + for (i = 0; i < iWidth; i++) { + j = (iWidth - i) * 3; + pabLine[j - 3] = pabRed[i]; + pabLine[j - 2] = pabGrn[i + iWidth]; + pabLine[j - 1] = pabBlu[i + iWidth * 2]; + } + } else { + /* not reversed */ + for (i = 0; i < iWidth; i++) { + pabLine[3 * i] = pabRed[i]; + pabLine[3 * i + 1] = pabGrn[i + iWidth]; + pabLine[3 * i + 2] = pabBlu[i + iWidth * 2]; + } + } +} + + +/* gets an unscrambled line from the circular buffer. the first couple of lines contain garbage */ +void CircBufferGetLine(int iHandle, TDataPipe *p, byte *pabLine, bool iReversedHead) +{ + if (iReversedHead) { + XferBufferGetLine(iHandle, p, &p->pabCircBuf[p->iRedLine * p->iBytesPerLine]); + } else { + XferBufferGetLine(iHandle, p, &p->pabCircBuf[p->iBluLine * p->iBytesPerLine]); + } + + if (pabLine != NULL) { + _UnscrambleLine(pabLine, + &p->pabCircBuf[p->iRedLine * p->iBytesPerLine], + &p->pabCircBuf[p->iGrnLine * p->iBytesPerLine], + &p->pabCircBuf[p->iBluLine * p->iBytesPerLine], + p->iBytesPerLine / 3, + iReversedHead); + } + + /* advance pointers */ + p->iRedLine = (p->iRedLine + 1) % p->iLinesPerCircBuf; + p->iGrnLine = (p->iGrnLine + 1) % p->iLinesPerCircBuf; + p->iBluLine = (p->iBluLine + 1) % p->iLinesPerCircBuf; +} + + +void CircBufferInit(int iHandle, TDataPipe *p, int iBytesPerLine, int iMisAlignment, bool iReversedHead) +{ + int i; + + p->iBytesPerLine = iBytesPerLine; + if (iMisAlignment == 0) { + p->iLinesPerCircBuf = 1; + } + else { + p->iLinesPerCircBuf = 3 * iMisAlignment; + } + + DBG(DBG_MSG, "_iBytesPerLine = %d\n", p->iBytesPerLine); + DBG(DBG_MSG, "_iLinesPerCircBuf = %d\n", p->iLinesPerCircBuf); + p->pabCircBuf = (byte *)malloc(iBytesPerLine * p->iLinesPerCircBuf); + if (p->pabCircBuf == NULL) { + DBG(DBG_ERR, "Unable to allocate %d bytes for circular buffer\n", (int)(iBytesPerLine * p->iLinesPerCircBuf)); + return; + } + DBG(DBG_MSG, "Allocated %d bytes for circular buffer\n", iBytesPerLine * p->iLinesPerCircBuf); + + if (iReversedHead) { + p->iBluLine = 0; + p->iGrnLine = iMisAlignment; + p->iRedLine = iMisAlignment * 2; + } else { + p->iRedLine = 0; + p->iGrnLine = iMisAlignment; + p->iBluLine = iMisAlignment * 2; + } + + p->iLinesPerXferBuf = XFER_BUF_SIZE / iBytesPerLine; + DBG(DBG_MSG, "_iLinesPerXferBuf = %d\n", p->iLinesPerXferBuf); + DBG(DBG_MSG, "Xfer block size = %d\n", p->iLinesPerXferBuf * p->iBytesPerLine); + + /* init transfer buffer */ + XferBufferInit(iHandle, p); + + /* fill circular buffer */ + for (i = 0; i < p->iLinesPerCircBuf; i++) { + CircBufferGetLine(iHandle, p, NULL, iReversedHead); + } +} + + +void CircBufferExit(TDataPipe *p) +{ + XferBufferExit(p); + if (p->pabCircBuf != NULL) { + DBG(DBG_MSG, "\n"); + free(p->pabCircBuf); + p->pabCircBuf = NULL; + } + else { + DBG(DBG_ERR, "CircBufferExit: Circular buffer not initialised!\n"); + } +} + + +/************************************************************************/ + +/************************************************************************* + ScanLines + ========= + Helper function to scan in an image and output the result to a file. + + IN pFile File to write image data to + pParams User-defineable settings describing the image to be scanned + pHWParams Scanner hardware settings + +*************************************************************************/ +void ScanLines(FILE *pFile, TScanParams *pParams, THWParams *pHWParams) +{ + static byte abBuf[HW_PIXELS * 3]; + int iBytesPerLine; + int iHeight; + int iHandle; + bool iReversedHead; + TDataPipe DataPipe; + + iHandle = pHWParams->iXferHandle; + + iHeight = pParams->iHeight; + iBytesPerLine = pParams->iWidth * 3; + DataPipe.iSkipLines = 0; + iReversedHead = pHWParams->iReversedHead; + + if (InitScan(pParams, pHWParams)) { + CircBufferInit(iHandle, &DataPipe, iBytesPerLine, pHWParams->iSensorSkew * pParams->iLpi / HW_LPI, iReversedHead); + while (iHeight-- > 0) { + CircBufferGetLine(iHandle, &DataPipe, abBuf, iReversedHead); + fwrite(abBuf, 1, iBytesPerLine, pFile); + } + CircBufferExit(&DataPipe); + } + FinishScan(pHWParams); +} + + +static int _CalcAvg(byte *pabBuf, int n, int iStep) +{ + int i, j, x; + + for (i = j = x = 0; i < n; i++) { + x += pabBuf[j]; + j += iStep; + } + return (x / n); +} + + +/* converts white line data and black point data into a calibration table */ +static void CreateCalibTable(byte *abWhite, byte bBlackR, byte bBlackG, + byte bBlackB, int iReversedHead, byte *pabCalibTable) +{ + int i, j, iGain, iOffset, iData; + byte *pabPixel; + + j = 0; + for (i = 0; i < HW_PIXELS; i++) { + if (iReversedHead) { + pabPixel = &abWhite[(HW_PIXELS - i - 1) * 3]; + } + else { + pabPixel = &abWhite[i * 3]; + } + /* red */ + if (bBlackR > 16) bBlackR = 16 ; + iGain = 65536 / MAX(1, pabPixel[0] - bBlackR); + iOffset = bBlackR * 4; + if (iOffset > 63) iOffset = 63 ; + iData = (iGain << 6) + iOffset; + pabCalibTable[j++] = (iData) & 255; + pabCalibTable[j++] = (iData >> 8) & 255; + /* green */ + if (bBlackG > 16) bBlackG = 16 ; + iGain = 65536 / MAX(1, pabPixel[1] - bBlackG); + iOffset = bBlackG * 4; + if (iOffset > 63) iOffset = 63 ; + iData = (iGain << 6) + iOffset; + pabCalibTable[j++] = (iData) & 255; + pabCalibTable[j++] = (iData >> 8) & 255; + /* blue */ + if (bBlackB > 16) bBlackB = 16 ; + iGain = 65536 / MAX(1, pabPixel[2] - bBlackB); + iOffset = bBlackB * 4; + if (iOffset > 63) iOffset = 63 ; + iData = (iGain << 6) + iOffset; + pabCalibTable[j++] = (iData) & 255; + pabCalibTable[j++] = (iData >> 8) & 255; + } +} + + +/************************************************************************* + Lamp control functions +*************************************************************************/ +bool GetLamp(THWParams *pHWParams, bool *pfLampIsOn) +{ + byte bData; + + Hp3300cRegRead(pHWParams->iXferHandle, 0x03, &bData); + *pfLampIsOn = ((bData & 0x01) != 0); + return TRUE; +} + + +bool SetLamp(THWParams *pHWParams, bool fLampOn) +{ + byte bData; + int iHandle; + + iHandle = pHWParams->iXferHandle; + + Hp3300cRegRead(iHandle, 0x03, &bData); + if (fLampOn) { + Hp3300cRegWrite(iHandle, 0x03, bData | 0x01); + } + else { + Hp3300cRegWrite(iHandle, 0x03, bData & ~0x01); + } + return TRUE; +} + + +/************************************************************************* + Experimental simple calibration + + Basic idea: + * a strip starting at position 0 is scanned in + * per-pixel white level is determined by average of first 4 lines + * global black level is determined by minimum value of all lines +*************************************************************************/ +bool SimpleCalib(THWParams *pHWPar, byte *pabCalibTable) +{ + byte bMinR, bMinG, bMinB; + TDataPipe DataPipe; + TScanParams Params; + byte abGamma[4096]; + int i, j; + static byte abBuf[HW_PIXELS * 3 * 71]; /* Carefull : see startWhite and endWhite below */ + static byte abLine[HW_PIXELS * 3]; + static byte abWhite[HW_PIXELS * 3]; + byte *pabWhite; + int iWhiteR, iWhiteG, iWhiteB; + int iHandle; + bool iReversedHead; + int startWhiteY, endWhiteY ; + int startBlackY, endBlackY ; + int startBlackX, endBlackX ; + + iHandle = pHWPar->iXferHandle; + iReversedHead = pHWPar->iReversedHead; + + DataPipe.iSkipLines = pHWPar->iSkipLines; + + Params.iDpi = HW_DPI; + Params.iLpi = HW_DPI; + if (iReversedHead) /* hp scanners */ + Params.iTop = 60; + else /* agfa scanners */ + Params.iTop = 30 ; + Params.iBottom = HP3300C_BOTTOM; + Params.iLeft = 0; + Params.iWidth = HW_PIXELS; + Params.iHeight = 54; + Params.fCalib = TRUE; + + /* write gamma table with neutral gain / offset */ + CalcGamma(abGamma, 1.0); + WriteGammaCalibTable(abGamma, abGamma, abGamma, NULL, 256, 0, pHWPar); + + if (!InitScan(&Params, pHWPar)) { + return FALSE; + } + + /* Definition of white and black areas */ + if (iReversedHead) { /* hp scanners */ + startWhiteY = 0 ; + endWhiteY = 15 ; + startBlackY = 16 ; + endBlackY = 135 ; + startBlackX = 0 ; + endBlackX = HW_PIXELS ; + } else { /* agfa scanners */ + startWhiteY = 0 ; + endWhiteY = 70 ; + startBlackY = 86 ; + endBlackY = 135 ; + startBlackX = 1666 ; + endBlackX = 3374 ; + } + + CircBufferInit(iHandle, &DataPipe, HW_PIXELS * 3, Params.iLpi / 150, iReversedHead); + /* white level */ + /* skip some lines */ + for (i = 0; i < startWhiteY; i++) { + CircBufferGetLine(iHandle, &DataPipe, abLine, iReversedHead); + } + /* Get white lines */ + for (i = 0; i < endWhiteY - startWhiteY + 1; i++) { + CircBufferGetLine(iHandle, &DataPipe, &abBuf[i * HW_PIXELS * 3], iReversedHead); + } + /* black level */ + bMinR = 255; bMinG = 255; bMinB = 255; + /* Skip some lines */ + for (i = 0; i < startBlackY; i++) { + CircBufferGetLine(iHandle, &DataPipe, abLine, iReversedHead); + } + for (i = 0; i < endBlackY - startBlackY + 1; i++) { + CircBufferGetLine(iHandle, &DataPipe, abLine, iReversedHead); + for (j = 0; j < endBlackX; j++) { + bMinR = MIN(abLine[j * 3 + 0], bMinR); + bMinG = MIN(abLine[j * 3 + 1], bMinG); + bMinB = MIN(abLine[j * 3 + 2], bMinB); + } + } + CircBufferExit(&DataPipe); + FinishScan(pHWPar); + + /* calc average white level */ + pabWhite = abBuf; + for (i = 0; i < HW_PIXELS; i++) { + abWhite[i * 3 + 0] = _CalcAvg(&pabWhite[i * 3 + 0], endWhiteY - startWhiteY + 1, HW_PIXELS * 3); + abWhite[i * 3 + 1] = _CalcAvg(&pabWhite[i * 3 + 1], endWhiteY - startWhiteY + 1, HW_PIXELS * 3); + abWhite[i * 3 + 2] = _CalcAvg(&pabWhite[i * 3 + 2], endWhiteY - startWhiteY + 1, HW_PIXELS * 3); + } + iWhiteR = _CalcAvg(&abWhite[0], HW_PIXELS, 3); + iWhiteG = _CalcAvg(&abWhite[1], HW_PIXELS, 3); + iWhiteB = _CalcAvg(&abWhite[2], HW_PIXELS, 3); + + DBG(DBG_MSG, "Black level (%d,%d,%d), White level (%d,%d,%d)\n", + (int)bMinR, (int)bMinG, (int)bMinB, iWhiteR, iWhiteG, iWhiteB); + + /* convert the white line and black point into a calibration table */ + CreateCalibTable(abWhite, bMinR, bMinG, bMinB, iReversedHead, + pabCalibTable); + + return TRUE; +} + + +/************************************************************************* + FinishScan + ========== + Finishes the scan. Makes the scanner head move back to the home position. + +*************************************************************************/ +void FinishScan(THWParams *pHWParams) +{ + Hp3300cRegWrite(pHWParams->iXferHandle, 0x02, 0x80); +} + + + diff -ruN sane-backends-1.0.12/backend/hp3300c.h sane-backends-1.0.12-patched/backend/hp3300c.h --- sane-backends-1.0.12/backend/hp3300c.h 1969-12-31 18:00:00.000000000 -0600 +++ sane-backends-1.0.12-patched/backend/hp3300c.h 2003-06-19 11:02:15.000000000 -0500 @@ -0,0 +1,113 @@ +/* + Copyright (C) 2001 Bertrik Sikken (bertrik@zonnet.nl) + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License + as published by the Free Software Foundation; either version 2 + of the License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + + $Id: hp3300c.h,v 1.24 2002/11/04 23:48:32 bertrik Exp $ +*/ + +/* + Core HP3300c functions. +*/ + + +#ifndef _HP3300C_H_ +#define _HP3300C_H_ + +#include + +#include "mytypes.h" +#include "hp3300c_xfer.h" /* for EScannerModel */ + +#define HP3300C_RIGHT 330 +#define HP3300C_TOP 452 +#define HP3300C_BOTTOM (HP3300C_TOP + 14200UL) + +#define HW_PIXELS 5300 /* number of pixels supported by hardware */ +#define HW_DPI 600 /* horizontal resolution of hardware */ +#define HW_LPI 1200 /* vertical resolution of hardware */ + + +typedef struct { + int iXferHandle; /* handle used for data transfer to HW */ + int iTopLeftX; /* in mm */ + int iTopLeftY; /* in mm */ + int iSensorSkew; /* in units of 1/1200 inch */ + int iSkipLines; /* lines of garbage to skip */ + bool fReg07; /* NIASH00019 */ + bool fGamma16; /* if TRUE, gamma entries are 16 bit */ + int iExpTime; + bool iReversedHead; /* Head is reversed */ + int iBufferSize; /* Size of internal scan buffer */ + EScannerModel eModel; +} THWParams; + + +typedef struct { + int iDpi; /* horizontal resolution */ + int iLpi; /* vertical resolution */ + int iTop; /* in HW coordinates */ + int iLeft; /* in HW coordinates */ + int iWidth; /* pixels */ + int iHeight; /* lines */ + int iBottom; + + int fCalib; /* if TRUE, disable backtracking? */ +} TScanParams; + + +typedef struct { + /* transfer buffer */ + byte *pabXferBuf; + int iCurLine, iBytesPerLine, iLinesPerXferBuf; + int iSkipLines; + /* circular buffer */ + byte *pabCircBuf; + int iLinesPerCircBuf; + int iRedLine, iGrnLine, iBluLine; + /* current line buffer */ + byte *pabLineBuf; + int iBytesLeft; +} TDataPipe; + + +int Hp3300cOpen(THWParams *pHWParams, char *pszName); +void Hp3300cClose(THWParams *pHWParams); + +void DumpHex(byte *pabData, int iLen, int iWidth); + +void ScanLines(FILE *pFile, TScanParams *pParams, THWParams *pHWParams); +bool SimpleCalib(THWParams *pHWPar, byte *pabCalibTable); + +bool GetLamp(THWParams *pHWParams, bool *pfLampIsOn); +bool SetLamp(THWParams *pHWParams, bool fLampOn); + +bool InitScan(TScanParams *pParams, THWParams *pHWParams); +void FinishScan(THWParams *pHWParams); + +void CalcGamma(byte *pabTable, double Gamma); +void WriteGammaCalibTable( byte *pabGammaR, byte *pabGammaG, byte *pabGammaB, + byte *pabCalibTable, int iGain, int iOffset, + THWParams *pHWPar); + +void CircBufferInit(int iHandle, TDataPipe *p, int iBytesPerLine, + int iMisAlignment, bool iReversedHead); +void CircBufferGetLine(int iHandle, TDataPipe *p, byte *pabLine, + bool iReversedHead); +void CircBufferExit(TDataPipe *p); + + +#endif /* NO _HP3300C_H_ */ + diff -ruN sane-backends-1.0.12/backend/hp3300c_ieee1284.c sane-backends-1.0.12-patched/backend/hp3300c_ieee1284.c --- sane-backends-1.0.12/backend/hp3300c_ieee1284.c 1969-12-31 18:00:00.000000000 -0600 +++ sane-backends-1.0.12-patched/backend/hp3300c_ieee1284.c 2003-06-19 11:02:15.000000000 -0500 @@ -0,0 +1,229 @@ +/* + Copyright (C) 2001 Bertrik Sikken (bertrik@zonnet.nl) + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License + as published by the Free Software Foundation; either version 2 + of the License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + + $Id: hp3300c_ieee1284.c,v 1.8 2002/11/19 22:58:31 bertrik Exp $ +*/ + +/* + Provides a simple interface to read and write data from the scanner, + without any knowledge whether it's a parallel or USB scanner +*/ + +#ifdef LIBIEEE1284_SUPPORT + +#include "mytypes.h" +#include "hp3300c_xfer.h" + +#include "ieee1284.h" + + +void +ParInit(TFnReportDevice *pfnReportDevice) +{ + int i; + static char abDeviceId[256]; + struct parport *pMyPort; + struct parport_list mylist; + TScannerModel *pModel; + + pMyPort = (struct parport *)-1; + + ieee1284_find_ports(&mylist, 0); + DBG(DBG_MSG, "Found %d parallel ports:\n", mylist.portc); + + for (i = 0; i < mylist.portc; i++) { + pMyPort = mylist.portv[i]; + DBG(DBG_MSG, "Port %3d : %s\n", i, pMyPort->name); + + /* try to get a device id, no daisy chain assumed */ + memset(abDeviceId, 0, sizeof(abDeviceId)); + if (ieee1284_get_deviceid(pMyPort, -1, 0, abDeviceId, sizeof(abDeviceId) - 1) >= 0) { + DBG(DBG_MSG, "Device ID: %s\n", abDeviceId + 2); + } + + /* hack: for now just let pModel to the first entry of ScannerModels */ + pModel = ScannerModels; + + pfnReportDevice(pModel, (char *)pMyPort->name); + } + ieee1284_free_ports(&mylist); +} + + +static int +ParOpen(char *pszName, EScannerModel *peModel) +{ + struct parport *pMyPort; + struct parport_list mylist; + int i, iCaps, iResult; + + iResult = -1; + ieee1284_find_ports(&mylist, 0); + for (i = 0; i < mylist.portc; i++) { + pMyPort = mylist.portv[i]; + if (strcmp(pMyPort->name, pszName) == 0) { + /* open port non-exclusively (exclusive won't work?) */ + if (ieee1284_open(pMyPort, 0, &iCaps) != E1284_OK) { + DBG(DBG_MSG, "Failed to open %s\n", pMyPort->name); + break; + } + + /* claim the port. We're abusing a bit here because a claim should be + reasonably short, while we keep the port claimed continuously. + */ + if (ieee1284_claim(pMyPort) != E1284_OK) { + DBG(DBG_MSG, "Failed to claim %s\n", pMyPort->name); + ieee1284_close(pMyPort); + break; + } + + DBG(DBG_MSG, "Successfully claimed %s, capabilities %04X\n", pMyPort->name, + iCaps); + iResult = (int)pMyPort; + break; + } + } + ieee1284_free_ports(&mylist); + return iResult; +} + + +static void +ParClose(int iHandle) +{ + struct parport *pMyPort; + + if (iHandle < 0) { + DBG(DBG_ERR, "ParExit: nothing to close\n"); + return; + } + + pMyPort = (struct parport *)iHandle; + + ieee1284_release(pMyPort); + ieee1284_close(pMyPort); +} + + +static void ParWriteReg(int iHandle, byte bReg, byte bData) +{ + int iRet; + struct parport *pMyPort; + + pMyPort = (struct parport *)iHandle; + + switch (bReg) { + case EPP_ADDR: + iRet = ieee1284_epp_write_addr(pMyPort, 0, &bData, 1); + if (iRet < 0) { + DBG(DBG_ERR, "ieee1284_epp_write_addr failed (%d)\n", iRet); + } + break; + case EPP_DATA_WRITE: + iRet = ieee1284_epp_write_data(pMyPort, 0, &bData, 1); + if (iRet < 0) { + DBG(DBG_ERR, "ieee1284_epp_write_data failed (%d)\n", iRet); + } + break; + case SPP_CONTROL: + /* TODO: check direction bit and explicitly set direction */ + ieee1284_write_control(pMyPort, bData); + break; + case SPP_DATA: + ieee1284_write_data(pMyPort, bData); + break; + default: + DBG(DBG_ERR, "Invalid write function requested (%d)\n", bReg); + break; + } +} + + +static void +ParReadReg(int iHandle, byte bReg, byte *pbData) +{ + int iRet; + struct parport *pMyPort; + + pMyPort = (struct parport *)iHandle; + + switch (bReg) { + case EPP_ADDR: + iRet = ieee1284_epp_read_addr(pMyPort, 0, pbData, 1); + if (iRet < 0) { + DBG(DBG_ERR, "ieee1284_epp_read_addr failed (%d)\n", iRet); + } + break; + case EPP_DATA_READ: + iRet = ieee1284_epp_read_data(pMyPort, 0, pbData, 1); + if (iRet < 0) { + DBG(DBG_ERR, "ieee1284_epp_read_data failed (%d)\n", iRet); + } + break; + case SPP_CONTROL: + *pbData = ieee1284_read_control(pMyPort); + break; + case SPP_DATA: + *pbData = ieee1284_read_data(pMyPort); + break; + default: + DBG(DBG_ERR, "Invalid read function requested (%d)\n", bReg); + break; + } +} + + +static void +ParWriteBulk(int iHandle, byte *pabData, int iSize) +{ + int iRet; + struct parport *pMyPort; + + pMyPort = (struct parport *)iHandle; + iRet = ieee1284_epp_write_data(pMyPort, 0, pabData, iSize); + if (iRet < 0) { + DBG(DBG_ERR, "ieee1284_epp_write_data failed (%d)\n", iRet); + } +} + + +static void +ParReadBulk(int iHandle, byte *pabData, int iSize) +{ + int iRet; + struct parport *pMyPort; + + pMyPort = (struct parport *)iHandle; + iRet = ieee1284_epp_read_data(pMyPort, 0, pabData, iSize); + if (iRet < 0) { + DBG(DBG_ERR, "ieee1284_epp_write_data failed (%d)\n", iRet); + } +} + + +XferModule IEEE1284Dev = { + "LibIEEE1284 parallel port", + ParInit, + ParOpen, + ParClose, + ParWriteReg, + ParReadReg, + ParWriteBulk, + ParReadBulk +}; + +#endif /* LIBIEEE1284_SUPPORT */ diff -ruN sane-backends-1.0.12/backend/hp3300c_saneiusb.c sane-backends-1.0.12-patched/backend/hp3300c_saneiusb.c --- sane-backends-1.0.12/backend/hp3300c_saneiusb.c 1969-12-31 18:00:00.000000000 -0600 +++ sane-backends-1.0.12-patched/backend/hp3300c_saneiusb.c 2003-06-19 11:02:15.000000000 -0500 @@ -0,0 +1,191 @@ +/* + Copyright (C) 2001 Bertrik Sikken (bertrik@zonnet.nl) + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License + as published by the Free Software Foundation; either version 2 + of the License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + + $Id: hp3300c_saneiusb.c,v 1.9 2002/11/12 21:24:43 bertrik Exp $ +*/ + +/* + This is the sanei_usb transfer method +*/ + +#include "mytypes.h" + +#include /* printf */ +#include + +#include "hp3300c_xfer.h" + + +static TFnReportDevice *_pfnReportDevice; +static TScannerModel *_pModel; + + +static void _SaneiUsbWriteControl(int fd, byte bValue, byte *pabData, int iSize) +{ + sanei_usb_control_msg(fd, + USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_OUT, + (iSize > 1) ? 0x04 : 0x0C, + bValue, + 0, + iSize, + pabData); +} + + +static void _SaneiUsbReadControl(int fd, byte bValue, byte *pabData, int iSize) +{ + sanei_usb_control_msg(fd, + USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN, + (iSize > 1) ? 0x04 : 0x0C, + bValue, + 0, + iSize, + pabData); +} + + +/* callback for sanei_usb_attach_matching_devices */ +static SANE_Status _AttachUsb(SANE_String_Const devname) +{ + DBG(DBG_MSG, "_AttachUsb: found %s\n", devname); + + _pfnReportDevice(_pModel, (char *)devname); + + return SANE_STATUS_GOOD; +} + + +static void UsbInit(TFnReportDevice *pfnReportDevice) +{ + TScannerModel *pModels = ScannerModels; + + sanei_usb_init(); + _pfnReportDevice = pfnReportDevice; + + /* loop over all scanner models */ + while (pModels->pszName != NULL) { + DBG(DBG_MSG, "Looking for %s...\n", pModels->pszName); + _pModel = pModels; + if (sanei_usb_find_devices((SANE_Int)pModels->iVendor, + (SANE_Int)pModels->iProduct, _AttachUsb) != SANE_STATUS_GOOD) { + + DBG(DBG_ERR, "Error invoking sanei_usb_find_devices"); + break; + } + pModels++; + } +} + + +static int UsbOpen(char *pszName, EScannerModel *peModel) +{ + SANE_Status status; + SANE_Word vendor, product; + int fd; + TScannerModel *pModel; + + DBG(DBG_MSG, "Trying to open %s...\n", pszName); + + status = sanei_usb_open(pszName, &fd); + if (status != SANE_STATUS_GOOD) { + return -1; + } + + status = sanei_usb_get_vendor_product(fd, &vendor, &product); + if (status == SANE_STATUS_GOOD) { + MatchUsbDevice(vendor, product, &pModel); + *peModel = pModel->eModel; + } + + return fd; +} + + +static void UsbClose(int fd) +{ + /* close usb device */ + if (fd != -1) { + sanei_usb_close(fd); + } +} + + +static void UsbWriteReg(int fd, byte bReg, byte bData) +{ + _SaneiUsbWriteControl(fd, bReg, &bData, 1); +} + + +static void UsbReadReg(int fd, byte bReg, byte *pbData) +{ + _SaneiUsbReadControl(fd, bReg, pbData, 1); +} + + +static void UsbWriteBulk(int fd, byte *pabData, int iSize) +{ + /* byte abSetup[8] = {0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; + HP3400 probably needs 0x01, 0x01 */ + byte abSetup[8] = {0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; + size_t size; + + if (fd == -1) { + return; + } + + abSetup[4] = (iSize) & 0xFF; + abSetup[5] = (iSize >> 8) & 0xFF; + _SaneiUsbWriteControl(fd, USB_SETUP, abSetup, 8); + + size = iSize; + if (sanei_usb_write_bulk(fd, pabData, &size) != SANE_STATUS_GOOD) { + DBG(DBG_ERR, "ERROR: Bulk write failed\n"); + } +} + + +static void UsbReadBulk(int fd, byte *pabData, int iSize) +{ + byte abSetup[8] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; + size_t size; + + if (fd == -1) { + return; + } + + abSetup[4] = (iSize) & 0xFF; + abSetup[5] = (iSize >> 8) & 0xFF; + _SaneiUsbWriteControl(fd, USB_SETUP, abSetup, 8); + + size = iSize; + if (sanei_usb_read_bulk(fd, pabData, &size) != SANE_STATUS_GOOD) { + DBG(DBG_ERR, "ERROR: Bulk read failed\n"); + } +} + + +XferModule SaneiUsbDev = { + "Sanei_USB", + UsbInit, + UsbOpen, + UsbClose, + UsbWriteReg, + UsbReadReg, + UsbWriteBulk, + UsbReadBulk +}; + diff -ruN sane-backends-1.0.12/backend/hp3300c_uscanner.c sane-backends-1.0.12-patched/backend/hp3300c_uscanner.c --- sane-backends-1.0.12/backend/hp3300c_uscanner.c 1969-12-31 18:00:00.000000000 -0600 +++ sane-backends-1.0.12-patched/backend/hp3300c_uscanner.c 2003-06-19 11:02:15.000000000 -0500 @@ -0,0 +1,234 @@ +/* + Copyright (C) 2001 Bertrik Sikken (bertrik@zonnet.nl) + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License + as published by the Free Software Foundation; either version 2 + of the License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + + $Id: hp3300c_uscanner.c,v 1.4 2002/11/27 23:24:10 saperski Exp $ +*/ + +/* + Provides a simple interface to read and write data from the scanner, + without any knowledge whether it's a parallel or USB scanner +*/ + +#ifdef USCANNER_SUPPORT + +#include "hp3300c_xfer.h" + +#include "mytypes.h" + +#include /* read, open, write */ +#include /* open */ +#include /* printf */ +#include /* better error reports */ +#include /* better error reports */ +#include +#include +#include + +#include + + +/************************************************************************ + USB transfer routines implemented with uscanner calls +************************************************************************/ + +#define MAX_DEV_TRY 16 + +static void +uscannerInit(TFnReportDevice *pfnReportDevice) +{ + struct usb_device_info usb_info; + TScannerModel *pModel; + struct stat fs; + char devname[PATH_MAX]; + int i, fd, rc; + + /* open scanner's device file */ + for (rc = -1, i = 0; rc < 0 && i < MAX_DEV_TRY; i++) { + snprintf(devname, PATH_MAX, "/dev/uscanner%d", i); + rc = stat(devname, &fs); + if (rc == 0) { + if ((fs.st_mode & S_IFCHR) == 0 ) { + DBG(DBG_ERR, "Not a characted device: %s\n", devname); + rc = -1; + } + } else + if (errno != ENOENT) + DBG(DBG_ERR, "Error accessing %s: %s\n", devname, strerror(errno)); + + } + if (rc < 0) { + DBG(DBG_ERR, "Cannot open any scanner device (/dev/uscanner*).\n"); + return; + } + if ((fd = open(devname, O_RDWR)) >= 0) { + if (ioctl(fd, USB_GET_DEVICEINFO, &usb_info) >= 0) { + DBG(DBG_MSG, "VendorId %s (0x%04X), ProductId %s (0x%04X)\n", + usb_info.udi_vendor, usb_info.udi_vendorNo, + usb_info.udi_product, usb_info.udi_productNo); + if (MatchUsbDevice(usb_info.udi_vendorNo, + usb_info.udi_productNo, &pModel)) + pfnReportDevice(pModel, devname); + } else + DBG(DBG_ERR, "USB_GET_DEVICEINFO not supported, check version of the uscanner driver"); + } else + DBG(DBG_ERR, "Cannot open %s: %s", devname, strerror(errno)); + close(fd); +} + +static int +uscannerOpen(char *devname, EScannerModel *peModel) +{ + int fd, rc = -1; + struct usb_device_info usb_info; + TScannerModel *pModel; + + fd = open(devname, O_RDWR); + if (fd > 0) + if (ioctl(fd, USB_GET_DEVICEINFO, &usb_info) >= 0) + if (MatchUsbDevice(usb_info.udi_vendorNo, + usb_info.udi_productNo, &pModel)) { + *peModel = pModel->eModel; + rc = fd; + } else + DBG(DBG_ERR, "Cannot match device at %s\n", devname); + else + DBG(DBG_ERR, "USB_GET_INFO failed on %s: %s\n", devname, strerror(errno)); + else + DBG(DBG_ERR, "Cannot open %s: %s\n", devname, strerror(errno)); + + return fd; +} + +static void +uscannerExit(int fd) +{ + /* close usb device */ + if (fd != -1) { + close(fd); + } +} + +static void +_uscannerReadControl(int fd, byte bValue, byte *pabData, int iSize) +{ + struct usb_ctl_request req; + + if (fd < 0) { + return; + } + + req.ucr_addr = 0; + req.ucr_data = pabData; + req.ucr_flags = 0; + req.ucr_actlen = 0; + req.ucr_request.bmRequestType = UT_READ_VENDOR_DEVICE; + req.ucr_request.bRequest = (iSize > 1) ? 0x04 : 0x0C; + USETW(req.ucr_request.wValue, bValue); + USETW(req.ucr_request.wIndex, 0); + USETW(req.ucr_request.wLength, iSize); + + if (fd != -1) { + ioctl(fd, USB_DO_REQUEST, &req); + } +} + + +static void +_uscannerWriteControl(int fd, byte bValue, byte *pabData, int iSize) +{ + struct usb_ctl_request req; + + if (fd < 0) { + return; + } + + req.ucr_addr = 0; + req.ucr_data = pabData; + req.ucr_flags = 0; + req.ucr_actlen = 0; + req.ucr_request.bmRequestType = UT_WRITE_VENDOR_DEVICE; + req.ucr_request.bRequest = (iSize > 1) ? 0x04 : 0x0C; + USETW(req.ucr_request.wValue, bValue); + USETW(req.ucr_request.wIndex, 0); + USETW(req.ucr_request.wLength, iSize); + + if (fd != -1) { + ioctl(fd, USB_DO_REQUEST, &req); + } +} + +static void +uscannerWriteReg(int fd, byte bReg, byte bData) +{ + _uscannerWriteControl(fd, bReg, &bData, 1); +} + + +static void +uscannerReadReg(int fd, byte bReg, byte *pbData) +{ + _uscannerReadControl(fd, bReg, pbData, 1); +} + + +static void +uscannerWriteBulk(int fd, byte *pabData, int iSize) +{ + byte abSetup[8] = {0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; + + if (fd < 0) { + return; + } + + abSetup[4] = (iSize) & 0xFF; + abSetup[5] = (iSize >> 8) & 0xFF; + _uscannerWriteControl(fd, USB_SETUP, abSetup, 8); + if (write(fd, pabData, iSize) != iSize) { + DBG(DBG_ERR, "ERROR: Bulk Write failed\n"); + } +} + + +static void +uscannerReadBulk(int fd, byte *pabData, int iSize) +{ + byte abSetup[8] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; + + if (fd < 0) { + return; + } + + abSetup[4] = (iSize) & 0xFF; + abSetup[5] = (iSize >> 8) & 0xFF; + _uscannerWriteControl(fd, USB_SETUP, abSetup, 8); + if (read(fd, pabData, iSize) != iSize) { + DBG(DBG_ERR, "ERROR: Bulk read failed\n"); + } +} + +XferModule uscannerDev = { + "BSD uscanner kernel module", + uscannerInit, + uscannerOpen, + uscannerExit, + uscannerWriteReg, + uscannerReadReg, + uscannerWriteBulk, + uscannerReadBulk +}; + +#endif /* USCANNER_SUPPORT */ diff -ruN sane-backends-1.0.12/backend/hp3300c_xfer.c sane-backends-1.0.12-patched/backend/hp3300c_xfer.c --- sane-backends-1.0.12/backend/hp3300c_xfer.c 1969-12-31 18:00:00.000000000 -0600 +++ sane-backends-1.0.12-patched/backend/hp3300c_xfer.c 2003-06-19 11:02:15.000000000 -0500 @@ -0,0 +1,275 @@ +/* + Copyright (C) 2001 Bertrik Sikken (bertrik@zonnet.nl) + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License + as published by the Free Software Foundation; either version 2 + of the License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + + $Id: hp3300c_xfer.c,v 1.31 2003/01/11 13:35:18 bertrik Exp $ +*/ + +/* + Provides a simple interface to read and write data from the scanner, + without any knowledge whether it's a parallel or USB scanner +*/ + +#include "mytypes.h" + +#include /* read, open, write */ +#include /* open */ +#include /* printf */ +#include /* better error reports */ +#include /* better error reports */ +#include /* malloc(), free() on FreeBSD */ + +#include "hp3300c_xfer.h" + +#define MAX_XFER_MODULES 5 + +static XferModule *_aXferModules[MAX_XFER_MODULES]; +static int _iNrXferModules; + +/* list of supported models */ +TScannerModel ScannerModels[] = { + {"Hewlett-Packard", "ScanJet 3300C", 0x3F0, 0x205, eHp3300c}, + {"Hewlett-Packard", "ScanJet 3400C", 0x3F0, 0x405, eHp3400c}, + {"Hewlett-Packard", "ScanJet 4300C", 0x3F0, 0x305, eHp4300c}, + {"Agfa", "Snapscan Touch", 0x6BD, 0x100, eAgfaTouch}, +/* last entry all zeros */ + {0, 0, 0, 0, 0} +}; + + +/* + MatchUsbDevice + ============== + Matches a given USB vendor and product id against a list of + supported scanners. + + IN iVendor USB vendor ID + iProduct USB product ID + OUT *ppModel Pointer to TScannerModel structure + + Returns TRUE if a matching USB scanner was found +*/ +bool MatchUsbDevice(int iVendor, int iProduct, TScannerModel **ppModel) +{ + TScannerModel *pModels = ScannerModels; + + DBG(DBG_MSG, "Matching USB device 0x%04X-0x%04X ... ", iVendor, iProduct); + while (pModels->pszName != NULL) { + if ((pModels->iVendor == iVendor) && (pModels->iProduct == iProduct)) { + DBG(DBG_MSG, "found %s %s\n", pModels->pszVendor, pModels->pszName); + *ppModel = pModels; + return TRUE; + } + /* next model to match */ + pModels++; + } + DBG(DBG_MSG, "nothing found\n"); + return FALSE; +} + +/************************************************************************ + Public functions +************************************************************************/ + + +/* + Hp3300cXferRegisterModule + ========================= + installs a transfer method + + IN pXferModule Module to registers + + Returns a negative number when an error occurred. +*/ +int Hp3300cXferRegisterModule(XferModule *pXferModule) +{ + DBG(DBG_MSG, "Registering transfer method %d: %s\n", _iNrXferModules, pXferModule->pszName); + + if (_iNrXferModules >= MAX_XFER_MODULES) { + DBG(DBG_ERR, "Max. number of installed transfer methods reached\n"); + return -1; + } + _aXferModules[_iNrXferModules++] = pXferModule; + + return 0; +} + + +/* + Hp3300cXferInit + =============== + Initialises all registered data transfer modules, which causes + them to report any devices found through the pfnReport callback. + + IN pfnReport Function to call to report a transfer device +*/ +void Hp3300cXferInit(TFnReportDevice *pfnReport) +{ + int i; + + for (i = 0; i < _iNrXferModules; i++) { + _aXferModules[i]->mfnInit(pfnReport); + } +} + + +int Hp3300cXferOpen (char *pszName, EScannerModel *peModel) +{ + TXferDev *pDev; + XferModule *pMod; + int i, iHandle; + + DBG(DBG_MSG, "Hp3300cXferOpen '%s'\n", pszName); + + /* try each method */ + for (i = 0; i < _iNrXferModules; i++) { + pMod = _aXferModules[i]; + DBG(DBG_MSG, "probing %s\n", pMod->pszName); + *peModel = eUnknownModel; + iHandle = pMod->mfnOpen(pszName, peModel); + if (iHandle >= 0) { + pDev = malloc(sizeof(TXferDev)); + pDev->iXferDev = pMod; + pDev->iHandle = iHandle; + return (int)pDev; + } + } + return -1; +} + + +void Hp3300cXferClose(int iHandle) +{ + TXferDev *pDev; + + if (iHandle <= 0) { + return; + } + pDev = (TXferDev *)iHandle; + + /* deinit the driver */ + if (pDev->iHandle >= 0) { + pDev->iXferDev->mfnExit(pDev->iHandle); + free((void *)iHandle); + } +} + + +void Hp3300cRegWrite(int iHandle, byte bReg, byte bData) +{ + TXferDev *pDev; + + if (iHandle <= 0) { + return; + } + pDev = (TXferDev *)iHandle; + + pDev->iXferDev->mfnWriteReg(pDev->iHandle, SPP_CONTROL, 0x14); + pDev->iXferDev->mfnWriteReg(pDev->iHandle, EPP_ADDR, bReg); + pDev->iXferDev->mfnWriteReg(pDev->iHandle, SPP_CONTROL, 0x14); + pDev->iXferDev->mfnWriteReg(pDev->iHandle, EPP_DATA_WRITE, bData); + pDev->iXferDev->mfnWriteReg(pDev->iHandle, SPP_CONTROL, 0x14); +} + + +void Hp3300cRegRead(int iHandle, byte bReg, byte *pbData) +{ + TXferDev *pDev; + + if (iHandle <= 0) { + return; + } + pDev = (TXferDev *)iHandle; + + pDev->iXferDev->mfnWriteReg(pDev->iHandle, SPP_CONTROL, 0x14); + pDev->iXferDev->mfnWriteReg(pDev->iHandle, EPP_ADDR, bReg); + pDev->iXferDev->mfnWriteReg(pDev->iHandle, SPP_CONTROL, 0x34); + pDev->iXferDev->mfnReadReg (pDev->iHandle, EPP_DATA_READ, pbData); + pDev->iXferDev->mfnWriteReg(pDev->iHandle, SPP_CONTROL, 0x14); +} + + +void Hp3300cBulkWrite(int iHandle, byte *pabBuf, int iSize) +{ + TXferDev *pDev; + + if (iHandle <= 0) { + return; + } + pDev = (TXferDev *)iHandle; + + /* select scanner register 0x24 */ + pDev->iXferDev->mfnWriteReg(pDev->iHandle, SPP_CONTROL, 0x14); + pDev->iXferDev->mfnWriteReg(pDev->iHandle, EPP_ADDR, 0x24); + pDev->iXferDev->mfnWriteReg(pDev->iHandle, SPP_CONTROL, 0x14); + /* do the bulk write */ + pDev->iXferDev->mfnWriteBulk(pDev->iHandle, pabBuf, iSize); +} + + +void Hp3300cBulkRead(int iHandle, byte *pabBuf, int iSize) +{ + TXferDev *pDev; + + if (iHandle <= 0) { + return; + } + pDev = (TXferDev *)iHandle; + + /* select scanner register 0x24 */ + pDev->iXferDev->mfnWriteReg(pDev->iHandle, SPP_CONTROL, 0x14); + pDev->iXferDev->mfnWriteReg(pDev->iHandle, EPP_ADDR, 0x24); + pDev->iXferDev->mfnWriteReg(pDev->iHandle, SPP_CONTROL, 0x14); + /* do the bulk read */ + pDev->iXferDev->mfnReadBulk(pDev->iHandle, pabBuf, iSize); +} + + +void Hp3300cWakeup(int iHandle) +{ + TXferDev *pDev; + byte abMagic[] = { 0xA0, 0xA8, 0x50, 0x58, 0x90, 0x98, 0xC0, 0xC8, + 0x90, 0x98, 0xE0, 0xE8}; + int i; + + if (iHandle <= 0) { + return; + } + pDev = (TXferDev *)iHandle; + + /* write magic startup sequence */ + pDev->iXferDev->mfnWriteReg(pDev->iHandle, SPP_CONTROL, 0x14); + for (i = 0; i < (int)sizeof(abMagic); i++) { + pDev->iXferDev->mfnWriteReg(pDev->iHandle, SPP_DATA, abMagic[i]); + } + + /* write 0x04 to scanner register 0x00 the hard way */ + pDev->iXferDev->mfnWriteReg(pDev->iHandle, SPP_DATA, 0x00); + pDev->iXferDev->mfnWriteReg(pDev->iHandle, SPP_CONTROL, 0x14); + pDev->iXferDev->mfnWriteReg(pDev->iHandle, SPP_CONTROL, 0x15); + pDev->iXferDev->mfnWriteReg(pDev->iHandle, SPP_CONTROL, 0x1D); + pDev->iXferDev->mfnWriteReg(pDev->iHandle, SPP_CONTROL, 0x15); + pDev->iXferDev->mfnWriteReg(pDev->iHandle, SPP_CONTROL, 0x14); + + pDev->iXferDev->mfnWriteReg(pDev->iHandle, SPP_DATA, 0x04); + pDev->iXferDev->mfnWriteReg(pDev->iHandle, SPP_CONTROL, 0x14); + pDev->iXferDev->mfnWriteReg(pDev->iHandle, SPP_CONTROL, 0x15); + pDev->iXferDev->mfnWriteReg(pDev->iHandle, SPP_CONTROL, 0x17); + pDev->iXferDev->mfnWriteReg(pDev->iHandle, SPP_CONTROL, 0x15); + pDev->iXferDev->mfnWriteReg(pDev->iHandle, SPP_CONTROL, 0x14); +} + + diff -ruN sane-backends-1.0.12/backend/hp3300c_xfer.h sane-backends-1.0.12-patched/backend/hp3300c_xfer.h --- sane-backends-1.0.12/backend/hp3300c_xfer.h 1969-12-31 18:00:00.000000000 -0600 +++ sane-backends-1.0.12-patched/backend/hp3300c_xfer.h 2003-06-19 11:02:15.000000000 -0500 @@ -0,0 +1,132 @@ +/* + Copyright (C) 2001 Bertrik Sikken (bertrik@zonnet.nl) + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License + as published by the Free Software Foundation; either version 2 + of the License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + + $Id: hp3300c_xfer.h,v 1.16 2002/11/04 23:48:33 bertrik Exp $ +*/ + +/* + Provides a simple interface to read and write data from the scanner, + without any knowledge whether it's a parallel or USB scanner +*/ + +#ifndef _HP3300C_XFER_H_ +#define _HP3300C_XFER_H_ + +#include "mytypes.h" +#include /* for FILE * */ + + +/* register codes for the USB - IEEE1284 bridge */ +#define USB_SETUP 0x82 +#define EPP_ADDR 0x83 +#define EPP_DATA_READ 0x84 +#define EPP_DATA_WRITE 0x85 +#define SPP_STATUS 0x86 +#define SPP_CONTROL 0x87 +#define SPP_DATA 0x88 + + +typedef enum { + eUnknownModel = 0, + eHp3300c, + eHp3400c, + eHp4300c, + eAgfaTouch +} EScannerModel; + + +typedef struct { + char *pszVendor; + char *pszName; + int iVendor; + int iProduct; + EScannerModel eModel; +} TScannerModel; + + +typedef int (TFnReportDevice)(TScannerModel *pModel, char *pszDeviceName); + +/* function pointer definitions */ +/* + The TFnInit function get passed a TFnReportDevice function pointer which is + called for each scanner device. + The TFnOpen function can then be called with one of the names as an argument + and returns a handle > 0 if the open was successful. +*/ +typedef void (TFnInit)(TFnReportDevice *pfnReportDevice); +typedef int (TFnOpen)(char *pszDeviceName, EScannerModel *peModel); +typedef void (TFnWriteReg)(int iHandle, byte bReg, byte bData); +typedef void (TFnReadReg)(int iHandle, byte bReg, byte *pbData); +typedef void (TFnWriteBulk)(int iHandle, byte *pabBuf, int iSize); +typedef void (TFnReadBulk)(int iHandle, byte *pabBuf, int iSize); +typedef void (TFnExit)(int iHandle); + + +typedef struct { + char *pszName; + TFnInit *mfnInit; + TFnOpen *mfnOpen; + TFnExit *mfnExit; + TFnWriteReg *mfnWriteReg; + TFnReadReg *mfnReadReg; + TFnWriteBulk *mfnWriteBulk; + TFnReadBulk *mfnReadBulk; +} XferModule; + + +typedef struct { + int iHandle; + XferModule *iXferDev; +} TXferDev; + + +/* Creates our own DBG definitions, externs are define in main.c*/ +#ifndef WITH_NIASH +#define DBG fprintf +extern FILE * DBG_MSG; +extern FILE * DBG_ERR; +extern FILE * BG_ASSERT; +#endif /* NO WITH_NIASH */ + + +/* USB device file name */ +extern char * usb_devfile; + + +/* list of supported models, the actual list is in hp3300c_xfer.c */ +extern TScannerModel ScannerModels[]; + + +/* The number returned by Hp3300cXferInit is a handle. This handle needs to + be passed to all other transfer functions. + Internally it is a pointer to structure containg function pointers + */ +int Hp3300cXferRegisterModule(XferModule *pXferModule); + +void Hp3300cXferInit (TFnReportDevice *pfnReport); +int Hp3300cXferOpen (char *pszName, EScannerModel *peModel); +void Hp3300cXferClose (int iXferHandle); + +void Hp3300cRegWrite (int iXferHandle, byte bReg, byte bData); +void Hp3300cRegRead (int iXferHandle, byte bReg, byte *pbData); +void Hp3300cBulkWrite (int iXferHandle, byte *pabBuf, int iSize); +void Hp3300cBulkRead (int iXferHandle, byte *pabBuf, int iSize); +void Hp3300cWakeup (int iXferHandle); + +bool MatchUsbDevice(int iVendor, int iProduct, TScannerModel **ppeModel); + +#endif /* _HP3300C_XFER_H_ */ diff -ruN sane-backends-1.0.12/backend/hp3300c_xfer_cfg.h sane-backends-1.0.12-patched/backend/hp3300c_xfer_cfg.h --- sane-backends-1.0.12/backend/hp3300c_xfer_cfg.h 1969-12-31 18:00:00.000000000 -0600 +++ sane-backends-1.0.12-patched/backend/hp3300c_xfer_cfg.h 2003-06-19 11:02:15.000000000 -0500 @@ -0,0 +1,75 @@ +/* + Copyright (C) 2001 Bertrik Sikken (bertrik@zonnet.nl) + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License + as published by the Free Software Foundation; either version 2 + of the License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + + $Id: hp3300c_xfer_cfg.h,v 1.5 2002/11/03 17:58:59 bertrik Exp $ +*/ + +/* + This file defines which transfer methods are compiled into the SANE backend + (Linux scanner kernel module, BSD uscanner kernel module, libusb, ieee1284, + dummy for scanner emulation, etc.) + + To disable a transfer method, comment out the corresponding #define + + #define SANEI_USB_SUPPORT + USB support using the SANE builtin functions from sanei_usb.h + sanei_usb.h version 1.0.7 supports Linux only (in fact it uses + the scanner kernel module internally). + + #define LINUX_USB_SUPPORT + USB support using the 'scanner' kernel module for Linux. + You need at least Linux kernel version 2.4.12 to use this. + + #define USCANNER_SUPPORT + USB support using the 'uscanner' kernel module for BSD. + This is obviously mutually exclusive with LINUX_USB_SUPPORT + + #define LIBUSB_SUPPORT + USB support using libusb (should be platform independent) + You need at least version 0.1.5 of libusb (+ devel package) to use this. + + #define LIBIEEE1284_SUPPORT + Parallel port support using libieee1284 (should be platform independent). + You need at least version ... of libieee1284 (+ devel package) to use this. + *** This transfer method has not been tested yet *** + + #define DUMMY_SCAN_SUPPORT + Dummy transfer method used for testing. + This method very simply emulates a specific type of scanner. + + Any changes in this file will have no effect until you recompile & install: + (in the sane-backends package, backend directory) + touch niash.c + make + make install +*/ + + +#define SANEI_USB_SUPPORT + +/* #define LINUX_USB_SUPPORT */ + +/* #define USCANNER_SUPPORT */ + +/* #define LIBUSB_SUPPORT */ + +/* not tested yet */ +/* #define LIBIEEE1284_SUPPORT */ + +/* not implemented yet */ +/* #define DUMMY_SCAN_SUPPORT */ + diff -ruN sane-backends-1.0.12/backend/mytypes.h sane-backends-1.0.12-patched/backend/mytypes.h --- sane-backends-1.0.12/backend/mytypes.h 1969-12-31 18:00:00.000000000 -0600 +++ sane-backends-1.0.12-patched/backend/mytypes.h 2003-06-19 11:02:15.000000000 -0500 @@ -0,0 +1,33 @@ +/* + Defines my types + + $Id: mytypes.h,v 1.3 2001/12/18 03:10:41 aggression Exp $ +*/ + + +#ifndef _MYTYPES_H_ +#define _MYTYPES_H_ + +#ifndef byte +typedef unsigned char byte; +#endif + +#ifndef word +typedef int word; +#endif + +#ifndef bool +typedef int bool; +#endif + +#ifndef FALSE +#define FALSE 0 +#endif + +#ifndef TRUE +#define TRUE 1 +#endif + +#endif + + diff -ruN sane-backends-1.0.12/backend/niash.c sane-backends-1.0.12-patched/backend/niash.c --- sane-backends-1.0.12/backend/niash.c 1969-12-31 18:00:00.000000000 -0600 +++ sane-backends-1.0.12-patched/backend/niash.c 2003-06-19 11:02:15.000000000 -0500 @@ -0,0 +1,869 @@ +/* + Copyright (C) 2001 Bertrik Sikken (bertrik@zonnet.nl) + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License + as published by the Free Software Foundation; either version 2 + of the License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + + $Id: niash.c,v 1.36 2003/03/24 19:14:47 bertrik Exp $ +*/ + +/* + Concept for a backend for scanners based on the NIASH chipset, + such as HP3300C, HP3400C, HP4300C, Agfa Touch. + Parts of this source were inspired by other backends. +*/ + +#include "sane/sane.h" +#include "sane/config.h" +#include "sane/sanei.h" +#include "sane/sanei_backend.h" +#include "sane/sanei_config.h" +#include "sane/saneopts.h" + +#include /* malloc, free */ +#include /* memcpy */ +#include + +/* definitions for debug */ +#define BACKEND_NAME niash +#define BUILD 1 + +#define DBG_ASSERT 1 +#define DBG_ERR 16 +#define DBG_MSG 32 + +#define NIASH_CONFIG_FILE "niash.conf" + +/* Just to avoid conflicts between niash backend and testtool */ +#define WITH_NIASH 1 + + +#include "hp3300c_xfer_cfg.h" + +/* (source) includes for data transfer methods */ +#include "hp3300c.c" +#include "hp3300c_xfer.c" +#include "hp3300c_saneiusb.c" +#if defined(LINUX_USB_SUPPORT) + #include "hp3300c_linux.c" +#endif +#if defined(USCANNER_SUPPORT) + #include "hp3300c_uscanner.c" +#endif +#if defined(LIBUSB_SUPPORT) + #include "hp3300c_libusb.c" +#endif +#if defined(LIBIEEE1284_SUPPORT) + #include "hp3300c_ieee1284.c" +#endif + + +#define ASSERT(cond) (!(cond) ? DBG(DBG_ASSERT, "!!! ASSERT(%S) FAILED!!!\n",STRINGIFY(cond));) + +/* other definitions */ +#define TRUE 1 +#define FALSE 0 + +#define MM_TO_PIXEL(_mm_, _dpi_) ((_mm_) * (_dpi_) / 25.4) +#define PIXEL_TO_MM(_pixel_, _dpi_) ((_pixel_) * 25.4 / (_dpi_)) + +/* Device filename for USB access */ +char * usb_devfile = "/dev/usb/scanner0"; + +/* options enumerator */ +typedef enum { + optCount = 0, + + optGroupGeometry, + optTLX, optTLY, optBRX, optBRY, + optDPI, + + optGroupImage, + optGammaTable, /* gamma table */ + + optGroupMisc, + optLamp, + + optLast, +/* put temporarily disabled options here after optLast */ + optCalibrate, + optGamma /* analog gamma = single number */ + +} EOptionIndex; + + +typedef union { + SANE_Word w; + SANE_Word *wa; /* word array */ + SANE_String s; +} TOptionValue; + + +typedef struct { + SANE_Option_Descriptor aOptions[optLast]; + TOptionValue aValues[optLast]; + + TScanParams ScanParams; + THWParams HWParams; + + TDataPipe DataPipe; + int iLinesLeft; + + SANE_Int aGammaTable[4096]; /* a 12-to-8 bit color lookup table */ + + int fScanning; /* TRUE if actively scanning */ + int fCanceled; +} TScanner; + + +/* linked list of SANE_Device structures */ +typedef struct TDevListEntry { + struct TDevListEntry *pNext; + SANE_Device dev; +} TDevListEntry; + + +static TDevListEntry *_pFirstSaneDev = 0; +static int iNumSaneDev = 0; +static const SANE_Device **_pSaneDevList = 0; + + +/* option constraints */ +static const SANE_Range rangeGammaTable = {0, 255, 1}; +static const SANE_Int setResolutions[] = {3, 150, 300, 600}; +static const SANE_Range rangeGamma = {SANE_FIX(0.25), SANE_FIX(4.0), + SANE_FIX(0.0)}; +static const SANE_Range rangeXmm = {0, 220, 1}; +static const SANE_Range rangeYmm = {0, 290, 1}; + + +static void _InitOptions(TScanner *s) +{ + int i, j; + SANE_Option_Descriptor *pDesc; + TOptionValue *pVal; + + for (i = optCount; i < optLast; i++) { + + pDesc = &s->aOptions[i]; + pVal = &s->aValues[i]; + + /* defaults */ + pDesc->name = ""; + pDesc->title = ""; + pDesc->desc = ""; + pDesc->type = SANE_TYPE_INT; + pDesc->unit = SANE_UNIT_NONE; + pDesc->size = sizeof(SANE_Word); + pDesc->constraint_type = SANE_CONSTRAINT_NONE; + pDesc->cap = 0; + + switch (i) { + + case optCount: + pDesc->title = SANE_TITLE_NUM_OPTIONS; + pDesc->desc = SANE_DESC_NUM_OPTIONS; + pDesc->cap = SANE_CAP_SOFT_DETECT; + pVal->w = (SANE_Word)optLast; + break; + + case optGroupGeometry: + pDesc->title = "Geometry"; + pDesc->type = SANE_TYPE_GROUP; + pDesc->size = 0; + break; + + case optTLX: + pDesc->name = SANE_NAME_SCAN_TL_X; + pDesc->title = SANE_TITLE_SCAN_TL_X; + pDesc->desc = SANE_DESC_SCAN_TL_X; + pDesc->unit = SANE_UNIT_MM; + pDesc->constraint_type = SANE_CONSTRAINT_RANGE; + pDesc->constraint.range = &rangeXmm; + pDesc->cap = SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT; + pVal->w = rangeXmm.min; + break; + + case optTLY: + pDesc->name = SANE_NAME_SCAN_TL_Y; + pDesc->title = SANE_TITLE_SCAN_TL_Y; + pDesc->desc = SANE_DESC_SCAN_TL_Y; + pDesc->unit = SANE_UNIT_MM; + pDesc->constraint_type = SANE_CONSTRAINT_RANGE; + pDesc->constraint.range = &rangeYmm; + pDesc->cap = SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT; + pVal->w = rangeYmm.min; + break; + + case optBRX: + pDesc->name = SANE_NAME_SCAN_BR_X; + pDesc->title = SANE_TITLE_SCAN_BR_X; + pDesc->desc = SANE_DESC_SCAN_BR_X; + pDesc->unit = SANE_UNIT_MM; + pDesc->constraint_type = SANE_CONSTRAINT_RANGE; + pDesc->constraint.range = &rangeXmm; + pDesc->cap = SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT; + pVal->w = rangeXmm.max; + break; + + case optBRY: + pDesc->name = SANE_NAME_SCAN_BR_Y; + pDesc->title = SANE_TITLE_SCAN_BR_Y; + pDesc->desc = SANE_DESC_SCAN_BR_Y; + pDesc->unit = SANE_UNIT_MM; + pDesc->constraint_type = SANE_CONSTRAINT_RANGE; + pDesc->constraint.range = &rangeYmm; + pDesc->cap = SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT; + pVal->w = rangeYmm.max; + break; + + case optDPI: + pDesc->name = SANE_NAME_SCAN_RESOLUTION; + pDesc->title = SANE_TITLE_SCAN_RESOLUTION; + pDesc->desc = SANE_DESC_SCAN_RESOLUTION; + pDesc->unit = SANE_UNIT_DPI; + pDesc->constraint_type = SANE_CONSTRAINT_WORD_LIST; + pDesc->constraint.word_list = setResolutions; + pDesc->cap = SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT; + pVal->w = setResolutions[1]; + break; + + case optGroupImage: + pDesc->title = SANE_I18N("Image"); + pDesc->type = SANE_TYPE_GROUP; + pDesc->size = 0; + break; + + case optGamma: + pDesc->name = SANE_NAME_ANALOG_GAMMA; + pDesc->title = SANE_TITLE_ANALOG_GAMMA; + pDesc->desc = SANE_DESC_ANALOG_GAMMA; + pDesc->type = SANE_TYPE_FIXED; + pDesc->constraint_type = SANE_CONSTRAINT_RANGE; + pDesc->constraint.range = &rangeGamma; + pDesc->cap = SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT; + pVal->w = SANE_FIX(1.0); + break; + + case optGammaTable: + pDesc->name = SANE_NAME_GAMMA_VECTOR; + pDesc->title = SANE_TITLE_GAMMA_VECTOR; + pDesc->desc = SANE_DESC_GAMMA_VECTOR; + pDesc->size = sizeof(s->aGammaTable); + pDesc->constraint_type = SANE_CONSTRAINT_RANGE; + pDesc->constraint.range = &rangeGammaTable; + pDesc->cap = SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT; + /* set a neutral gamma */ + for (j = 0; j < 4096; j++) { + s->aGammaTable[j] = j / 16; + } + pVal->wa = s->aGammaTable; + break; + + case optGroupMisc: + pDesc->title = SANE_I18N("Miscellaneous"); + pDesc->type = SANE_TYPE_GROUP; + pDesc->size = 0; + break; + + case optLamp: + pDesc->name = "lamp"; + pDesc->title = SANE_I18N("Lamp status"); + pDesc->desc = SANE_I18N("Switches the lamp on or off."); + pDesc->type = SANE_TYPE_BOOL; + pDesc->cap = SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT; + /* switch the lamp on when starting for first the time */ + pVal->w = SANE_TRUE; + break; + + case optCalibrate: + pDesc->name = "calibrate"; + pDesc->title = SANE_I18N("Calibrate"); + pDesc->desc = SANE_I18N("Calibrates for black and white level."); + pDesc->type = SANE_TYPE_BUTTON; + pDesc->cap = SANE_CAP_SOFT_SELECT; + pDesc->size = 0; + break; + + default: + DBG(DBG_ERR, "Uninitialised option %d\n", i); + break; + } + } +} + + +static int _ReportDevice(TScannerModel *pModel, char *pszDeviceName) +{ + TDevListEntry *pNew, *pDev; + + DBG(DBG_MSG, "niash: _ReportDevice '%s'\n", pszDeviceName); + + pNew = malloc(sizeof(TDevListEntry)); + if (!pNew) { + DBG(DBG_ERR, "no mem\n"); + return -1; + } + + /* add new element to the end of the list */ + if (_pFirstSaneDev == 0) { + _pFirstSaneDev = pNew; + } + else { + for (pDev = _pFirstSaneDev; pDev->pNext; pDev = pDev->pNext) { + ; + } + pDev->pNext = pNew; + } + + /* fill in new element */ + pNew->pNext = 0; + pNew->dev.name = strdup(pszDeviceName); + pNew->dev.vendor = pModel->pszVendor; + pNew->dev.model = pModel->pszName; + pNew->dev.type = "flatbed scanner"; + + iNumSaneDev++; + + return 0; +} + +/*****************************************************************************/ + +SANE_Status +sane_init(SANE_Int *piVersion, SANE_Auth_Callback pfnAuth) +{ + FILE * conf_fp; /* Config file stream */ + SANE_Char line[PATH_MAX]; + SANE_Char * str = NULL; + SANE_String_Const proper_str; + int nline = 0; + + /* prevent compiler from complaing about unused parameters */ + pfnAuth = pfnAuth; + + DBG_INIT(); + DBG(DBG_MSG, "sane_init\n"); + + /* install transfer methods */ +#if defined(SANEI_USB_SUPPORT) + Hp3300cXferRegisterModule(&SaneiUsbDev); +#endif +#if defined(LINUX_USB_SUPPORT) + Hp3300cXferRegisterModule(&LnxUsbDev); +#endif +#if defined(USCANNER_SUPPORT) + Hp3300cXferRegisterModule(&uscannerDev); +#endif +#if defined(LIBUSB_SUPPORT) + Hp3300cXferRegisterModule(&LibUsbDev); +#endif +#if defined(LIBIEEE1284_SUPPORT) + Hp3300cXferRegisterModule(&IEEE1284Dev); +#endif + + conf_fp = sanei_config_open (NIASH_CONFIG_FILE); + + if (conf_fp) { + DBG(DBG_MSG, "Reading config file\n"); + + while (sanei_config_read (line, sizeof (line), conf_fp)) { + ++nline; + + if (str) { + free(str); + } + + proper_str = sanei_config_get_string (line, &str); + + /* Discards white lines and comments */ + if (!str || proper_str == line || str[0] == '#' ) { + DBG(DBG_MSG, "Discarding line %d\n", nline); + } + else { + /* If line's not blank or a comment, then it's the device + * filename. usb_devfile is resized to hold the device filename string */ + usb_devfile = malloc ( sizeof (line) * sizeof(SANE_Char) ); + if (usb_devfile == NULL) { + DBG(DBG_ERR, "Unable to allocate memory for device filename string\n"); + DBG(DBG_MSG, "Using default built-in values\n"); + break; + } + strcpy (usb_devfile, line); + DBG(DBG_MSG, "Using %s as device file\n", usb_devfile); + } + } /* while */ + fclose(conf_fp); + } + else { + DBG (DBG_ERR, "Unable to read config file \"%s\": %s\n", NIASH_CONFIG_FILE, + strerror(errno)); + DBG (DBG_MSG, "Using default built-in values\n"); + } + + if (piVersion != NULL) { + *piVersion = SANE_VERSION_CODE (V_MAJOR, V_MINOR, BUILD); + } + + /* initialise transfer methods */ + iNumSaneDev = 0; + Hp3300cXferInit(_ReportDevice); + + return SANE_STATUS_GOOD; +} + + +void +sane_exit(void) +{ + TDevListEntry *pDev, *pNext; + + DBG(DBG_MSG, "sane_exit\n"); + + /* free device list memory */ + if (_pSaneDevList) { + for (pDev = _pFirstSaneDev; pDev; pDev = pNext) { + pNext = pDev->pNext; + free((void *)pDev->dev.name); + free(pDev); + } + _pFirstSaneDev = 0; + free(_pSaneDevList); + _pSaneDevList = 0; + } +} + + +SANE_Status +sane_get_devices(const SANE_Device ***device_list, SANE_Bool local_only) +{ + TDevListEntry *pDev; + int i; + + DBG(DBG_MSG, "sane_get_devices\n"); + + local_only = local_only; + + if (_pSaneDevList) { + free(_pSaneDevList); + } + + _pSaneDevList = malloc(sizeof(*_pSaneDevList) * (iNumSaneDev + 1)); + if (!_pSaneDevList) { + DBG(DBG_MSG, "no mem\n"); + return SANE_STATUS_NO_MEM; + } + i = 0; + for (pDev = _pFirstSaneDev; pDev; pDev = pDev->pNext) { + _pSaneDevList[i++] = &pDev->dev; + } + _pSaneDevList[i++] = 0; /* last entry is 0 */ + + *device_list = _pSaneDevList; + + return SANE_STATUS_GOOD; +} + + +SANE_Status +sane_open(SANE_String_Const name, SANE_Handle *h) +{ + TScanner *s; + + DBG(DBG_MSG, "sane_open: %s\n", name); + + /* check the name */ + if (strlen(name) == 0) { + /* default to first available device */ + name = _pFirstSaneDev->dev.name; + } + + s = malloc(sizeof(TScanner)); + if (!s) { + DBG(DBG_MSG, "malloc failed\n"); + return SANE_STATUS_NO_MEM; + } + + if (Hp3300cOpen(&s->HWParams, (char *)name) < 0) { + /* is this OK ? */ + DBG(DBG_ERR, "Hp3300cOpen failed\n"); + free((void *)s); + return SANE_STATUS_DEVICE_BUSY; + } + _InitOptions(s); + *h = s; + + /* Turn on lamp by default at startup */ + SetLamp(&s->HWParams, TRUE); + + return SANE_STATUS_GOOD; +} + + +void +sane_close(SANE_Handle h) +{ + TScanner *s; + + DBG(DBG_MSG, "sane_close\n"); + + s = (TScanner *)h; + + /* turn off scanner lamp */ + SetLamp(&s->HWParams, FALSE); + + /* close scanner */ + Hp3300cClose(&s->HWParams); + + /* free scanner object memory */ + free((void *)s); +} + + +const SANE_Option_Descriptor * +sane_get_option_descriptor(SANE_Handle h, SANE_Int n) +{ + TScanner *s; + + DBG(DBG_MSG, "sane_get_option_descriptor %d\n", n); + + if ((n < optCount) || (n >= optLast)) { + return NULL; + } + + s = (TScanner *)h; + return &s->aOptions[n]; +} + + +SANE_Status +sane_control_option(SANE_Handle h, SANE_Int n, SANE_Action Action, void *pVal, + SANE_Int *pInfo) +{ + TScanner *s; + int fVal; + static char szTable[15000]; + char szTemp[16]; + int *pi; + int i; + SANE_Int info; + bool fLampIsOn; + + DBG(DBG_MSG, "sane_control_option: option %d, action %d\n", n, Action); + + s = (TScanner *)h; + info = 0; + + switch (Action) { + case SANE_ACTION_GET_VALUE: + switch (n) { + + /* Get options of type SANE_Word */ + case optCount: + case optDPI: + case optGamma: + case optTLX: case optTLY: case optBRX: case optBRY: + DBG(DBG_MSG, "sane_control_option: SANE_ACTION_GET_VALUE %d = %d\n", n, + (int)s->aValues[n].w); + *(SANE_Word*)pVal = s->aValues[n].w; + break; + + /* Get options of type SANE_Word array */ + case optGammaTable: + DBG(DBG_MSG, "Reading gamma table\n"); + memcpy(pVal, s->aValues[n].wa, s->aOptions[n].size); + break; + + /* Get options of type SANE_Bool */ + case optLamp: + GetLamp(&s->HWParams, &fLampIsOn); + *(SANE_Bool *)pVal = fLampIsOn; + break; + + case optCalibrate: + /* although this option has nothing to read, + it's added here to avoid a warning when running scanimage --help */ + break; + + default: + DBG(DBG_MSG, "SANE_ACTION_GET_VALUE: Invalid option (%d)\n", n); + } + break; + + + case SANE_ACTION_SET_VALUE: + if (s->fScanning) { + DBG(DBG_ERR, "sane_control_option: SANE_ACTION_SET_VALUE not allowed during scan\n"); + return SANE_STATUS_INVAL; + } + switch (n) { + + case optCount: + return SANE_STATUS_INVAL; + + case optDPI: case optTLX: case optTLY: case optBRX: case optBRY: + info |= SANE_INFO_RELOAD_PARAMS; + /* fall through */ + + case optGamma: + DBG(DBG_MSG, "sane_control_option: SANE_ACTION_SET_VALUE %d = %d\n", n, + (int)s->aValues[n].w); + s->aValues[n].w = *(SANE_Word *)pVal; + break; + + case optGammaTable: + DBG(DBG_MSG, "Writing gamma table\n"); + pi = (SANE_Int *)pVal; + strcpy(szTable, ""); + for (i = 0; i < 4096; i++) { + if ((i % 32) == 0) { + sprintf(szTemp, " %04X", pi[i]); + strcat(szTable, szTemp); + } + } + memcpy(s->aValues[n].wa, pVal, s->aOptions[n].size); + DBG(DBG_MSG, "Gamma table summary:\n%s\n", szTable); + break; + + case optLamp: + fVal = *(SANE_Bool *)pVal; + DBG(DBG_MSG, "lamp %s\n", fVal ? "on" : "off"); + SetLamp(&s->HWParams, fVal); + break; + + case optCalibrate: +/* SimpleCalib(&s->HWParams); */ + break; + + default: + DBG(DBG_ERR, "SANE_ACTION_SET_VALUE: Invalid option (%d)\n", n); + } + if (pInfo != NULL) { + *pInfo = info; + } + break; + + + case SANE_ACTION_SET_AUTO: + return SANE_STATUS_UNSUPPORTED; + + + default: + DBG(DBG_ERR, "Invalid action (%d)\n", Action); + return SANE_STATUS_INVAL; + } + + return SANE_STATUS_GOOD; +} + + + +SANE_Status +sane_get_parameters(SANE_Handle h, SANE_Parameters *p) +{ + TScanner *s; + DBG(DBG_MSG, "sane_get_parameters\n"); + + s = (TScanner *)h; + + /* first do some checks */ + if (s->aValues[optTLX].w >= s->aValues[optBRX].w) { + DBG(DBG_ERR, "TLX should be smaller than BRX\n"); + return SANE_STATUS_INVAL; /* proper error code? */ + } + if (s->aValues[optTLY].w >= s->aValues[optBRY].w) { + DBG(DBG_ERR, "TLY should be smaller than BRY\n"); + return SANE_STATUS_INVAL; /* proper error code? */ + } + + /* return the data */ + p->format = SANE_FRAME_RGB; + p->last_frame = SANE_TRUE; + + p->lines = MM_TO_PIXEL(s->aValues[optBRY].w - s->aValues[optTLY].w, + s->aValues[optDPI].w); + p->depth = 8; + p->pixels_per_line = MM_TO_PIXEL(s->aValues[optBRX].w - s->aValues[optTLX].w, + s->aValues[optDPI].w); + p->bytes_per_line = p->pixels_per_line * 3; + + return SANE_STATUS_GOOD; +} + + +SANE_Status +sane_start(SANE_Handle h) +{ + TScanner *s; + SANE_Parameters par; + int i, iLineCorr; + static byte abGamma[4096]; + static byte abCalibTable[HW_PIXELS * 6]; + + DBG(DBG_MSG, "sane_start\n"); + + s = (TScanner *)h; + + if (sane_get_parameters(h, &par) != SANE_STATUS_GOOD) { + DBG(DBG_MSG, "Invalid scan parameters\n"); + return SANE_STATUS_INVAL; + } + s->iLinesLeft = par.lines; + + /* fill in the scanparams using the option values */ + s->ScanParams.iDpi = s->aValues[optDPI].w; + s->ScanParams.iLpi = s->aValues[optDPI].w; + + /* calculate correction for filling of circular buffer */ + iLineCorr = 3 * s->HWParams.iSensorSkew; /* usually 16 motor steps */ + /* calculate correction for garbage lines */ + iLineCorr += s->HWParams.iSkipLines * (HW_LPI / s->ScanParams.iLpi); + + s->ScanParams.iTop = + MM_TO_PIXEL(s->aValues[optTLY].w + s->HWParams.iTopLeftY, HW_LPI) - iLineCorr; + s->ScanParams.iLeft = + MM_TO_PIXEL(s->aValues[optTLX].w + s->HWParams.iTopLeftX, HW_DPI); + + s->ScanParams.iWidth = par.pixels_per_line; + s->ScanParams.iHeight = par.lines; + s->ScanParams.iBottom = 14200UL; + s->ScanParams.fCalib = FALSE; + + /* perform a simple calibration just before scanning */ + SimpleCalib(&s->HWParams, abCalibTable); + + /* copy gamma table */ + for (i = 0; i < 4096; i++) { + abGamma[i] = s->aValues[optGammaTable].wa[i]; + } + + WriteGammaCalibTable(abGamma, abGamma, abGamma, abCalibTable, 0, 0, &s->HWParams); + + /* prepare the actual scan */ + if (!InitScan(&s->ScanParams, &s->HWParams)) { + DBG(DBG_MSG, "Invalid scan parameters\n"); + return SANE_STATUS_INVAL; + } + + /* init data pipe */ + s->DataPipe.iSkipLines = s->HWParams.iSkipLines; + /* on the hp3400 and hp4300 we cannot set the top of the scan area (yet), + so instead we just scan and throw away the data until the top */ + if ((s->HWParams.eModel == eHp4300c) || (s->HWParams.eModel == eHp3400c)) { + s->DataPipe.iSkipLines += MM_TO_PIXEL(s->aValues[optTLY].w + s->HWParams.iTopLeftY, s->aValues[optDPI].w); + } + s->DataPipe.iBytesLeft = 0; + /* hack */ + s->DataPipe.pabLineBuf = (byte *)malloc(HW_PIXELS * 3); + CircBufferInit( s->HWParams.iXferHandle, &s->DataPipe, par.bytes_per_line, + s->ScanParams.iLpi * s->HWParams.iSensorSkew / HW_LPI, s->HWParams.iReversedHead); + + s->fScanning = TRUE; + return SANE_STATUS_GOOD; +} + + +SANE_Status +sane_read(SANE_Handle h, SANE_Byte *buf, SANE_Int maxlen, SANE_Int *len) +{ + TScanner *s; + TDataPipe *p; + + DBG(DBG_MSG, "sane_read: buf=%p, maxlen=%d, ", buf, maxlen); + + s = (TScanner *)h; + + /* sane_read only allowed after sane_start */ + if (!s->fScanning) { + DBG(DBG_ERR, "sane_read: sane_read only allowed after sane_start\n"); + return SANE_STATUS_INVAL; + } + + p = &s->DataPipe; + + /* anything left to read? */ + if ((s->iLinesLeft == 0) && (p->iBytesLeft == 0)) { + CircBufferExit(&s->DataPipe); + free(p->pabLineBuf); + FinishScan(&s->HWParams); + *len = 0; + DBG(DBG_MSG, "sane_read: end of scan\n"); + s->fScanning = FALSE; + return SANE_STATUS_EOF; + } + + /* time to read the next line? */ + if (p->iBytesLeft == 0) { + CircBufferGetLine(s->HWParams.iXferHandle, p, p->pabLineBuf, s->HWParams.iReversedHead); + p->iBytesLeft = p->iBytesPerLine; + s->iLinesLeft--; + } + + /* copy (part of) a line */ + *len = MIN(maxlen, p->iBytesLeft); + memcpy(buf, &p->pabLineBuf[p->iBytesPerLine - p->iBytesLeft], *len); + p->iBytesLeft -= *len; + + DBG(DBG_MSG, " read=%d\n", *len); + + return SANE_STATUS_GOOD; +} + + +void +sane_cancel(SANE_Handle h) +{ + TScanner *s; + + DBG(DBG_MSG, "sane_cancel\n"); + + s = (TScanner *)h; + + /* to be implemented more thoroughly */ + + /* Make sure the scanner head returns home */ + FinishScan(&s->HWParams); + + s->fCanceled = TRUE; + s->fScanning = FALSE; +} + + +SANE_Status +sane_set_io_mode(SANE_Handle h, SANE_Bool m) +{ + DBG(DBG_MSG, "sane_set_io_mode %s\n", m ? "non-blocking" : "blocking"); + + /* prevent compiler from complaining about unused parameters */ + h = h; + + if (m) { + return SANE_STATUS_UNSUPPORTED; + } + return SANE_STATUS_GOOD; +} + + +SANE_Status +sane_get_select_fd(SANE_Handle h, SANE_Int *fd) +{ + DBG(DBG_MSG, "sane_select_fd\n"); + + /* prevent compiler from complaining about unused parameters */ + h = h; + fd = fd; + + return SANE_STATUS_UNSUPPORTED; +} + diff -ruN sane-backends-1.0.12/backend/niash.conf sane-backends-1.0.12-patched/backend/niash.conf --- sane-backends-1.0.12/backend/niash.conf 1969-12-31 18:00:00.000000000 -0600 +++ sane-backends-1.0.12-patched/backend/niash.conf 2003-06-19 11:02:15.000000000 -0500 @@ -0,0 +1,9 @@ +# Device filename to use for scanner access +# Uncomment the following line if you are using the SANE backend +# and want to use the kernel scanner module instead of libusb: +# +#Linux: +#/dev/usbscanner +# +#FreeBSD/NetBSD: +#/dev/uscanner0 diff -ruN sane-backends-1.0.12/doc/Makefile.in sane-backends-1.0.12-patched/doc/Makefile.in --- sane-backends-1.0.12/doc/Makefile.in 2003-04-30 18:12:55.000000000 -0500 +++ sane-backends-1.0.12-patched/doc/Makefile.in 2003-06-19 11:02:15.000000000 -0500 @@ -38,7 +38,7 @@ @SET_MAKE@ SECT1 = saned.1 scanimage.1 sane-config.1 sane-find-scanner.1 gamma4scanimage.1 -SECT5 = sane-abaton.5 sane-agfafocus.5 sane-apple.5 sane-as6e.5 sane-dll.5 \ +SECT5 = sane-abaton.5 sane-agfafocus.5 sane-apple.5 sane-as6e.5 sane-dll.5 sane-niash.5 \ sane-dc25.5 sane-dmc.5 sane-epson.5 sane-hp.5 sane-gphoto2.5 \ sane-leo.5 sane-matsushita.5 sane-microtek.5 \ sane-microtek2.5 sane-mustek.5 sane-nec.5 sane-net.5 sane-pie.5 \ @@ -88,7 +88,7 @@ sane-artec.man sane-as6e.man sane-avision.man sane-bh.man \ sane-canon.man sane-canon630u.man sane-config.man sane-coolscan.man \ sane-coolscan2.man sane-dc210.man sane-dc240.man \ - sane-dc25.man sane-dll.man sane-dmc.man sane-epson.man \ + sane-dc25.man sane-dll.man sane-niash.man sane-dmc.man sane-epson.man \ sane-find-scanner.man sane-fujitsu.man sane-gphoto2.man sane-hp.man \ sane-logo.png sane-logo2.jpg sane-matsushita.man sane-microtek.man \ sane-leo.man sane-microtek2.man \ diff -ruN sane-backends-1.0.12/doc/sane-niash.man sane-backends-1.0.12-patched/doc/sane-niash.man --- sane-backends-1.0.12/doc/sane-niash.man 1969-12-31 18:00:00.000000000 -0600 +++ sane-backends-1.0.12-patched/doc/sane-niash.man 2003-06-19 11:02:15.000000000 -0500 @@ -0,0 +1,113 @@ +.\" $Id: sane-niash.man,v 1.7 2002/02/07 03:28:53 aggression Exp $ +.TH sane-niash 5 "17 Dec 2001" +.IX sane-niash + +.SH NAME +sane-niash - SANE backend for scanners based on the NIASH chipset. + +.SH DESCRIPTION +The +.B sane-niash +implements a SANE (Scanner Access Now Easy) backend that +provides access to NIASH chipset based scanners. This backend will try to support +the following models: + +MANUFACTURER: MODEL: USB ID: +.br +--------------- -------------- --------- +.br +Agfa Snapscan Touch 06BD-0100 (1)(a) +.br +Hewlett-Packard Scanjet 3300c 03F0-0205 (1)(a)(b) +.br +Hewlett-Packard Scanjet 3400c 03F0-0405 (2)(b) +.br +Hewlett-Packard Scanjet 4300c 03F0-0305 (2)(a) +.PP +.br +ASIC: (1) - NIASH00014 / (2) - NIASH00019 +.br +ANALOG FRONT-END: (a) - ESIC ES8100QA / (b) - WM8143-12 +.br + +.SH "DEVICE NAMES" +This backend expects device names of the form: +.PP +.RS +.I special +.RE +.PP +Where +.I special +is a path-name for the special device that corresponds to a USB scanner. +With GNU/Linux systems, such a device name could be +.I /dev/usb/scanner0 +or +.IR /dev/usbscanner1 , +for example. + + +.SH CONFIGURATION +The +.I niash.conf +file contains the device name that correspond to the NIASH +scanner. Empty lines and lines starting with a hash mark (#) are +ignored. +.PP +A sample configuration file is shown below: +.PP +.RS +# Comment +.br +/dev/usbscanner +.RE +.PP +The first line is ignored. The second line is the device filename to use +in order to access the NIASH Scanner. If no device is given, the +backend will use libUSB. + +.SH FILES +.TP +.I @CONFIGDIR@/niash.conf +The backend configuration file (see also description of SANE_CONFIG_DIR below). + +.TP +.I @LIBDIR@/libsane-niash.a +The static library implementing this backend. + +.TP +.I @LIBDIR@/libsane-niash.so +The shared library implementing this backend (present on systems that +support dynamic loading). +.SH ENVIRONMENT + +.TP +.B SANE_CONFIG_DIR +This environment variable specifies the list of directories that may +contain the configuration file. Under UNIX, the directories are +separated by a colon (`:'), under OS/2, they are separated by a +semi-colon (`;'). If this variable is not set, the configuration file +is searched in two default directories: first, the current working +directory (".") and then in @CONFIGDIR@. If the value of the +environment variable ends with the directory separator character, then +the default directories are searched after the explicitly specified +directories. For example, setting +.B SANE_CONFIG_DIR +to "/tmp/config:" would result in directories "tmp/config", ".", and +"@CONFIGDIR@" being searched (in this order). +.TP + +.B SANE_DEBUG_NIASH +If the library was compiled with debug support enabled, this +environment variable controls the debug level for this backend. Higher +debug levels increase the verbosity of the output. + +Example: +export SANE_DEBUG_NIASH=255 + +.SH "SEE ALSO" +sane(7), sane\-usb(5) +.br +http://www.sourceforge.net/projects/hp3300backend +.SH AUTHOR +Bertrik Sikken