* backend/canon_dr.[ch], backend/canon_dr-cmd.h: backend v15 thru v18

- add byte-oriented duplex interlace code
- add RRGGBB color interlace code
- add basic support for DR-2580C, DR-2050C, DR-2080C, DR-2510C
- add more unknown setwindow bits
- add support for 16 byte status packets
- clean do_usb_cmd error handling (call reset more often)
- set status packet size from config file
- rewrite config file parsing to reset options after each scanner
- add config options for vendor, model, version
- dont call inquiry if those 3 options are set
- remove default config file from code
- add initial gray deinterlacing code for DR-2510C
- rename do_usb_reset to do_usb_clear
* doc/descriptions/canon_dr.desc: backend v18, update model status
* backend/canon_dr.conf.in: added better comments and new options
merge-requests/1/head
m. allan noah 2009-03-22 02:56:45 +00:00
rodzic 110b81d946
commit cd0b09ddf4
6 zmienionych plików z 612 dodań i 251 usunięć

Wyświetl plik

@ -1,3 +1,21 @@
2009-03-21 m. allan noah <kitno455 a t gmail d o t com>
* backend/canon_dr.[ch], backend/canon_dr-cmd.h: backend v15 thru v18
- add byte-oriented duplex interlace code
- add RRGGBB color interlace code
- add basic support for DR-2580C, DR-2050C, DR-2080C, DR-2510C
- add more unknown setwindow bits
- add support for 16 byte status packets
- clean do_usb_cmd error handling (call reset more often)
- set status packet size from config file
- rewrite config file parsing to reset options after each scanner
- add config options for vendor, model, version
- dont call inquiry if those 3 options are set
- remove default config file from code
- add initial gray deinterlacing code for DR-2510C
- rename do_usb_reset to do_usb_clear
* doc/descriptions/canon_dr.desc: backend v18, update model status
* backend/canon_dr.conf.in: added better comments and new options
2009-03-21 Pierre Willenbrock <pierre@pirsoft.dnsalias.org> 2009-03-21 Pierre Willenbrock <pierre@pirsoft.dnsalias.org>
* backend/genesys_devices.c: Enable Motor again for combined * backend/genesys_devices.c: Enable Motor again for combined
dark/bright calibration, fix calculation of pixel number used in dark/bright calibration, fix calculation of pixel number used in

Wyświetl plik

@ -11,7 +11,7 @@
#define USB_HEADER_LEN 12 #define USB_HEADER_LEN 12
#define USB_COMMAND_LEN 12 #define USB_COMMAND_LEN 12
#define USB_STATUS_LEN 4 #define USB_STATUS_LEN_MAX 32
#define USB_STATUS_OFFSET 0 #define USB_STATUS_OFFSET 0
#define USB_COMMAND_TIME 30000 #define USB_COMMAND_TIME 30000
#define USB_DATA_TIME 30000 #define USB_DATA_TIME 30000
@ -338,6 +338,16 @@ putnbyte (unsigned char *pnt, unsigned int value, unsigned int nbytes)
#define CANCEL_code 0xd8 #define CANCEL_code 0xd8
#define CANCEL_len 6 #define CANCEL_len 6
/* ==================================================================== */
/* Coarse Calibration */
#define COR_CAL_code 0xe1
#define COR_CAL_len 10
#define set_CC_xferlen(sb, len) putnbyte(sb + 0x06, len, 3)
/* the payload */
#define CC_pay_len 0x20
/* ==================================================================== */ /* ==================================================================== */
/* window descriptor macros for SET_WINDOW and GET_WINDOW */ /* window descriptor macros for SET_WINDOW and GET_WINDOW */
@ -358,7 +368,7 @@ putnbyte (unsigned char *pnt, unsigned int value, unsigned int nbytes)
#define set_WD_Xres(sb, val) putnbyte(sb + 0x02, val, 2) #define set_WD_Xres(sb, val) putnbyte(sb + 0x02, val, 2)
#define get_WD_Xres(sb) getnbyte(sb + 0x02, 2) #define get_WD_Xres(sb) getnbyte(sb + 0x02, 2)
/* 0x04,0x05 - X resolution in dpi */ /* 0x04,0x05 - Y resolution in dpi */
#define set_WD_Yres(sb, val) putnbyte(sb + 0x04, val, 2) #define set_WD_Yres(sb, val) putnbyte(sb + 0x04, val, 2)
#define get_WD_Yres(sb) getnbyte(sb + 0x04, 2) #define get_WD_Yres(sb) getnbyte(sb + 0x04, 2)
@ -417,8 +427,8 @@ putnbyte (unsigned char *pnt, unsigned int value, unsigned int nbytes)
/* 0x1d - Reverse image, reserved area, padding type */ /* 0x1d - Reverse image, reserved area, padding type */
#define set_WD_rif(sb, val) setbitfield(sb + 0x1d, 1, 7, val) #define set_WD_rif(sb, val) setbitfield(sb + 0x1d, 1, 7, val)
#define get_WD_rif(sb) getbitfield(sb + 0x1d, 1, 7) #define get_WD_rif(sb) getbitfield(sb + 0x1d, 1, 7)
#define set_WD_reserved(sb, val) setbitfield(sb + 0x1d, 1, 5, val) #define set_WD_reserved(sb, val) sb[0x1d] = val
#define get_WD_reserved(sb) getbitfield(sb + 0x1d, 1, 5) #define get_WD_reserved(sb) sb[0x1d]
/* 0x1e,0x1f - Bit ordering */ /* 0x1e,0x1f - Bit ordering */
#define set_WD_bitorder(sb, val) putnbyte(sb + 0x1e, val, 2) #define set_WD_bitorder(sb, val) putnbyte(sb + 0x1e, val, 2)
@ -444,6 +454,9 @@ putnbyte (unsigned char *pnt, unsigned int value, unsigned int nbytes)
/* 0x28-0x2c - vendor unique */ /* 0x28-0x2c - vendor unique */
/* FIXME: more params here? */ /* FIXME: more params here? */
#define set_WD_reserved2(sb, val) sb[0x2a] = val
#define get_WD_reserved2(sb) sb[0x2a]
/* ==================================================================== */ /* ==================================================================== */

Wyświetl plik

