static SANE_Status get_image_status (Tamarack_Scanner *s) { uint8_t result[12]; SANE_Status status; size_t len; int busy; #if 1 do { len = sizeof (result); status = sanei_scsi_cmd (s->fd, get_status, sizeof (get_status), result, &len); if ((status != SANE_STATUS_GOOD) && (status != SANE_STATUS_DEVICE_BUSY)) return status; busy = (result[2] != 8) || (status == SANE_STATUS_DEVICE_BUSY); if (busy) usleep (100000); if (!s->scanning) return do_cancel (s); } while (busy); #else /* XXX Test if this works one day... */ wait_ready (s); #endif len = sizeof (result); status = sanei_scsi_cmd (s->fd, get_status, sizeof (get_status), result, &len); if ((status != SANE_STATUS_GOOD) && (status != SANE_STATUS_DEVICE_BUSY)) return status; s->params.bytes_per_line = result[ 8] | (result[ 7] << 8) | (result[6] << 16); s->params.lines = result[11] | (result[10] << 8) | (result[9] << 16); switch (s->mode) { case DITHERED: case THRESHOLDED: s->params.pixels_per_line = 8 * s->params.bytes_per_line; break; case GREYSCALE: case TRUECOLOR: s->params.pixels_per_line = s->params.bytes_per_line; break; } DBG(1, "get_image_status: bytes_per_line=%d, lines=%d\n", s->params.bytes_per_line, s->params.lines); return SANE_STATUS_GOOD; }
static SANE_Status send_command (struct scanner * s, struct cmd * c) { SANE_Status st = SANE_STATUS_GOOD; if (s->bus == USB) { struct response r; memset (&r, 0, sizeof (r)); st = usb_send_command (s, c, &r, s->buffer); if (st) return st; if (r.status) { u8 b[sizeof (struct bulk_header) + RESPONSE_SIZE]; struct cmd c2 = { {0}, 6, 0, RESPONSE_SIZE, CMD_IN }; c2.cmd[0] = REQUEST_SENSE; c2.cmd[4] = RESPONSE_SIZE; st = usb_send_command (s, &c2, &r, b); if (st) return st; st = kvs20xx_sense_handler (0, b + sizeof (struct bulk_header), NULL); } } else { if (c->dir == CMD_OUT) { memcpy (s->buffer, c->cmd, c->cmd_size); memcpy (s->buffer + c->cmd_size, c->data, c->data_size); st = sanei_scsi_cmd (s->file, s->buffer, c->cmd_size + c->data_size, NULL, NULL); } else if (c->dir == CMD_IN) { c->data = s->buffer; st = sanei_scsi_cmd (s->file, c->cmd, c->cmd_size, c->data, (size_t *) & c->data_size); } else { st = sanei_scsi_cmd (s->file, c->cmd, c->cmd_size, NULL, NULL); } } return st; }
static SANE_Status wait_ready (int fd) { SANE_Status status; int i; for (i = 0; i < 1000; ++i) { DBG(3, "wait_ready: sending TEST_UNIT_READY\n"); status = sanei_scsi_cmd (fd, test_unit_ready, sizeof (test_unit_ready), 0, 0); switch (status) { default: /* Ignore errors while waiting for scanner to become ready. Some SCSI drivers return EIO while the scanner is returning to the home position. */ DBG(1, "wait_ready: test unit ready failed (%s)\n", sane_strstatus (status)); /* fall through */ case SANE_STATUS_DEVICE_BUSY: usleep (100000); /* retry after 100ms */ break; case SANE_STATUS_GOOD: return status; } } DBG(1, "wait_ready: timed out after %d attempts\n", i); return SANE_STATUS_INVAL; }
static SANE_Status read_data (Tamarack_Scanner *s, SANE_Byte *buf, int lines, int bpl) { struct command_header_10 cmd; size_t nbytes; SANE_Status status; #ifdef DEBUG int dt; struct timeval tv_start,tv_end; #endif nbytes = bpl * lines; memset (&cmd,'\0',sizeof (cmd)); cmd.opc = 0x28; set_triple (cmd.len,nbytes); #ifdef DEBUG if (verbose) DBG (1, "Doing read_data... \n"); gettimeofday (&tv_start,NULL); #endif status = sanei_scsi_cmd (s->fd, &cmd, sizeof (cmd), buf, &nbytes); #ifdef DEBUG gettimeofday (&tv_end,NULL); dt = tv_end.tv_usec - tv_start.tv_usec + (tv_end.tv_sec - tv_start.tv_sec) * 1000000; if (verbose) DBG(1, "Read took %d.%06d seconds.", dt/1000000,dt%1000000); dt = 1000000 * nbytes / dt; if (verbose) DBG(1, "which is %d.%03d bytes per second.\n",dt,0); #endif return status; }
static SANE_Status mode_select (Tamarack_Scanner *s) { struct { struct command_header cmd; struct page_header hdr; struct tamarack_page page; } c; memset (&c, '\0', sizeof (c)); c.cmd.opc = TAMARACK_SCSI_MODE_SELECT; c.cmd.pad0[0] = 0x10; /* Suddenly the pad bytes are no long pad... */ c.cmd.pad0[1] = 0; c.cmd.len = sizeof (struct page_header) + sizeof (struct tamarack_page); c.hdr.code = 0; c.hdr.length = 6; c.page.gamma = 2; c.page.thresh = 0x80; /* XXX Option? */ switch (s->mode) { case THRESHOLDED: case DITHERED: case GREYSCALE: c.page.masks = 0x80; break; case TRUECOLOR: c.page.masks = 0x40 >> s->pass; break; } c.page.delay = 0x10; /* XXX Option? */ c.page.features = (s->val[OPT_TRANS].w ? TAM_TRANS_ON:0) | 1; return sanei_scsi_cmd (s->fd, &c, sizeof (c), 0, 0); }
static SANE_Status stop_scan (Tamarack_Scanner *s) { /* XXX I don't think a TAMARACK can stop in mid-scan. Just stop sending it requests for data.... */ return sanei_scsi_cmd (s->fd, stop, sizeof (stop), 0, 0); }
static SANE_Status st400_set_window( ST400_Device *dev ) { unsigned short xoff, yoff; SANE_Byte th; struct { /* 10byte command */ SANE_Byte cmd, lun, reserved1[4], tr_len[3], ctrl; /* 40byte window struct */ SANE_Byte reserved2[6], wd_len[2], winnr, reserved3; SANE_Byte x_res[2], y_res[2]; /* resolution: 200, 300, 400 */ SANE_Byte x_ul[2], y_ul[2]; /* upper left corner */ SANE_Byte width[2], height[2]; SANE_Byte reserved4, threshold; SANE_Byte reserved5, halftone; /* ht: 0 or 2 */ SANE_Byte bitsperpixel, reserved6[13]; /* bpp: 1 or 8 */ } scsi_cmd; /* The PC/Amiga source uses reserved5 to indicate A4/A5 paper size * (values 4 and 5), but a comment implies that this is only for the * scanning program and the value is ignored by the scanner. */ SANE_Status status; memset(&scsi_cmd, 0, sizeof(scsi_cmd)); scsi_cmd.cmd = CMD_SET_WINDOW; set24(scsi_cmd.tr_len, 40); set16(scsi_cmd.wd_len, 32); /* These offsets seem to be required to avoid damaging the scanner: * If a scan with 0/0 as the top left corner is started, the scanner * seems to try to move the carriage over the bottom end (not a * pretty sound). */ xoff = (11L * dev->val[OPT_RESOLUTION]) / 100; yoff = 6; th = (double)maxval(dev->model->bits) * SANE_UNFIX(dev->val[OPT_THRESHOLD]) / 100.0; scsi_cmd.winnr = 1; set16(scsi_cmd.x_res, (unsigned short)dev->val[OPT_RESOLUTION]); set16(scsi_cmd.y_res, (unsigned short)dev->val[OPT_RESOLUTION]); set16(scsi_cmd.x_ul, dev->x + xoff); set16(scsi_cmd.y_ul, dev->wy + yoff); set16(scsi_cmd.width, dev->w); set16(scsi_cmd.height, dev->wh); scsi_cmd.threshold = th; scsi_cmd.halftone = (dev->val[OPT_DEPTH] == 1) ? 0 : 2; scsi_cmd.bitsperpixel = dev->val[OPT_DEPTH]; DBG(DSCSI, "SCSI: sending SET_WINDOW (x=%hu y=%hu w=%hu h=%hu wy=%hu wh=%hu th=%d\n", dev->x, dev->y, dev->w, dev->h, dev->wy, dev->wh, (int)th); status = sanei_scsi_cmd(dev->fd, &scsi_cmd, sizeof(scsi_cmd), 0, 0); DBG(DSCSI, "SCSI: result=%s\n", sane_strstatus(status)); return status; }
static SANE_Status start_scan (Tamarack_Scanner *s) { struct { struct command_header cmd; unsigned char winid[1]; } c; memset (&c,'\0',sizeof (c)); c.cmd.opc = TAMARACK_SCSI_START_STOP; c.cmd.len = sizeof (c.winid); c.winid[0] = WINID; return sanei_scsi_cmd (s->fd, &c, sizeof (c), 0, 0); }
static SANE_Status start_scan (Abaton_Scanner * s) { SANE_Status status; uint8_t start[7]; memset (start, 0, sizeof (start)); start[0] = START_STOP; start[4] = 1; status = sanei_scsi_cmd (s->fd, start, sizeof (start), 0, 0); return status; }
SANE_Status sanei_epson_scsi_inquiry (int fd, int page_code, void *buf, size_t * buf_size) { u_char cmd[6]; int status; memset (cmd, 0, 6); cmd[0] = INQUIRY_COMMAND; cmd[2] = page_code; cmd[4] = *buf_size > 255 ? 255 : *buf_size; status = sanei_scsi_cmd (fd, cmd, sizeof cmd, buf, buf_size); return status; }
static SANE_Status st400_read10( int fd, SANE_Byte *buf, size_t *lenP ) { struct { SANE_Byte cmd, lun, res[4], tr_len[3], ctrl; } scsi_cmd; SANE_Status status; memset(&scsi_cmd, 0, sizeof(scsi_cmd)); scsi_cmd.cmd = CMD_READ10; set24(scsi_cmd.tr_len, *lenP); DBG(DSCSI, "SCSI: sending READ10 (%lu bytes)\n", (u_long)(*lenP)); status = sanei_scsi_cmd(fd, &scsi_cmd, sizeof(scsi_cmd), buf, lenP); DBG(DSCSI, "SCSI: result=%s (%lu bytes)\n", sane_strstatus(status), (u_long)(*lenP)); return status; }
static SANE_Status st400_cmd6( int fd, SANE_Byte cmd, SANE_Byte ctrl ) { struct { SANE_Byte cmd, lun, reserved[2], tr_len, ctrl; } scsi_cmd; SANE_Status status; memset(&scsi_cmd, 0, sizeof(scsi_cmd)); scsi_cmd.cmd = cmd; scsi_cmd.ctrl = ctrl; DBG(DSCSI, "SCSI: sending cmd6 0x%02x (ctrl=%d)\n", (int)cmd, (int)ctrl); status = sanei_scsi_cmd(fd, &scsi_cmd, sizeof(scsi_cmd), 0, 0); DBG(DSCSI, "SCSI: result=%s\n", sane_strstatus(status)); return status; }
static SANE_Status request_sense (Abaton_Scanner * s) { uint8_t cmd[6]; uint8_t result[22]; size_t size = sizeof (result); SANE_Status status; memset (cmd, 0, sizeof (cmd)); memset (result, 0, sizeof (result)); cmd[0] = REQUEST_SENSE; STORE8 (cmd + 4, sizeof (result)); sanei_scsi_cmd (s->fd, cmd, sizeof (cmd), result, &size); if (result[7] != 14) { DBG (ERROR_MESSAGE, "Additional Length %u\n", (unsigned int) result[7]); status = SANE_STATUS_IO_ERROR; } status = sense_handler (s->fd, result, NULL); if (status == SANE_STATUS_IO_ERROR) { /* Since I haven't figured out the vendor unique error codes on this thing, I'll just handle the normal ones for now */ if (result[18] & 0x80) DBG (ERROR_MESSAGE, "Sense: Dim Light (output of lamp below 70%%).\n"); if (result[18] & 0x40) DBG (ERROR_MESSAGE, "Sense: No Light at all.\n"); if (result[18] & 0x20) DBG (ERROR_MESSAGE, "Sense: No Home.\n"); if (result[18] & 0x10) DBG (ERROR_MESSAGE, "Sense: No Limit. Tried to scan out of range.\n"); } DBG (USER_MESSAGE, "Sense: Optical gain %u.\n", (unsigned int) result[20]); return status; }
int sanei_epson_scsi_read (int fd, void *buf, size_t buf_size, SANE_Status * status) { u_char cmd[6]; memset (cmd, 0, 6); cmd[0] = READ_6_COMMAND; cmd[2] = buf_size >> 16; cmd[3] = buf_size >> 8; cmd[4] = buf_size; if (SANE_STATUS_GOOD == (*status = sanei_scsi_cmd (fd, cmd, sizeof (cmd), buf, &buf_size))) return buf_size; return 0; }
static SANE_Status wait_ready (int fd) { #define MAX_WAITING_TIME 60 /* one minute, at most */ struct timeval now, start; SANE_Status status; gettimeofday (&start, 0); while (1) { DBG (USER_MESSAGE, "wait_ready: sending TEST_UNIT_READY\n"); status = sanei_scsi_cmd (fd, test_unit_ready, sizeof (test_unit_ready), 0, 0); switch (status) { default: /* Ignore errors while waiting for scanner to become ready. Some SCSI drivers return EIO while the scanner is returning to the home position. */ DBG (ERROR_MESSAGE, "wait_ready: test unit ready failed (%s)\n", sane_strstatus (status)); /* fall through */ case SANE_STATUS_DEVICE_BUSY: gettimeofday (&now, 0); if (now.tv_sec - start.tv_sec >= MAX_WAITING_TIME) { DBG (ERROR_MESSAGE, "wait_ready: timed out after %ld seconds\n", (long) (now.tv_sec - start.tv_sec)); return SANE_STATUS_INVAL; } usleep (100000); /* retry after 100ms */ break; case SANE_STATUS_GOOD: return status; } } return SANE_STATUS_INVAL; }
SANE_Status sane_read (SANE_Handle handle, SANE_Byte * buf, SANE_Int max_len, SANE_Int * len) { Abaton_Scanner *s = handle; SANE_Status status; uint8_t get_data_status[10]; uint8_t read[10]; uint8_t result[12]; size_t size; SANE_Int data_av = 0; SANE_Int data_length = 0; SANE_Int offset = 0; SANE_Int rread = 0; SANE_Bool Pseudo8bit = SANE_FALSE; *len = 0; /* don't let bogus read requests reach the scanner */ /* this is a sub-optimal way of doing this, I'm sure */ if (!s->scanning) return SANE_STATUS_EOF; if (!strcmp (s->val[OPT_MODE].s, "Gray16")) Pseudo8bit = SANE_TRUE; memset (get_data_status, 0, sizeof (get_data_status)); get_data_status[0] = GET_DATA_STATUS; /* This means "block" for Apple scanners, it seems to be the same for Abaton. The scanner will do non-blocking I/O, but I don't want to go there right now. */ get_data_status[1] = 1; STORE8 (get_data_status + 8, sizeof (result)); memset (read, 0, sizeof (read)); read[0] = READ_10; do { size = sizeof (result); /* this isn't necessary */ /* memset (result, 0, size); */ status = sanei_scsi_cmd (s->fd, get_data_status, sizeof (get_data_status), result, &size); if (status != SANE_STATUS_GOOD) return status; if (!size) { DBG (ERROR_MESSAGE, "sane_read: cannot get_data_status.\n"); return SANE_STATUS_IO_ERROR; } /* this is not an accurate name, but oh well... */ data_length = GET24 (result); data_av = GET24 (result + 9); /* don't check result[3] here, because that screws things up somewhat */ if (data_length) { DBG (IO_MESSAGE, "sane_read: (status) Available in scanner buffer %u.\n", data_av); if (Pseudo8bit) { if ((data_av * 2) + offset > max_len) rread = (max_len - offset) / 2; else rread = data_av; } else if (data_av + offset > max_len) { rread = max_len - offset; } else { rread = data_av; } DBG (IO_MESSAGE, "sane_read: (action) Actual read request for %u bytes.\n", rread); size = rread; STORE24 (read + 6, rread); status = sanei_scsi_cmd (s->fd, read, sizeof (read), buf + offset, &size); if (Pseudo8bit) { SANE_Int byte; SANE_Int pos = offset + (rread << 1) - 1; SANE_Byte B; for (byte = offset + rread - 1; byte >= offset; byte--) { B = buf[byte]; /* don't invert these! */ buf[pos--] = B << 4; /* low (right) nibble */ buf[pos--] = B & 0xF0; /* high (left) nibble */ } /* putting an end to bitop abuse here */ offset += size * 2; } else offset += size; DBG (IO_MESSAGE, "sane_read: Buffer %u of %u full %g%%\n", offset, max_len, (double) (offset * 100. / max_len)); } } while (offset < max_len && data_length != 0 && !s->AbortedByUser); if (s->AbortedByUser) { s->scanning = SANE_FALSE; if (status != SANE_STATUS_GOOD) { DBG (ERROR_MESSAGE, "sane_read: request_sense revealed error: %s\n", sane_strstatus (status)); return status; } status = sanei_scsi_cmd (s->fd, test_unit_ready, sizeof (test_unit_ready), 0, 0); if (status != SANE_STATUS_GOOD || status != SANE_STATUS_INVAL) return status; return SANE_STATUS_CANCELLED; } if (!data_length) { s->scanning = SANE_FALSE; DBG (IO_MESSAGE, "sane_read: (status) No more data..."); if (!offset) { /* this shouldn't happen */ *len = 0; DBG (IO_MESSAGE, "EOF\n"); return SANE_STATUS_EOF; } else { *len = offset; DBG (IO_MESSAGE, "GOOD\n"); return SANE_STATUS_GOOD; } } DBG (FLOW_CONTROL, "sane_read: Normal Exiting, Aborted=%u, data_length=%u\n", s->AbortedByUser, data_av); *len = offset; return SANE_STATUS_GOOD; }
static SANE_Status set_window (Abaton_Scanner * s) { uint8_t cmd[10 + 40]; uint8_t *window = cmd + 10 + 8; int invert; memset (cmd, 0, sizeof (cmd)); cmd[0] = SET_WINDOW; cmd[8] = 40; /* Just like the Apple scanners, we put the resolution here */ STORE16 (window + 2, s->val[OPT_X_RESOLUTION].w); STORE16 (window + 4, s->val[OPT_Y_RESOLUTION].w); /* Unlike Apple scanners, these are pixel values */ STORE16 (window + 6, s->ULx); STORE16 (window + 8, s->ULy); STORE16 (window + 10, s->Width); STORE16 (window + 12, s->Height); STORE8 (window + 14, s->val[OPT_BRIGHTNESS].w); STORE8 (window + 15, s->val[OPT_THRESHOLD].w); STORE8 (window + 16, s->val[OPT_CONTRAST].w); invert = s->val[OPT_NEGATIVE].w; if (!strcmp (s->val[OPT_MODE].s, SANE_VALUE_SCAN_MODE_LINEART)) { STORE8 (window + 17, 0); } else if (!strcmp (s->val[OPT_MODE].s, SANE_VALUE_SCAN_MODE_HALFTONE)) { STORE8 (window + 17, 1); } else if (!strcmp (s->val[OPT_MODE].s, "Gray256") || !strcmp (s->val[OPT_MODE].s, "Gray16")) { STORE8 (window + 17, 2); invert = !s->val[OPT_NEGATIVE].w; } else { DBG (ERROR_MESSAGE, "Can't match mode %s\n", s->val[OPT_MODE].s); return SANE_STATUS_INVAL; } STORE8 (window + 18, s->bpp); if (!strcmp (s->val[OPT_HALFTONE_PATTERN].s, "spiral")) { STORE8 (window + 20, 0); } else if (!strcmp (s->val[OPT_HALFTONE_PATTERN].s, "bayer")) { STORE8 (window + 20, 1); } else { DBG (ERROR_MESSAGE, "Can't match haftone pattern %s\n", s->val[OPT_HALFTONE_PATTERN].s); return SANE_STATUS_INVAL; } /* We have to invert these ones for some reason, so why not let the scanner do it for us... */ STORE8 (window + 21, invert ? 0x80 : 0); STORE16 (window + 22, (s->val[OPT_MIRROR].w != 0)); return sanei_scsi_cmd (s->fd, cmd, sizeof (cmd), 0, 0); }
static SANE_Status attach (const char *devname, Abaton_Device ** devp, int may_wait) { char result[INQ_LEN]; const char *model_name = result + 44; int fd, abaton_scanner; Abaton_Device *dev; SANE_Status status; size_t size; for (dev = first_dev; dev; dev = dev->next) if (strcmp (dev->sane.name, devname) == 0) { if (devp) *devp = dev; return SANE_STATUS_GOOD; } DBG (USER_MESSAGE, "attach: opening %s\n", devname); status = sanei_scsi_open (devname, &fd, sense_handler, 0); if (status != SANE_STATUS_GOOD) { DBG (ERROR_MESSAGE, "attach: open failed (%s)\n", sane_strstatus (status)); return SANE_STATUS_INVAL; } if (may_wait) wait_ready (fd); DBG (USER_MESSAGE, "attach: sending INQUIRY\n"); size = sizeof (result); status = sanei_scsi_cmd (fd, inquiry, sizeof (inquiry), result, &size); if (status != SANE_STATUS_GOOD) { DBG (ERROR_MESSAGE, "attach: inquiry failed (%s)\n", sane_strstatus (status)); sanei_scsi_close (fd); return status; } status = wait_ready (fd); sanei_scsi_close (fd); if (status != SANE_STATUS_GOOD) return status; /* check that we've got an Abaton */ abaton_scanner = (strncmp (result + 8, "ABATON ", 8) == 0); model_name = result + 16; /* make sure it's a scanner ;-) */ abaton_scanner = abaton_scanner && (result[0] == 0x06); if (!abaton_scanner) { DBG (ERROR_MESSAGE, "attach: device doesn't look like an Abaton scanner " "(result[0]=%#02x)\n", result[0]); return SANE_STATUS_INVAL; } dev = malloc (sizeof (*dev)); if (!dev) return SANE_STATUS_NO_MEM; memset (dev, 0, sizeof (*dev)); dev->sane.name = strdup (devname); dev->sane.vendor = "Abaton"; dev->sane.model = strndup (model_name, 16); dev->sane.type = "flatbed scanner"; if (!strncmp (model_name, "SCAN 300/GS", 11)) { dev->ScannerModel = ABATON_300GS; } else if (!strncmp (model_name, "SCAN 300/S", 10)) { dev->ScannerModel = ABATON_300S; } DBG (USER_MESSAGE, "attach: found Abaton scanner model %s (%s)\n", dev->sane.model, dev->sane.type); ++num_devices; dev->next = first_dev; first_dev = dev; if (devp) *devp = dev; return SANE_STATUS_GOOD; }
static SANE_Status st400_inquiry( int fd, ST400_Model **modelP ) { struct { SANE_Byte cmd, lun, reserved[2], tr_len, ctrl; } scsi_cmd; /* struct { SANE_Byte devtype, devqual, version; SANE_Byte reserved1, additionallength; SANE_Byte reserved2[2], flags; SANE_Byte vendor[8], product[16], release[4]; SANE_Byte reserved3[60]; } inqdata; */ struct { SANE_Byte bytes[96]; } inqdata; size_t inqlen; SANE_Status status; ST400_Model *model; inqlen = sizeof(inqdata); memset(&scsi_cmd, 0, sizeof(scsi_cmd)); scsi_cmd.cmd = CMD_INQUIRY; scsi_cmd.tr_len = inqlen; DBG(DSCSI, "SCSI: sending INQUIRY (%lu bytes)\n", (u_long)inqlen); status = sanei_scsi_cmd(fd, &scsi_cmd, sizeof(scsi_cmd), &inqdata, &inqlen); DBG(DSCSI, "SCSI: result=%s (%lu bytes)\n", sane_strstatus(status), (u_long)inqlen); if( status != SANE_STATUS_GOOD ) return status; if( st400_dump_data ) { const char *home = getenv ("HOME"); char basename[] = "st400.dump"; char *name; FILE *fp; if (home) { name = malloc (strlen (home) + sizeof (basename) + 1); sprintf (name, "%s/%s", home, basename); } else name = basename; fp = fopen(name, "ab"); if( fp != NULL ) { fwrite(inqdata.bytes, 1, inqlen, fp); fclose(fp); } if (name != basename) free (name); } if( inqlen != sizeof(inqdata) ) return SANE_STATUS_IO_ERROR; for( model = st400_models; model->inq_vendor; model++ ) { if( str_at_offset(model->inq_vendor, model->inq_voffset, inqdata.bytes) && str_at_offset(model->inq_model, model->inq_moffset, inqdata.bytes) ) { *modelP = model; DBG(DINFO, "found matching scanner model \"%s %s\" in list\n", model->sane_vendor, model->sane_model); return SANE_STATUS_GOOD; } } return SANE_STATUS_UNSUPPORTED; }
static SANE_Status attach (const char *devname, Tamarack_Device **devp) { char result[INQ_LEN]; int fd; Tamarack_Device *dev; SANE_Status status; size_t size; char *mfg, *model; char *p; for (dev = first_dev; dev; dev = dev->next) if (strcmp (dev->sane.name, devname) == 0) { if (devp) *devp = dev; return SANE_STATUS_GOOD; } DBG(3, "attach: opening %s\n", devname); status = sanei_scsi_open (devname, &fd, sense_handler, 0); if (status != SANE_STATUS_GOOD) { DBG(1, "attach: open failed (%s)\n", sane_strstatus (status)); return SANE_STATUS_INVAL; } DBG(3, "attach: sending INQUIRY\n"); size = sizeof (result); status = sanei_scsi_cmd (fd, inquiry, sizeof (inquiry), result, &size); if (status != SANE_STATUS_GOOD || size != INQ_LEN) { DBG(1, "attach: inquiry failed (%s)\n", sane_strstatus (status)); sanei_scsi_close (fd); return status; } status = wait_ready (fd); sanei_scsi_close (fd); if (status != SANE_STATUS_GOOD) return status; result[33]= '\0'; p = strchr(result+16,' '); if (p) *p = '\0'; model = strdup (result+16); result[16]= '\0'; p = strchr(result+8,' '); if (p) *p = '\0'; mfg = strdup (result+8); DBG(1, "attach: Inquiry gives mfg=%s, model=%s.\n", mfg, model); if (strcmp (mfg, "TAMARACK") != 0) { DBG(1, "attach: device doesn't look like a Tamarack scanner " "(result[0]=%#02x)\n", result[0]); return SANE_STATUS_INVAL; } dev = malloc (sizeof (*dev)); if (!dev) return SANE_STATUS_NO_MEM; memset (dev, 0, sizeof (*dev)); dev->sane.name = strdup (devname); dev->sane.vendor = "Tamarack"; dev->sane.model = model; dev->sane.type = "flatbed scanner"; dev->x_range.min = 0; dev->y_range.min = 0; dev->x_range.quant = 0; dev->y_range.quant = 0; dev->dpi_range.min = SANE_FIX (1); dev->dpi_range.quant = SANE_FIX (1); dev->x_range.max = SANE_FIX (8.5 * MM_PER_INCH); dev->y_range.max = SANE_FIX (11.0 * MM_PER_INCH); dev->dpi_range.max = SANE_FIX (600); DBG(3, "attach: found Tamarack scanner model %s (%s)\n", dev->sane.model, dev->sane.type); ++num_devices; dev->next = first_dev; first_dev = dev; if (devp) *devp = dev; return SANE_STATUS_GOOD; }
static SANE_Status scan_area_and_windows (Tamarack_Scanner *s) { struct def_win_par dwp; memset (&dwp,'\0',sizeof (dwp)); dwp.dwph.opc = TAMARACK_SCSI_AREA_AND_WINDOWS; set_triple (dwp.dwph.len,8 + sizeof (dwp.wdb)); set_double (dwp.wdh.wpll, sizeof (dwp.wdb)); dwp.wdb.winid = WINID; set_double (dwp.wdb.xres, (int) SANE_UNFIX (s->val[OPT_RESOLUTION].w)); set_double (dwp.wdb.yres, (int) SANE_UNFIX (s->val[OPT_RESOLUTION].w)); set_quad (dwp.wdb.ulx, (int) (47.2 * SANE_UNFIX (s->val[OPT_TL_X].w))); set_quad (dwp.wdb.uly, (int) (47.2 * SANE_UNFIX (s->val[OPT_TL_Y].w))); set_quad (dwp.wdb.width, (int) (47.2 * SANE_UNFIX (s->val[OPT_BR_X].w - s->val[OPT_TL_X].w))); set_quad (dwp.wdb.length, (int) (47.2 * SANE_UNFIX (s->val[OPT_BR_Y].w - s->val[OPT_TL_Y].w))); dwp.wdb.brightness = sign_mag (SANE_UNFIX (s->val[OPT_BRIGHTNESS].w)); dwp.wdb.contrast = sign_mag (SANE_UNFIX (s->val[OPT_CONTRAST].w)); dwp.wdb.thresh = 0x80; switch (s->mode) { case THRESHOLDED: dwp.wdb.bpp = 1; dwp.wdb.image_comp = 0; dwp.wdb.thresh = 1 + 2.55 * (SANE_UNFIX (s->val[OPT_THRESHOLD].w)); break; case DITHERED: dwp.wdb.bpp = 1; dwp.wdb.image_comp = 1; break; case GREYSCALE: dwp.wdb.bpp = 8; dwp.wdb.image_comp = 2; break; case TRUECOLOR: dwp.wdb.bpp = 8; dwp.wdb.image_comp = 2; break; default: DBG(1, "Invalid mode. %d\n", s->mode); return SANE_STATUS_INVAL; } DBG(1, "bright, thresh, contrast = %d(%5.1f), %d, %d(%5.1f)\n", dwp.wdb.brightness, SANE_UNFIX (s->val[OPT_BRIGHTNESS].w), dwp.wdb.thresh , dwp.wdb.contrast , SANE_UNFIX (s->val[OPT_CONTRAST].w)); set_double (dwp.wdb.halftone, 1); /* XXX What does this do again ? */ dwp.wdb.pad_type = 3; /* This is the only usable pad-type. */ dwp.wdb.exposure = 0x6f; /* XXX Option? */ dwp.wdb.compr_type = 0; /* XXX Shouldn't this be sizeof (dwp) */ return sanei_scsi_cmd (s->fd, &dwp, (10+8+38), 0, 0); }