1141cc406Sopenharmony_ci/** 2141cc406Sopenharmony_ci * Description of the Primax PagePartner model 3141cc406Sopenharmony_ci */ 4141cc406Sopenharmony_cistatic P5_Model pagepartner_model = { 5141cc406Sopenharmony_ci "Primax PagePartner", 6141cc406Sopenharmony_ci "Primax", 7141cc406Sopenharmony_ci "PagePartner", 8141cc406Sopenharmony_ci SANE_I18N ("sheetfed scanner"), 9141cc406Sopenharmony_ci 10141cc406Sopenharmony_ci {300, 200, 150, 100, 0}, 11141cc406Sopenharmony_ci /* 500 seems also possible */ 12141cc406Sopenharmony_ci {600, 400, 300, 200, 150, 100, 0}, 13141cc406Sopenharmony_ci 14141cc406Sopenharmony_ci 300, 15141cc406Sopenharmony_ci 600, 16141cc406Sopenharmony_ci 100, 17141cc406Sopenharmony_ci 100, 18141cc406Sopenharmony_ci 16, 19141cc406Sopenharmony_ci 20141cc406Sopenharmony_ci SANE_FIX (0.0), 21141cc406Sopenharmony_ci SANE_FIX (0.0), 22141cc406Sopenharmony_ci SANE_FIX (215.9), 23141cc406Sopenharmony_ci SANE_FIX (300.0), 24141cc406Sopenharmony_ci}; 25141cc406Sopenharmony_ci 26141cc406Sopenharmony_ci#ifdef HAVE_LINUX_PPDEV_H 27141cc406Sopenharmony_cistatic char * 28141cc406Sopenharmony_ciaddr_name (uint16_t addr) 29141cc406Sopenharmony_ci{ 30141cc406Sopenharmony_ci switch (addr) 31141cc406Sopenharmony_ci { 32141cc406Sopenharmony_ci case DATA: 33141cc406Sopenharmony_ci return "DATA"; 34141cc406Sopenharmony_ci break; 35141cc406Sopenharmony_ci case STATUS: 36141cc406Sopenharmony_ci return "STATUS"; 37141cc406Sopenharmony_ci break; 38141cc406Sopenharmony_ci case CONTROL: 39141cc406Sopenharmony_ci return "CONTROL"; 40141cc406Sopenharmony_ci break; 41141cc406Sopenharmony_ci case EPPADR: 42141cc406Sopenharmony_ci return "EPPADR"; 43141cc406Sopenharmony_ci break; 44141cc406Sopenharmony_ci case EPPDATA: 45141cc406Sopenharmony_ci return "EPPDATA"; 46141cc406Sopenharmony_ci break; 47141cc406Sopenharmony_ci default: 48141cc406Sopenharmony_ci return "*ERROR*"; 49141cc406Sopenharmony_ci } 50141cc406Sopenharmony_ci} 51141cc406Sopenharmony_ci#endif 52141cc406Sopenharmony_ci 53141cc406Sopenharmony_ci/** @brief low level hardware access functions 54141cc406Sopenharmony_ci * @{ 55141cc406Sopenharmony_ci */ 56141cc406Sopenharmony_ci 57141cc406Sopenharmony_cistatic uint8_t 58141cc406Sopenharmony_cip5_inb (int fd, uint16_t addr) 59141cc406Sopenharmony_ci{ 60141cc406Sopenharmony_ci#ifdef HAVE_LINUX_PPDEV_H 61141cc406Sopenharmony_ci uint8_t val = 0xff; 62141cc406Sopenharmony_ci int rc, mode = 0xff; 63141cc406Sopenharmony_ci 64141cc406Sopenharmony_ci switch (addr) 65141cc406Sopenharmony_ci { 66141cc406Sopenharmony_ci case DATA: 67141cc406Sopenharmony_ci rc = ioctl (fd, PPRDATA, &val); 68141cc406Sopenharmony_ci break; 69141cc406Sopenharmony_ci case STATUS: 70141cc406Sopenharmony_ci rc = ioctl (fd, PPRSTATUS, &val); 71141cc406Sopenharmony_ci break; 72141cc406Sopenharmony_ci case CONTROL: 73141cc406Sopenharmony_ci rc = ioctl (fd, PPRCONTROL, &val); 74141cc406Sopenharmony_ci break; 75141cc406Sopenharmony_ci case EPPDATA: 76141cc406Sopenharmony_ci mode = 1; /* data_reverse */ 77141cc406Sopenharmony_ci rc = ioctl (fd, PPDATADIR, &mode); 78141cc406Sopenharmony_ci mode = IEEE1284_MODE_EPP | IEEE1284_DATA; 79141cc406Sopenharmony_ci rc = ioctl (fd, PPSETMODE, &mode); 80141cc406Sopenharmony_ci#ifdef PPSETFLAGS 81141cc406Sopenharmony_ci mode = PP_FASTREAD; 82141cc406Sopenharmony_ci rc = ioctl (fd, PPSETFLAGS, &mode); 83141cc406Sopenharmony_ci#endif 84141cc406Sopenharmony_ci rc = read (fd, &val, 1); 85141cc406Sopenharmony_ci break; 86141cc406Sopenharmony_ci default: 87141cc406Sopenharmony_ci DBG (DBG_error, "p5_inb(%s) escaped ppdev\n", addr_name (addr)); 88141cc406Sopenharmony_ci return 0xFF; 89141cc406Sopenharmony_ci } 90141cc406Sopenharmony_ci if (rc < 0) 91141cc406Sopenharmony_ci { 92141cc406Sopenharmony_ci DBG (DBG_error, "ppdev ioctl returned <%s>\n", strerror (errno)); 93141cc406Sopenharmony_ci } 94141cc406Sopenharmony_ci return val; 95141cc406Sopenharmony_ci#else 96141cc406Sopenharmony_ci if(fd && addr) 97141cc406Sopenharmony_ci return 0; 98141cc406Sopenharmony_ci return 0; 99141cc406Sopenharmony_ci#endif 100141cc406Sopenharmony_ci} 101141cc406Sopenharmony_ci 102141cc406Sopenharmony_cistatic void 103141cc406Sopenharmony_cip5_outb (int fd, uint16_t addr, uint8_t value) 104141cc406Sopenharmony_ci{ 105141cc406Sopenharmony_ci#ifdef HAVE_LINUX_PPDEV_H 106141cc406Sopenharmony_ci int rc = 0, mode = 0xff; 107141cc406Sopenharmony_ci 108141cc406Sopenharmony_ci switch (addr) 109141cc406Sopenharmony_ci { 110141cc406Sopenharmony_ci case DATA: 111141cc406Sopenharmony_ci rc = ioctl (fd, PPWDATA, &value); 112141cc406Sopenharmony_ci break; 113141cc406Sopenharmony_ci case CONTROL: 114141cc406Sopenharmony_ci mode = value & 0x20; 115141cc406Sopenharmony_ci rc = ioctl (fd, PPDATADIR, &mode); 116141cc406Sopenharmony_ci if (!rc) 117141cc406Sopenharmony_ci { 118141cc406Sopenharmony_ci value = value & 0xDF; 119141cc406Sopenharmony_ci rc = ioctl (fd, PPWCONTROL, &value); 120141cc406Sopenharmony_ci } 121141cc406Sopenharmony_ci break; 122141cc406Sopenharmony_ci case EPPDATA: 123141cc406Sopenharmony_ci mode = 0; /* data forward */ 124141cc406Sopenharmony_ci rc = ioctl (fd, PPDATADIR, &mode); 125141cc406Sopenharmony_ci mode = IEEE1284_MODE_EPP | IEEE1284_DATA; 126141cc406Sopenharmony_ci rc = ioctl (fd, PPSETMODE, &mode); 127141cc406Sopenharmony_ci rc = write (fd, &value, 1); 128141cc406Sopenharmony_ci break; 129141cc406Sopenharmony_ci case EPPADR: 130141cc406Sopenharmony_ci mode = 0; /* data forward */ 131141cc406Sopenharmony_ci rc = ioctl (fd, PPDATADIR, &mode); 132141cc406Sopenharmony_ci mode = IEEE1284_MODE_EPP | IEEE1284_ADDR; 133141cc406Sopenharmony_ci rc = ioctl (fd, PPSETMODE, &mode); 134141cc406Sopenharmony_ci rc = write (fd, &value, 1); 135141cc406Sopenharmony_ci break; 136141cc406Sopenharmony_ci default: 137141cc406Sopenharmony_ci DBG (DBG_error, "p5_outb(%s,0x%02x) escaped ppdev\n", addr_name (addr), 138141cc406Sopenharmony_ci value); 139141cc406Sopenharmony_ci break; 140141cc406Sopenharmony_ci } 141141cc406Sopenharmony_ci if (rc < 0) 142141cc406Sopenharmony_ci { 143141cc406Sopenharmony_ci DBG (DBG_error, "ppdev ioctl returned <%s>\n", strerror (errno)); 144141cc406Sopenharmony_ci } 145141cc406Sopenharmony_ci#else 146141cc406Sopenharmony_ci if(fd && addr && value) 147141cc406Sopenharmony_ci return; 148141cc406Sopenharmony_ci#endif /* HAVE_LINUX_PPDEV_H */ 149141cc406Sopenharmony_ci} 150141cc406Sopenharmony_ci 151141cc406Sopenharmony_cistatic void 152141cc406Sopenharmony_ciwrite_reg (int fd, uint8_t index, uint8_t value) 153141cc406Sopenharmony_ci{ 154141cc406Sopenharmony_ci uint8_t idx; 155141cc406Sopenharmony_ci 156141cc406Sopenharmony_ci /* both nibbles hold the same value */ 157141cc406Sopenharmony_ci idx = index & 0x0F; 158141cc406Sopenharmony_ci DBG (DBG_io2, "write_reg(REG%X,0x%x)\n", idx, value); 159141cc406Sopenharmony_ci idx = idx << 4 | idx; 160141cc406Sopenharmony_ci p5_outb (fd, EPPADR, idx); 161141cc406Sopenharmony_ci p5_outb (fd, EPPDATA, value); 162141cc406Sopenharmony_ci} 163141cc406Sopenharmony_ci 164141cc406Sopenharmony_cistatic uint8_t 165141cc406Sopenharmony_ciread_reg (int fd, uint8_t index) 166141cc406Sopenharmony_ci{ 167141cc406Sopenharmony_ci uint8_t idx; 168141cc406Sopenharmony_ci 169141cc406Sopenharmony_ci /* both nibbles hold the same value */ 170141cc406Sopenharmony_ci idx = index & 0x0F; 171141cc406Sopenharmony_ci idx = idx << 4 | idx; 172141cc406Sopenharmony_ci p5_outb (fd, EPPADR, idx); 173141cc406Sopenharmony_ci return p5_inb (fd, EPPDATA); 174141cc406Sopenharmony_ci} 175141cc406Sopenharmony_ci 176141cc406Sopenharmony_ci#ifdef HAVE_LINUX_PPDEV_H 177141cc406Sopenharmony_cistatic int 178141cc406Sopenharmony_ciread_data (int fd, uint8_t * data, int length) 179141cc406Sopenharmony_ci{ 180141cc406Sopenharmony_ci int mode, rc, nb; 181141cc406Sopenharmony_ci unsigned char bval; 182141cc406Sopenharmony_ci 183141cc406Sopenharmony_ci bval = REG8; 184141cc406Sopenharmony_ci mode = IEEE1284_MODE_EPP | IEEE1284_ADDR; 185141cc406Sopenharmony_ci rc = ioctl (fd, PPSETMODE, &mode); 186141cc406Sopenharmony_ci rc = write (fd, &bval, 1); 187141cc406Sopenharmony_ci 188141cc406Sopenharmony_ci mode = 1; /* data_reverse */ 189141cc406Sopenharmony_ci rc = ioctl (fd, PPDATADIR, &mode); 190141cc406Sopenharmony_ci#ifdef PPSETFLAGS 191141cc406Sopenharmony_ci mode = PP_FASTREAD; 192141cc406Sopenharmony_ci rc = ioctl (fd, PPSETFLAGS, &mode); 193141cc406Sopenharmony_ci#endif 194141cc406Sopenharmony_ci mode = IEEE1284_MODE_EPP | IEEE1284_DATA; 195141cc406Sopenharmony_ci rc = ioctl (fd, PPSETMODE, &mode); 196141cc406Sopenharmony_ci nb = 0; 197141cc406Sopenharmony_ci while (nb < length) 198141cc406Sopenharmony_ci { 199141cc406Sopenharmony_ci rc = read (fd, data + nb, length - nb); 200141cc406Sopenharmony_ci if (rc < 0) 201141cc406Sopenharmony_ci { 202141cc406Sopenharmony_ci DBG (DBG_error, "memtest: error reading data back!\n"); 203141cc406Sopenharmony_ci return 0; 204141cc406Sopenharmony_ci } 205141cc406Sopenharmony_ci else 206141cc406Sopenharmony_ci { 207141cc406Sopenharmony_ci nb += rc; 208141cc406Sopenharmony_ci } 209141cc406Sopenharmony_ci } 210141cc406Sopenharmony_ci 211141cc406Sopenharmony_ci return 1; 212141cc406Sopenharmony_ci} 213141cc406Sopenharmony_ci 214141cc406Sopenharmony_cistatic void 215141cc406Sopenharmony_ciindex_write_data (int fd, uint8_t index, uint8_t * data, int length) 216141cc406Sopenharmony_ci{ 217141cc406Sopenharmony_ci int mode; 218141cc406Sopenharmony_ci unsigned char bval; 219141cc406Sopenharmony_ci 220141cc406Sopenharmony_ci bval = index; 221141cc406Sopenharmony_ci mode = IEEE1284_MODE_EPP | IEEE1284_ADDR; 222141cc406Sopenharmony_ci ioctl (fd, PPSETMODE, &mode); 223141cc406Sopenharmony_ci write (fd, &bval, 1); 224141cc406Sopenharmony_ci 225141cc406Sopenharmony_ci mode = IEEE1284_MODE_EPP | IEEE1284_DATA; 226141cc406Sopenharmony_ci ioctl (fd, PPSETMODE, &mode); 227141cc406Sopenharmony_ci mode = 0; /* data forward */ 228141cc406Sopenharmony_ci ioctl (fd, PPDATADIR, &mode); 229141cc406Sopenharmony_ci write (fd, data, length); 230141cc406Sopenharmony_ci return; 231141cc406Sopenharmony_ci} 232141cc406Sopenharmony_ci 233141cc406Sopenharmony_cistatic void 234141cc406Sopenharmony_ciwrite_data (int fd, uint8_t * data, int length) 235141cc406Sopenharmony_ci{ 236141cc406Sopenharmony_ci index_write_data (fd, REG8, data, length); 237141cc406Sopenharmony_ci} 238141cc406Sopenharmony_ci 239141cc406Sopenharmony_cistatic void 240141cc406Sopenharmony_ciwrite_reg2 (int fd, uint8_t index, uint16_t value) 241141cc406Sopenharmony_ci{ 242141cc406Sopenharmony_ci uint8_t data2[2]; 243141cc406Sopenharmony_ci 244141cc406Sopenharmony_ci data2[0] = value & 0xff; 245141cc406Sopenharmony_ci data2[1] = value >> 8; 246141cc406Sopenharmony_ci index_write_data (fd, index, data2, 2); 247141cc406Sopenharmony_ci} 248141cc406Sopenharmony_ci#else 249141cc406Sopenharmony_ci 250141cc406Sopenharmony_cistatic int 251141cc406Sopenharmony_ciread_data (int fd, uint8_t * data, int length) 252141cc406Sopenharmony_ci{ 253141cc406Sopenharmony_ci if(fd && data && length) 254141cc406Sopenharmony_ci return -1; 255141cc406Sopenharmony_ci return -1; 256141cc406Sopenharmony_ci} 257141cc406Sopenharmony_ci 258141cc406Sopenharmony_cistatic void 259141cc406Sopenharmony_ciwrite_data (int fd, uint8_t * data, int length) 260141cc406Sopenharmony_ci{ 261141cc406Sopenharmony_ci if(fd && data && length) 262141cc406Sopenharmony_ci return; 263141cc406Sopenharmony_ci} 264141cc406Sopenharmony_ci 265141cc406Sopenharmony_cistatic void 266141cc406Sopenharmony_ciwrite_reg2 (int fd, uint8_t index, uint16_t value) 267141cc406Sopenharmony_ci{ 268141cc406Sopenharmony_ci if(fd && index && value) 269141cc406Sopenharmony_ci return; 270141cc406Sopenharmony_ci} 271141cc406Sopenharmony_ci#endif 272141cc406Sopenharmony_ci 273141cc406Sopenharmony_ci/** 274141cc406Sopenharmony_ci * @} 275141cc406Sopenharmony_ci */ 276141cc406Sopenharmony_ci 277141cc406Sopenharmony_ci 278141cc406Sopenharmony_ci/** @brief This function checks a memory buffer. 279141cc406Sopenharmony_ci * This function writes at the given memory address then read it back 280141cc406Sopenharmony_ci * to check the scanner is correctly working. 281141cc406Sopenharmony_ci * @param fd file descriptor used to access hardware 282141cc406Sopenharmony_ci * @param addr address where to write and read 283141cc406Sopenharmony_ci * @return SANE_TRUE on success, SANE_FALSE otherwise 284141cc406Sopenharmony_ci */ 285141cc406Sopenharmony_cistatic int 286141cc406Sopenharmony_cimemtest (int fd, uint16_t addr) 287141cc406Sopenharmony_ci{ 288141cc406Sopenharmony_ci uint8_t sent[256]; 289141cc406Sopenharmony_ci uint8_t back[256]; 290141cc406Sopenharmony_ci int i; 291141cc406Sopenharmony_ci 292141cc406Sopenharmony_ci write_reg2 (fd, REG1, addr); 293141cc406Sopenharmony_ci for (i = 0; i < 256; i++) 294141cc406Sopenharmony_ci { 295141cc406Sopenharmony_ci sent[i] = (uint8_t) i; 296141cc406Sopenharmony_ci back[i] = 0; 297141cc406Sopenharmony_ci } 298141cc406Sopenharmony_ci write_data (fd, sent, 256); 299141cc406Sopenharmony_ci read_data (fd, back, 256); 300141cc406Sopenharmony_ci 301141cc406Sopenharmony_ci /* check if data read back is the same that the one sent */ 302141cc406Sopenharmony_ci for (i = 0; i < 256; i++) 303141cc406Sopenharmony_ci { 304141cc406Sopenharmony_ci if (back[i] != sent[i]) 305141cc406Sopenharmony_ci { 306141cc406Sopenharmony_ci return SANE_FALSE; 307141cc406Sopenharmony_ci } 308141cc406Sopenharmony_ci } 309141cc406Sopenharmony_ci 310141cc406Sopenharmony_ci return SANE_TRUE; 311141cc406Sopenharmony_ci} 312141cc406Sopenharmony_ci 313141cc406Sopenharmony_ci 314141cc406Sopenharmony_ci#define P5_INB(k,y,z) val=p5_inb(k,y); if(val!=z) { DBG(DBG_error,"expected 0x%02x, got 0x%02x\n",z, val); return SANE_FALSE; } 315141cc406Sopenharmony_ci 316141cc406Sopenharmony_ci/** @brief connect to scanner 317141cc406Sopenharmony_ci * This function sends the connect sequence for the scanner. 318141cc406Sopenharmony_ci * @param fd filedescriptor of the parallel port communication channel 319141cc406Sopenharmony_ci * @return SANE_TRUE in case of success, SANE_FALSE otherwise 320141cc406Sopenharmony_ci */ 321141cc406Sopenharmony_cistatic int 322141cc406Sopenharmony_ciconnect (int fd) 323141cc406Sopenharmony_ci{ 324141cc406Sopenharmony_ci uint8_t val; 325141cc406Sopenharmony_ci 326141cc406Sopenharmony_ci p5_inb (fd, CONTROL); 327141cc406Sopenharmony_ci p5_outb (fd, CONTROL, 0x04); 328141cc406Sopenharmony_ci p5_outb (fd, DATA, 0x02); 329141cc406Sopenharmony_ci P5_INB (fd, DATA, 0x02); 330141cc406Sopenharmony_ci p5_outb (fd, DATA, 0x03); 331141cc406Sopenharmony_ci P5_INB (fd, DATA, 0x03); 332141cc406Sopenharmony_ci p5_outb (fd, DATA, 0x03); 333141cc406Sopenharmony_ci p5_outb (fd, DATA, 0x83); 334141cc406Sopenharmony_ci p5_outb (fd, DATA, 0x03); 335141cc406Sopenharmony_ci p5_outb (fd, DATA, 0x83); 336141cc406Sopenharmony_ci P5_INB (fd, DATA, 0x83); 337141cc406Sopenharmony_ci p5_outb (fd, DATA, 0x82); 338141cc406Sopenharmony_ci P5_INB (fd, DATA, 0x82); 339141cc406Sopenharmony_ci p5_outb (fd, DATA, 0x02); 340141cc406Sopenharmony_ci p5_outb (fd, DATA, 0x82); 341141cc406Sopenharmony_ci p5_outb (fd, DATA, 0x02); 342141cc406Sopenharmony_ci p5_outb (fd, DATA, 0x82); 343141cc406Sopenharmony_ci P5_INB (fd, DATA, 0x82); 344141cc406Sopenharmony_ci p5_outb (fd, DATA, 0x82); 345141cc406Sopenharmony_ci P5_INB (fd, DATA, 0x82); 346141cc406Sopenharmony_ci p5_outb (fd, DATA, 0x02); 347141cc406Sopenharmony_ci p5_outb (fd, DATA, 0x82); 348141cc406Sopenharmony_ci p5_outb (fd, DATA, 0x02); 349141cc406Sopenharmony_ci p5_outb (fd, DATA, 0x82); 350141cc406Sopenharmony_ci P5_INB (fd, DATA, 0x82); 351141cc406Sopenharmony_ci p5_outb (fd, DATA, 0x83); 352141cc406Sopenharmony_ci P5_INB (fd, DATA, 0x83); 353141cc406Sopenharmony_ci p5_outb (fd, DATA, 0x03); 354141cc406Sopenharmony_ci p5_outb (fd, DATA, 0x83); 355141cc406Sopenharmony_ci p5_outb (fd, DATA, 0x03); 356141cc406Sopenharmony_ci p5_outb (fd, DATA, 0x83); 357141cc406Sopenharmony_ci P5_INB (fd, DATA, 0x83); 358141cc406Sopenharmony_ci p5_outb (fd, DATA, 0x82); 359141cc406Sopenharmony_ci P5_INB (fd, DATA, 0x82); 360141cc406Sopenharmony_ci p5_outb (fd, DATA, 0x02); 361141cc406Sopenharmony_ci p5_outb (fd, DATA, 0x82); 362141cc406Sopenharmony_ci p5_outb (fd, DATA, 0x02); 363141cc406Sopenharmony_ci p5_outb (fd, DATA, 0x82); 364141cc406Sopenharmony_ci P5_INB (fd, DATA, 0x82); 365141cc406Sopenharmony_ci p5_outb (fd, DATA, 0x83); 366141cc406Sopenharmony_ci P5_INB (fd, DATA, 0x83); 367141cc406Sopenharmony_ci p5_outb (fd, DATA, 0x03); 368141cc406Sopenharmony_ci p5_outb (fd, DATA, 0x83); 369141cc406Sopenharmony_ci p5_outb (fd, DATA, 0x03); 370141cc406Sopenharmony_ci p5_outb (fd, DATA, 0x83); 371141cc406Sopenharmony_ci P5_INB (fd, DATA, 0x83); 372141cc406Sopenharmony_ci p5_outb (fd, DATA, 0x83); 373141cc406Sopenharmony_ci P5_INB (fd, DATA, 0x83); 374141cc406Sopenharmony_ci p5_outb (fd, DATA, 0x03); 375141cc406Sopenharmony_ci p5_outb (fd, DATA, 0x83); 376141cc406Sopenharmony_ci p5_outb (fd, DATA, 0x03); 377141cc406Sopenharmony_ci p5_outb (fd, DATA, 0x83); 378141cc406Sopenharmony_ci P5_INB (fd, DATA, 0x83); 379141cc406Sopenharmony_ci p5_outb (fd, DATA, 0x82); 380141cc406Sopenharmony_ci P5_INB (fd, DATA, 0x82); 381141cc406Sopenharmony_ci p5_outb (fd, DATA, 0x02); 382141cc406Sopenharmony_ci p5_outb (fd, DATA, 0x82); 383141cc406Sopenharmony_ci p5_outb (fd, DATA, 0x02); 384141cc406Sopenharmony_ci p5_outb (fd, DATA, 0x82); 385141cc406Sopenharmony_ci p5_outb (fd, DATA, 0xFF); 386141cc406Sopenharmony_ci DBG (DBG_info, "connect() OK...\n"); 387141cc406Sopenharmony_ci return SANE_TRUE; 388141cc406Sopenharmony_ci} 389141cc406Sopenharmony_ci 390141cc406Sopenharmony_cistatic int 391141cc406Sopenharmony_cidisconnect (int fd) 392141cc406Sopenharmony_ci{ 393141cc406Sopenharmony_ci uint8_t val; 394141cc406Sopenharmony_ci 395141cc406Sopenharmony_ci p5_outb (fd, CONTROL, 0x04); 396141cc406Sopenharmony_ci p5_outb (fd, DATA, 0x00); 397141cc406Sopenharmony_ci P5_INB (fd, DATA, 0x00); 398141cc406Sopenharmony_ci p5_outb (fd, DATA, 0x01); 399141cc406Sopenharmony_ci P5_INB (fd, DATA, 0x01); 400141cc406Sopenharmony_ci p5_outb (fd, DATA, 0x01); 401141cc406Sopenharmony_ci p5_outb (fd, DATA, 0x81); 402141cc406Sopenharmony_ci p5_outb (fd, DATA, 0x01); 403141cc406Sopenharmony_ci p5_outb (fd, DATA, 0x81); 404141cc406Sopenharmony_ci P5_INB (fd, DATA, 0x81); 405141cc406Sopenharmony_ci p5_outb (fd, DATA, 0x80); 406141cc406Sopenharmony_ci P5_INB (fd, DATA, 0x80); 407141cc406Sopenharmony_ci p5_outb (fd, DATA, 0x00); 408141cc406Sopenharmony_ci p5_outb (fd, DATA, 0x80); 409141cc406Sopenharmony_ci p5_outb (fd, DATA, 0x00); 410141cc406Sopenharmony_ci p5_outb (fd, DATA, 0x80); 411141cc406Sopenharmony_ci P5_INB (fd, DATA, 0x80); 412141cc406Sopenharmony_ci p5_outb (fd, DATA, 0x80); 413141cc406Sopenharmony_ci P5_INB (fd, DATA, 0x80); 414141cc406Sopenharmony_ci p5_outb (fd, DATA, 0x00); 415141cc406Sopenharmony_ci p5_outb (fd, DATA, 0x80); 416141cc406Sopenharmony_ci p5_outb (fd, DATA, 0x00); 417141cc406Sopenharmony_ci p5_outb (fd, DATA, 0x80); 418141cc406Sopenharmony_ci P5_INB (fd, DATA, 0x80); 419141cc406Sopenharmony_ci p5_outb (fd, DATA, 0x81); 420141cc406Sopenharmony_ci P5_INB (fd, DATA, 0x81); 421141cc406Sopenharmony_ci p5_outb (fd, DATA, 0x01); 422141cc406Sopenharmony_ci p5_outb (fd, DATA, 0x81); 423141cc406Sopenharmony_ci p5_outb (fd, DATA, 0x01); 424141cc406Sopenharmony_ci p5_outb (fd, DATA, 0x81); 425141cc406Sopenharmony_ci P5_INB (fd, DATA, 0x81); 426141cc406Sopenharmony_ci p5_outb (fd, DATA, 0x80); 427141cc406Sopenharmony_ci P5_INB (fd, DATA, 0x80); 428141cc406Sopenharmony_ci p5_outb (fd, DATA, 0x00); 429141cc406Sopenharmony_ci p5_outb (fd, DATA, 0x80); 430141cc406Sopenharmony_ci p5_outb (fd, DATA, 0x00); 431141cc406Sopenharmony_ci p5_outb (fd, DATA, 0x80); 432141cc406Sopenharmony_ci P5_INB (fd, DATA, 0x80); 433141cc406Sopenharmony_ci p5_outb (fd, DATA, 0x00); 434141cc406Sopenharmony_ci p5_outb (fd, DATA, 0x80); 435141cc406Sopenharmony_ci p5_outb (fd, DATA, 0x00); 436141cc406Sopenharmony_ci p5_outb (fd, DATA, 0x80); 437141cc406Sopenharmony_ci P5_INB (fd, DATA, 0x80); 438141cc406Sopenharmony_ci p5_outb (fd, DATA, 0x00); 439141cc406Sopenharmony_ci p5_outb (fd, DATA, 0x80); 440141cc406Sopenharmony_ci p5_outb (fd, DATA, 0x00); 441141cc406Sopenharmony_ci p5_outb (fd, DATA, 0x80); 442141cc406Sopenharmony_ci P5_INB (fd, DATA, 0x80); 443141cc406Sopenharmony_ci p5_outb (fd, DATA, 0x00); 444141cc406Sopenharmony_ci p5_outb (fd, DATA, 0x80); 445141cc406Sopenharmony_ci p5_outb (fd, DATA, 0x00); 446141cc406Sopenharmony_ci p5_outb (fd, DATA, 0x80); 447141cc406Sopenharmony_ci p5_inb (fd, CONTROL); 448141cc406Sopenharmony_ci p5_outb (fd, CONTROL, 0x0C); 449141cc406Sopenharmony_ci 450141cc406Sopenharmony_ci return SANE_STATUS_GOOD; 451141cc406Sopenharmony_ci} 452141cc406Sopenharmony_ci 453141cc406Sopenharmony_cistatic void 454141cc406Sopenharmony_cisetadresses (int fd, uint16_t start, uint16_t end) 455141cc406Sopenharmony_ci{ 456141cc406Sopenharmony_ci write_reg (fd, REG3, start & 0xff); 457141cc406Sopenharmony_ci write_reg (fd, REG4, start >> 8); 458141cc406Sopenharmony_ci write_reg (fd, REG5, end & 0xff); 459141cc406Sopenharmony_ci write_reg (fd, REG6, end >> 8); 460141cc406Sopenharmony_ci DBG (DBG_io, "setadresses(0x%x,0x%x); OK...\n", start, end); 461141cc406Sopenharmony_ci} 462141cc406Sopenharmony_ci 463141cc406Sopenharmony_ci#ifdef HAVE_LINUX_PPDEV_H 464141cc406Sopenharmony_ci/** @brief open parallel port device 465141cc406Sopenharmony_ci * opens parallel port's low level device in EPP mode 466141cc406Sopenharmony_ci * @param devicename nam of the real device or the special value 'auto' 467141cc406Sopenharmony_ci * @return file descriptor in cas of successn -1 otherwise 468141cc406Sopenharmony_ci */ 469141cc406Sopenharmony_cistatic int 470141cc406Sopenharmony_ciopen_pp (const char *devicename) 471141cc406Sopenharmony_ci{ 472141cc406Sopenharmony_ci int fd, mode = 0; 473141cc406Sopenharmony_ci char *name; 474141cc406Sopenharmony_ci 475141cc406Sopenharmony_ci DBG (DBG_proc, "open_pp: start, devicename=%s\n", devicename); 476141cc406Sopenharmony_ci /* TODO improve auto device finding */ 477141cc406Sopenharmony_ci if (strncmp (devicename, "auto", 4) == 0) 478141cc406Sopenharmony_ci { 479141cc406Sopenharmony_ci name = strdup("/dev/parport0"); 480141cc406Sopenharmony_ci } 481141cc406Sopenharmony_ci else 482141cc406Sopenharmony_ci { 483141cc406Sopenharmony_ci name = strdup(devicename); 484141cc406Sopenharmony_ci } 485141cc406Sopenharmony_ci 486141cc406Sopenharmony_ci /* open device */ 487141cc406Sopenharmony_ci fd = open (name, O_RDWR); 488141cc406Sopenharmony_ci if (fd < 0) 489141cc406Sopenharmony_ci { 490141cc406Sopenharmony_ci switch (errno) 491141cc406Sopenharmony_ci { 492141cc406Sopenharmony_ci case ENOENT: 493141cc406Sopenharmony_ci#ifdef ENIO 494141cc406Sopenharmony_ci case ENXIO: 495141cc406Sopenharmony_ci#endif 496141cc406Sopenharmony_ci#ifdef ENODEV 497141cc406Sopenharmony_ci case ENODEV: 498141cc406Sopenharmony_ci#endif 499141cc406Sopenharmony_ci DBG (DBG_error, "open_pp: no %s device ...\n", name); 500141cc406Sopenharmony_ci break; 501141cc406Sopenharmony_ci case EACCES: 502141cc406Sopenharmony_ci DBG (DBG_error, 503141cc406Sopenharmony_ci "open_pp: current user cannot use existing %s device ...\n", 504141cc406Sopenharmony_ci name); 505141cc406Sopenharmony_ci break; 506141cc406Sopenharmony_ci default: 507141cc406Sopenharmony_ci DBG (DBG_error, "open_pp: %s while opening %s\n", strerror (errno), 508141cc406Sopenharmony_ci name); 509141cc406Sopenharmony_ci } 510141cc406Sopenharmony_ci return -1; 511141cc406Sopenharmony_ci } 512141cc406Sopenharmony_ci free(name); 513141cc406Sopenharmony_ci 514141cc406Sopenharmony_ci /* claim device and set it to EPP */ 515141cc406Sopenharmony_ci ioctl (fd, PPCLAIM); 516141cc406Sopenharmony_ci ioctl (fd, PPGETMODES, &mode); 517141cc406Sopenharmony_ci if (mode & PARPORT_MODE_PCSPP) 518141cc406Sopenharmony_ci DBG (DBG_io, "PARPORT_MODE_PCSPP\n"); 519141cc406Sopenharmony_ci if (mode & PARPORT_MODE_TRISTATE) 520141cc406Sopenharmony_ci DBG (DBG_io, "PARPORT_MODE_TRISTATE\n"); 521141cc406Sopenharmony_ci if (mode & PARPORT_MODE_EPP) 522141cc406Sopenharmony_ci DBG (DBG_io, "PARPORT_MODE_EPP\n"); 523141cc406Sopenharmony_ci if (mode & PARPORT_MODE_ECP) 524141cc406Sopenharmony_ci DBG (DBG_io, "PARPORT_MODE_ECP\n"); 525141cc406Sopenharmony_ci if (mode & PARPORT_MODE_COMPAT) 526141cc406Sopenharmony_ci DBG (DBG_io, "PARPORT_MODE_COMPAT\n"); 527141cc406Sopenharmony_ci if (mode & PARPORT_MODE_DMA) 528141cc406Sopenharmony_ci DBG (DBG_io, "PARPORT_MODE_DMA\n"); 529141cc406Sopenharmony_ci if (mode & PARPORT_MODE_EPP) 530141cc406Sopenharmony_ci { 531141cc406Sopenharmony_ci mode = IEEE1284_MODE_EPP; 532141cc406Sopenharmony_ci } 533141cc406Sopenharmony_ci else 534141cc406Sopenharmony_ci { 535141cc406Sopenharmony_ci /* 536141cc406Sopenharmony_ci if (mode & PARPORT_MODE_ECP) 537141cc406Sopenharmony_ci { 538141cc406Sopenharmony_ci mode = IEEE1284_MODE_ECP; 539141cc406Sopenharmony_ci } 540141cc406Sopenharmony_ci else 541141cc406Sopenharmony_ci */ 542141cc406Sopenharmony_ci { 543141cc406Sopenharmony_ci mode = -1; 544141cc406Sopenharmony_ci } 545141cc406Sopenharmony_ci } 546141cc406Sopenharmony_ci if (mode == -1) 547141cc406Sopenharmony_ci { 548141cc406Sopenharmony_ci DBG (DBG_error, "open_pp: no EPP mode, giving up ...\n"); 549141cc406Sopenharmony_ci ioctl (fd, PPRELEASE); 550141cc406Sopenharmony_ci close (fd); 551141cc406Sopenharmony_ci return -1; 552141cc406Sopenharmony_ci } 553141cc406Sopenharmony_ci ioctl (fd, PPNEGOT, &mode); 554141cc406Sopenharmony_ci ioctl (fd, PPSETMODE, &mode); 555141cc406Sopenharmony_ci DBG (DBG_proc, "open_pp: exit\n"); 556141cc406Sopenharmony_ci return fd; 557141cc406Sopenharmony_ci} 558141cc406Sopenharmony_ci 559141cc406Sopenharmony_ci/** close low level device 560141cc406Sopenharmony_ci * release and close low level hardware device 561141cc406Sopenharmony_ci */ 562141cc406Sopenharmony_cistatic void 563141cc406Sopenharmony_ciclose_pp (int fd) 564141cc406Sopenharmony_ci{ 565141cc406Sopenharmony_ci int mode = IEEE1284_MODE_COMPAT; 566141cc406Sopenharmony_ci 567141cc406Sopenharmony_ci if (fd > 2) 568141cc406Sopenharmony_ci { 569141cc406Sopenharmony_ci ioctl (fd, PPNEGOT, &mode); 570141cc406Sopenharmony_ci ioctl (fd, PPRELEASE); 571141cc406Sopenharmony_ci close (fd); 572141cc406Sopenharmony_ci } 573141cc406Sopenharmony_ci} 574141cc406Sopenharmony_ci 575141cc406Sopenharmony_ci#else /* HAVE_LINUX_PPDEV_H */ 576141cc406Sopenharmony_ci 577141cc406Sopenharmony_cistatic int 578141cc406Sopenharmony_ciopen_pp (const char *devicename) 579141cc406Sopenharmony_ci{ 580141cc406Sopenharmony_ci if(devicename) 581141cc406Sopenharmony_ci return -1; 582141cc406Sopenharmony_ci return -1; 583141cc406Sopenharmony_ci} 584141cc406Sopenharmony_ci 585141cc406Sopenharmony_cistatic void 586141cc406Sopenharmony_ciclose_pp (int fd) 587141cc406Sopenharmony_ci{ 588141cc406Sopenharmony_ci if(fd) 589141cc406Sopenharmony_ci return; 590141cc406Sopenharmony_ci} 591141cc406Sopenharmony_ci#endif /* HAVE_LINUX_PPDEV_H */ 592141cc406Sopenharmony_ci 593141cc406Sopenharmony_ci/** @brief test if a document is inserted 594141cc406Sopenharmony_ci * Test if a document is inserted by reading register E 595141cc406Sopenharmony_ci * @param fd file descriptor to access scanner 596141cc406Sopenharmony_ci * @return SANE_STATUS_NO_DOCS if no document or SANE_STATUS_GOOD 597141cc406Sopenharmony_ci * if something is present. 598141cc406Sopenharmony_ci */ 599141cc406Sopenharmony_cistatic SANE_Status 600141cc406Sopenharmony_citest_document (int fd) 601141cc406Sopenharmony_ci{ 602141cc406Sopenharmony_ci int detector; 603141cc406Sopenharmony_ci 604141cc406Sopenharmony_ci /* check for document presence 0xC6: present, 0xC3 no document */ 605141cc406Sopenharmony_ci detector = read_reg (fd, REGE); 606141cc406Sopenharmony_ci DBG (DBG_io, "test_document: detector=0x%02X\n", detector); 607141cc406Sopenharmony_ci 608141cc406Sopenharmony_ci /* document inserted */ 609141cc406Sopenharmony_ci if (detector & 0x04) 610141cc406Sopenharmony_ci return SANE_STATUS_GOOD; 611141cc406Sopenharmony_ci 612141cc406Sopenharmony_ci return SANE_STATUS_NO_DOCS; 613141cc406Sopenharmony_ci} 614141cc406Sopenharmony_ci 615141cc406Sopenharmony_ci/** 616141cc406Sopenharmony_ci * return the amount of scanned data available 617141cc406Sopenharmony_ci * @param fd file descriptor to access scanner 618141cc406Sopenharmony_ci * @return available byte number 619141cc406Sopenharmony_ci */ 620141cc406Sopenharmony_cistatic int 621141cc406Sopenharmony_ciavailable_bytes (int fd) 622141cc406Sopenharmony_ci{ 623141cc406Sopenharmony_ci int counter; 624141cc406Sopenharmony_ci 625141cc406Sopenharmony_ci /* read the number of 256 bytes block of scanned data */ 626141cc406Sopenharmony_ci counter = read_reg (fd, REG9); 627141cc406Sopenharmony_ci DBG (DBG_io, "available_bytes: available_bytes=0x%02X\n", counter); 628141cc406Sopenharmony_ci return 256 * counter; 629141cc406Sopenharmony_ci} 630141cc406Sopenharmony_ci 631141cc406Sopenharmony_cistatic SANE_Status 632141cc406Sopenharmony_cibuild_correction (P5_Device * dev, unsigned int dpi, unsigned int mode, 633141cc406Sopenharmony_ci unsigned int start, unsigned int width) 634141cc406Sopenharmony_ci{ 635141cc406Sopenharmony_ci unsigned int i, j, shift, step; 636141cc406Sopenharmony_ci 637141cc406Sopenharmony_ci DBG (DBG_proc, "build_correction: start=%d, width=%d\n", start, width); 638141cc406Sopenharmony_ci DBG (DBG_trace, "build_correction: dpi=%d, mode=%d\n", dpi, mode); 639141cc406Sopenharmony_ci 640141cc406Sopenharmony_ci /* loop on calibration data to find the matching one */ 641141cc406Sopenharmony_ci j = 0; 642141cc406Sopenharmony_ci while (dev->calibration_data[j]->dpi != dpi) 643141cc406Sopenharmony_ci { 644141cc406Sopenharmony_ci j++; 645141cc406Sopenharmony_ci if (j > MAX_RESOLUTIONS) 646141cc406Sopenharmony_ci { 647141cc406Sopenharmony_ci DBG (DBG_error, "build_correction: couldn't find calibration!\n"); 648141cc406Sopenharmony_ci return SANE_STATUS_INVAL; 649141cc406Sopenharmony_ci } 650141cc406Sopenharmony_ci } 651141cc406Sopenharmony_ci 652141cc406Sopenharmony_ci if (dev->gain != NULL) 653141cc406Sopenharmony_ci { 654141cc406Sopenharmony_ci free (dev->gain); 655141cc406Sopenharmony_ci dev->gain = NULL; 656141cc406Sopenharmony_ci } 657141cc406Sopenharmony_ci if (dev->offset != NULL) 658141cc406Sopenharmony_ci { 659141cc406Sopenharmony_ci free (dev->offset); 660141cc406Sopenharmony_ci dev->offset = NULL; 661141cc406Sopenharmony_ci } 662141cc406Sopenharmony_ci dev->gain = (float *) malloc (width * sizeof (float)); 663141cc406Sopenharmony_ci if (dev->gain == NULL) 664141cc406Sopenharmony_ci { 665141cc406Sopenharmony_ci DBG (DBG_error, 666141cc406Sopenharmony_ci "build_correction: failed to allocate memory for gain!\n"); 667141cc406Sopenharmony_ci return SANE_STATUS_NO_MEM; 668141cc406Sopenharmony_ci } 669141cc406Sopenharmony_ci dev->offset = (uint8_t *) malloc (width); 670141cc406Sopenharmony_ci if (dev->offset == NULL) 671141cc406Sopenharmony_ci { 672141cc406Sopenharmony_ci DBG (DBG_error, 673141cc406Sopenharmony_ci "build_correction: failed to allocate memory for offset!\n"); 674141cc406Sopenharmony_ci return SANE_STATUS_NO_MEM; 675141cc406Sopenharmony_ci } 676141cc406Sopenharmony_ci 677141cc406Sopenharmony_ci /* compute starting point of calibration data to use */ 678141cc406Sopenharmony_ci shift = start; 679141cc406Sopenharmony_ci step = 1; 680141cc406Sopenharmony_ci if (mode == MODE_GRAY) 681141cc406Sopenharmony_ci { 682141cc406Sopenharmony_ci /* we use green data */ 683141cc406Sopenharmony_ci shift += 1; 684141cc406Sopenharmony_ci step = 3; 685141cc406Sopenharmony_ci } 686141cc406Sopenharmony_ci for (i = 0; i < width; i += step) 687141cc406Sopenharmony_ci { 688141cc406Sopenharmony_ci if (dev->calibration_data[j]->white_data[shift + i] - 689141cc406Sopenharmony_ci dev->calibration_data[0]->black_data[shift + i] > BLACK_LEVEL) 690141cc406Sopenharmony_ci { 691141cc406Sopenharmony_ci dev->gain[i] = 692141cc406Sopenharmony_ci WHITE_TARGET / 693141cc406Sopenharmony_ci ((float) 694141cc406Sopenharmony_ci (dev->calibration_data[j]->white_data[shift + i] - 695141cc406Sopenharmony_ci dev->calibration_data[j]->black_data[shift + i])); 696141cc406Sopenharmony_ci dev->offset[i] = dev->calibration_data[j]->black_data[shift + i]; 697141cc406Sopenharmony_ci } 698141cc406Sopenharmony_ci else 699141cc406Sopenharmony_ci { 700141cc406Sopenharmony_ci dev->gain[i] = 1.0; 701141cc406Sopenharmony_ci dev->offset[i] = 0; 702141cc406Sopenharmony_ci } 703141cc406Sopenharmony_ci } 704141cc406Sopenharmony_ci return SANE_STATUS_GOOD; 705141cc406Sopenharmony_ci DBG (DBG_proc, "build_correction: end\n"); 706141cc406Sopenharmony_ci} 707141cc406Sopenharmony_ci 708141cc406Sopenharmony_ci/** @brief start up a real scan 709141cc406Sopenharmony_ci * This function starts the scan with the given parameters. 710141cc406Sopenharmony_ci * @param dev device describing hardware 711141cc406Sopenharmony_ci * @param mode color, gray level or lineart. 712141cc406Sopenharmony_ci * @param dpi desired scan resolution. 713141cc406Sopenharmony_ci * @param startx coordinate of the first pixel to scan in 714141cc406Sopenharmony_ci * scan's resolution coordinate 715141cc406Sopenharmony_ci * @param width width of the scanned area 716141cc406Sopenharmony_ci * scanner's physical scan aread. 717141cc406Sopenharmony_ci * @return SANE_STATUS_GOOD if scan is successfully started 718141cc406Sopenharmony_ci */ 719141cc406Sopenharmony_cistatic SANE_Status 720141cc406Sopenharmony_cistart_scan (P5_Device * dev, int mode, unsigned int dpi, unsigned int startx, 721141cc406Sopenharmony_ci unsigned int width) 722141cc406Sopenharmony_ci{ 723141cc406Sopenharmony_ci uint8_t reg0=0; 724141cc406Sopenharmony_ci uint8_t reg2=0; 725141cc406Sopenharmony_ci uint8_t regF=0; 726141cc406Sopenharmony_ci uint16_t addr=0; 727141cc406Sopenharmony_ci uint16_t start, end; 728141cc406Sopenharmony_ci unsigned int xdpi; 729141cc406Sopenharmony_ci 730141cc406Sopenharmony_ci DBG (DBG_proc, "start_scan: start \n"); 731141cc406Sopenharmony_ci DBG (DBG_io, "start_scan: startx=%d, width=%d, dpi=%d\n", startx, width, 732141cc406Sopenharmony_ci dpi); 733141cc406Sopenharmony_ci 734141cc406Sopenharmony_ci /** @brief register values 735141cc406Sopenharmony_ci * - reg2 : reg2 seems related to x dpi and provides only 100, 736141cc406Sopenharmony_ci * 150, 200 and 300 resolutions. 737141cc406Sopenharmony_ci * - regF : lower nibble gives y dpi resolution ranging from 150 738141cc406Sopenharmony_ci * to 1200 dpi. 739141cc406Sopenharmony_ci */ 740141cc406Sopenharmony_ci xdpi = dpi; 741141cc406Sopenharmony_ci switch (dpi) 742141cc406Sopenharmony_ci { 743141cc406Sopenharmony_ci case 100: 744141cc406Sopenharmony_ci reg2 = 0x90; 745141cc406Sopenharmony_ci regF = 0xA2; 746141cc406Sopenharmony_ci break; 747141cc406Sopenharmony_ci case 150: 748141cc406Sopenharmony_ci reg2 = 0x10; 749141cc406Sopenharmony_ci regF = 0xA4; 750141cc406Sopenharmony_ci break; 751141cc406Sopenharmony_ci case 200: 752141cc406Sopenharmony_ci reg2 = 0x80; 753141cc406Sopenharmony_ci regF = 0xA6; 754141cc406Sopenharmony_ci break; 755141cc406Sopenharmony_ci case 300: 756141cc406Sopenharmony_ci reg2 = 0x00; 757141cc406Sopenharmony_ci regF = 0xA8; 758141cc406Sopenharmony_ci break; 759141cc406Sopenharmony_ci case 400: 760141cc406Sopenharmony_ci reg2 = 0x80; /* xdpi=200 */ 761141cc406Sopenharmony_ci regF = 0xAA; 762141cc406Sopenharmony_ci xdpi = 200; 763141cc406Sopenharmony_ci break; 764141cc406Sopenharmony_ci case 500: 765141cc406Sopenharmony_ci reg2 = 0x00; 766141cc406Sopenharmony_ci regF = 0xAC; 767141cc406Sopenharmony_ci xdpi = 300; 768141cc406Sopenharmony_ci break; 769141cc406Sopenharmony_ci case 600: 770141cc406Sopenharmony_ci reg2 = 0x00; 771141cc406Sopenharmony_ci regF = 0xAE; 772141cc406Sopenharmony_ci xdpi = 300; 773141cc406Sopenharmony_ci break; 774141cc406Sopenharmony_ci } 775141cc406Sopenharmony_ci 776141cc406Sopenharmony_ci switch (mode) 777141cc406Sopenharmony_ci { 778141cc406Sopenharmony_ci case MODE_COLOR: 779141cc406Sopenharmony_ci reg0 = 0x00; 780141cc406Sopenharmony_ci addr = 0x0100; 781141cc406Sopenharmony_ci break; 782141cc406Sopenharmony_ci case MODE_GRAY: 783141cc406Sopenharmony_ci /* green channel only */ 784141cc406Sopenharmony_ci reg0 = 0x20; 785141cc406Sopenharmony_ci addr = 0x0100; 786141cc406Sopenharmony_ci break; 787141cc406Sopenharmony_ci case MODE_LINEART: 788141cc406Sopenharmony_ci reg0 = 0x40; 789141cc406Sopenharmony_ci addr = 0x0908; 790141cc406Sopenharmony_ci break; 791141cc406Sopenharmony_ci } 792141cc406Sopenharmony_ci 793141cc406Sopenharmony_ci write_reg (dev->fd, REG1, 0x01); 794141cc406Sopenharmony_ci write_reg (dev->fd, REG7, 0x00); 795141cc406Sopenharmony_ci write_reg (dev->fd, REG0, reg0); 796141cc406Sopenharmony_ci write_reg (dev->fd, REG1, 0x00); 797141cc406Sopenharmony_ci write_reg (dev->fd, REGF, regF); 798141cc406Sopenharmony_ci /* the memory addr used to test need not to be related 799141cc406Sopenharmony_ci * to resolution, 0x0100 could be always used */ 800141cc406Sopenharmony_ci /* TODO get rid of it */ 801141cc406Sopenharmony_ci memtest (dev->fd, addr); 802141cc406Sopenharmony_ci 803141cc406Sopenharmony_ci /* handle case where dpi>xdpi */ 804141cc406Sopenharmony_ci start = startx; 805141cc406Sopenharmony_ci if (dpi > xdpi) 806141cc406Sopenharmony_ci { 807141cc406Sopenharmony_ci width = (width * xdpi) / dpi; 808141cc406Sopenharmony_ci start = (startx * xdpi) / dpi; 809141cc406Sopenharmony_ci } 810141cc406Sopenharmony_ci 811141cc406Sopenharmony_ci /* compute and set start addr */ 812141cc406Sopenharmony_ci if (mode == MODE_COLOR) 813141cc406Sopenharmony_ci { 814141cc406Sopenharmony_ci start = start * 3; 815141cc406Sopenharmony_ci width = width * 3; 816141cc406Sopenharmony_ci } 817141cc406Sopenharmony_ci end = start + width + 1; 818141cc406Sopenharmony_ci 819141cc406Sopenharmony_ci /* build calibration data for the scan */ 820141cc406Sopenharmony_ci if (dev->calibrated) 821141cc406Sopenharmony_ci { 822141cc406Sopenharmony_ci build_correction (dev, xdpi, mode, start, width); 823141cc406Sopenharmony_ci } 824141cc406Sopenharmony_ci 825141cc406Sopenharmony_ci setadresses (dev->fd, start, end); 826141cc406Sopenharmony_ci 827141cc406Sopenharmony_ci write_reg (dev->fd, REG1, addr >> 8); 828141cc406Sopenharmony_ci write_reg (dev->fd, REG2, reg2); 829141cc406Sopenharmony_ci regF = (regF & 0x0F) | 0x80; 830141cc406Sopenharmony_ci write_reg (dev->fd, REGF, regF); 831141cc406Sopenharmony_ci write_reg (dev->fd, REG0, reg0); 832141cc406Sopenharmony_ci if (mode == MODE_LINEART) 833141cc406Sopenharmony_ci { 834141cc406Sopenharmony_ci write_reg (dev->fd, 0x07, 0x04); 835141cc406Sopenharmony_ci } 836141cc406Sopenharmony_ci else 837141cc406Sopenharmony_ci { 838141cc406Sopenharmony_ci write_reg (dev->fd, 0x07, 0x00); 839141cc406Sopenharmony_ci } 840141cc406Sopenharmony_ci write_reg (dev->fd, REG1, addr >> 8); 841141cc406Sopenharmony_ci write_reg2 (dev->fd, REG1, addr); 842141cc406Sopenharmony_ci write_reg (dev->fd, REGF, regF | 0x01); 843141cc406Sopenharmony_ci write_reg (dev->fd, REG0, reg0 | 0x0C); 844141cc406Sopenharmony_ci if (mode == MODE_LINEART) 845141cc406Sopenharmony_ci { 846141cc406Sopenharmony_ci write_reg (dev->fd, REG1, 0x19); 847141cc406Sopenharmony_ci } 848141cc406Sopenharmony_ci else 849141cc406Sopenharmony_ci { 850141cc406Sopenharmony_ci write_reg (dev->fd, REG1, 0x11); 851141cc406Sopenharmony_ci } 852141cc406Sopenharmony_ci DBG (DBG_proc, "start_scan: exit\n"); 853141cc406Sopenharmony_ci return SANE_STATUS_GOOD; 854141cc406Sopenharmony_ci} 855141cc406Sopenharmony_ci 856141cc406Sopenharmony_ci/** read a line of scan data 857141cc406Sopenharmony_ci * @param dev device to read 858141cc406Sopenharmony_ci * @param data pointer where to store data 859141cc406Sopenharmony_ci * @param length total bytes to read on one line 860141cc406Sopenharmony_ci * @param ltr total number of lines to read 861141cc406Sopenharmony_ci * @param retry signals that the function must read as much lines it can 862141cc406Sopenharmony_ci * @param x2 tells that lines must be enlarged by a 2 factor 863141cc406Sopenharmony_ci * @param mode COLOR_MODE if color mode 864141cc406Sopenharmony_ci * @returns number of data lines read, -1 in case of error 865141cc406Sopenharmony_ci */ 866141cc406Sopenharmony_cistatic int 867141cc406Sopenharmony_ciread_line (P5_Device * dev, uint8_t * data, size_t length, int ltr, 868141cc406Sopenharmony_ci SANE_Bool retry, SANE_Bool x2, int mode, SANE_Bool correction) 869141cc406Sopenharmony_ci{ 870141cc406Sopenharmony_ci uint8_t counter, read, cnt; 871141cc406Sopenharmony_ci uint8_t inbuffer[MAX_SENSOR_PIXELS * 2 * 3 + 2]; 872141cc406Sopenharmony_ci unsigned int i, factor; 873141cc406Sopenharmony_ci float val; 874141cc406Sopenharmony_ci 875141cc406Sopenharmony_ci DBG (DBG_proc, "read_line: trying to read %d lines of %lu bytes\n", ltr, 876141cc406Sopenharmony_ci (unsigned long)length); 877141cc406Sopenharmony_ci 878141cc406Sopenharmony_ci counter = read_reg (dev->fd, REG9); 879141cc406Sopenharmony_ci DBG (DBG_io, "read_line: %d bytes available\n", counter * 256); 880141cc406Sopenharmony_ci read = 0; 881141cc406Sopenharmony_ci if (x2 == SANE_FALSE) 882141cc406Sopenharmony_ci { 883141cc406Sopenharmony_ci factor = 1; 884141cc406Sopenharmony_ci } 885141cc406Sopenharmony_ci else 886141cc406Sopenharmony_ci { 887141cc406Sopenharmony_ci factor = 2; 888141cc406Sopenharmony_ci } 889141cc406Sopenharmony_ci 890141cc406Sopenharmony_ci /* in retry mode we read until not enough data, but in no retry 891141cc406Sopenharmony_ci * read only one line , counter give us 256 bytes block available 892141cc406Sopenharmony_ci * and we want an number multiple of color channels */ 893141cc406Sopenharmony_ci cnt = (255 + length / factor) / 256; 894141cc406Sopenharmony_ci while ((counter > cnt && retry == 1) || (counter > cnt && read == 0)) 895141cc406Sopenharmony_ci { 896141cc406Sopenharmony_ci /* read data from scanner, first and last byte aren't picture data */ 897141cc406Sopenharmony_ci read_data (dev->fd, inbuffer, length / factor + 2); 898141cc406Sopenharmony_ci 899141cc406Sopenharmony_ci /* image correction */ 900141cc406Sopenharmony_ci if (correction == SANE_TRUE) 901141cc406Sopenharmony_ci { 902141cc406Sopenharmony_ci for (i = 0; i < length / factor; i++) 903141cc406Sopenharmony_ci { 904141cc406Sopenharmony_ci val = inbuffer[i + 1] - dev->offset[i]; 905141cc406Sopenharmony_ci if (val > 0) 906141cc406Sopenharmony_ci { 907141cc406Sopenharmony_ci val = val * dev->gain[i]; 908141cc406Sopenharmony_ci if (val < 255) 909141cc406Sopenharmony_ci inbuffer[i + 1] = val; 910141cc406Sopenharmony_ci else 911141cc406Sopenharmony_ci inbuffer[i + 1] = 255; 912141cc406Sopenharmony_ci } 913141cc406Sopenharmony_ci else 914141cc406Sopenharmony_ci { 915141cc406Sopenharmony_ci inbuffer[i + 1] = 0; 916141cc406Sopenharmony_ci } 917141cc406Sopenharmony_ci } 918141cc406Sopenharmony_ci } 919141cc406Sopenharmony_ci 920141cc406Sopenharmony_ci /* handle horizontal data doubling */ 921141cc406Sopenharmony_ci if (x2 == SANE_FALSE) 922141cc406Sopenharmony_ci { 923141cc406Sopenharmony_ci memcpy (data + read * length, inbuffer + 1, length); 924141cc406Sopenharmony_ci } 925141cc406Sopenharmony_ci else 926141cc406Sopenharmony_ci { 927141cc406Sopenharmony_ci if (mode == MODE_COLOR) 928141cc406Sopenharmony_ci { 929141cc406Sopenharmony_ci for (i = 0; i < length / factor; i += 3) 930141cc406Sopenharmony_ci { 931141cc406Sopenharmony_ci data[read * length + i * factor] = inbuffer[i + 1]; 932141cc406Sopenharmony_ci data[read * length + i * factor + 1] = inbuffer[i + 2]; 933141cc406Sopenharmony_ci data[read * length + i * factor + 2] = inbuffer[i + 3]; 934141cc406Sopenharmony_ci data[read * length + i * factor + 3] = inbuffer[i + 1]; 935141cc406Sopenharmony_ci data[read * length + i * factor + 4] = inbuffer[i + 2]; 936141cc406Sopenharmony_ci data[read * length + i * factor + 5] = inbuffer[i + 3]; 937141cc406Sopenharmony_ci } 938141cc406Sopenharmony_ci } 939141cc406Sopenharmony_ci else 940141cc406Sopenharmony_ci { 941141cc406Sopenharmony_ci for (i = 0; i < length / factor; i++) 942141cc406Sopenharmony_ci { 943141cc406Sopenharmony_ci data[read * length + i * factor] = inbuffer[i + 1]; 944141cc406Sopenharmony_ci data[read * length + i * factor + 1] = inbuffer[i + 1]; 945141cc406Sopenharmony_ci } 946141cc406Sopenharmony_ci } 947141cc406Sopenharmony_ci } 948141cc406Sopenharmony_ci read++; 949141cc406Sopenharmony_ci if (retry == SANE_TRUE) 950141cc406Sopenharmony_ci { 951141cc406Sopenharmony_ci read_reg (dev->fd, REGF); 952141cc406Sopenharmony_ci read_reg (dev->fd, REGA); 953141cc406Sopenharmony_ci read_reg (dev->fd, REG9); 954141cc406Sopenharmony_ci counter = read_reg (dev->fd, REG9); 955141cc406Sopenharmony_ci read_reg (dev->fd, REGA); 956141cc406Sopenharmony_ci if (read >= ltr) 957141cc406Sopenharmony_ci { 958141cc406Sopenharmony_ci DBG (DBG_io, "read_line returning %d lines\n", read); 959141cc406Sopenharmony_ci return read; 960141cc406Sopenharmony_ci } 961141cc406Sopenharmony_ci counter = read_reg (dev->fd, REG9); 962141cc406Sopenharmony_ci } 963141cc406Sopenharmony_ci } 964141cc406Sopenharmony_ci read_reg (dev->fd, REGF); 965141cc406Sopenharmony_ci read_reg (dev->fd, REGA); 966141cc406Sopenharmony_ci read_reg (dev->fd, REG9); 967141cc406Sopenharmony_ci counter = read_reg (dev->fd, REG9); 968141cc406Sopenharmony_ci read_reg (dev->fd, REGA); 969141cc406Sopenharmony_ci DBG (DBG_io, "read_line returning %d lines\n", read); 970141cc406Sopenharmony_ci return read; 971141cc406Sopenharmony_ci} 972141cc406Sopenharmony_ci 973141cc406Sopenharmony_ci 974141cc406Sopenharmony_cistatic SANE_Status 975141cc406Sopenharmony_cieject (int fd) 976141cc406Sopenharmony_ci{ 977141cc406Sopenharmony_ci int detector; 978141cc406Sopenharmony_ci 979141cc406Sopenharmony_ci DBG (DBG_proc, "eject: start ...\n"); 980141cc406Sopenharmony_ci 981141cc406Sopenharmony_ci do 982141cc406Sopenharmony_ci { 983141cc406Sopenharmony_ci write_reg2 (fd, REG1, 0x1110); 984141cc406Sopenharmony_ci detector = read_reg (fd, REGE); 985141cc406Sopenharmony_ci detector = read_reg (fd, REGE); 986141cc406Sopenharmony_ci } 987141cc406Sopenharmony_ci while ((detector & 0x04) != 0); 988141cc406Sopenharmony_ci write_reg (fd, REG0, 0x00); 989141cc406Sopenharmony_ci write_reg (fd, REG1, 0x00); 990141cc406Sopenharmony_ci write_reg (fd, REGF, 0x82); 991141cc406Sopenharmony_ci write_reg (fd, REG7, 0x00); 992141cc406Sopenharmony_ci 993141cc406Sopenharmony_ci DBG (DBG_proc, "eject: end.\n"); 994141cc406Sopenharmony_ci return SANE_STATUS_GOOD; 995141cc406Sopenharmony_ci} 996141cc406Sopenharmony_ci 997141cc406Sopenharmony_ci/** @brief wait for document to be present in feeder 998141cc406Sopenharmony_ci * Polls document sensor until something is present. Give up after 20 seconds 999141cc406Sopenharmony_ci * @param fd file descriptor of the physical device 1000141cc406Sopenharmony_ci */ 1001141cc406Sopenharmony_ci/* static int 1002141cc406Sopenharmony_ciwait_document (int fd, uint8_t detector) 1003141cc406Sopenharmony_ci{ 1004141cc406Sopenharmony_ci int count = 0; 1005141cc406Sopenharmony_ci uint8_t val; 1006141cc406Sopenharmony_ci 1007141cc406Sopenharmony_ci write_reg (fd, REG1, 0x00); 1008141cc406Sopenharmony_ci write_reg (fd, REG7, 0x00); 1009141cc406Sopenharmony_ci detector = read_reg (fd, REGE); 1010141cc406Sopenharmony_ci while (detector == 0xc3 && count < 20) 1011141cc406Sopenharmony_ci { 1012141cc406Sopenharmony_ci sleep (1); 1013141cc406Sopenharmony_ci count++; 1014141cc406Sopenharmony_ci detector = read_reg (fd, REGE); 1015141cc406Sopenharmony_ci } 1016141cc406Sopenharmony_ci setadresses (fd, 0x002d, 0x09c7); 1017141cc406Sopenharmony_ci write_reg (fd, REG1, 0x00); 1018141cc406Sopenharmony_ci write_reg (fd, REG2, 0x90); 1019141cc406Sopenharmony_ci write_reg (fd, REGF, 0x82); 1020141cc406Sopenharmony_ci write_reg (fd, REG0, 0x00); 1021141cc406Sopenharmony_ci val = p5_inb (fd, STATUS) & 0xf8; 1022141cc406Sopenharmony_ci if (val != 0xf8) 1023141cc406Sopenharmony_ci { 1024141cc406Sopenharmony_ci DBG (DBG_error, "wait_document: unexpected STATUS value 0x%02x instead of 0xf8", val); 1025141cc406Sopenharmony_ci } 1026141cc406Sopenharmony_ci if (count >= 20) 1027141cc406Sopenharmony_ci { 1028141cc406Sopenharmony_ci DBG (DBG_error, "wait_document: failed to detect document!\n"); 1029141cc406Sopenharmony_ci return 0; 1030141cc406Sopenharmony_ci } 1031141cc406Sopenharmony_ci return 1; 1032141cc406Sopenharmony_ci} */ 1033141cc406Sopenharmony_ci 1034141cc406Sopenharmony_ci/** @brief move at 150 dpi 1035141cc406Sopenharmony_ci * move the paper at 150 dpi motor speed by the amount specified 1036141cc406Sopenharmony_ci * @params dev pointer to the device structure 1037141cc406Sopenharmony_ci */ 1038141cc406Sopenharmony_cistatic SANE_Status 1039141cc406Sopenharmony_cimove (P5_Device * dev) 1040141cc406Sopenharmony_ci{ 1041141cc406Sopenharmony_ci int skip, done, read, count; 1042141cc406Sopenharmony_ci SANE_Status status = SANE_STATUS_GOOD; 1043141cc406Sopenharmony_ci unsigned char buffer[256]; 1044141cc406Sopenharmony_ci 1045141cc406Sopenharmony_ci DBG (DBG_proc, "move: start\n"); 1046141cc406Sopenharmony_ci 1047141cc406Sopenharmony_ci /* compute number of lines to skip */ 1048141cc406Sopenharmony_ci skip = dev->ystart; 1049141cc406Sopenharmony_ci 1050141cc406Sopenharmony_ci /* works, but remains to be explained ... */ 1051141cc406Sopenharmony_ci if (dev->ydpi > 300) 1052141cc406Sopenharmony_ci skip = skip / 2; 1053141cc406Sopenharmony_ci 1054141cc406Sopenharmony_ci DBG (DBG_io, "move: skipping %d lines at %d dpi\n", skip, dev->ydpi); 1055141cc406Sopenharmony_ci 1056141cc406Sopenharmony_ci /* we do a real scan of small width, discarding data */ 1057141cc406Sopenharmony_ci done = 0; 1058141cc406Sopenharmony_ci status = start_scan (dev, MODE_GRAY, dev->ydpi, 0, 256); 1059141cc406Sopenharmony_ci if (status != SANE_STATUS_GOOD) 1060141cc406Sopenharmony_ci { 1061141cc406Sopenharmony_ci DBG (DBG_error, "move: failed to start scan\n"); 1062141cc406Sopenharmony_ci return SANE_STATUS_INVAL; 1063141cc406Sopenharmony_ci } 1064141cc406Sopenharmony_ci 1065141cc406Sopenharmony_ci do 1066141cc406Sopenharmony_ci { 1067141cc406Sopenharmony_ci /* test if document left the feeder */ 1068141cc406Sopenharmony_ci status = test_document (dev->fd); 1069141cc406Sopenharmony_ci if (status == SANE_STATUS_NO_DOCS) 1070141cc406Sopenharmony_ci { 1071141cc406Sopenharmony_ci DBG (DBG_info, 1072141cc406Sopenharmony_ci "move: document was shorter than the required move\n"); 1073141cc406Sopenharmony_ci return SANE_STATUS_INVAL; 1074141cc406Sopenharmony_ci } 1075141cc406Sopenharmony_ci /* test if data is available */ 1076141cc406Sopenharmony_ci count = available_bytes (dev->fd); 1077141cc406Sopenharmony_ci if (count) 1078141cc406Sopenharmony_ci { 1079141cc406Sopenharmony_ci read = 1080141cc406Sopenharmony_ci read_line (dev, buffer, 256, 1, SANE_FALSE, SANE_FALSE, 1081141cc406Sopenharmony_ci MODE_GRAY, SANE_FALSE); 1082141cc406Sopenharmony_ci if (read == -1) 1083141cc406Sopenharmony_ci { 1084141cc406Sopenharmony_ci DBG (DBG_error, "move: failed to read data\n"); 1085141cc406Sopenharmony_ci return SANE_STATUS_INVAL; 1086141cc406Sopenharmony_ci } 1087141cc406Sopenharmony_ci done += read; 1088141cc406Sopenharmony_ci } 1089141cc406Sopenharmony_ci } 1090141cc406Sopenharmony_ci while (done < skip); 1091141cc406Sopenharmony_ci 1092141cc406Sopenharmony_ci /* reset scanner */ 1093141cc406Sopenharmony_ci write_reg2 (dev->fd, REG1, 0x1110); 1094141cc406Sopenharmony_ci count = read_reg (dev->fd, REGE); 1095141cc406Sopenharmony_ci count = read_reg (dev->fd, REGE); 1096141cc406Sopenharmony_ci write_reg (dev->fd, REG0, 0x00); 1097141cc406Sopenharmony_ci write_reg (dev->fd, REG1, 0x00); 1098141cc406Sopenharmony_ci write_reg (dev->fd, REGF, 0x82); 1099141cc406Sopenharmony_ci write_reg (dev->fd, REG7, 0x00); 1100141cc406Sopenharmony_ci 1101141cc406Sopenharmony_ci DBG (DBG_proc, "move: exit\n"); 1102141cc406Sopenharmony_ci return status; 1103141cc406Sopenharmony_ci} 1104141cc406Sopenharmony_ci 1105141cc406Sopenharmony_ci/** clean up calibration data 1106141cc406Sopenharmony_ci * @param dev device to clean up 1107141cc406Sopenharmony_ci */ 1108141cc406Sopenharmony_cistatic void 1109141cc406Sopenharmony_cicleanup_calibration (P5_Device * dev) 1110141cc406Sopenharmony_ci{ 1111141cc406Sopenharmony_ci int i; 1112141cc406Sopenharmony_ci 1113141cc406Sopenharmony_ci for (i = 0; i < MAX_RESOLUTIONS * 2; i++) 1114141cc406Sopenharmony_ci { 1115141cc406Sopenharmony_ci if (dev->calibration_data[i] != NULL) 1116141cc406Sopenharmony_ci { 1117141cc406Sopenharmony_ci free (dev->calibration_data[i]); 1118141cc406Sopenharmony_ci dev->calibration_data[i] = NULL; 1119141cc406Sopenharmony_ci } 1120141cc406Sopenharmony_ci } 1121141cc406Sopenharmony_ci dev->calibrated = SANE_FALSE; 1122141cc406Sopenharmony_ci} 1123141cc406Sopenharmony_ci 1124141cc406Sopenharmony_ci/** detect a black scan line 1125141cc406Sopenharmony_ci * parses the given buffer and return SANE_TRUE if the line is an 1126141cc406Sopenharmony_ci * acceptable black line for calibration 1127141cc406Sopenharmony_ci * @param buffer data line to parse 1128141cc406Sopenharmony_ci * @param pixels number of pixels 1129141cc406Sopenharmony_ci * @param mode MODE_COLOR or MODE_GRAY 1130141cc406Sopenharmony_ci * @returns SANE_TRUE if it is considered as a white line 1131141cc406Sopenharmony_ci */ 1132141cc406Sopenharmony_cistatic SANE_Bool 1133141cc406Sopenharmony_ciis_black_line (uint8_t * buffer, unsigned int pixels, int mode) 1134141cc406Sopenharmony_ci{ 1135141cc406Sopenharmony_ci unsigned int i, start, end, count, width; 1136141cc406Sopenharmony_ci 1137141cc406Sopenharmony_ci /* compute width in bytes */ 1138141cc406Sopenharmony_ci if (mode == MODE_COLOR) 1139141cc406Sopenharmony_ci { 1140141cc406Sopenharmony_ci width = pixels * 3; 1141141cc406Sopenharmony_ci } 1142141cc406Sopenharmony_ci else 1143141cc406Sopenharmony_ci { 1144141cc406Sopenharmony_ci width = pixels; 1145141cc406Sopenharmony_ci } 1146141cc406Sopenharmony_ci 1147141cc406Sopenharmony_ci /* we allow the calibration target to be narrower than full width, ie 1148141cc406Sopenharmony_ci * black margin at both ends of the line */ 1149141cc406Sopenharmony_ci start = (5 * width) / 100; 1150141cc406Sopenharmony_ci end = (95 * width) / 100; 1151141cc406Sopenharmony_ci count = 0; 1152141cc406Sopenharmony_ci 1153141cc406Sopenharmony_ci /* count number of black bytes */ 1154141cc406Sopenharmony_ci for (i = start; i < end; i++) 1155141cc406Sopenharmony_ci { 1156141cc406Sopenharmony_ci if (buffer[i] > BLACK_LEVEL) 1157141cc406Sopenharmony_ci { 1158141cc406Sopenharmony_ci count++; 1159141cc406Sopenharmony_ci } 1160141cc406Sopenharmony_ci } 1161141cc406Sopenharmony_ci 1162141cc406Sopenharmony_ci /* we allow 3% black pixels maximum */ 1163141cc406Sopenharmony_ci if (count > (3 * width) / 100) 1164141cc406Sopenharmony_ci { 1165141cc406Sopenharmony_ci DBG (DBG_io, "is_black_line=SANE_FALSE\n"); 1166141cc406Sopenharmony_ci return SANE_FALSE; 1167141cc406Sopenharmony_ci } 1168141cc406Sopenharmony_ci 1169141cc406Sopenharmony_ci DBG (DBG_io, "is_black_line=SANE_TRUE\n"); 1170141cc406Sopenharmony_ci return SANE_TRUE; 1171141cc406Sopenharmony_ci} 1172141cc406Sopenharmony_ci 1173141cc406Sopenharmony_ci/** detect a white scan line 1174141cc406Sopenharmony_ci * parses the given buffer and return SANE_TRUE if the line is an 1175141cc406Sopenharmony_ci * acceptable white line for calibration 1176141cc406Sopenharmony_ci * @param buffer data line to parse 1177141cc406Sopenharmony_ci * @param pixels number of pixels 1178141cc406Sopenharmony_ci * @param mode MODE_COLOR or MODE_GRAY 1179141cc406Sopenharmony_ci * @returns SANE_TRUE if it is considered as a white line 1180141cc406Sopenharmony_ci */ 1181141cc406Sopenharmony_cistatic SANE_Bool 1182141cc406Sopenharmony_ciis_white_line (uint8_t * buffer, unsigned int pixels, int mode) 1183141cc406Sopenharmony_ci{ 1184141cc406Sopenharmony_ci unsigned int i, start, end, count, width; 1185141cc406Sopenharmony_ci 1186141cc406Sopenharmony_ci /* compute width in bytes */ 1187141cc406Sopenharmony_ci if (mode == MODE_COLOR) 1188141cc406Sopenharmony_ci { 1189141cc406Sopenharmony_ci width = pixels * 3; 1190141cc406Sopenharmony_ci } 1191141cc406Sopenharmony_ci else 1192141cc406Sopenharmony_ci { 1193141cc406Sopenharmony_ci width = pixels; 1194141cc406Sopenharmony_ci } 1195141cc406Sopenharmony_ci 1196141cc406Sopenharmony_ci /* we allow the calibration target to be narrower than full width, ie 1197141cc406Sopenharmony_ci * black margin at both ends of the line */ 1198141cc406Sopenharmony_ci start = (5 * width) / 100; 1199141cc406Sopenharmony_ci end = (95 * width) / 100; 1200141cc406Sopenharmony_ci count = 0; 1201141cc406Sopenharmony_ci 1202141cc406Sopenharmony_ci /* count number of black bytes */ 1203141cc406Sopenharmony_ci for (i = start; i < end; i++) 1204141cc406Sopenharmony_ci { 1205141cc406Sopenharmony_ci if (buffer[i] < BLACK_LEVEL) 1206141cc406Sopenharmony_ci { 1207141cc406Sopenharmony_ci count++; 1208141cc406Sopenharmony_ci } 1209141cc406Sopenharmony_ci } 1210141cc406Sopenharmony_ci 1211141cc406Sopenharmony_ci /* we allow 3% black pixels maximum */ 1212141cc406Sopenharmony_ci if (count > (3 * width) / 100) 1213141cc406Sopenharmony_ci { 1214141cc406Sopenharmony_ci DBG (DBG_io, "is_white_line=SANE_FALSE\n"); 1215141cc406Sopenharmony_ci return SANE_FALSE; 1216141cc406Sopenharmony_ci } 1217141cc406Sopenharmony_ci 1218141cc406Sopenharmony_ci DBG (DBG_io, "is_white_line=SANE_TRUE\n"); 1219141cc406Sopenharmony_ci return SANE_TRUE; 1220141cc406Sopenharmony_ci} 1221141cc406Sopenharmony_ci 1222141cc406Sopenharmony_ci/* ------------------------------------------------------------------------- */ 1223141cc406Sopenharmony_ci/* writes gray data to a pnm file */ 1224141cc406Sopenharmony_ci/* 1225141cc406Sopenharmony_cistatic void 1226141cc406Sopenharmony_ciwrite_gray_data (unsigned char *image, char *name, SANE_Int width, 1227141cc406Sopenharmony_ci SANE_Int height) 1228141cc406Sopenharmony_ci{ 1229141cc406Sopenharmony_ci FILE *fdbg = NULL; 1230141cc406Sopenharmony_ci 1231141cc406Sopenharmony_ci fdbg = fopen (name, "wb"); 1232141cc406Sopenharmony_ci if (fdbg == NULL) 1233141cc406Sopenharmony_ci return; 1234141cc406Sopenharmony_ci fprintf (fdbg, "P5\n%d %d\n255\n", width, height); 1235141cc406Sopenharmony_ci fwrite (image, width, height, fdbg); 1236141cc406Sopenharmony_ci fclose (fdbg); 1237141cc406Sopenharmony_ci} 1238141cc406Sopenharmony_ci*/ 1239141cc406Sopenharmony_ci 1240141cc406Sopenharmony_ci/* ------------------------------------------------------------------------- */ 1241141cc406Sopenharmony_ci/* writes rgb data to a pnm file */ 1242141cc406Sopenharmony_cistatic void 1243141cc406Sopenharmony_ciwrite_rgb_data (char *name, unsigned char *image, SANE_Int width, 1244141cc406Sopenharmony_ci SANE_Int height) 1245141cc406Sopenharmony_ci{ 1246141cc406Sopenharmony_ci FILE *fdbg = NULL; 1247141cc406Sopenharmony_ci 1248141cc406Sopenharmony_ci fdbg = fopen (name, "wb"); 1249141cc406Sopenharmony_ci if (fdbg == NULL) 1250141cc406Sopenharmony_ci return; 1251141cc406Sopenharmony_ci fprintf (fdbg, "P6\n%d %d\n255\n", width, height); 1252141cc406Sopenharmony_ci fwrite (image, width * 3, height, fdbg); 1253141cc406Sopenharmony_ci fclose (fdbg); 1254141cc406Sopenharmony_ci} 1255141cc406Sopenharmony_ci 1256141cc406Sopenharmony_ci/** give calibration file name 1257141cc406Sopenharmony_ci * computes the calibration file name to use based on the 1258141cc406Sopenharmony_ci * backend name and device 1259141cc406Sopenharmony_ci */ 1260141cc406Sopenharmony_cistatic char * 1261141cc406Sopenharmony_cicalibration_file (const char *devicename) 1262141cc406Sopenharmony_ci{ 1263141cc406Sopenharmony_ci char *ptr = NULL; 1264141cc406Sopenharmony_ci char tmp_str[PATH_MAX]; 1265141cc406Sopenharmony_ci 1266141cc406Sopenharmony_ci ptr = getenv ("HOME"); 1267141cc406Sopenharmony_ci if (ptr != NULL) 1268141cc406Sopenharmony_ci { 1269141cc406Sopenharmony_ci sprintf (tmp_str, "%s/.sane/p5-%s.cal", ptr, devicename); 1270141cc406Sopenharmony_ci } 1271141cc406Sopenharmony_ci else 1272141cc406Sopenharmony_ci { 1273141cc406Sopenharmony_ci ptr = getenv ("TMPDIR"); 1274141cc406Sopenharmony_ci if (ptr != NULL) 1275141cc406Sopenharmony_ci { 1276141cc406Sopenharmony_ci sprintf (tmp_str, "%s/p5-%s.cal", ptr, devicename); 1277141cc406Sopenharmony_ci } 1278141cc406Sopenharmony_ci else 1279141cc406Sopenharmony_ci { 1280141cc406Sopenharmony_ci sprintf (tmp_str, "/tmp/p5-%s.cal", devicename); 1281141cc406Sopenharmony_ci } 1282141cc406Sopenharmony_ci } 1283141cc406Sopenharmony_ci DBG (DBG_trace, "calibration_file: using >%s< for calibration file name\n", 1284141cc406Sopenharmony_ci tmp_str); 1285141cc406Sopenharmony_ci return strdup (tmp_str); 1286141cc406Sopenharmony_ci} 1287141cc406Sopenharmony_ci 1288141cc406Sopenharmony_ci/** restore calibration data 1289141cc406Sopenharmony_ci * restore calibration data by loading previously saved calibration data 1290141cc406Sopenharmony_ci * @param dev device to restore 1291141cc406Sopenharmony_ci * @return SANE_STATUS_GOOD on success, otherwise error code 1292141cc406Sopenharmony_ci */ 1293141cc406Sopenharmony_cistatic SANE_Status 1294141cc406Sopenharmony_cirestore_calibration (P5_Device * dev) 1295141cc406Sopenharmony_ci{ 1296141cc406Sopenharmony_ci SANE_Status status = SANE_STATUS_GOOD; 1297141cc406Sopenharmony_ci char *fname = NULL; 1298141cc406Sopenharmony_ci FILE *fcalib = NULL; 1299141cc406Sopenharmony_ci size_t size; 1300141cc406Sopenharmony_ci int i; 1301141cc406Sopenharmony_ci 1302141cc406Sopenharmony_ci DBG (DBG_proc, "restore_calibration: start\n"); 1303141cc406Sopenharmony_ci cleanup_calibration (dev); 1304141cc406Sopenharmony_ci fname = calibration_file (dev->model->name); 1305141cc406Sopenharmony_ci fcalib = fopen (fname, "rb"); 1306141cc406Sopenharmony_ci if (fcalib == NULL) 1307141cc406Sopenharmony_ci { 1308141cc406Sopenharmony_ci DBG (DBG_error, "restore_calibration: failed to open %s!\n", fname); 1309141cc406Sopenharmony_ci free (fname); 1310141cc406Sopenharmony_ci return SANE_STATUS_IO_ERROR; 1311141cc406Sopenharmony_ci } 1312141cc406Sopenharmony_ci 1313141cc406Sopenharmony_ci /* loop filling calibration data until EOF reached */ 1314141cc406Sopenharmony_ci i = 0; 1315141cc406Sopenharmony_ci while (!feof (fcalib) && (i < 2 * MAX_RESOLUTIONS)) 1316141cc406Sopenharmony_ci { 1317141cc406Sopenharmony_ci dev->calibration_data[i] = malloc (sizeof (P5_Calibration_Data)); 1318141cc406Sopenharmony_ci if (dev->calibration_data[i] == NULL) 1319141cc406Sopenharmony_ci { 1320141cc406Sopenharmony_ci cleanup_calibration (dev); 1321141cc406Sopenharmony_ci free (fname); 1322141cc406Sopenharmony_ci fclose (fcalib); 1323141cc406Sopenharmony_ci DBG (DBG_error, 1324141cc406Sopenharmony_ci "restore_calibration: failed to allocate memory for calibration\n"); 1325141cc406Sopenharmony_ci return SANE_STATUS_NO_MEM; 1326141cc406Sopenharmony_ci } 1327141cc406Sopenharmony_ci size = 1328141cc406Sopenharmony_ci fread (dev->calibration_data[i], 1, sizeof (P5_Calibration_Data), 1329141cc406Sopenharmony_ci fcalib); 1330141cc406Sopenharmony_ci if (feof (fcalib)) 1331141cc406Sopenharmony_ci { 1332141cc406Sopenharmony_ci free (dev->calibration_data[i]); 1333141cc406Sopenharmony_ci dev->calibration_data[i] = NULL; 1334141cc406Sopenharmony_ci } 1335141cc406Sopenharmony_ci else if (size != sizeof (P5_Calibration_Data)) 1336141cc406Sopenharmony_ci { 1337141cc406Sopenharmony_ci cleanup_calibration (dev); 1338141cc406Sopenharmony_ci free (fname); 1339141cc406Sopenharmony_ci fclose (fcalib); 1340141cc406Sopenharmony_ci DBG (DBG_error, "restore_calibration: failed to read from file\n"); 1341141cc406Sopenharmony_ci return SANE_STATUS_IO_ERROR; 1342141cc406Sopenharmony_ci } 1343141cc406Sopenharmony_ci DBG (DBG_trace, 1344141cc406Sopenharmony_ci "restore_calibration: read 1 calibration structure from file\n"); 1345141cc406Sopenharmony_ci i++; 1346141cc406Sopenharmony_ci } 1347141cc406Sopenharmony_ci 1348141cc406Sopenharmony_ci dev->calibrated = SANE_TRUE; 1349141cc406Sopenharmony_ci fclose (fcalib); 1350141cc406Sopenharmony_ci free (fname); 1351141cc406Sopenharmony_ci 1352141cc406Sopenharmony_ci DBG (DBG_proc, "restore_calibration: end\n"); 1353141cc406Sopenharmony_ci return status; 1354141cc406Sopenharmony_ci} 1355141cc406Sopenharmony_ci 1356141cc406Sopenharmony_ci/** save calibration data 1357141cc406Sopenharmony_ci * save calibration data from memory to file 1358141cc406Sopenharmony_ci * @param dev device calibration to save 1359141cc406Sopenharmony_ci * @return SANE_STATUS_GOOD on success, otherwise error code 1360141cc406Sopenharmony_ci */ 1361141cc406Sopenharmony_cistatic SANE_Status 1362141cc406Sopenharmony_cisave_calibration (P5_Device * dev) 1363141cc406Sopenharmony_ci{ 1364141cc406Sopenharmony_ci SANE_Status status = SANE_STATUS_GOOD; 1365141cc406Sopenharmony_ci char *fname = NULL; 1366141cc406Sopenharmony_ci FILE *fcalib = NULL; 1367141cc406Sopenharmony_ci int i; 1368141cc406Sopenharmony_ci size_t size; 1369141cc406Sopenharmony_ci 1370141cc406Sopenharmony_ci DBG (DBG_proc, "save_calibration: start\n"); 1371141cc406Sopenharmony_ci fname = calibration_file (dev->model->name); 1372141cc406Sopenharmony_ci fcalib = fopen (fname, "wb"); 1373141cc406Sopenharmony_ci if (fcalib == NULL) 1374141cc406Sopenharmony_ci { 1375141cc406Sopenharmony_ci DBG (DBG_error, "save_calibration: failed to open %s!\n", fname); 1376141cc406Sopenharmony_ci free (fname); 1377141cc406Sopenharmony_ci return SANE_STATUS_IO_ERROR; 1378141cc406Sopenharmony_ci } 1379141cc406Sopenharmony_ci 1380141cc406Sopenharmony_ci /* loop filling calibration data until EOF reached */ 1381141cc406Sopenharmony_ci i = 0; 1382141cc406Sopenharmony_ci while (dev->calibration_data[i] != NULL && (i < 2 * MAX_RESOLUTIONS)) 1383141cc406Sopenharmony_ci { 1384141cc406Sopenharmony_ci size = 1385141cc406Sopenharmony_ci fwrite (dev->calibration_data[i], sizeof (P5_Calibration_Data), 1, 1386141cc406Sopenharmony_ci fcalib); 1387141cc406Sopenharmony_ci if (size != sizeof (P5_Calibration_Data)) 1388141cc406Sopenharmony_ci { 1389141cc406Sopenharmony_ci free (fname); 1390141cc406Sopenharmony_ci fclose (fcalib); 1391141cc406Sopenharmony_ci DBG (DBG_error, "save_calibration: failed to write to file\n"); 1392141cc406Sopenharmony_ci return SANE_STATUS_IO_ERROR; 1393141cc406Sopenharmony_ci } 1394141cc406Sopenharmony_ci DBG (DBG_trace, 1395141cc406Sopenharmony_ci "save_calibration: wrote 1 calibration structure to file\n"); 1396141cc406Sopenharmony_ci i++; 1397141cc406Sopenharmony_ci } 1398141cc406Sopenharmony_ci 1399141cc406Sopenharmony_ci fclose (fcalib); 1400141cc406Sopenharmony_ci free (fname); 1401141cc406Sopenharmony_ci 1402141cc406Sopenharmony_ci DBG (DBG_proc, "save_calibration: end\n"); 1403141cc406Sopenharmony_ci return status; 1404141cc406Sopenharmony_ci} 1405141cc406Sopenharmony_ci 1406141cc406Sopenharmony_ci/** calibrate scanner 1407141cc406Sopenharmony_ci * calibrates scanner by scanning a white sheet to get 1408141cc406Sopenharmony_ci * reference data. The black reference data is extracted from the lines 1409141cc406Sopenharmony_ci * that precede the physical document. 1410141cc406Sopenharmony_ci * Calibration is done at 300 color, then data is built for other modes 1411141cc406Sopenharmony_ci * and resolutions. 1412141cc406Sopenharmony_ci * @param dev device to calibrate 1413141cc406Sopenharmony_ci */ 1414141cc406Sopenharmony_cistatic SANE_Status 1415141cc406Sopenharmony_cisheetfed_calibration (P5_Device * dev) 1416141cc406Sopenharmony_ci{ 1417141cc406Sopenharmony_ci uint8_t buffer[MAX_SENSOR_PIXELS * 3]; 1418141cc406Sopenharmony_ci uint16_t white_data[MAX_SENSOR_PIXELS * 3]; 1419141cc406Sopenharmony_ci uint16_t black_data[MAX_SENSOR_PIXELS * 3]; 1420141cc406Sopenharmony_ci unsigned int i, j, k, dpi, pixels, read, black, white; 1421141cc406Sopenharmony_ci float coeff; 1422141cc406Sopenharmony_ci unsigned int red, green, blue; 1423141cc406Sopenharmony_ci int line; 1424141cc406Sopenharmony_ci SANE_Status status; 1425141cc406Sopenharmony_ci char title[40]; 1426141cc406Sopenharmony_ci 1427141cc406Sopenharmony_ci FILE *dbg = fopen ("debug.pnm", "wb"); 1428141cc406Sopenharmony_ci fprintf (dbg, "P6\n%d %d\n255\n", MAX_SENSOR_PIXELS, 1429141cc406Sopenharmony_ci CALIBRATION_SKIP_LINES * 4); 1430141cc406Sopenharmony_ci 1431141cc406Sopenharmony_ci DBG (DBG_proc, "sheetfed_calibration: start\n"); 1432141cc406Sopenharmony_ci 1433141cc406Sopenharmony_ci /* check calibration target has been loaded in ADF */ 1434141cc406Sopenharmony_ci status = test_document (dev->fd); 1435141cc406Sopenharmony_ci if (status == SANE_STATUS_NO_DOCS) 1436141cc406Sopenharmony_ci { 1437141cc406Sopenharmony_ci DBG (DBG_error, 1438141cc406Sopenharmony_ci "sheetfed_calibration: no calibration target present!\n"); 1439141cc406Sopenharmony_ci return SANE_STATUS_NO_DOCS; 1440141cc406Sopenharmony_ci } 1441141cc406Sopenharmony_ci 1442141cc406Sopenharmony_ci /* clean up calibration data */ 1443141cc406Sopenharmony_ci cleanup_calibration (dev); 1444141cc406Sopenharmony_ci 1445141cc406Sopenharmony_ci /* a RGB scan to get reference data */ 1446141cc406Sopenharmony_ci /* initialize calibration slot for the resolution */ 1447141cc406Sopenharmony_ci i = 0; 1448141cc406Sopenharmony_ci dpi = dev->model->max_xdpi; 1449141cc406Sopenharmony_ci pixels = MAX_SENSOR_PIXELS; 1450141cc406Sopenharmony_ci dev->calibration_data[i] = 1451141cc406Sopenharmony_ci (P5_Calibration_Data *) malloc (sizeof (P5_Calibration_Data)); 1452141cc406Sopenharmony_ci if (dev->calibration_data[i] == NULL) 1453141cc406Sopenharmony_ci { 1454141cc406Sopenharmony_ci cleanup_calibration (dev); 1455141cc406Sopenharmony_ci DBG (DBG_error, 1456141cc406Sopenharmony_ci "sheetfed_calibration: failed to allocate memory for calibration\n"); 1457141cc406Sopenharmony_ci return SANE_STATUS_NO_MEM; 1458141cc406Sopenharmony_ci } 1459141cc406Sopenharmony_ci dev->calibration_data[i]->dpi = dpi; 1460141cc406Sopenharmony_ci 1461141cc406Sopenharmony_ci /* start scan */ 1462141cc406Sopenharmony_ci status = start_scan (dev, MODE_COLOR, dpi, 0, pixels); 1463141cc406Sopenharmony_ci if (status != SANE_STATUS_GOOD) 1464141cc406Sopenharmony_ci { 1465141cc406Sopenharmony_ci cleanup_calibration (dev); 1466141cc406Sopenharmony_ci DBG (DBG_error, 1467141cc406Sopenharmony_ci "sheetfed_calibration: failed to start scan at %d dpi\n", dpi); 1468141cc406Sopenharmony_ci return SANE_STATUS_INVAL; 1469141cc406Sopenharmony_ci } 1470141cc406Sopenharmony_ci 1471141cc406Sopenharmony_ci white = 0; 1472141cc406Sopenharmony_ci black = 0; 1473141cc406Sopenharmony_ci read = 0; 1474141cc406Sopenharmony_ci for (j = 0; j < pixels * 3; j++) 1475141cc406Sopenharmony_ci { 1476141cc406Sopenharmony_ci black_data[j] = 0; 1477141cc406Sopenharmony_ci white_data[j] = 0; 1478141cc406Sopenharmony_ci } 1479141cc406Sopenharmony_ci 1480141cc406Sopenharmony_ci /* read lines and gather black and white ones until enough for sensor's 1481141cc406Sopenharmony_ci * native resolution */ 1482141cc406Sopenharmony_ci do 1483141cc406Sopenharmony_ci { 1484141cc406Sopenharmony_ci status = test_document (dev->fd); 1485141cc406Sopenharmony_ci if (status == SANE_STATUS_NO_DOCS && (white < 10 || black < 10)) 1486141cc406Sopenharmony_ci { 1487141cc406Sopenharmony_ci cleanup_calibration (dev); 1488141cc406Sopenharmony_ci DBG (DBG_error, 1489141cc406Sopenharmony_ci "sheetfed_calibration: calibration sheet too short!\n"); 1490141cc406Sopenharmony_ci return SANE_STATUS_INVAL; 1491141cc406Sopenharmony_ci } 1492141cc406Sopenharmony_ci memset (buffer, 0x00, MAX_SENSOR_PIXELS * 3); 1493141cc406Sopenharmony_ci line = 1494141cc406Sopenharmony_ci read_line (dev, buffer, pixels * 3, 1, SANE_FALSE, SANE_FALSE, 1495141cc406Sopenharmony_ci MODE_COLOR, SANE_FALSE); 1496141cc406Sopenharmony_ci if (line == -1) 1497141cc406Sopenharmony_ci { 1498141cc406Sopenharmony_ci DBG (DBG_error, "sheetfed_calibration: failed to read data\n"); 1499141cc406Sopenharmony_ci return SANE_STATUS_INVAL; 1500141cc406Sopenharmony_ci } 1501141cc406Sopenharmony_ci 1502141cc406Sopenharmony_ci /* if a data line has been read, add it to reference data */ 1503141cc406Sopenharmony_ci if (line) 1504141cc406Sopenharmony_ci { 1505141cc406Sopenharmony_ci read++; 1506141cc406Sopenharmony_ci fwrite (buffer, pixels * 3, 1, dbg); 1507141cc406Sopenharmony_ci if (is_white_line (buffer, pixels, MODE_COLOR) && white < 256) 1508141cc406Sopenharmony_ci { 1509141cc406Sopenharmony_ci white++; 1510141cc406Sopenharmony_ci /* first calibration lines are skipped */ 1511141cc406Sopenharmony_ci for (j = 0; j < pixels * 3 && read > CALIBRATION_SKIP_LINES; 1512141cc406Sopenharmony_ci j++) 1513141cc406Sopenharmony_ci { 1514141cc406Sopenharmony_ci white_data[j] += buffer[j]; 1515141cc406Sopenharmony_ci } 1516141cc406Sopenharmony_ci } 1517141cc406Sopenharmony_ci if (is_black_line (buffer, pixels, MODE_COLOR) && black < 256) 1518141cc406Sopenharmony_ci { 1519141cc406Sopenharmony_ci black++; 1520141cc406Sopenharmony_ci for (j = 0; j < pixels * 3; j++) 1521141cc406Sopenharmony_ci { 1522141cc406Sopenharmony_ci black_data[j] += buffer[j]; 1523141cc406Sopenharmony_ci } 1524141cc406Sopenharmony_ci } 1525141cc406Sopenharmony_ci } 1526141cc406Sopenharmony_ci } 1527141cc406Sopenharmony_ci while (test_document (dev->fd) != SANE_STATUS_NO_DOCS); 1528141cc406Sopenharmony_ci DBG (DBG_trace, "sheetfed_calibration: white lines=%d, black lines=%d\n", 1529141cc406Sopenharmony_ci white, black); 1530141cc406Sopenharmony_ci 1531141cc406Sopenharmony_ci /* average pixels and store in per dpi calibration data */ 1532141cc406Sopenharmony_ci for (j = 0; j < pixels * 3; j++) 1533141cc406Sopenharmony_ci { 1534141cc406Sopenharmony_ci dev->calibration_data[i]->white_data[j] = white_data[j] / white; 1535141cc406Sopenharmony_ci dev->calibration_data[i]->black_data[j] = black_data[j] / black; 1536141cc406Sopenharmony_ci } 1537141cc406Sopenharmony_ci 1538141cc406Sopenharmony_ci /* we average red, green and blue offset on the full sensor */ 1539141cc406Sopenharmony_ci red = 0; 1540141cc406Sopenharmony_ci green = 0; 1541141cc406Sopenharmony_ci blue = 0; 1542141cc406Sopenharmony_ci for (j = 0; j < pixels * 3; j += 3) 1543141cc406Sopenharmony_ci { 1544141cc406Sopenharmony_ci red += dev->calibration_data[i]->black_data[j]; 1545141cc406Sopenharmony_ci green += dev->calibration_data[i]->black_data[j + 1]; 1546141cc406Sopenharmony_ci blue += dev->calibration_data[i]->black_data[j + 2]; 1547141cc406Sopenharmony_ci } 1548141cc406Sopenharmony_ci for (j = 0; j < pixels * 3; j += 3) 1549141cc406Sopenharmony_ci { 1550141cc406Sopenharmony_ci dev->calibration_data[i]->black_data[j] = red / pixels; 1551141cc406Sopenharmony_ci dev->calibration_data[i]->black_data[j + 1] = green / pixels; 1552141cc406Sopenharmony_ci dev->calibration_data[i]->black_data[j + 2] = blue / pixels; 1553141cc406Sopenharmony_ci } 1554141cc406Sopenharmony_ci 1555141cc406Sopenharmony_ci /* trace calibration data for debug */ 1556141cc406Sopenharmony_ci if (DBG_LEVEL > DBG_data) 1557141cc406Sopenharmony_ci { 1558141cc406Sopenharmony_ci sprintf (title, "calibration-white-%d.pnm", 1559141cc406Sopenharmony_ci dev->calibration_data[i]->dpi); 1560141cc406Sopenharmony_ci write_rgb_data (title, dev->calibration_data[i]->white_data, pixels, 1); 1561141cc406Sopenharmony_ci sprintf (title, "calibration-black-%d.pnm", 1562141cc406Sopenharmony_ci dev->calibration_data[i]->dpi); 1563141cc406Sopenharmony_ci write_rgb_data (title, dev->calibration_data[i]->black_data, pixels, 1); 1564141cc406Sopenharmony_ci } 1565141cc406Sopenharmony_ci 1566141cc406Sopenharmony_ci /* loop on all remaining resolution and compute calibration data from it */ 1567141cc406Sopenharmony_ci for (i = 1; i < MAX_RESOLUTIONS && dev->model->xdpi_values[i] > 0; i++) 1568141cc406Sopenharmony_ci { 1569141cc406Sopenharmony_ci dev->calibration_data[i] = 1570141cc406Sopenharmony_ci (P5_Calibration_Data *) malloc (sizeof (P5_Calibration_Data)); 1571141cc406Sopenharmony_ci if (dev->calibration_data[i] == NULL) 1572141cc406Sopenharmony_ci { 1573141cc406Sopenharmony_ci cleanup_calibration (dev); 1574141cc406Sopenharmony_ci DBG (DBG_error, 1575141cc406Sopenharmony_ci "sheetfed_calibration: failed to allocate memory for calibration\n"); 1576141cc406Sopenharmony_ci return SANE_STATUS_INVAL; 1577141cc406Sopenharmony_ci } 1578141cc406Sopenharmony_ci dev->calibration_data[i]->dpi = dev->model->xdpi_values[i]; 1579141cc406Sopenharmony_ci 1580141cc406Sopenharmony_ci coeff = ((float) dev->model->xdpi_values[i]) / (float) dpi; 1581141cc406Sopenharmony_ci 1582141cc406Sopenharmony_ci /* generate data by decimation */ 1583141cc406Sopenharmony_ci for (j = 0; j < pixels / coeff; j++) 1584141cc406Sopenharmony_ci { 1585141cc406Sopenharmony_ci k = j * coeff; 1586141cc406Sopenharmony_ci dev->calibration_data[i]->white_data[j] = 1587141cc406Sopenharmony_ci dev->calibration_data[0]->white_data[k]; 1588141cc406Sopenharmony_ci dev->calibration_data[i]->white_data[j + 1] = 1589141cc406Sopenharmony_ci dev->calibration_data[0]->white_data[k + 1]; 1590141cc406Sopenharmony_ci dev->calibration_data[i]->white_data[j + 2] = 1591141cc406Sopenharmony_ci dev->calibration_data[0]->white_data[k + 2]; 1592141cc406Sopenharmony_ci dev->calibration_data[i]->black_data[j] = 1593141cc406Sopenharmony_ci dev->calibration_data[0]->black_data[k]; 1594141cc406Sopenharmony_ci dev->calibration_data[i]->black_data[j + 1] = 1595141cc406Sopenharmony_ci dev->calibration_data[0]->black_data[k + 1]; 1596141cc406Sopenharmony_ci dev->calibration_data[i]->black_data[j + 2] = 1597141cc406Sopenharmony_ci dev->calibration_data[0]->black_data[k + 2]; 1598141cc406Sopenharmony_ci } 1599141cc406Sopenharmony_ci } 1600141cc406Sopenharmony_ci 1601141cc406Sopenharmony_ci fclose (dbg); 1602141cc406Sopenharmony_ci dev->calibrated = SANE_TRUE; 1603141cc406Sopenharmony_ci 1604141cc406Sopenharmony_ci /* eject calibration target */ 1605141cc406Sopenharmony_ci eject (dev->fd); 1606141cc406Sopenharmony_ci 1607141cc406Sopenharmony_ci DBG (DBG_proc, "sheetfed_calibration: end\n"); 1608141cc406Sopenharmony_ci return SANE_STATUS_GOOD; 1609141cc406Sopenharmony_ci} 1610141cc406Sopenharmony_ci 1611141cc406Sopenharmony_ci/* vim: set sw=2 cino=>2se-1sn-1s{s^-1st0(0u0 smarttab expandtab: */ 1612