@ -129,6 +129,24 @@
v14 2009-03-07, MAN v14 2009-03-07, MAN
- remove HARD_SELECT from counter (Legitimate, but API violation) - remove HARD_SELECT from counter (Legitimate, but API violation)
- attach to CR-series scanners as well - attach to CR-series scanners as well
v15 2009-03-15, MAN
- add byte-oriented duplex interlace code
- add RRGGBB color interlace code
- add basic support for DR-2580C
v16 2009-03-20, MAN
- add more unknown setwindow bits
- add support for 16 byte status packets
- clean do_usb_cmd error handling (call reset more often)
- add basic support for DR-2050C, DR-2080C, DR-2510C
v17 2009-03-20, MAN
- set status packet size from config file
v18 2009-03-21, MAN
- rewrite config file parsing to reset options after each scanner
- add config options for vendor, model, version
- dont call inquiry if those 3 options are set
- remove default config file from code
- add initial gray deinterlacing code for DR-2510C
- rename do_usb_reset to do_usb_clear
SANE FLOW DIAGRAM SANE FLOW DIAGRAM
@ -189,7 +207,7 @@
#include "canon_dr.h" #include "canon_dr.h"
#define DEBUG 1 #define DEBUG 1
#define BUILD 14 #define BUILD 18
/* values for SANE_DEBUG_CANON_DR env var: /* values for SANE_DEBUG_CANON_DR env var:
- errors 5 - errors 5
@ -236,7 +254,13 @@ static const char string_Front[] = "Front";
static const char string_Back[] = "Back"; static const char string_Back[] = "Back";
/* Also set via config file. */ /* Also set via config file. */
static int global_buffer_size = 64 * 1024; static int global_buffer_size;
static int global_buffer_size_default = 64 * 1024;
static int global_status_length;
static int global_status_length_default = 4;
static char global_vendor_name[9];
static char global_model_name[17];
static char global_version_name[5];
/* /*
* used by attach* and sane_get_devices * used by attach* and sane_get_devices
@ -330,8 +354,8 @@ sane_get_devices (const SANE_Device *** device_list, SANE_Bool local_only)
sanei_usb_init(); sanei_usb_init();
/* set this to 64K before reading the file */ /* reset globals before reading the file */
global_buffer_size = 64 * 1024; default_globals();
fp = sanei_config_open (CANON_DR_CONFIG_FILE); fp = sanei_config_open (CANON_DR_CONFIG_FILE);
@ -352,13 +376,13 @@ sane_get_devices (const SANE_Device *** device_list, SANE_Bool local_only)
if (*lp == 0) if (*lp == 0)
continue; continue;
if ((strncmp ("option", lp, 6) == 0) && isspace (lp[6])) { if (!strncmp ("option", lp, 6) && isspace (lp[6])) {
lp += 6; lp += 6;
lp = sanei_config_skip_whitespace (lp); lp = sanei_config_skip_whitespace (lp);
/* we allow setting buffersize too big */ /* BUFFERSIZE: > 4K */
if ((strncmp (lp, "buffer-size", 11) == 0) && isspace (lp[11])) { if (!strncmp (lp, "buffer-size", 11) && isspace (lp[11])) {
int buf; int buf;
lp += 11; lp += 11;
@ -366,104 +390,113 @@ sane_get_devices (const SANE_Device *** device_list, SANE_Bool local_only)
buf = atoi (lp); buf = atoi (lp);
if (buf < 4096) { if (buf < 4096) {
DBG (5, "sane_get_devices: config option \"buffer-size\" (%d) is < 4096, ignoring!\n", buf); DBG (5, "sane_get_devices: config option \"buffer-size\" "
"(%d) is < 4096, ignoring!\n", buf);
continue; continue;
} }
if (buf > 64*1024) { if (buf > 64*1024) {
DBG (5, "sane_get_devices: config option \"buffer-size\" (%d) is > %d, warning!\n", buf, 64*1024); DBG (5, "sane_get_devices: config option \"buffer-size\" "
"(%d) is > %d, warning!\n", buf, 64*1024);
} }
DBG (15, "sane_get_devices: setting \"buffer-size\" to %d\n", buf); DBG (15, "sane_get_devices: setting \"buffer-size\" to %d\n",
buf);
global_buffer_size = buf; global_buffer_size = buf;
} }
/* STATUS: we clamp from 1 to 32 */
else if (!strncmp (lp, "status-length", 13) && isspace (lp[13])) {
int buf;
lp += 13;
lp = sanei_config_skip_whitespace (lp);
buf = atoi (lp);
if (buf < 1) {
DBG (5, "sane_get_devices: config option \"status-length\" "
"(%d) is < 1, ignoring!\n", buf);
continue;
}
if (buf > 32) {
DBG (5, "sane_get_devices: config option \"status-length\" "
"(%d) is > 32, ignoring!\n", buf);
}
DBG (15, "sane_get_devices: setting \"status-length\" "
"to %d\n", buf);
global_status_length = buf;
}
/* VENDOR: we ingest up to 8 bytes */
else if (!strncmp (lp, "vendor-name", 11) && isspace (lp[11])) {
lp += 11;
lp = sanei_config_skip_whitespace (lp);
strncpy(global_vendor_name, lp, 8);
global_vendor_name[8] = 0;
DBG (15, "sane_get_devices: setting \"vendor-name\" to %s\n",
global_vendor_name);
}
/* MODEL: we ingest up to 16 bytes */
else if (!strncmp (lp, "model-name", 10) && isspace (lp[10])) {
lp += 10;
lp = sanei_config_skip_whitespace (lp);
strncpy(global_model_name, lp, 16);
global_model_name[16] = 0;
DBG (15, "sane_get_devices: setting \"model-name\" to %s\n",
global_model_name);
}
/* VERSION: we ingest up to 4 bytes */
else if (!strncmp (lp, "version-name", 12) && isspace (lp[12])) {
lp += 12;
lp = sanei_config_skip_whitespace (lp);
strncpy(global_version_name, lp, 4);
global_version_name[4] = 0;
DBG (15, "sane_get_devices: setting \"version-name\" to %s\n",
global_version_name);
}
else { else {
DBG (5, "sane_get_devices: config option \"%s\" unrecognized - ignored.\n", lp); DBG (5, "sane_get_devices: config option \"%s\" unrecognized "
"- ignored.\n", lp);
} }
} }
else if ((strncmp ("usb", lp, 3) == 0) && isspace (lp[3])) { else if ((strncmp ("usb", lp, 3) == 0) && isspace (lp[3])) {
DBG (15, "sane_get_devices: looking for '%s'\n", lp); DBG (15, "sane_get_devices: looking for '%s'\n", lp);
sanei_usb_attach_matching_devices(lp, attach_one_usb); sanei_usb_attach_matching_devices(lp, attach_one_usb);
/* re-default these after reading the usb line */
default_globals();
} }
else if ((strncmp ("scsi", lp, 4) == 0) && isspace (lp[4])) { else if ((strncmp ("scsi", lp, 4) == 0) && isspace (lp[4])) {
DBG (15, "sane_get_devices: looking for '%s'\n", lp); DBG (15, "sane_get_devices: looking for '%s'\n", lp);
sanei_config_attach_matching_devices (lp, attach_one_scsi); sanei_config_attach_matching_devices (lp, attach_one_scsi);
/* re-default these after reading the scsi line */
default_globals();
} }
else{ else{
DBG (5, "sane_get_devices: config line \"%s\" unrecognized - ignored.\n", lp); DBG (5, "sane_get_devices: config line \"%s\" unrecognized - "
"ignored.\n", lp);
} }
} }
fclose (fp); fclose (fp);
} }
else { else {
DBG (5, "sane_get_devices: no config file '%s', using defaults\n", CANON_DR_CONFIG_FILE); DBG (5, "sane_get_devices: missing required config file '%s'!\n",
CANON_DR_CONFIG_FILE);
DBG (15, "sane_get_devices: looking for 'scsi CANON CR'\n");
sanei_config_attach_matching_devices ("scsi CANON CR", attach_one_scsi);
DBG (15, "sane_get_devices: looking for 'scsi CANON DR'\n");
sanei_config_attach_matching_devices ("scsi CANON DR", attach_one_scsi);
DBG (15, "sane_get_devices: looking for 'usb 0x04a9 0x1601'\n");
sanei_usb_attach_matching_devices("usb 0x04a9 0x1601", attach_one_usb);
DBG (15, "sane_get_devices: looking for 'usb 0x04a9 0x1602'\n");
sanei_usb_attach_matching_devices("usb 0x04a9 0x1602", attach_one_usb);
DBG (15, "sane_get_devices: looking for 'usb 0x04a9 0x1603'\n");
sanei_usb_attach_matching_devices("usb 0x04a9 0x1603", attach_one_usb);
DBG (15, "sane_get_devices: looking for 'usb 0x04a9 0x1604'\n");
sanei_usb_attach_matching_devices("usb 0x04a9 0x1604", attach_one_usb);
DBG (15, "sane_get_devices: looking for 'usb 0x04a9 0x1606'\n");
sanei_usb_attach_matching_devices("usb 0x04a9 0x1606", attach_one_usb);
DBG (15, "sane_get_devices: looking for 'usb 0x04a9 0x1607'\n");
sanei_usb_attach_matching_devices("usb 0x04a9 0x1607", attach_one_usb);
DBG (15, "sane_get_devices: looking for 'usb 0x04a9 0x1608'\n");
sanei_usb_attach_matching_devices("usb 0x04a9 0x1608", attach_one_usb);
DBG (15, "sane_get_devices: looking for 'usb 0x04a9 0x1609'\n");
sanei_usb_attach_matching_devices("usb 0x04a9 0x1609", attach_one_usb);
DBG (15, "sane_get_devices: looking for 'usb 0x04a9 0x160a'\n");
sanei_usb_attach_matching_devices("usb 0x04a9 0x160a", attach_one_usb);
DBG (15, "sane_get_devices: looking for 'usb 0x04a9 0x160b'\n");
sanei_usb_attach_matching_devices("usb 0x04a9 0x160b", attach_one_usb);
DBG (15, "sane_get_devices: looking for 'usb 0x1083 0x160c'\n");
sanei_usb_attach_matching_devices("usb 0x1083 0x160c", attach_one_usb);
DBG (15, "sane_get_devices: looking for 'usb 0x1083 0x160f'\n");
sanei_usb_attach_matching_devices("usb 0x1083 0x160f", attach_one_usb);
DBG (15, "sane_get_devices: looking for 'usb 0x04a9 0x2222'\n");
sanei_usb_attach_matching_devices("usb 0x04a9 0x2222", attach_one_usb);
DBG (15, "sane_get_devices: looking for 'usb 0x1083 0x1614'\n");
sanei_usb_attach_matching_devices("usb 0x1083 0x1614", attach_one_usb);
DBG (15, "sane_get_devices: looking for 'usb 0x1083 0x1617'\n");
sanei_usb_attach_matching_devices("usb 0x1083 0x1617", attach_one_usb);
DBG (15, "sane_get_devices: looking for 'usb 0x1083 0x1618'\n");
sanei_usb_attach_matching_devices("usb 0x1083 0x1618", attach_one_usb);
DBG (15, "sane_get_devices: looking for 'usb 0x1083 0x161a'\n");
sanei_usb_attach_matching_devices("usb 0x1083 0x161a", attach_one_usb);
DBG (15, "sane_get_devices: looking for 'usb 0x1083 0x161b'\n");
sanei_usb_attach_matching_devices("usb 0x1083 0x161b", attach_one_usb);
DBG (15, "sane_get_devices: looking for 'usb 0x1083 0x161d'\n");
sanei_usb_attach_matching_devices("usb 0x1083 0x161d", attach_one_usb);
DBG (15, "sane_get_devices: looking for 'usb 0x1083 0x1620'\n");
sanei_usb_attach_matching_devices("usb 0x1083 0x1620", attach_one_usb);
} }
/*delete missing scanners from list*/ /*delete missing scanners from list*/
@ -559,8 +592,9 @@ attach_one (const char *device_name, int connType)
if ((s = calloc (sizeof (*s), 1)) == NULL) if ((s = calloc (sizeof (*s), 1)) == NULL)
return SANE_STATUS_NO_MEM; return SANE_STATUS_NO_MEM;
/* scsi command/data buffer */ /* config file settings */
s->buffer_size = global_buffer_size; s->buffer_size = global_buffer_size;
s->status_length = global_status_length;
/* copy the device name */ /* copy the device name */
strcpy (s->device_name, device_name); strcpy (s->device_name, device_name);
@ -568,15 +602,18 @@ attach_one (const char *device_name, int connType)
/* connect the fd */ /* connect the fd */
s->connection = connType; s->connection = connType;
s->fd = -1; s->fd = -1;
s->fds[0] = -1;
s->fds[1] = -1;
ret = connect_fd(s); ret = connect_fd(s);
if(ret != SANE_STATUS_GOOD){ if(ret != SANE_STATUS_GOOD){
free (s); free (s);
return ret; return ret;
} }
/* Now query the device to load its vendor/model/version */ /* query the device to load its vendor/model/version, */
/* if config file doesn't give all three */
if ( !strlen(global_vendor_name)
|| !strlen(global_model_name)
|| !strlen(global_version_name)
){
ret = init_inquire (s); ret = init_inquire (s);
if (ret != SANE_STATUS_GOOD) { if (ret != SANE_STATUS_GOOD) {
disconnect_fd(s); disconnect_fd(s);
@ -584,8 +621,18 @@ attach_one (const char *device_name, int connType)
DBG (5, "attach_one: inquiry failed\n"); DBG (5, "attach_one: inquiry failed\n");
return ret; return ret;
} }
}
/* override any inquiry settings with those from config file */
if(strlen(global_vendor_name))
strcpy(s->vendor_name, global_vendor_name);
if(strlen(global_model_name))
strcpy(s->model_name, global_model_name);
if(strlen(global_version_name))
strcpy(s->version_name, global_version_name);
/* load detailed specs/capabilities from the device */ /* load detailed specs/capabilities from the device */
/* if a model cannot support inquiry vpd, this function will die */
ret = init_vpd (s); ret = init_vpd (s);
if (ret != SANE_STATUS_GOOD) { if (ret != SANE_STATUS_GOOD) {
disconnect_fd(s); disconnect_fd(s);
@ -595,7 +642,7 @@ attach_one (const char *device_name, int connType)
} }
/* clean up the scanner struct based on model */ /* clean up the scanner struct based on model */
/* this is the only piece of model specific code */ /* this is the big piece of model specific code */
ret = init_model (s); ret = init_model (s);
if (ret != SANE_STATUS_GOOD) { if (ret != SANE_STATUS_GOOD) {
disconnect_fd(s); disconnect_fd(s);
@ -692,6 +739,7 @@ connect_fd (struct scanner *s)
/* first generation usb scanners can get flaky if not closed /* first generation usb scanners can get flaky if not closed
* properly after last use. very first commands sent to device * properly after last use. very first commands sent to device
* must be prepared to correct this- see wait_scanner() */ * must be prepared to correct this- see wait_scanner() */
sleep(1);
ret = wait_scanner(s); ret = wait_scanner(s);
if (ret != SANE_STATUS_GOOD) { if (ret != SANE_STATUS_GOOD) {
DBG (5, "connect_fd: could not wait_scanner\n"); DBG (5, "connect_fd: could not wait_scanner\n");
@ -740,6 +788,7 @@ init_inquire (struct scanner *s)
); );
if (ret != SANE_STATUS_GOOD){ if (ret != SANE_STATUS_GOOD){
DBG (10, "init_inquire: failed: %d\n", ret);
return ret; return ret;
} }
@ -766,14 +815,16 @@ init_inquire (struct scanner *s)
/*check for vendor name*/ /*check for vendor name*/
if (strcmp ("CANON", s->vendor_name)) { if (strcmp ("CANON", s->vendor_name)) {
DBG (5, "The device at '%s' is reported to be made by '%s'\n", s->device_name, s->vendor_name); DBG (5, "The device at '%s' is reported to be made by '%s'\n",
s->device_name, s->vendor_name);
DBG (5, "This backend only supports Canon products.\n"); DBG (5, "This backend only supports Canon products.\n");
return SANE_STATUS_INVAL; return SANE_STATUS_INVAL;
} }
/*check for model name*/ /*check for model name*/
if (strncmp ("DR", s->model_name, 2) && strncmp ("CR", s->model_name, 2)) { if (strncmp ("DR", s->model_name, 2) && strncmp ("CR", s->model_name, 2)) {
DBG (5, "The device at '%s' is reported to be a '%s'\n", s->device_name, s->model_name); DBG (5, "The device at '%s' is reported to be a '%s'\n",
s->device_name, s->model_name);
DBG (5, "This backend only supports Canon CR & DR-series products.\n"); DBG (5, "This backend only supports Canon CR & DR-series products.\n");
return SANE_STATUS_INVAL; return SANE_STATUS_INVAL;
} }
@ -949,13 +1000,10 @@ init_model (struct scanner *s)
s->reverse_by_mode[MODE_GRAYSCALE] = 0; s->reverse_by_mode[MODE_GRAYSCALE] = 0;
s->reverse_by_mode[MODE_COLOR] = 0; s->reverse_by_mode[MODE_COLOR] = 0;
s->can_color = 1; s->has_counter = 1;
s->has_rif = 0;
s->has_adf = 1; s->has_adf = 1;
s->has_duplex = 1; s->has_duplex = 1;
s->has_buffer = 1; s->has_buffer = 1;
s->has_back = 0;
s->has_comp_JPEG = 0;
s->brightness_steps = 255; s->brightness_steps = 255;
s->contrast_steps = 255; s->contrast_steps = 255;
@ -969,16 +1017,42 @@ init_model (struct scanner *s)
s->max_x_fb = s->max_x; s->max_x_fb = s->max_x;
s->max_y_fb = s->max_y; s->max_y_fb = s->max_y;
/* any settings missing from vpd */ /* generic settings missing from vpd */
if (strstr (s->model_name,"C")){
s->can_color = 1;
}
if (strstr (s->model_name,"DR-1")
|| strstr (s->model_name,"DR-2")
){
s->color_interlace = COLOR_INTERLACE_RRGGBB;
s->duplex_interlace = DUPLEX_INTERLACE_BYTE;
s->can_halftone = 0;
s->can_monochrome = 0;
s->has_counter = 0;
}
/* specific settings missing from vpd */
if (strstr (s->model_name,"DR-9080")){ if (strstr (s->model_name,"DR-9080")){
s->has_comp_JPEG = 1; s->has_comp_JPEG = 1;
s->unknown_byte = 0x20;
}
else if (strstr (s->model_name,"DR-7580")){
s->has_comp_JPEG = 1;
s->unknown_byte = 0x20;
}
else if (strstr (s->model_name,"DR-2580")){
s->invert_tly = 1;
s->unknown_byte = 0x10;
s->has_counter = 1; s->has_counter = 1;
} }
if (strstr (s->model_name,"DR-7580")){ else if (strstr (s->model_name,"DR-2510")){
s->can_color = 0; s->unknown_byte = 0x10;
s->has_comp_JPEG = 1; s->unknown_byte2 = 0x80;
s->has_counter = 1; s->has_counter = 1;
s->head_interlace = HEAD_INTERLACE_2510;
} }
DBG (10, "init_model: finish\n"); DBG (10, "init_model: finish\n");
@ -2952,15 +3026,7 @@ sane_start (SANE_Handle handle)
} }
/* /*
* Creates a temporary file, opens it, and stores file pointer for it. * callocs a buffer to hold the scan data
* OR, callocs a buffer to hold the scan data
*
* Will only create a file that
* doesn't exist already. The function will also unlink ("delete") the file
* immediately after it is created. In any "sane" programming environment this
* has the effect that the file can be used for reading and writing as normal
* but vanishes as soon as it's closed - so no cleanup required if the
* process dies etc.
*/ */
static SANE_Status static SANE_Status
setup_buffers (struct scanner *s) setup_buffers (struct scanner *s)
@ -2970,18 +3036,8 @@ setup_buffers (struct scanner *s)
DBG (10, "setup_buffers: start\n"); DBG (10, "setup_buffers: start\n");
/* cleanup existing first */
for(side=0;side<2;side++){ for(side=0;side<2;side++){
/* close old file */
if (s->fds[side] != -1) {
DBG (15, "setup_buffers: closing old tempfile %d.\n",side);
if(close(s->fds[side])){
DBG (5, "setup_buffers: attempt to close tempfile %d returned %d.\n", side, errno);
}
s->fds[side] = -1;
}
/* free old mem */ /* free old mem */
if (s->buffers[side]) { if (s->buffers[side]) {
DBG (15, "setup_buffers: free buffer %d.\n",side); DBG (15, "setup_buffers: free buffer %d.\n",side);
@ -3047,8 +3103,13 @@ set_window (struct scanner *s)
/* we have to center the window ourselves */ /* we have to center the window ourselves */
set_WD_ULX (desc1, s->tl_x + (s->max_x - s->page_width) / 2); set_WD_ULX (desc1, s->tl_x + (s->max_x - s->page_width) / 2);
set_WD_ULY (desc1, s->tl_y); set_WD_ULY (desc1, s->tl_y);
/* some models require that the tly value be inverted? */
if(s->invert_tly){
set_WD_ULY (desc1, ~s->tl_y);
}
set_WD_width (desc1, s->params.pixels_per_line * 1200/s->resolution_x); set_WD_width (desc1, s->params.pixels_per_line * 1200/s->resolution_x);
set_WD_length (desc1, s->params.lines * 1200/s->resolution_y); set_WD_length (desc1, s->params.lines * 1200/s->resolution_y);
@ -3074,7 +3135,8 @@ set_window (struct scanner *s)
set_WD_rif (desc1, s->rif); set_WD_rif (desc1, s->rif);
/*FIXME: what is this? */ /*FIXME: what is this? */
set_WD_reserved(desc1, 1); set_WD_reserved(desc1, s->unknown_byte);
set_WD_reserved2(desc1, s->unknown_byte2);
set_WD_compress_type(desc1, COMP_NONE); set_WD_compress_type(desc1, COMP_NONE);
set_WD_compress_arg(desc1, 0); set_WD_compress_arg(desc1, 0);
@ -3270,6 +3332,7 @@ sane_read (SANE_Handle handle, SANE_Byte * buf, SANE_Int max_len, SANE_Int * len
/* alternating pnm interlacing */ /* alternating pnm interlacing */
if(s->source == SOURCE_ADF_DUPLEX if(s->source == SOURCE_ADF_DUPLEX
&& s->params.format != SANE_FRAME_JPEG
&& s->duplex_interlace == DUPLEX_INTERLACE_ALT){ && s->duplex_interlace == DUPLEX_INTERLACE_ALT){
/* buffer front side */ /* buffer front side */
@ -3292,6 +3355,31 @@ sane_read (SANE_Handle handle, SANE_Byte * buf, SANE_Int max_len, SANE_Int * len
} /* end alt pnm */ } /* end alt pnm */
/* byte-level pnm interlacing */
else if(s->source == SOURCE_ADF_DUPLEX
&& s->params.format != SANE_FRAME_JPEG
&& s->duplex_interlace == DUPLEX_INTERLACE_BYTE){
/* buffer both sides */
if ( s->bytes_tot[SIDE_FRONT] > s->bytes_rx[SIDE_FRONT]
|| s->bytes_tot[SIDE_BACK] > s->bytes_rx[SIDE_BACK]){
ret = read_from_scanner_duplex(s);
if(ret){
DBG(5,"sane_read: front returning %d\n",ret);
return ret;
}
/* we have finished reading, clean up */
/* grab a bit more so scanner will send eof */
if(s->connection == CONNECTION_USB
&& s->bytes_tot[SIDE_FRONT] == s->bytes_rx[SIDE_FRONT]
&& s->bytes_tot[SIDE_BACK] == s->bytes_rx[SIDE_BACK]
){
read_from_scanner_duplex(s);
}
}
}
/* simplex or non-alternating duplex */ /* simplex or non-alternating duplex */
else{ else{
@ -3306,9 +3394,7 @@ sane_read (SANE_Handle handle, SANE_Byte * buf, SANE_Int max_len, SANE_Int * len
/* grab a bit more so scanner will send eof */ /* grab a bit more so scanner will send eof */
if(s->connection == CONNECTION_USB if(s->connection == CONNECTION_USB
&& s->bytes_rx[s->side] == s->bytes_tot[s->side] && s->bytes_rx[s->side] == s->bytes_tot[s->side]
&& (s->compress != COMP_JPEG && s->params.format != SANE_FRAME_JPEG
|| s->mode == MODE_HALFTONE
|| s->mode == MODE_LINEART)
){ ){
read_from_scanner(s, s->side); read_from_scanner(s, s->side);
} }
@ -3411,9 +3497,7 @@ read_from_scanner(struct scanner *s, int side)
} }
/* this is jpeg data, we need to fix the missing image size */ /* this is jpeg data, we need to fix the missing image size */
if(s->compress == COMP_JPEG if(s->params.format == SANE_FRAME_JPEG){
&& (s->mode == MODE_GRAYSCALE || s->mode == MODE_COLOR)
){
/* look for the SOF header near the beginning */ /* look for the SOF header near the beginning */
if(s->jpeg_stage == JPEG_STAGE_NONE || s->jpeg_ff_offset < 0x0d){ if(s->jpeg_stage == JPEG_STAGE_NONE || s->jpeg_ff_offset < 0x0d){
@ -3458,21 +3542,25 @@ read_from_scanner(struct scanner *s, int side)
} }
} }
} }
}
/* non-jpeg color, swap bgr to rgb, assumes full lines
else if (s->mode == MODE_COLOR){
unsigned char temp;
for (i=0; i < inLen/3; i++){
temp = in[i*3];
in[i*3] = in[i*3+2];
in[i*3+2] = temp;
}
}
*/
if(inLen && !extra){ if(inLen && !extra){
copy_buffer (s, in, inLen, side); copy_buffer (s, in, inLen, side);
} }
}
/*non-jpeg, scrambled read-heads*/
/*FIXME: color and duplex untested */
else if(s->head_interlace == HEAD_INTERLACE_2510){
if(inLen && !extra){
copy_buffer_2510 (s, in, inLen, side);
}
}
/*normal data*/
else {
if(inLen && !extra){
copy_buffer (s, in, inLen, side);
}
}
free(in); free(in);
@ -3486,6 +3574,134 @@ read_from_scanner(struct scanner *s, int side)
return ret; return ret;
} }
/* cheaper scanners interlace duplex scans on a byte basis
* this code splits that data into the front/back buffers */
static SANE_Status
read_from_scanner_duplex(struct scanner *s)
{
SANE_Status ret=SANE_STATUS_GOOD;
unsigned char cmd[READ_len];
size_t cmdLen = READ_len;
unsigned char * in;
size_t inLen = 0;
int bytes = s->buffer_size;
int remain = s->bytes_tot[SIDE_FRONT]+s->bytes_tot[SIDE_BACK]
- (s->bytes_rx[SIDE_FRONT]+s->bytes_rx[SIDE_BACK]);
int extra = 0;
DBG (10, "read_from_scanner_duplex: start\n");
/* figure out the max amount to transfer */
if(bytes > remain){
bytes = remain;
}
/* all requests must end on WIDE line boundary */
bytes -= (bytes % (s->params.bytes_per_line*2));
/* these machines always send 1 extra line, and they need to send EOF too
* so we ask for 2 lines extra, and throw them away */
if(!bytes){
DBG(5, "read_from_scanner_duplex: no bytes, asking for two lines\n");
bytes = 4 * s->params.bytes_per_line;
extra = 1;
}
DBG(15, "read_from_scanner_duplex: re:%d bu:%d pa:%d\n",
remain, s->buffer_size, bytes);
inLen = bytes;
in = malloc(inLen);
if(!in){
DBG(5, "read_from_scanner_duplex: not enough mem for buffer: %d\n",(int)inLen);
return SANE_STATUS_NO_MEM;
}
memset(cmd,0,cmdLen);
set_SCSI_opcode(cmd, READ_code);
set_R_datatype_code (cmd, SR_datatype_image);
set_R_xfer_length (cmd, inLen);
ret = do_cmd (
s, 1, 0,
cmd, cmdLen,
NULL, 0,
in, &inLen
);
if (ret == SANE_STATUS_GOOD) {
DBG(15, "read_from_scanner_duplex: got GOOD, returning GOOD\n");
}
else if (ret == SANE_STATUS_EOF) {
DBG(15, "read_from_scanner_duplex: got EOF, finishing\n");
}
else if (ret == SANE_STATUS_DEVICE_BUSY) {
DBG(5, "read_from_scanner_duplex: got BUSY, returning GOOD\n");
inLen = 0;
ret = SANE_STATUS_GOOD;
}
else {
DBG(5, "read_from_scanner_duplex: error reading data block status = %d\n",ret);
inLen = 0;
}
/* split the data between two buffers
* assumes that first byte of buffer is frontside data
* and that the buffer starts/ends on a wide line boundary */
if(inLen && !extra){
size_t i;
int j;
/*frontside, just copy*/
for(i=0; i<inLen; i+=2*s->params.bytes_per_line){
for(j=0; j<2*s->params.bytes_per_line; j+=2){
s->buffers[SIDE_FRONT][s->bytes_rx[SIDE_FRONT]++] = in[i+j];
}
}
/*backside color: channels are in RGB order, but each is mirrored*/
if(s->mode == MODE_COLOR){
for(i=0; i<inLen; i+=2*s->params.bytes_per_line){
for(j=s->params.pixels_per_line; j>0; j--){
s->buffers[SIDE_BACK][s->bytes_rx[SIDE_BACK]++] = in[i+j*2-1];
}
for(j=s->params.pixels_per_line; j>0; j--){
s->buffers[SIDE_BACK][s->bytes_rx[SIDE_BACK]++]
= in[i+2*s->params.pixels_per_line+j*2-1];
}
for(j=s->params.pixels_per_line; j>0; j--){
s->buffers[SIDE_BACK][s->bytes_rx[SIDE_BACK]++]
= in[i+4*s->params.pixels_per_line+j*2-1];
}
}
}
/*backside gray: single mirrored channel*/
else{
for(i=0; i<inLen; i+=2*s->params.bytes_per_line){
for(j=2*s->params.bytes_per_line; j>0; j-=2){
s->buffers[SIDE_BACK][s->bytes_rx[SIDE_BACK]++] = in[i+j-1];
}
}
}
}
free(in);
if(ret == SANE_STATUS_EOF){
s->bytes_tot[SIDE_FRONT] = s->bytes_rx[SIDE_FRONT];
s->bytes_tot[SIDE_BACK] = s->bytes_rx[SIDE_BACK];
ret = SANE_STATUS_GOOD;
}
DBG (10, "read_from_scanner_duplex: finish\n");
return ret;
}
static SANE_Status static SANE_Status
copy_buffer(struct scanner *s, unsigned char * buf, int len, int side) copy_buffer(struct scanner *s, unsigned char * buf, int len, int side)
{ {
@ -3501,6 +3717,41 @@ copy_buffer(struct scanner *s, unsigned char * buf, int len, int side)
return ret; return ret;
} }
/* NOTE: this code assumes buffer is scanline aligned */
static SANE_Status
copy_buffer_2510(struct scanner *s, unsigned char * buf, int len, int side)
{
SANE_Status ret=SANE_STATUS_GOOD;
int i, j;
int bwidth = s->params.bytes_per_line;
int twidth = bwidth/3;
int qwidth = bwidth/4;
DBG (10, "copy_buffer_2510: start\n");
for(i=0; i<len; i+=bwidth){
/* first head in 'blue' channel, 1/3rd width, mirrored */
for(j=0; j<twidth; j++){
s->buffers[side][s->bytes_rx[side]++] = buf[i+(twidth-j)*3-1];
}
/* second head in 'red' channel, 1/4 width, mirrored, shifted left */
for(j=0;j<qwidth;j++){
s->buffers[side][s->bytes_rx[side]++] = buf[i+(qwidth-j)*3-3];
}
/* third head in 'green' channel, 1/3rd width, mirrored */
for(j=0;j<twidth;j++){
s->buffers[side][s->bytes_rx[side]++] = buf[i+(twidth-j)*3-2];
}
}
DBG (10, "copy_buffer_2510: finish\n");
return ret;
}
static SANE_Status static SANE_Status
read_from_buffer(struct scanner *s, SANE_Byte * buf, read_from_buffer(struct scanner *s, SANE_Byte * buf,
SANE_Int max_len, SANE_Int * len, int side) SANE_Int max_len, SANE_Int * len, int side)
@ -3527,7 +3778,54 @@ read_from_buffer(struct scanner *s, SANE_Byte * buf,
return SANE_STATUS_GOOD; return SANE_STATUS_GOOD;
} }
/* jpeg data does not use typical interlacing or inverting, just copy */
if(s->compress == COMP_JPEG &&
(s->mode == MODE_COLOR || s->mode == MODE_GRAYSCALE)){
memcpy(buf,s->buffers[side]+s->bytes_tx[side],bytes); memcpy(buf,s->buffers[side]+s->bytes_tx[side],bytes);
}
/* not using jpeg, colors maybe interlaced, pixels maybe inverted */
else {
/* scanners interlace colors in many different ways */
/* use separate code to convert to regular rgb */
if(s->mode == MODE_COLOR){
int byteOff, lineOff;
switch (s->color_interlace) {
/* scanner returns pixel data as bgrbgr... */
case COLOR_INTERLACE_BGR:
for (i=0; i < bytes; i++){
byteOff = s->bytes_tx[side] + i;
buf[i] = s->buffers[side][ byteOff-((byteOff%3)-1)*2 ];
}
break;
/* one line has the following format:
* rrr...rrrggg...gggbbb...bbb */
case COLOR_INTERLACE_RRGGBB:
for (i=0; i < bytes; i++){
byteOff = s->bytes_tx[side] + i;
lineOff = byteOff % s->params.bytes_per_line;
buf[i] = s->buffers[side][
byteOff - lineOff /* line */
+ (lineOff%3)*s->params.pixels_per_line /* color */
+ (lineOff/3) /* pixel */
];
}
break;
default:
memcpy(buf,s->buffers[side]+s->bytes_tx[side],bytes);
break;
}
}
/* gray/ht/binary */
else{
memcpy(buf,s->buffers[side]+s->bytes_tx[side],bytes);
}
/* invert image if scanner needs it for this mode */ /* invert image if scanner needs it for this mode */
if (s->reverse_by_mode[s->mode]){ if (s->reverse_by_mode[s->mode]){
@ -3535,6 +3833,7 @@ read_from_buffer(struct scanner *s, SANE_Byte * buf,
buf[i] ^= 0xff; buf[i] ^= 0xff;
} }
} }
}
s->bytes_tx[side] += *len; s->bytes_tx[side] += *len;
@ -3676,6 +3975,16 @@ sane_exit (void)
/* /*
* @@ Section 5 - misc helper functions * @@ Section 5 - misc helper functions
*/ */
static void
default_globals(void)
{
global_buffer_size = global_buffer_size_default;
global_status_length = global_status_length_default;
global_vendor_name[0] = 0;
global_model_name[0] = 0;
global_version_name[0] = 0;
}
/* /*
* Called by the SANE SCSI core and our usb code on device errors * Called by the SANE SCSI core and our usb code on device errors
* parses the request sense return data buffer, * parses the request sense return data buffer,
@ -3947,7 +4256,7 @@ do_cmd(struct scanner *s, int runRS, int shortTime,
return SANE_STATUS_INVAL; return SANE_STATUS_INVAL;
} }
SANE_Status static SANE_Status
do_scsi_cmd(struct scanner *s, int runRS, int shortTime, do_scsi_cmd(struct scanner *s, int runRS, int shortTime,
unsigned char * cmdBuff, size_t cmdLen, unsigned char * cmdBuff, size_t cmdLen,
unsigned char * outBuff, size_t outLen, unsigned char * outBuff, size_t outLen,
@ -3997,7 +4306,7 @@ do_scsi_cmd(struct scanner *s, int runRS, int shortTime,
return ret; return ret;
} }
SANE_Status static SANE_Status
do_usb_cmd(struct scanner *s, int runRS, int shortTime, do_usb_cmd(struct scanner *s, int runRS, int shortTime,
unsigned char * cmdBuff, size_t cmdLen, unsigned char * cmdBuff, size_t cmdLen,
unsigned char * outBuff, size_t outLen, unsigned char * outBuff, size_t outLen,
@ -4008,13 +4317,13 @@ do_usb_cmd(struct scanner *s, int runRS, int shortTime,
* so make some local copies */ * so make some local copies */
size_t usb_cmdLen = USB_HEADER_LEN + USB_COMMAND_LEN; size_t usb_cmdLen = USB_HEADER_LEN + USB_COMMAND_LEN;
size_t usb_outLen = USB_HEADER_LEN + outLen; size_t usb_outLen = USB_HEADER_LEN + outLen;
size_t usb_statLen = USB_STATUS_LEN; size_t usb_statLen = s->status_length;
size_t askLen = 0; size_t askLen = 0;
/*copy the callers buffs into larger, padded ones*/ /*copy the callers buffs into larger, padded ones*/
unsigned char usb_cmdBuff[USB_HEADER_LEN + USB_COMMAND_LEN]; unsigned char usb_cmdBuff[USB_HEADER_LEN + USB_COMMAND_LEN];
unsigned char * usb_outBuff; unsigned char * usb_outBuff;
unsigned char usb_statBuff[USB_STATUS_LEN]; unsigned char usb_statBuff[USB_STATUS_LEN_MAX];
int cmdTime = USB_COMMAND_TIME; int cmdTime = USB_COMMAND_TIME;
int outTime = USB_DATA_TIME; int outTime = USB_DATA_TIME;
@ -4044,7 +4353,7 @@ do_usb_cmd(struct scanner *s, int runRS, int shortTime,
sanei_usb_set_timeout(cmdTime); sanei_usb_set_timeout(cmdTime);
/* write the command out */ /* write the command out */
DBG(25, "cmd: writing %lu bytes, timeout %d\n", (u_long)usb_cmdLen, DBG(25, "cmd: writing %d bytes, timeout %d\n", (int)usb_cmdLen,
cmdTime); cmdTime);
hexdump(30, "cmd: >>", usb_cmdBuff, usb_cmdLen); hexdump(30, "cmd: >>", usb_cmdBuff, usb_cmdLen);
ret = sanei_usb_write_bulk(s->fd, usb_cmdBuff, &usb_cmdLen); ret = sanei_usb_write_bulk(s->fd, usb_cmdBuff, &usb_cmdLen);
@ -4112,88 +4421,72 @@ do_usb_cmd(struct scanner *s, int runRS, int shortTime,
/* change timeout */ /* change timeout */
sanei_usb_set_timeout(inTime); sanei_usb_set_timeout(inTime);
DBG(25, "in: reading %lu bytes, timeout %d\n", DBG(25, "in: reading %d bytes, timeout %d\n", (int)askLen, inTime);
(unsigned long)askLen, inTime);
ret = sanei_usb_read_bulk(s->fd, inBuff, inLen); ret = sanei_usb_read_bulk(s->fd, inBuff, inLen);
DBG(25, "in: retVal %d\n", ret); DBG(25, "in: read %d bytes, retval %d\n", (int)*inLen, ret);
hexdump(30, "in: <<", inBuff, *inLen);
if(ret == SANE_STATUS_EOF){ if(!*inLen){
DBG(5,"in: got EOF, clearing\n"); DBG(5,"in: got no data, clearing\n");
return do_usb_reset(s,runRS); return do_usb_clear(s,runRS);
} }
if(ret != SANE_STATUS_GOOD){ if(ret != SANE_STATUS_GOOD){
DBG(5,"in: return error '%s'\n",sane_strstatus(ret)); DBG(5,"in: return error '%s'\n",sane_strstatus(ret));
return ret; return ret;
} }
if(*inLen != askLen){
DBG(25, "in: read %lu bytes\n", (unsigned long)*inLen);
if(*inLen){
hexdump(30, "in: <<", inBuff, *inLen);
}
if(*inLen && *inLen != askLen){
ret = SANE_STATUS_EOF; ret = SANE_STATUS_EOF;
DBG(5,"in: short read, %lu/%lu\n", DBG(5,"in: wrong size, %d/%d\n", (int)*inLen,(int)askLen);
(unsigned long)*inLen,(unsigned long)askLen);
} }
} }
/*gather the scsi status byte. use ret2 instead of ret for status*/ /*gather the scsi status byte. use ret2 instead of ret for status*/
memset(&usb_statBuff,0,USB_STATUS_LEN_MAX);
memset(&usb_statBuff,0,USB_STATUS_LEN);
/* change timeout */ /* change timeout */
sanei_usb_set_timeout(statTime); sanei_usb_set_timeout(statTime);
DBG(25, "stat: reading %d bytes, timeout %d\n", USB_STATUS_LEN, statTime); DBG(25, "stat: reading %d bytes, timeout %d\n", (int)usb_statLen, statTime);
ret2 = sanei_usb_read_bulk(s->fd, usb_statBuff, &usb_statLen); ret2 = sanei_usb_read_bulk(s->fd, usb_statBuff, &usb_statLen);
hexdump(30, "stat: <<", usb_statBuff, usb_statLen);
DBG(25, "stat: read %d bytes, retVal %d\n", (int)usb_statLen, ret2); DBG(25, "stat: read %d bytes, retVal %d\n", (int)usb_statLen, ret2);
hexdump(30, "stat: <<", usb_statBuff, usb_statLen);
if(ret2 == SANE_STATUS_EOF){ if(!usb_statLen){
DBG(5,"in: got EOF, clearing\n"); DBG(5,"stat: got no data, clearing\n");
return do_usb_reset(s,runRS); return do_usb_clear(s,runRS);
} }
if(ret2 != SANE_STATUS_GOOD){ if(ret2 != SANE_STATUS_GOOD){
DBG(5,"stat: return error '%s'\n",sane_strstatus(ret2)); DBG(5,"stat: return error '%s'\n",sane_strstatus(ret2));
return ret2; return ret2;
} }
if(usb_statLen != USB_STATUS_LEN){ if(usb_statLen != (size_t)s->status_length){
DBG(5,"stat: wrong size %d/%d\n", USB_STATUS_LEN, (int)usb_statLen); DBG(5,"stat: wrong size %d/%d\n", s->status_length, (int)usb_statLen);
return SANE_STATUS_IO_ERROR; return SANE_STATUS_IO_ERROR;
} }
/* busy status /* FIXME: interpret the status fields
if(usb_statBuff[USB_STATUS_OFFSET] == 8){ if(usb_statBuff[0] || usb_statBuff[1] || usb_statBuff[2] || usb_statBuff[3]){
DBG(25,"stat: busy\n");
return SANE_STATUS_DEVICE_BUSY;
}
*/
/* if there is a non-busy status >0, try to figure out why */
if(usb_statBuff[USB_STATUS_OFFSET] > 0
|| usb_statBuff[1] > 0
|| usb_statBuff[2] > 0
|| usb_statBuff[3] > 0){
DBG(25,"stat: bad stat?\n"); DBG(25,"stat: bad stat?\n");
return SANE_STATUS_IO_ERROR; return SANE_STATUS_IO_ERROR;
} }
*/
DBG (10, "do_usb_cmd: finish\n"); DBG (10, "do_usb_cmd: finish\n");
return ret; return ret;
} }
SANE_Status static SANE_Status
do_usb_reset(struct scanner *s, int runRS) do_usb_clear(struct scanner *s, int runRS)
{ {
SANE_Status ret, ret2; SANE_Status ret, ret2;
DBG (10, "do_usb_clear: start\n");
ret = sanei_usb_clear_halt(s->fd); ret = sanei_usb_clear_halt(s->fd);
if(ret != SANE_STATUS_GOOD){ if(ret != SANE_STATUS_GOOD){
DBG(5,"do_usb_reset: cant clear halt, returning %d\n", ret); DBG(5,"do_usb_clear: cant clear halt, returning %d\n", ret);
return ret; return ret;
} }
@ -4231,21 +4524,13 @@ do_usb_reset(struct scanner *s, int runRS)
/* parse the rs data */ /* parse the rs data */
ret2 = sense_handler( 0, rs_in, (void *)s ); ret2 = sense_handler( 0, rs_in, (void *)s );
/* this was a short read, but the usb layer did not know DBG (10, "do_usb_clear: finish after RS\n");
if(ret2 == SANE_STATUS_EOF && s->rs_info
&& inBuff && inLen && inTime){
*inLen = askLen - s->rs_info;
s->rs_info = 0;
DBG(5,"do_usb_cmd: short read via rs, %lu/%lu\n",
(unsigned long)*inLen,(unsigned long)askLen);
}
*/
return ret2; return ret2;
} }
DBG (10, "do_usb_reset: finish\n"); DBG (10, "do_usb_clear: finish with io error\n");
return ret; return SANE_STATUS_IO_ERROR;
} }
static SANE_Status static SANE_Status

Wyświetl plik

@ -1,11 +1,29 @@
# NOTE: any 'option' lines only apply to #######################################################################
# scanners discovered later in this file # NOTE: 'option' lines only apply to the devices found by
# the NEXT 'usb' or 'scsi' line. You may repeat the option line if
# required for multiple scanners of different models/connections.
# to set data buffer size, in bytes #######################################################################
# the value ranges from 4096 - infinity # Some machines are incapable of providing basic inquiry info, and will
# but you may have scanning problems with # lock up if asked for it. The driver will not ask for this info if all
# a value larger than 65536 (the default) # three of these options are provided. They should NOT be used unless
option buffer-size 65536 # you know for sure that your machine requires it.
# NOTE: the vendor and model must be correct. The version need not.
#option vendor-name CANON
#option model-name DR-2050C
#option version-name XXXX
#######################################################################
# Set data buffer size, in bytes. The value ranges from 4096 - infinity
# but you may have scanning problems with a value larger than default (64k)
#option buffer-size 65536
#######################################################################
# Most scanners use a 4 byte status, but some use 16
#option status-length 4
#######################################################################
# SCSI scanners:
# To search for any CANON scsi device, if name starts with 'CR' or 'DR' # To search for any CANON scsi device, if name starts with 'CR' or 'DR'
scsi CANON CR scsi CANON CR
@ -14,6 +32,9 @@ scsi CANON DR
# To use a specific scsi device # To use a specific scsi device
#scsi /dev/sg1 #scsi /dev/sg1
#######################################################################
# USB scanners:
# For Canon scanners connected via USB on a known device (kernel driver): # For Canon scanners connected via USB on a known device (kernel driver):
#usb /dev/usb/scanner0 #usb /dev/usb/scanner0
@ -22,9 +43,13 @@ scsi CANON DR
# NOTE: if you have to add your device here- please send the id and model # NOTE: if you have to add your device here- please send the id and model
# to the author via email, so it can be included in next version. kitno455 at # to the author via email, so it can be included in next version. kitno455 at
# gmail dot com - with Fujitsu in the subject line # gmail dot com - with canon_dr in the subject line
# DR-2080C # DR-2080C (uses weird protocol)
option vendor-name CANON
option model-name DR-2080C
option version-name XXXX
option status-length 16
usb 0x04a9 0x1601 usb 0x04a9 0x1601
# CR-180 # CR-180
@ -48,7 +73,11 @@ usb 0x04a9 0x1608
# DR-3080CII # DR-3080CII
usb 0x04a9 0x1609 usb 0x04a9 0x1609
# DR-2050C/SP # DR-2050C/SP (uses weird protocol)
option vendor-name CANON
option model-name DR-2050C
option version-name XXXX
option status-length 16
usb 0x04a9 0x160a usb 0x04a9 0x160a
# DR-7580 # DR-7580

Wyświetl plik

@ -112,6 +112,7 @@ struct scanner
int max_x_basic; int max_x_basic;
int max_y_basic; int max_y_basic;
/*FIXME: 4 more unknown values here*/
int can_grayscale; int can_grayscale;
int can_halftone; int can_halftone;
int can_monochrome; int can_monochrome;
@ -143,8 +144,15 @@ struct scanner
int has_comp_JPEG; int has_comp_JPEG;
int has_buffer; int has_buffer;
int invert_tly; /* weird bug in some smaller scanners */
int unknown_byte; /* weird byte, required, meaning unknown */
int unknown_byte2; /* weird byte, required, meaning unknown */
size_t status_length; /* usually 4, sometimes 16 */
int color_interlace; /* different models interlace colors differently */ int color_interlace; /* different models interlace colors differently */
int duplex_interlace; /* different models interlace sides differently */ int duplex_interlace; /* different models interlace sides differently */
int head_interlace; /* different models interlace heads differently */
int jpeg_interlace; /* different models interlace jpeg sides differently */
int reverse_by_mode[6]; /* mode specific */ int reverse_by_mode[6]; /* mode specific */
@ -264,7 +272,6 @@ struct scanner
int bytes_tx[2]; int bytes_tx[2];
unsigned char * buffers[2]; unsigned char * buffers[2];
int fds[2];
/* --------------------------------------------------------------------- */ /* --------------------------------------------------------------------- */
/* values used by the command and data sending functions (scsi/usb) */ /* values used by the command and data sending functions (scsi/usb) */
@ -321,13 +328,19 @@ enum {
#define COLOR_WHITE 1 #define COLOR_WHITE 1
#define COLOR_BLACK 2 #define COLOR_BLACK 2
#define COLOR_INTERLACE_UNK 0 #define HEAD_INTERLACE_NONE 0
#define COLOR_INTERLACE_RGB 1 #define HEAD_INTERLACE_2510 1
#define COLOR_INTERLACE_BGR 2
#define COLOR_INTERLACE_RRGGBB 3 #define COLOR_INTERLACE_RGB 0
#define COLOR_INTERLACE_BGR 1
#define COLOR_INTERLACE_RRGGBB 2
#define DUPLEX_INTERLACE_NONE 0 #define DUPLEX_INTERLACE_NONE 0
#define DUPLEX_INTERLACE_ALT 1 #define DUPLEX_INTERLACE_ALT 1
#define DUPLEX_INTERLACE_BYTE 2
#define JPEG_INTERLACE_ALT 0
#define JPEG_INTERLACE_NONE 1
#define CROP_RELATIVE 0 #define CROP_RELATIVE 0
#define CROP_ABSOLUTE 1 #define CROP_ABSOLUTE 1
@ -428,7 +441,7 @@ do_usb_cmd(struct scanner *s, int runRS, int shortTime,
unsigned char * inBuff, size_t * inLen unsigned char * inBuff, size_t * inLen
); );
static SANE_Status do_usb_reset(struct scanner *s, int runRS); static SANE_Status do_usb_clear(struct scanner *s, int runRS);
static SANE_Status wait_scanner (struct scanner *s); static SANE_Status wait_scanner (struct scanner *s);
@ -451,14 +464,17 @@ static SANE_Status start_scan (struct scanner *s);
static SANE_Status cancel(struct scanner *s); static SANE_Status cancel(struct scanner *s);
static SANE_Status read_from_scanner(struct scanner *s, int side); static SANE_Status read_from_scanner(struct scanner *s, int side);
static SANE_Status read_from_scanner_duplex(struct scanner *s);
static SANE_Status copy_buffer(struct scanner *s, unsigned char * buf, int len, int side); static SANE_Status copy_buffer(struct scanner *s, unsigned char * buf, int len, int side);
static SANE_Status copy_buffer_2510(struct scanner *s, unsigned char * buf, int len, int side);
static SANE_Status read_from_buffer(struct scanner *s, SANE_Byte * buf, SANE_Int max_len, SANE_Int * len, int side); static SANE_Status read_from_buffer(struct scanner *s, SANE_Byte * buf, SANE_Int max_len, SANE_Int * len, int side);
static SANE_Status setup_buffers (struct scanner *s); static SANE_Status setup_buffers (struct scanner *s);
static void hexdump (int level, char *comment, unsigned char *p, int l); static void hexdump (int level, char *comment, unsigned char *p, int l);
static void default_globals (void);
static size_t maxStringSize (const SANE_String_Const strings[]); static size_t maxStringSize (const SANE_String_Const strings[]);

Wyświetl plik

@ -11,7 +11,7 @@
:backend "canon_dr" ; name of backend :backend "canon_dr" ; name of backend
:url "http://www.thebility.com/canon/" :url "http://www.thebility.com/canon/"
:version "13" ; version of backend :version "18" ; version of backend
:manpage "sane-canon_dr" ; name of manpage (if it exists) :manpage "sane-canon_dr" ; name of manpage (if it exists)
:comment "New backend as of SANE release 1.1.0, testers needed, see manpage" :comment "New backend as of SANE release 1.1.0, testers needed, see manpage"
:devicetype :scanner ; start of a list of devices.... :devicetype :scanner ; start of a list of devices....
@ -62,8 +62,8 @@
:model "DR-2050C" :model "DR-2050C"
:interface "USB" :interface "USB"
:usbid "0x04a9" "0x160a" :usbid "0x04a9" "0x160a"
:status :untested :status :basic
:comment "Please test!" :comment ""
:model "DR-2050SP" :model "DR-2050SP"
:interface "USB" :interface "USB"
@ -74,20 +74,20 @@
:model "DR-2080C" :model "DR-2080C"
:interface "USB SCSI" :interface "USB SCSI"
:usbid "0x04a9" "0x1601" :usbid "0x04a9" "0x1601"
:status :untested :status :basic
:comment "Please test!" :comment ""
:model "DR-2510C" :model "DR-2510C"
:interface "USB" :interface "USB"
:usbid "0x1083" "0x1617" :usbid "0x1083" "0x1617"
:status :untested :status :basic
:comment "Please test!" :comment "Only simplex gray works, requires user to always scan full-width."
:model "DR-2580C" :model "DR-2580C"
:interface "USB SCSI" :interface "USB SCSI"
:usbid "0x04a9" "0x1608" :usbid "0x04a9" "0x1608"
:status :untested :status :basic
:comment "Please test!" :comment "Gray and color, simplex and duplex working. Poor calibration."
:model "DR-3010C" :model "DR-3010C"
:interface "USB" :interface "USB"
@ -125,7 +125,7 @@
:interface "USB" :interface "USB"
:usbid "0x1083" "0x1614" :usbid "0x1083" "0x1614"
:status :good :status :good
:comment "" :comment "Multistream unsupported"
:model "DR4080U" :model "DR4080U"
:interface "USB" :interface "USB"