kopia lustrzana https://gitlab.com/sane-project/backends
				
				
				
			
		
			
				
	
	
		
			3552 wiersze
		
	
	
		
			110 KiB
		
	
	
	
		
			C
		
	
	
			
		
		
	
	
			3552 wiersze
		
	
	
		
			110 KiB
		
	
	
	
		
			C
		
	
	
| /*
 | ||
|  * kodakaio.c - SANE library for Kodak ESP Aio scanners.
 | ||
|  *
 | ||
|  * Copyright (C)   2011-2017 Paul Newall
 | ||
|  *
 | ||
|  * Based on the Magicolor sane backend:
 | ||
|  * Based on the epson2 sane backend:
 | ||
|  * Based on Kazuhiro Sasayama previous
 | ||
|  * work on epson.[ch] file from the SANE package.
 | ||
|  * Please see those files for additional copyrights.
 | ||
|  * Author: Paul Newall
 | ||
|  *
 | ||
|  * This program is free software; you can redistribute it and/or
 | ||
|  * modify it under the terms of the GNU General Public License as
 | ||
|  * published by the Free Software Foundation, version 2.
 | ||
| 
 | ||
|  * Modified 30/12/14 to fix bug where network connection was broken after 30s of idle time.
 | ||
|  * The connection is now made in sane_start and ended in sane_cancel.
 | ||
|  * 01/01/13 Now with adf, the scan can be padded to make up the full page length,
 | ||
|  * or the page can terminate at the end of the paper. This is a selectable option.
 | ||
|  * 25/11/12 Using avahi now for net autodiscovery. Use configure option --with-avahi to make sure it's enabled
 | ||
|  * 1/5/17 patched to use local pointer for avahi callback
 | ||
|  */
 | ||
| 
 | ||
| /*
 | ||
| Packages to add to a clean ubuntu install
 | ||
| libavahi-client-dev
 | ||
| libusb-dev
 | ||
| libsnmp-dev
 | ||
| 
 | ||
| convenient lines to paste
 | ||
| export SANE_DEBUG_KODAKAIO=20
 | ||
| 
 | ||
| for ubuntu prior to 12.10
 | ||
| ./configure --prefix=/usr --sysconfdir=/etc --localstatedir=/var BACKENDS="kodakaio test"
 | ||
| 
 | ||
| for ubuntu 12.10
 | ||
| ./configure --prefix=/usr --libdir=/usr/lib/i386-linux-gnu --sysconfdir=/etc --localstatedir=/var BACKENDS="kodakaio test"
 | ||
| 
 | ||
| for ubuntu 14.10 up to at least 17.04
 | ||
| ./configure --prefix=/usr --libdir=/usr/lib/x86_64-linux-gnu --sysconfdir=/etc --localstatedir=/var BACKENDS="kodakaio test"
 | ||
| 
 | ||
| If you want to use the test backend, for example with sane-troubleshoot, you should enable it in /etc/sane.d/dll.conf
 | ||
| 
 | ||
| */
 | ||
| 
 | ||
| /* SANE-FLOW-DIAGRAM  Kodakaio commands in [] brackets
 | ||
| 
 | ||
|    - sane_init() : initialize backend, attach scanners(devicename,0)
 | ||
|    . - sane_get_devices() : query list of scanner-devices
 | ||
|    . - sane_open() : open a particular scanner-device and attach_scanner(devicename,&dev)
 | ||
|    . . - sane_set_io_mode : set blocking-mode
 | ||
|    . . - sane_get_select_fd : get scanner-fd
 | ||
|    . . - sane_get_option_descriptor() : get option information
 | ||
|    . . - sane_control_option() : change option values
 | ||
|    . .
 | ||
|    . . - sane_start() : start image acquisition [V,L,F,S,C,D,O,Z] first time or after cancel. [(F),E,G] every time
 | ||
|    . .   - sane_get_parameters() : returns actual scan-parameters
 | ||
|    . .   - sane_read() : read image-data (from pipe)
 | ||
|    . . - sane_cancel() : cancel operation, kill reader_process [(F), U]
 | ||
| 
 | ||
|    . - sane_close() : close opened scanner-device, do_cancel, free buffer and handle
 | ||
|    - sane_exit() : terminate use of backend, free devicename and device-struture
 | ||
| */
 | ||
| /* FUNCTION-TREE
 | ||
| 	sane_init
 | ||
| 	sane_open
 | ||
| 		device_detect
 | ||
| 			k_dev_init
 | ||
| 			open_scanner
 | ||
| 			close_scanner
 | ||
| 		sane_get_devices
 | ||
| 		init_options
 | ||
| 		(open_scanner - moved to sane_start 27/12/14 )
 | ||
| 	sane_control_option
 | ||
| 		getvalue
 | ||
| 		setvalue
 | ||
| 			search_string_list
 | ||
| 			change_source
 | ||
| 				activateOption
 | ||
| 				deactivateOption
 | ||
| 	sane_start
 | ||
| 		open_scanner
 | ||
| 		k_init_parametersta
 | ||
| 		k_lock_scanner
 | ||
| 			k_hello
 | ||
| 		k_set_scanning_parameters
 | ||
| 		print_params
 | ||
| 		k_start_scan
 | ||
| 			cmd_start_scan
 | ||
| 				print_status
 | ||
| 				k_send
 | ||
| 				kodakaio_txrxack
 | ||
| 	sane_get_parameters
 | ||
| 		print_params
 | ||
| 	sane_read
 | ||
| 		k_read
 | ||
| 			cmd_read_data (reads one block)
 | ||
| 				k_recv
 | ||
| 			cmp_array
 | ||
| 	sane_cancel
 | ||
| 		cmd_cancel_scan
 | ||
| 		close_scanner
 | ||
| 	sane_close
 | ||
| 		(close_scanner - moved to sane_cancel 27/12/14)
 | ||
| 	sane_exit
 | ||
| 		free_devices
 | ||
| 	k_recv
 | ||
| 		kodakaio_net_read
 | ||
| 		dump_hex_buffer_dense
 | ||
| 	k_send
 | ||
| 		sanei_kodakaio_net_write_raw
 | ||
| 		dump_hex_buffer_dense
 | ||
| 	open_scanner
 | ||
| 		sanei_kodakaio_net_open
 | ||
| 	close_scanner
 | ||
| 		k_scan_finish
 | ||
| 			cmd_cancel_scan
 | ||
| 		sanei_kodakaio_net_close or sanei_usb_close
 | ||
| 	detect_usb
 | ||
| 		kodakaio_getNumberOfUSBProductIds
 | ||
| 	attach_one_config - (Passed to sanei_configure_attach)
 | ||
| 		kodakaio_getNumberOfUSBProductIds
 | ||
| 		kodak_network_discovery
 | ||
| 			client_callback
 | ||
| 			browse_callback
 | ||
| 				resolve_callback
 | ||
| 					ProcessAvahiDevice
 | ||
| 		attach_one_net
 | ||
| 	attach_one_net
 | ||
| 		attach
 | ||
| 			device_detect
 | ||
| 	attach_one_usb - (passed to sanei_usb_find_devices)
 | ||
| 		attach
 | ||
| 			device_detect
 | ||
| 	k_lock_scanner
 | ||
| 		kodakaio_txrx
 | ||
| 			k_send
 | ||
| 			k_recv
 | ||
| 	kodakaio_txrxack
 | ||
| 		k_send
 | ||
| 		k_recv
 | ||
| 	cmd_set_color_curve
 | ||
| 		kodakaio_expect_ack
 | ||
| 			k_recv
 | ||
| 	cmd_cancel_scan
 | ||
| 		kodakaio_txrxack
 | ||
| 	cmd_set_scanning_parameters
 | ||
| 		kodakaio_txrxack
 | ||
| 	device_detect
 | ||
| 		k_dev_init
 | ||
| */
 | ||
| 
 | ||
| 
 | ||
| #define KODAKAIO_VERSION	02
 | ||
| #define KODAKAIO_REVISION	7
 | ||
| #define KODAKAIO_BUILD		3
 | ||
| 
 | ||
| /* for usb (but also used for net though it's not required). */
 | ||
| #define MAX_BLOCK_SIZE		32768
 | ||
| 
 | ||
| #define SCANNER_READ_TIMEOUT	15
 | ||
| /* POLL_ITN_MS sets the individual poll timeout for network discovery */
 | ||
| #define POLL_ITN_MS 20
 | ||
| 
 | ||
| 
 | ||
| /* debugging levels:
 | ||
| In terminal use: export SANE_DEBUG_KODAKAIO=40 to set the level to 40 or whatever
 | ||
| level you want.
 | ||
| Then you can scan with scanimage or simple-scan from terminal and see debug info
 | ||
| 
 | ||
| use these defines to promote certain functions that you are interested in
 | ||
| define low values to make detail of a section appear when DBG level is low
 | ||
| define a high value eg 99 to get normal behaviour. */
 | ||
| #define DBG_READ		99
 | ||
| #define DBG_AUTO		99  /* for autodiscovery */
 | ||
| 
 | ||
| /*
 | ||
| normal levels. This system is a plan rather than a reality
 | ||
|  *
 | ||
|  *     127	recv buffer
 | ||
|  *     125	send buffer
 | ||
|  *	35	fine-grained status and progress
 | ||
|  *	30	sane_read
 | ||
|  *	25	setvalue, getvalue, control_option
 | ||
|  *	20	low-level (I/O) functions
 | ||
|  *	15	mid-level  functions
 | ||
|  *	10	high-level  functions
 | ||
|  *	 7	open/close/attach
 | ||
|  *	 6	print_params
 | ||
|  *	 5	basic functions
 | ||
|  *	 3	status info and progress
 | ||
|  *	 2	sane api
 | ||
|  *	 1	errors & warnings
 | ||
|  */
 | ||
| 
 | ||
| #include "sane/config.h"
 | ||
| 
 | ||
| #include <limits.h>
 | ||
| #include <stdio.h>
 | ||
| #include <string.h>
 | ||
| #include <stdlib.h>
 | ||
| #include <ctype.h>
 | ||
| #include <fcntl.h>
 | ||
| #include <unistd.h>
 | ||
| #include <errno.h>
 | ||
| #include <sys/time.h>
 | ||
| #include <math.h>
 | ||
| #include <poll.h>
 | ||
| #include <time.h>
 | ||
| #include <sys/socket.h>
 | ||
| 
 | ||
| #if WITH_AVAHI
 | ||
| /* used for auto detecting network printers  */
 | ||
| #include <assert.h>
 | ||
| #include <avahi-client/client.h>
 | ||
| #include <avahi-client/lookup.h>
 | ||
| #include <avahi-common/simple-watch.h>
 | ||
| #include <avahi-common/malloc.h>
 | ||
| #include <avahi-common/error.h>
 | ||
| #endif
 | ||
| 
 | ||
| #include "../include/sane/saneopts.h"
 | ||
| #include "../include/sane/sanei_usb.h"
 | ||
| #include "../include/sane/sanei_tcp.h"
 | ||
| #include "../include/sane/sanei_udp.h"
 | ||
| #include "../include/sane/sanei_config.h"
 | ||
| #include "../include/sane/sanei_backend.h"
 | ||
| 
 | ||
| #include "kodakaio.h"
 | ||
| 
 | ||
| /* vendor and product ids that are allowed */
 | ||
| #define SANE_KODAKAIO_VENDOR_ID	(0x040a)
 | ||
| 
 | ||
| #define min(x,y) (((x)<(y))?(x):(y))
 | ||
| 
 | ||
| /* I think these timeouts (ms) are defaults, overridden by any timeouts in the kodakaio.conf file */
 | ||
| static int K_SNMP_Timeout = 3000; /* used for any auto detection method */
 | ||
| static int K_Scan_Data_Timeout = 10000;
 | ||
| static int K_Request_Timeout = 5000;
 | ||
| 
 | ||
| /* static int bitposn=0; was used to pack bits into bytes in lineart mode */
 | ||
| 
 | ||
| /* This file is used to store directly the raster returned by the scanner for debugging
 | ||
| If RawScanPath has no length it will not be created */
 | ||
| FILE *RawScan = NULL;
 | ||
| /* example: char RawScanPath[] = "TestRawScan.pgm"; */
 | ||
| char RawScanPath[] = ""; /* empty path means no raw scan file is made */
 | ||
| 
 | ||
| /*
 | ||
|  *   Devices supported by this backend
 | ||
| */
 | ||
| 
 | ||
| /* kodak command strings */
 | ||
| static unsigned char KodakEsp_V[]      = {0x1b,'S','V',0,0,0,0,0};  /* version?? */
 | ||
| static unsigned char KodakEsp_v[]      = {0x1b,'s','v',0,0,0,0,0};  /* reply to version?? */
 | ||
| static unsigned char KodakEsp_Lock[]   = {0x1b,'S','L',0,0,0,0,0}; /* Locks scanner */
 | ||
| static unsigned char KodakEsp_UnLock[] = {0x1b,'S','U',0,0,0,0,0}; /* Unlocks scanner */
 | ||
| static unsigned char KodakEsp_Ack[]    = {0x1b,'S','S',0,0,0,0,0}; /* Acknowledge for all commands */
 | ||
| /* the bytes after esc S S 0 may indicate status: S S 0 1 = docs in adf */
 | ||
| static unsigned char KodakEsp_F[]      = {0x1b,'S','F',0,0,0,0,0}; /* Purpose not known? colour balance?*/
 | ||
| static unsigned char KodakEsp_Comp[]   = {0x1b,'S','C',3,8,3,0,0}; /* 3,8,3,1,0 does compression. */
 | ||
| /* The compression method is unknown */
 | ||
| /* static unsigned char KodakEsp_E[]   = {0x1b,'S','E',1,0,0,0,0};  NET Purpose not known */
 | ||
| /* the extra 1 below could be despeckle option? maybe only for Hero 9.1 but no errors with ESP5250 */
 | ||
| static unsigned char KodakEsp_E[]      = {0x1b,'S','E',1,1,0,0,0};
 | ||
| static unsigned char KodakEsp_Go[]     = {0x1b,'S','G',0,0,0,0,0}; /* Starts the scan */
 | ||
| /* Other commands are: D (resolution), O (top left), Z (bottom right), R, G, B (curves) */
 | ||
| 
 | ||
| /* What is the relationship between these and the ranges in cap? */
 | ||
| static SANE_Int kodakaio_resolution_list[] = {75, 150, 300, 600, 1200};
 | ||
| static SANE_Int kodakaio_depth_list[] = {1,8}; /* The first value is the number of following entries */
 | ||
| 
 | ||
| /* strings to try and match the model ';' separator
 | ||
| static unsigned char SupportedMatchString[] = "KODAK ESP;KODAK HERO;KODAK OFFICE HERO;ADVENT WiFi AIO;"; */
 | ||
| 
 | ||
| static struct KodakaioCap kodakaio_cap[] = {
 | ||
| /* usbid,commandtype, modelname, USBoutEP, USBinEP,
 | ||
| 	opticalres, {dpi range}, pointer to res list, res list size
 | ||
| 	max depth, pointer to depth list,
 | ||
| 	flatbed x range, flatbed y range,
 | ||
| 	adf present, adf duplex,
 | ||
| 	adf x range, adf y range (y range should be set a little shorter than the paper being scanned)
 | ||
| 
 | ||
| The following are not used but may be in future
 | ||
| commandtype, max depth, pointer to depth list
 | ||
| */
 | ||
| 
 | ||
| /* list of cap data the first scanner is the default
 | ||
| */
 | ||
|   /* KODAK AIO DEFAULT,  */
 | ||
|   {
 | ||
|       0x9999, "esp", "KODAK AIO DEFAULT",
 | ||
|       -1, 0x82, /* USBoutEP, USBinEP (-1 means find one) */
 | ||
|       600, {75, 600, 0}, kodakaio_resolution_list, 4,  /* 600 dpi max, 4 resolutions */
 | ||
|       8, kodakaio_depth_list,                          /* color depth max 8, list above */
 | ||
|       {0, SANE_FIX(8.5 * MM_PER_INCH), 0}, {0, SANE_FIX(11.7 * MM_PER_INCH), 0}, /* FBF x/y ranges */
 | ||
|       SANE_FALSE, SANE_FALSE, /* ADF, duplex */
 | ||
|       {0, SANE_FIX(100), 0}, {0, SANE_FIX(100), 0} /* ADF x/y ranges (TODO!) */
 | ||
|   },
 | ||
|   /* KODAK ESP 5100, */
 | ||
|   {
 | ||
|       0x4025, "esp", "KODAK ESP 5100 AiO",
 | ||
|       -1, 0x82, /* USBoutEP, USBinEP (-1 means find one) */
 | ||
|       600, {75, 600, 0}, kodakaio_resolution_list, 4,  /* 600 dpi max, 4 resolutions */
 | ||
|       8, kodakaio_depth_list,                          /* color depth max 8, list above */
 | ||
|       {0, SANE_FIX(8.5 * MM_PER_INCH), 0}, {0, SANE_FIX(11.7 * MM_PER_INCH), 0}, /* FBF x/y ranges */
 | ||
|       SANE_FALSE, SANE_FALSE, /* ADF, duplex */
 | ||
|       {0, SANE_FIX(8.5 * MM_PER_INCH), 0}, {0, SANE_FIX(14 * MM_PER_INCH), 0} /* 14 ADF x/y ranges */
 | ||
|   },
 | ||
|   /* KODAK ESP 5300, */
 | ||
|   {
 | ||
|       0x4026, "esp", "KODAK ESP 5300 AiO",
 | ||
|       -1, 0x82, /* USBoutEP, USBinEP (-1 means find one) */
 | ||
|       600, {75, 600, 0}, kodakaio_resolution_list, 4,  /* 600 dpi max, 4 resolutions */
 | ||
|       8, kodakaio_depth_list,                          /* color depth max 8, list above */
 | ||
|       {0, SANE_FIX(8.5 * MM_PER_INCH), 0}, {0, SANE_FIX(11.7 * MM_PER_INCH), 0}, /* FBF x/y ranges */
 | ||
|       SANE_FALSE, SANE_FALSE, /* ADF, duplex */
 | ||
|       {0, SANE_FIX(8.5 * MM_PER_INCH), 0}, {0, SANE_FIX(14 * MM_PER_INCH), 0} /* 14 ADF x/y ranges */
 | ||
|   },
 | ||
|   /* KODAK ESP 5500, */
 | ||
|   {
 | ||
|       0x4027, "esp", "KODAK ESP 5500 AiO",
 | ||
|       -1, 0x82, /* USBoutEP, USBinEP (-1 means find one) */
 | ||
|       600, {75, 600, 0}, kodakaio_resolution_list, 4,  /* 600 dpi max, 4 resolutions */
 | ||
|       8, kodakaio_depth_list,                          /* color depth max 8, list above */
 | ||
|       {0, SANE_FIX(8.5 * MM_PER_INCH), 0}, {0, SANE_FIX(11.7 * MM_PER_INCH), 0}, /* FBF x/y ranges */
 | ||
|       SANE_FALSE, SANE_FALSE, /* ADF, duplex */
 | ||
|       {0, SANE_FIX(8.5 * MM_PER_INCH), 0}, {0, SANE_FIX(14 * MM_PER_INCH), 0} /* 14 ADF x/y ranges */
 | ||
|   },
 | ||
|   /* KODAK ESP 5000, */
 | ||
|   {
 | ||
|       0x4028, "esp", "KODAK ESP 5000 Series AiO",
 | ||
|       -1, 0x82, /* USBoutEP, USBinEP (-1 means find one) */
 | ||
|       600, {75, 600, 0}, kodakaio_resolution_list, 4,  /* 600 dpi max, 4 resolutions */
 | ||
|       8, kodakaio_depth_list,                          /* color depth max 8, list above */
 | ||
|       {0, SANE_FIX(8.5 * MM_PER_INCH), 0}, {0, SANE_FIX(11.7 * MM_PER_INCH), 0}, /* FBF x/y ranges */
 | ||
|       SANE_FALSE, SANE_FALSE, /* ADF, duplex */
 | ||
|       {0, SANE_FIX(8.5 * MM_PER_INCH), 0}, {0, SANE_FIX(14 * MM_PER_INCH), 0} /* 14 ADF x/y ranges */
 | ||
|   },
 | ||
|    /* KODAK ESP 3300, */
 | ||
|   {
 | ||
|       0x4031, "esp", "KODAK ESP 3300 Series AiO",
 | ||
|       -1, 0x82, /* USBoutEP, USBinEP (-1 means find one) */
 | ||
|       600, {75, 600, 0}, kodakaio_resolution_list, 4,  /* 600 dpi max, 4 resolutions */
 | ||
|       8, kodakaio_depth_list,                          /* color depth max 8, list above */
 | ||
|       {0, SANE_FIX(8.5 * MM_PER_INCH), 0}, {0, SANE_FIX(11.7 * MM_PER_INCH), 0}, /* FBF x/y ranges */
 | ||
|       SANE_FALSE, SANE_FALSE, /* ADF, duplex */
 | ||
|       {0, SANE_FIX(8.5 * MM_PER_INCH), 0}, {0, SANE_FIX(14 * MM_PER_INCH), 0} /* 14 ADF x/y ranges */
 | ||
|   },
 | ||
|   /* KODAK ESP5, */
 | ||
|   {
 | ||
|       0x4032, "esp", "KODAK ESP 5 AiO",
 | ||
|       -1, 0x82, /* USBoutEP, USBinEP (-1 means find one) */
 | ||
|       600, {75, 600, 0}, kodakaio_resolution_list, 4,  /* 600 dpi max, 4 resolutions */
 | ||
|       8, kodakaio_depth_list,                          /* color depth max 8, list above */
 | ||
|       {0, SANE_FIX(8.5 * MM_PER_INCH), 0}, {0, SANE_FIX(11.7 * MM_PER_INCH), 0}, /* FBF x/y ranges */
 | ||
|       SANE_FALSE, SANE_FALSE, /* ADF, duplex */
 | ||
|       {0, SANE_FIX(8.5 * MM_PER_INCH), 0}, {0, SANE_FIX(14 * MM_PER_INCH), 0} /* 14 ADF x/y ranges */
 | ||
|   },
 | ||
|   /* KODAK ESP7, */
 | ||
|   {
 | ||
|       0x403E, "esp", "KODAK ESP 7 AiO",
 | ||
|       -1, 0x82, /* USBoutEP, USBinEP (-1 means find one) */
 | ||
|       600, {75, 600, 0}, kodakaio_resolution_list, 4,  /* 600 dpi max, 4 resolutions */
 | ||
|       8, kodakaio_depth_list,                          /* color depth max 8, list above */
 | ||
|       {0, SANE_FIX(8.5 * MM_PER_INCH), 0}, {0, SANE_FIX(11.7 * MM_PER_INCH), 0}, /* FBF x/y ranges */
 | ||
|       SANE_FALSE, SANE_FALSE, /* ADF, duplex */
 | ||
|       {0, SANE_FIX(8.5 * MM_PER_INCH), 0}, {0, SANE_FIX(14 * MM_PER_INCH), 0} /* 14 ADF x/y ranges */
 | ||
|   },
 | ||
|   /* KODAK ESP9, */
 | ||
|   {
 | ||
|       0x403F, "esp", "KODAK ESP 9 AiO",
 | ||
|       -1, 0x82, /* USBoutEP, USBinEP (-1 means find one) */
 | ||
|       600, {75, 600, 0}, kodakaio_resolution_list, 4,  /* 600 dpi max, 4 resolutions */
 | ||
|       8, kodakaio_depth_list,                          /* color depth max 8, list above */
 | ||
|       {0, SANE_FIX(8.5 * MM_PER_INCH), 0}, {0, SANE_FIX(11.7 * MM_PER_INCH), 0}, /* FBF x/y ranges */
 | ||
|       SANE_FALSE, SANE_FALSE, /* ADF, duplex */
 | ||
|       {0, SANE_FIX(8.5 * MM_PER_INCH), 0}, {0, SANE_FIX(14 * MM_PER_INCH), 0} /* 14 ADF x/y ranges */
 | ||
|   },
 | ||
|   /* KODAK ESP5210 or 5250, */
 | ||
|   {
 | ||
|       0x4041, "esp", "KODAK ESP 5200 Series AiO",
 | ||
|       -1, 0x82, /* USBoutEP, USBinEP (-1 means find one) */
 | ||
|       600, {75, 600, 0}, kodakaio_resolution_list, 4,  /* 600 dpi max, 4 resolutions */
 | ||
|       8, kodakaio_depth_list,                          /* color depth max 8, list above */
 | ||
|       {0, SANE_FIX(8.5 * MM_PER_INCH), 0}, {0, SANE_FIX(11.7 * MM_PER_INCH), 0}, /* FBF x/y ranges */
 | ||
|       SANE_FALSE, SANE_FALSE, /* ADF, duplex */
 | ||
|       {0, SANE_FIX(8.5 * MM_PER_INCH), 0}, {0, SANE_FIX(14 * MM_PER_INCH), 0} /* 14 ADF x/y ranges */
 | ||
|   },
 | ||
|   /* KODAK ESP3200 ,  */
 | ||
|   {
 | ||
|       0x4043, "esp", "KODAK ESP 3200 Series AiO",
 | ||
|       -1, 0x82,
 | ||
|       600, {75, 600, 0}, kodakaio_resolution_list, 4,  /* 600 dpi max, 4 resolutions */
 | ||
|       8, kodakaio_depth_list,                          /* color depth max 8, list above */
 | ||
|       {0, SANE_FIX(8.5 * MM_PER_INCH), 0}, {0, SANE_FIX(11.7 * MM_PER_INCH), 0}, /* FBF x/y ranges */
 | ||
|       SANE_FALSE, SANE_FALSE, /* ADF, duplex */
 | ||
|       {0, SANE_FIX(8.5 * MM_PER_INCH), 0}, {0, SANE_FIX(14 * MM_PER_INCH), 0} /* 14 ADF x/y ranges */
 | ||
|   },
 | ||
|   /* KODAK ESP4100 ,  */
 | ||
|   {
 | ||
|       0x4053, "esp", "KODAK ESP Office 4100 Series AiO",
 | ||
|       -1, 0x82,
 | ||
|       600, {75, 600, 0}, kodakaio_resolution_list, 4,  /* 600 dpi max, 4 resolutions */
 | ||
|       8, kodakaio_depth_list,                          /* color depth max 8, list above */
 | ||
|       {0, SANE_FIX(8.5 * MM_PER_INCH), 0}, {0, SANE_FIX(11.7 * MM_PER_INCH), 0}, /* FBF x/y ranges */
 | ||
|       SANE_FALSE, SANE_FALSE, /* ADF, duplex */
 | ||
|       {0, SANE_FIX(8.5 * MM_PER_INCH), 0}, {0, SANE_FIX(14 * MM_PER_INCH), 0} /* 14 ADF x/y ranges */
 | ||
|   },
 | ||
|   /* KODAK ESP6100 ,  */
 | ||
|   {
 | ||
|       0x4054, "esp", "KODAK ESP Office 6100 Series AiO",
 | ||
|       -1, 0x82,
 | ||
|       600, {75, 600, 0}, kodakaio_resolution_list, 4,  /* 600 dpi max, 4 resolutions */
 | ||
|       8, kodakaio_depth_list,                          /* color depth max 8, list above */
 | ||
|       {0, SANE_FIX(8.5 * MM_PER_INCH), 0}, {0, SANE_FIX(11.7 * MM_PER_INCH), 0}, /* FBF x/y ranges */
 | ||
|       SANE_TRUE, SANE_FALSE, /* ADF, duplex */
 | ||
|       {0, SANE_FIX(8.5 * MM_PER_INCH), 0}, {0, SANE_FIX(14 * MM_PER_INCH), 0} /* 14 ADF x/y ranges */
 | ||
|   },
 | ||
|   /* KODAK ESP7200 ,  */
 | ||
|   {
 | ||
|       0x4056, "esp", "KODAK ESP 7200 Series AiO",
 | ||
|       -1, 0x82,
 | ||
|       600, {75, 600, 0}, kodakaio_resolution_list, 4,  /* 600 dpi max, 4 resolutions */
 | ||
|       8, kodakaio_depth_list,                          /* color depth max 8, list above */
 | ||
|       {0, SANE_FIX(8.5 * MM_PER_INCH), 0}, {0, SANE_FIX(11.7 * MM_PER_INCH), 0}, /* FBF x/y ranges */
 | ||
|       SANE_FALSE, SANE_FALSE, /* ADF, duplex */
 | ||
|       {0, SANE_FIX(8.5 * MM_PER_INCH), 0}, {0, SANE_FIX(14 * MM_PER_INCH), 0} /* 14 ADF x/y ranges */
 | ||
|   },
 | ||
|   /* KODAK ESP C110 ,  */
 | ||
|   {
 | ||
|       0x4057, "esp", "KODAK ESP C110 AiO",
 | ||
|       -1, 0x82,
 | ||
|       600, {75, 600, 0}, kodakaio_resolution_list, 4,  /* 600 dpi max, 4 resolutions */
 | ||
|       8, kodakaio_depth_list,                          /* color depth max 8, list above */
 | ||
|       {0, SANE_FIX(8.5 * MM_PER_INCH), 0}, {0, SANE_FIX(11.7 * MM_PER_INCH), 0}, /* FBF x/y ranges */
 | ||
|       SANE_FALSE, SANE_FALSE, /* ADF, duplex */
 | ||
|       {0, SANE_FIX(8.5 * MM_PER_INCH), 0}, {0, SANE_FIX(14 * MM_PER_INCH), 0} /* 14 ADF x/y ranges */
 | ||
|   },
 | ||
|   /* KODAK ESP C115 ,  */
 | ||
|   {
 | ||
|       0x4058, "esp", "KODAK ESP C115 AiO",
 | ||
|       -1, 0x82,
 | ||
|       600, {75, 600, 0}, kodakaio_resolution_list, 4,  /* 600 dpi max, 4 resolutions */
 | ||
|       8, kodakaio_depth_list,                          /* color depth max 8, list above */
 | ||
|       {0, SANE_FIX(8.5 * MM_PER_INCH), 0}, {0, SANE_FIX(11.7 * MM_PER_INCH), 0}, /* FBF x/y ranges */
 | ||
|       SANE_FALSE, SANE_FALSE, /* ADF, duplex */
 | ||
|       {0, SANE_FIX(8.5 * MM_PER_INCH), 0}, {0, SANE_FIX(14 * MM_PER_INCH), 0} /* 14 ADF x/y ranges */
 | ||
|   },
 | ||
|   /* KODAK ESP 2150 ,  */
 | ||
|   {
 | ||
|       0x4059, "esp", "KODAK ESP Office 2150 Series",
 | ||
|       -1, 0x82,
 | ||
|       600, {75, 600, 0}, kodakaio_resolution_list, 4,  /* 600 dpi max, 4 resolutions */
 | ||
|       8, kodakaio_depth_list,                          /* color depth max 8, list above */
 | ||
|       {0, SANE_FIX(8.5 * MM_PER_INCH), 0}, {0, SANE_FIX(11.7 * MM_PER_INCH), 0}, /* FBF x/y ranges */
 | ||
|       SANE_TRUE, SANE_FALSE, /* ADF, duplex */
 | ||
|       {0, SANE_FIX(8.5 * MM_PER_INCH), 0}, {0, SANE_FIX(14 * MM_PER_INCH), 0} /* 14 ADF x/y ranges */
 | ||
|   },
 | ||
|   /* KODAK ESP C310 ,  */
 | ||
|   {
 | ||
|       0x405D, "esp", "KODAK ESP C310 AiO",
 | ||
|       -1, 0x82,
 | ||
|       600, {75, 600, 0}, kodakaio_resolution_list, 4,  /* 600 dpi max, 4 resolutions */
 | ||
|       8, kodakaio_depth_list,                          /* color depth max 8, list above */
 | ||
|       {0, SANE_FIX(8.5 * MM_PER_INCH), 0}, {0, SANE_FIX(11.7 * MM_PER_INCH), 0}, /* FBF x/y ranges */
 | ||
|       SANE_FALSE, SANE_FALSE, /* ADF, duplex */
 | ||
|       {0, SANE_FIX(8.5 * MM_PER_INCH), 0}, {0, SANE_FIX(14 * MM_PER_INCH), 0} /* 14 ADF x/y ranges */
 | ||
|   },
 | ||
|   /* KODAK ESP C315 ,  */
 | ||
|   {
 | ||
|       0x405E, "esp", "KODAK ESP C315 AiO",
 | ||
|       -1, 0x82,
 | ||
|       600, {75, 600, 0}, kodakaio_resolution_list, 4,  /* 600 dpi max, 4 resolutions */
 | ||
|       8, kodakaio_depth_list,                          /* color depth max 8, list above */
 | ||
|       {0, SANE_FIX(8.5 * MM_PER_INCH), 0}, {0, SANE_FIX(11.7 * MM_PER_INCH), 0}, /* FBF x/y ranges */
 | ||
|       SANE_FALSE, SANE_FALSE, /* ADF, duplex */
 | ||
|       {0, SANE_FIX(8.5 * MM_PER_INCH), 0}, {0, SANE_FIX(14 * MM_PER_INCH), 0} /* 14 ADF x/y ranges */
 | ||
|   },
 | ||
|   /* ADVENT AW10,   */
 | ||
|   {
 | ||
|       0x4060, "esp", "ADVENT WiFi AIO AW10",
 | ||
|       -1, 0x82,
 | ||
|       600, {75, 600, 0}, kodakaio_resolution_list, 4, /* 600 dpi max, {from, to, 0} 4 resolutions */
 | ||
|       8, kodakaio_depth_list,                          /* color depth max 8, list above */
 | ||
|       {0, SANE_FIX(8.5 * MM_PER_INCH), 0}, {0, SANE_FIX(11.7 * MM_PER_INCH), 0}, /* FBF x/y ranges */
 | ||
|       SANE_TRUE, SANE_FALSE, /* ADF, duplex. */
 | ||
|       {0, SANE_FIX(8.5 * MM_PER_INCH), 0}, {0, SANE_FIX(14 * MM_PER_INCH), 0} /* 14 ADF x/y ranges */
 | ||
|   },
 | ||
|   /* KODAK HERO 6.1,   */
 | ||
|   {
 | ||
|       0x4062, "esp", "KODAK OFFICE HERO 6.1 AiO",
 | ||
|       -1, 0x82,
 | ||
|       600, {75, 600, 0}, kodakaio_resolution_list, 4, /* 600 dpi max, {from, to, 0} 4 resolutions */
 | ||
|       8, kodakaio_depth_list,                          /* color depth max 8, list above */
 | ||
|       {0, SANE_FIX(8.5 * MM_PER_INCH), 0}, {0, SANE_FIX(11.7 * MM_PER_INCH), 0}, /* FBF x/y ranges */
 | ||
|       SANE_TRUE, SANE_FALSE, /* ADF, duplex. */
 | ||
|       {0, SANE_FIX(8.5 * MM_PER_INCH), 0}, {0, SANE_FIX(14 * MM_PER_INCH), 0} /* 14 ADF x/y ranges */
 | ||
|   },
 | ||
|   /* KODAK HERO 7.1,   */
 | ||
|   {
 | ||
|       0x4063, "esp", "KODAK HERO 7.1 AiO",
 | ||
|       -1, 0x82,
 | ||
|       600, {75, 600, 0}, kodakaio_resolution_list, 4, /* 600 dpi max, {from, to, 0} 4 resolutions */
 | ||
|       8, kodakaio_depth_list,                          /* color depth max 8, list above */
 | ||
|       {0, SANE_FIX(8.5 * MM_PER_INCH), 0}, {0, SANE_FIX(11.7 * MM_PER_INCH), 0}, /* FBF x/y ranges */
 | ||
|       SANE_FALSE, SANE_TRUE, /* ADF, duplex. */
 | ||
|       {0, SANE_FIX(8.5 * MM_PER_INCH), 0}, {0, SANE_FIX(14 * MM_PER_INCH), 0} /* 14 ADF x/y ranges */
 | ||
|   },
 | ||
|   /* KODAK HERO 5.1,   */
 | ||
|   {
 | ||
|       0x4064, "esp", "KODAK HERO 5.1 AiO",
 | ||
|       -1, 0x82,
 | ||
|       600, {75, 600, 0}, kodakaio_resolution_list, 4, /* 600 dpi max, {from, to, 0} 4 resolutions */
 | ||
|       8, kodakaio_depth_list,                          /* color depth max 8, list above */
 | ||
|       {0, SANE_FIX(8.5 * MM_PER_INCH), 0}, {0, SANE_FIX(11.7 * MM_PER_INCH), 0}, /* FBF x/y ranges */
 | ||
|       SANE_FALSE, SANE_TRUE, /* ADF, duplex.*/
 | ||
|       {0, SANE_FIX(8.5 * MM_PER_INCH), 0}, {0, SANE_FIX(14 * MM_PER_INCH), 0} /* 14 ADF x/y ranges */
 | ||
|   },
 | ||
|   /* KODAK ESP9200 ,  */
 | ||
|   {
 | ||
|       0x4065, "esp", "KODAK ESP 9200 Series AiO",
 | ||
|       -1, 0x82,
 | ||
|       600, {75, 600, 0}, kodakaio_resolution_list, 4,  /* 600 dpi max, 4 resolutions */
 | ||
|       8, kodakaio_depth_list,                          /* color depth max 8, list above */
 | ||
|       {0, SANE_FIX(8.5 * MM_PER_INCH), 0}, {0, SANE_FIX(11.7 * MM_PER_INCH), 0}, /* FBF x/y ranges */
 | ||
|       SANE_TRUE, SANE_FALSE, /* ADF, duplex */
 | ||
|       {0, SANE_FIX(8.5 * MM_PER_INCH), 0}, {0, SANE_FIX(14 * MM_PER_INCH), 0} /* 14 ADF x/y ranges */
 | ||
|   },
 | ||
|   /* KODAK ESP2170 ,  */
 | ||
|   {
 | ||
|       0x4066, "esp", "KODAK ESP Office 2170 Series",
 | ||
|       -1, 0x82,
 | ||
|       1200, {75, 1200, 0}, kodakaio_resolution_list, 5, /* 1200 dpi optical, {from, to, 0} 5 resolutions */
 | ||
|       8, kodakaio_depth_list,                          /* color depth max 8, list above */
 | ||
|       {0, SANE_FIX(8.5 * MM_PER_INCH), 0}, {0, SANE_FIX(11.7 * MM_PER_INCH), 0}, /* FBF x/y ranges */
 | ||
|       SANE_TRUE, SANE_FALSE, /* ADF, duplex */
 | ||
|       {0, SANE_FIX(8.5 * MM_PER_INCH), 0}, {0, SANE_FIX(14 * MM_PER_INCH), 0} /* 14 ADF x/y ranges */
 | ||
|   },
 | ||
|   /* KODAK HERO 9.1,   */
 | ||
|   {
 | ||
|       0x4067, "esp", "KODAK HERO 9.1 AiO",
 | ||
|       -1, 0x82,
 | ||
|       1200, {75, 1200, 0}, kodakaio_resolution_list, 5, /* 1200 dpi optical, {from, to, 0} 5 resolutions */
 | ||
|       8, kodakaio_depth_list,                          /* color depth max 8, list above */
 | ||
|       {0, SANE_FIX(8.5 * MM_PER_INCH), 0}, {0, SANE_FIX(11.7 * MM_PER_INCH), 0}, /* FBF x/y ranges */
 | ||
|       SANE_TRUE, SANE_FALSE, /* ADF, duplex. */
 | ||
|       {0, SANE_FIX(8.5 * MM_PER_INCH), 0}, {0, SANE_FIX(14 * MM_PER_INCH), 0} /* 14 ADF x/y ranges */
 | ||
|   },
 | ||
|   /* KODAK HERO 4.1,   */
 | ||
|   {
 | ||
|       0x4069, "esp", "KODAK HERO 4.1 AiO",
 | ||
|       -1, 0x82,
 | ||
|       600, {75, 600, 0}, kodakaio_resolution_list, 4, /* 600 dpi max, {from, to, 0} 4 resolutions */
 | ||
|       8, kodakaio_depth_list,                          /* color depth max 8, list above */
 | ||
|       {0, SANE_FIX(8.5 * MM_PER_INCH), 0}, {0, SANE_FIX(11.7 * MM_PER_INCH), 0}, /* FBF x/y ranges */
 | ||
|       SANE_TRUE, SANE_FALSE, /* ADF, duplex.*/
 | ||
| 
 | ||
|       {0, SANE_FIX(8.5 * MM_PER_INCH), 0}, {0, SANE_FIX(14 * MM_PER_INCH), 0} /* 14 ADF x/y ranges */
 | ||
|   },
 | ||
| 
 | ||
|   /* KODAK HERO 3.1,   */
 | ||
|   {
 | ||
|       0x406D, "esp", "KODAK HERO 3.1 AiO",
 | ||
|       -1, 0x82,
 | ||
|       600, {75, 600, 0}, kodakaio_resolution_list, 4, /* 600 dpi max, {from, to, 0} 4 resolutions */
 | ||
|       8, kodakaio_depth_list,                          /* color depth max 8, list above */
 | ||
|       {0, SANE_FIX(8.5 * MM_PER_INCH), 0}, {0, SANE_FIX(11.7 * MM_PER_INCH), 0}, /* FBF x/y ranges */
 | ||
|       SANE_FALSE, SANE_TRUE, /* ADF, duplex. */
 | ||
|       {0, SANE_FIX(8.5 * MM_PER_INCH), 0}, {0, SANE_FIX(14 * MM_PER_INCH), 0} /* 14 ADF x/y ranges */
 | ||
|   },
 | ||
|   /* spare use for specified usbid */
 | ||
|   {
 | ||
|       0, "esp", "specified",
 | ||
|       -1, 0x82,
 | ||
|       600, {75, 600, 0}, kodakaio_resolution_list, 4, /* 600 dpi max, {from, to, 0} 4 resolutions */
 | ||
|       8, kodakaio_depth_list,                          /* color depth max 8, list above */
 | ||
|       {0, SANE_FIX(8.5 * MM_PER_INCH), 0}, {0, SANE_FIX(11.7 * MM_PER_INCH), 0}, /* FBF x/y ranges */
 | ||
|       SANE_FALSE, SANE_TRUE, /* ADF, duplex. */
 | ||
|       {0, SANE_FIX(8.5 * MM_PER_INCH), 0}, {0, SANE_FIX(14 * MM_PER_INCH), 0} /* 14 ADF x/y ranges */
 | ||
|   }
 | ||
| };
 | ||
| 
 | ||
| /****************************************************************************
 | ||
|  *   General configuration parameter definitions ****************************************************************************/
 | ||
| 
 | ||
| 
 | ||
| /*
 | ||
|  * Definition of the mode_param struct, that is used to
 | ||
|  * specify the valid parameters for the different scan modes.
 | ||
|  *
 | ||
|  * The depth variable gets updated when the bit depth is modified.
 | ||
|  */
 | ||
| 
 | ||
| /* could be affecting what data sane delivers */
 | ||
| static struct mode_param mode_params[] = {
 | ||
| 	{0x03, 3, 24},  /* Color, 3 colors, 24 bit */
 | ||
| 	{0x02, 1, 8}, /* Grayscale, 1 color, 8 bit */
 | ||
| 	{0x00, 1, 1}  /* Lineart, 1 color, 8 bit (was 8 bit)   */
 | ||
| };
 | ||
| 
 | ||
| static SANE_String_Const mode_list[] = {
 | ||
| 	SANE_VALUE_SCAN_MODE_COLOR,
 | ||
| 	SANE_VALUE_SCAN_MODE_GRAY,
 | ||
| 	SANE_VALUE_SCAN_MODE_LINEART,
 | ||
| 	NULL
 | ||
| };
 | ||
| 
 | ||
| static const SANE_String_Const adf_mode_list[] = {
 | ||
| 	SANE_I18N("Simplex"),
 | ||
| 	SANE_I18N("Duplex"),
 | ||
| 	NULL
 | ||
| };
 | ||
| 
 | ||
| /* Define the different scan sources */
 | ||
| #define FBF_STR	SANE_I18N("Flatbed")
 | ||
| #define ADF_STR	SANE_I18N("Automatic Document Feeder")
 | ||
| 
 | ||
| /*
 | ||
|  * source list need one dummy entry (save device settings is crashing).
 | ||
|  * NOTE: no const - this list gets created while exploring the capabilities
 | ||
|  * of the scanner. Here space is reserved for 3 entries + NULL ?
 | ||
|  */
 | ||
| 
 | ||
| static SANE_String_Const source_list[] = {
 | ||
| 	FBF_STR,
 | ||
| 	NULL,
 | ||
| 	NULL,
 | ||
| 	NULL
 | ||
| };
 | ||
| 
 | ||
| static const SANE_Range percent_range_fixed = {SANE_FIX(0.0), SANE_FIX(100.0), SANE_FIX(1.0)};
 | ||
| /*static const SANE_Range percent_range_int = {0, 100, 1};*/
 | ||
| 
 | ||
| /* prototypes */
 | ||
| static SANE_Status attach_one_usb(SANE_String_Const devname);
 | ||
| static SANE_Status attach_one_net(SANE_String_Const devname, unsigned int device);
 | ||
| void kodakaio_com_str(unsigned char *buf, char *fmt_buf);
 | ||
| int cmparray (unsigned char *array1, unsigned char *array2, size_t len);
 | ||
| #if WITH_AVAHI
 | ||
| static struct KodakaioCap *get_device_from_identification (const char *ident, const char *vid, const char *pid);
 | ||
| void ProcessAvahiDevice(const char *device_id, const char *vid, const char *pid, const char *ip_addr);
 | ||
| #endif
 | ||
| 
 | ||
| 
 | ||
| /* Some utility functions */
 | ||
| 
 | ||
| static size_t
 | ||
| max_string_size(const SANE_String_Const strings[])
 | ||
| {
 | ||
| /* returns the length of the longest string in an array of strings */
 | ||
| 	size_t size, max_size = 0;
 | ||
| 	int i;
 | ||
| 
 | ||
| 	for (i = 0; strings[i]; i++) {
 | ||
| 		size = strlen(strings[i]) + 1;
 | ||
| 		if (size > max_size)
 | ||
| 			max_size = size;
 | ||
| 	}
 | ||
| 	return max_size;
 | ||
| }
 | ||
| 
 | ||
| 
 | ||
| 
 | ||
| static void
 | ||
| print_params(const SANE_Parameters params, int level)
 | ||
| {
 | ||
| 	DBG(level, "formats: binary=?, grey=%d, colour=%d\n",SANE_FRAME_GRAY, SANE_FRAME_RGB );
 | ||
| 	DBG(level, "params.format          = %d\n", params.format);
 | ||
| 	DBG(level, "params.last_frame      = %d\n", params.last_frame);
 | ||
| 	DBG(level, "params.bytes_per_line  = %d\n", params.bytes_per_line);
 | ||
| 	DBG(level, "params.pixels_per_line = %d\n", params.pixels_per_line);
 | ||
| 	DBG(level, "params.lines           = %d\n", params.lines);
 | ||
| 	DBG(level, "params.depth           = %d\n", params.depth);
 | ||
| }
 | ||
| 
 | ||
| static void
 | ||
| print_status(KodakAio_Scanner *s,int level)
 | ||
| {
 | ||
| 	DBG(level, "print_status with level %d\n", level);
 | ||
| 	DBG(level, "s->bytes_unread          = %d\n", s->bytes_unread);
 | ||
| /*
 | ||
| 	DBG(level, "params.last_frame      = %d\n", params.last_frame);
 | ||
| 	DBG(level, "params.bytes_per_line  = %d\n", params.bytes_per_line);
 | ||
| 	DBG(level, "params.pixels_per_line = %d\n", params.pixels_per_line);
 | ||
| 	DBG(level, "params.lines           = %d\n", params.lines);
 | ||
| 	DBG(level, "params.depth           = %d\n", params.depth);
 | ||
| */
 | ||
| }
 | ||
| 
 | ||
| /****************************************************************************
 | ||
|  *   Low-level Network communication functions ****************************************************************************/
 | ||
| 
 | ||
| static int
 | ||
| kodakaio_net_read(struct KodakAio_Scanner *s, unsigned char *buf, size_t wanted,
 | ||
| 		       SANE_Status * status)
 | ||
| /* there seems to be a condition where this returns no error and no data without detecting a timeout
 | ||
| That is probably if the scanner disconnected the network connection
 | ||
| */
 | ||
| {
 | ||
| 	size_t size, read = 0;
 | ||
| 	struct pollfd fds[1];
 | ||
| 	int pollreply;
 | ||
| 
 | ||
| 	*status = SANE_STATUS_GOOD;
 | ||
| 
 | ||
| 	/* poll for data-to-be-read (using K_Request_Timeout) */
 | ||
| 	fds[0].fd = s->fd;
 | ||
| 	fds[0].events = POLLIN;
 | ||
| 	fds[0].revents = 0;
 | ||
| 	if ((pollreply = poll (fds, 1, K_Request_Timeout)) <= 0) {
 | ||
| 		if (pollreply == 0)
 | ||
| 			DBG(1, "net poll timeout\n");
 | ||
| 		else
 | ||
| 			/* pollreply is -ve */
 | ||
| 			DBG(1, "net poll error\n");
 | ||
| 		*status = SANE_STATUS_IO_ERROR;
 | ||
| 	}
 | ||
| 	else if((fds[0].revents & POLLIN) && !(fds[0].revents & (POLLERR | POLLHUP | POLLNVAL))) {
 | ||
| 		while (read < wanted) {
 | ||
| 			DBG(50, "reading: read %lu, wanted %lu\n",read, wanted);
 | ||
| 			size = sanei_tcp_read(s->fd, buf + read, wanted - read);
 | ||
| 			if (size == 0) {
 | ||
| 				DBG(1, "No data read. Scanner may have disconnected\n");
 | ||
| 				break;
 | ||
| 			}
 | ||
| 			read += size;
 | ||
| 		}
 | ||
| 
 | ||
| 		if (read == 0)
 | ||
| 			*status = SANE_STATUS_IO_ERROR;
 | ||
| 
 | ||
| 		DBG(32, "net read %lu bytes:%x,%x,%x,%x,%x,%x,%x,%x\n",(unsigned long)read,buf[0],buf[1],buf[2],buf[3],buf[4],buf[5],buf[6],buf[7]);
 | ||
| 	}
 | ||
| 	else
 | ||
| 		DBG(1, "Unknown problem with poll\n");
 | ||
| 
 | ||
| 	return read;
 | ||
| }
 | ||
| 
 | ||
| 
 | ||
| static int
 | ||
| sanei_kodakaio_net_write_raw(struct KodakAio_Scanner *s,
 | ||
| 			      const unsigned char *buf, size_t buf_size,
 | ||
| 			      SANE_Status *status)
 | ||
| {
 | ||
| 	DBG(32, "net write:%x,%x,%x,%x,%x,%x,%x,%x\n",buf[0],buf[1],buf[2],buf[3],buf[4],buf[5],buf[6],buf[7]);
 | ||
| 
 | ||
| 	sanei_tcp_write(s->fd, buf, buf_size);
 | ||
| 	/* TODO: Check whether sending failed... */
 | ||
| 
 | ||
| 	*status = SANE_STATUS_GOOD;
 | ||
| 	return buf_size;
 | ||
| }
 | ||
| 
 | ||
| static SANE_Status
 | ||
| sanei_kodakaio_net_open(struct KodakAio_Scanner *s)
 | ||
| {
 | ||
| 	struct timeval tv;
 | ||
| 
 | ||
| 	tv.tv_sec = 5;
 | ||
| 	tv.tv_usec = 0;
 | ||
| 
 | ||
| 	DBG(5, "%s\n", __func__);
 | ||
| 
 | ||
| 	setsockopt(s->fd, SOL_SOCKET, SO_RCVTIMEO, (char *)&tv,  sizeof(tv));
 | ||
| 	return SANE_STATUS_GOOD;
 | ||
| }
 | ||
| 
 | ||
| static SANE_Status
 | ||
| sanei_kodakaio_net_close(struct KodakAio_Scanner *s)
 | ||
| {
 | ||
| 	NOT_USED(s);
 | ||
| 	/* Does nothing - maybe should close the socket ? */
 | ||
| 	return SANE_STATUS_GOOD;
 | ||
| }
 | ||
| 
 | ||
| 
 | ||
| /****************************************************************************
 | ||
|  *   Low-level USB communication functions ****************************************************************************/
 | ||
| 
 | ||
| static int
 | ||
| kodakaio_getNumberOfUSBProductIds (void)
 | ||
| {
 | ||
|   return sizeof (kodakaio_cap) / sizeof (struct KodakaioCap);
 | ||
| }
 | ||
| 
 | ||
| /****************************************************************************
 | ||
|  *   low-level communication commands ****************************************************************************/
 | ||
| 
 | ||
| static void dump_hex_buffer_dense (int level, const unsigned char *buf, size_t buf_size)
 | ||
| {
 | ||
| 	size_t k;
 | ||
| 	char msg[1024], fmt_buf[1024];
 | ||
| 	memset (&msg[0], 0x00, 1024);
 | ||
| 	memset (&fmt_buf[0], 0x00, 1024);
 | ||
| 	for (k = 0; k < min(buf_size, 80); k++) {
 | ||
| 		if (k % 16 == 0) {
 | ||
| 			if (k>0) {
 | ||
| 				DBG (level, "%s\n", msg);
 | ||
| 				memset (&msg[0], 0x00, 1024);
 | ||
| 			}
 | ||
| 			sprintf (fmt_buf, "     0x%04lx  ", (unsigned long)k);
 | ||
| 			strcat (msg, fmt_buf);
 | ||
| 		}
 | ||
| 		if (k % 8 == 0) {
 | ||
| 			strcat (msg, " ");
 | ||
| 		}
 | ||
| 		sprintf (fmt_buf, " %02x" , buf[k]);
 | ||
| 		strcat (msg, fmt_buf);
 | ||
| 	}
 | ||
| 	if (msg[0] != 0 ) {
 | ||
| 		DBG (level, "%s\n", msg);
 | ||
| 	}
 | ||
| }
 | ||
| 
 | ||
| /* changing params to char seems to cause a stack problem */
 | ||
| void kodakaio_com_str(unsigned char *buf, char *fmt_buf)
 | ||
| {
 | ||
| /* returns a printable string version of the first 8 bytes assuming they are a kodakaio command*/
 | ||
| 	if(buf[0] == 0x1b) {
 | ||
| 		sprintf (fmt_buf, "esc %c %c %02x %02x %02x %02x %02x",
 | ||
| 			 buf[1], buf[2], buf[3], buf[4], buf[5], buf[6], buf[7]);
 | ||
| 	}
 | ||
| 	else {
 | ||
| 		sprintf (fmt_buf, "%02x %02x %02x %02x %02x %02x %02x %02x",
 | ||
| 			buf[0],buf[1], buf[2], buf[3], buf[4], buf[5], buf[6], buf[7]);
 | ||
| 	}
 | ||
| }
 | ||
| 
 | ||
| static int
 | ||
| k_send(KodakAio_Scanner * s, void *buf, size_t buf_size, SANE_Status * status)
 | ||
| {
 | ||
| 	char fmt_buf[25];
 | ||
| 
 | ||
| 	kodakaio_com_str(buf, fmt_buf);
 | ||
| 	DBG(15, "%s: size = %lu :%s\n", __func__, (u_long) buf_size, fmt_buf);
 | ||
| 
 | ||
| 	if (DBG_LEVEL >= 125) {
 | ||
| 		const unsigned char *s = buf;
 | ||
| 		DBG(125, "complete buffer:\n");
 | ||
| 		dump_hex_buffer_dense (125, s, buf_size);
 | ||
| 	}
 | ||
| 
 | ||
| 	if (s->hw->connection == SANE_KODAKAIO_NET) {
 | ||
| 		return sanei_kodakaio_net_write_raw(s, buf, buf_size, status);
 | ||
| 	} else if (s->hw->connection == SANE_KODAKAIO_USB) {
 | ||
| 		size_t n;
 | ||
| 		n = buf_size;
 | ||
| 		*status = sanei_usb_write_bulk(s->fd, buf, &n);
 | ||
| 		DBG(50, "USB: wrote %lu bytes, status: %s\n", (unsigned long)n, sane_strstatus(*status));
 | ||
| 		return n;
 | ||
| 	}
 | ||
| 
 | ||
| 	*status = SANE_STATUS_INVAL;
 | ||
| 	return 0;
 | ||
| }
 | ||
| 
 | ||
| static ssize_t
 | ||
| k_recv(KodakAio_Scanner * s, void *buf, ssize_t buf_size,
 | ||
| 	    SANE_Status * status)
 | ||
| {
 | ||
| /* requests and receives data this function makes the split between USB and NET
 | ||
| this function called by a number of others
 | ||
| 
 | ||
| In USB mode, this function will wait until data is available for a maximum of SCANNER_READ_TIMEOUT seconds.
 | ||
| In NET mode the timeout is in kodakaio_net_read
 | ||
| */
 | ||
| 	ssize_t n = 0;
 | ||
| 	char fmt_buf[25];
 | ||
| 	time_t time_start;
 | ||
| 	time_t time_now;
 | ||
| 	struct timespec usb_delay, usb_rem;
 | ||
| 	usb_delay.tv_sec = 0;
 | ||
| 	usb_delay.tv_nsec = 300000000; /* 0.3 sec */
 | ||
| 
 | ||
| 	if (s->hw->connection == SANE_KODAKAIO_NET) {
 | ||
| 
 | ||
| 		time(&time_start);
 | ||
| 		DBG(min(16,DBG_READ), "[%ld]  %s: net req size = %ld  ", (long) time_start, __func__, (long) buf_size);
 | ||
|  		n = kodakaio_net_read(s, buf, buf_size, status);
 | ||
| 		DBG(min(16,DBG_READ), "returned %lu\n", (unsigned long)n);
 | ||
| 		if (*status != SANE_STATUS_GOOD) {
 | ||
| 			DBG(1, "%s: err returned from kodakaio_net_read, %s\n", __func__, sane_strstatus(*status));
 | ||
| 		}
 | ||
| 
 | ||
| 
 | ||
| 	} else if (s->hw->connection == SANE_KODAKAIO_USB) {
 | ||
| 		/* Start the clock for USB timeout */
 | ||
| 		time(&time_start);
 | ||
| 
 | ||
| 		/* Loop until we have data */
 | ||
| 		while (n == 0) {
 | ||
| 			n = buf_size;
 | ||
| /* but what if the data is an exact number of blocks? */
 | ||
| 			DBG(min(16,DBG_READ), "[%ld]  %s: usb req size = %ld  ", (long) time_start,  __func__, (long) n);
 | ||
| 			*status = sanei_usb_read_bulk(s->fd, (SANE_Byte *) buf, (size_t *) & n);
 | ||
| 			DBG(min(16,DBG_READ), "returned %ld\n", (long) n);
 | ||
| 
 | ||
| 			if(*status != SANE_STATUS_GOOD) {
 | ||
| 
 | ||
| 				DBG(min(16,DBG_READ), "sanei_usb_read_bulk gave %s\n", sane_strstatus(*status));
 | ||
| 
 | ||
| 				if (*status == SANE_STATUS_EOF) {
 | ||
| 					/* If we have EOF status, wait for more data */
 | ||
| 					time(&time_now);
 | ||
| 					if (difftime(time_now, time_start) < SCANNER_READ_TIMEOUT) {
 | ||
| 						nanosleep(&usb_delay, &usb_rem);
 | ||
| 					}
 | ||
| 					else {
 | ||
| 						/* Timeout */
 | ||
| 						return n;
 | ||
| 					}
 | ||
| 				}
 | ||
| 				else {
 | ||
| 					/*  If we've encountered another type of error, return */
 | ||
| 					return n;
 | ||
| 				}
 | ||
| 			}
 | ||
| 		}
 | ||
| 	}
 | ||
| 
 | ||
| 	if (n == 8) {
 | ||
| 		kodakaio_com_str(buf, fmt_buf);
 | ||
| 		DBG(min(14,DBG_READ), "%s: size = %ld, got %s\n", __func__, (long int)n, fmt_buf);
 | ||
| 	}
 | ||
| 	/* dump buffer if appropriate */
 | ||
| 	if (DBG_LEVEL >= 127 && n > 0) {
 | ||
| 		const unsigned char* b=buf;
 | ||
| 		dump_hex_buffer_dense (125, b, buf_size);
 | ||
| 	}
 | ||
| 	return n;
 | ||
| }
 | ||
| 
 | ||
| 
 | ||
| static SANE_Status
 | ||
| kodakaio_expect_ack(KodakAio_Scanner *s, unsigned char *rxbuf)
 | ||
| /* gets 8 byte reply, checks reply is an Ack and returns appropriate status */
 | ||
| {
 | ||
| 	SANE_Status status;
 | ||
| 
 | ||
| 	k_recv(s, rxbuf, 8, &status);
 | ||
| 	if (status != SANE_STATUS_GOOD) {
 | ||
| 		DBG(1, "%s: rx err, %s\n", __func__, sane_strstatus(status));
 | ||
| 		return status;
 | ||
| 	}
 | ||
| 	/* strncmp ignores diffent possible responses like escSS00000 and escSS02000 */
 | ||
| 	if (strncmp((char *)KodakEsp_Ack,(char *)rxbuf,4)!=0) {
 | ||
| 		DBG (1, "No Ack received, Expected 0x%2x %2x %2x %2x... got 0x%2x %2x %2x %2x...\n",
 | ||
| 		KodakEsp_Ack[0], KodakEsp_Ack[1], KodakEsp_Ack[2], KodakEsp_Ack[3],rxbuf[0], rxbuf[1], rxbuf[2], rxbuf[3]);
 | ||
| 		return SANE_STATUS_IO_ERROR;
 | ||
| 	}
 | ||
| 
 | ||
| 	return status;
 | ||
| }
 | ||
| 
 | ||
| static SANE_Status
 | ||
| kodakaio_txrx(KodakAio_Scanner *s, unsigned char *txbuf, unsigned char *rxbuf)
 | ||
| /* Sends 8 byte data to scanner and returns reply and appropriate status. */
 | ||
| {
 | ||
| 	SANE_Status status;
 | ||
| 	ssize_t n = 0;
 | ||
| 
 | ||
| 	k_send(s, txbuf, 8, &status);
 | ||
| 	if (status != SANE_STATUS_GOOD) {
 | ||
| 		DBG(1, "%s: tx err, %s\n", __func__, sane_strstatus(status));
 | ||
| 		return status;
 | ||
| 	}
 | ||
| 	n = k_recv(s, rxbuf, 8, &status);
 | ||
| 	if (status != SANE_STATUS_GOOD) {
 | ||
| 		DBG(1, "%s: %s gave rx err, %s\n", __func__, "txvalue", sane_strstatus(status));
 | ||
| 		return status;
 | ||
| 	}
 | ||
| 	if (n == 0) {
 | ||
| 		DBG(1, "%s: try 1 k_recv returned 0 bytes with status %s\n", __func__, sane_strstatus(status));
 | ||
| 		n = k_recv(s, rxbuf, 8, &status);
 | ||
| 		if (status != SANE_STATUS_GOOD) {
 | ||
| 			DBG(1, "%s: %s gave rx err, %s\n", __func__, "txvalue", sane_strstatus(status));
 | ||
| 			return status;
 | ||
| 		}
 | ||
| 		if (n == 0) {
 | ||
| 			DBG(1, "%s: try 2 k_recv returned 0 bytes with status %s\n", __func__, sane_strstatus(status));
 | ||
| 			return status;
 | ||
| 		}
 | ||
| 	}
 | ||
| 	return status;
 | ||
| }
 | ||
| 
 | ||
| static SANE_Status
 | ||
| kodakaio_txrxack(KodakAio_Scanner *s, unsigned char *txbuf, unsigned char *rxbuf)
 | ||
| /*
 | ||
| Sends 8 byte data to scanner, gets 8 byte reply, checks reply is an Ack
 | ||
| and returns appropriate status
 | ||
| */
 | ||
| {
 | ||
| 	SANE_Status status;
 | ||
| 
 | ||
| 	k_send(s, txbuf, 8, &status);
 | ||
| 	if (status != SANE_STATUS_GOOD) {
 | ||
| 		DBG(1, "%s: tx err, %s\n", __func__, sane_strstatus(status));
 | ||
| 		return status;
 | ||
| 	}
 | ||
| 
 | ||
| 	k_recv(s, rxbuf, 8, &status);
 | ||
| 	if (status != SANE_STATUS_GOOD) {
 | ||
| 		DBG(1, "%s: %s gave rx err, %s\n", __func__, "txvalue", sane_strstatus(status));
 | ||
| 		return status;
 | ||
| 	}
 | ||
| 	/* strncmp ignores different possible responses like escSS00000 and escSS02000 */
 | ||
| 	if (strncmp((char *)KodakEsp_Ack,(char *)rxbuf,3) == 0) { /* was 4 byte comp */
 | ||
| 		if (rxbuf[4] == 0x01 && s->adf_loaded == SANE_FALSE) {
 | ||
| 			s->adf_loaded = SANE_TRUE;
 | ||
| 			DBG(5, "%s: News - docs in ADF\n", __func__);
 | ||
| 		}
 | ||
| 		else if (rxbuf[4] !=
 | ||
| 0x01 && s->adf_loaded == SANE_TRUE) {
 | ||
| 			s->adf_loaded = SANE_FALSE;
 | ||
| 			DBG(5, "%s: News - ADF is empty\n", __func__);
 | ||
| 		}
 | ||
| 	}
 | ||
| 	else {
 | ||
| 		DBG (1, "No Ack received, Sent 0x%2x %2x %2x %2x... got 0x%2x %2x %2x %2x...\n",
 | ||
| 		txbuf[0], txbuf[1], txbuf[2], txbuf[3],rxbuf[0], rxbuf[1], rxbuf[2], rxbuf[3]);
 | ||
| 		return SANE_STATUS_IO_ERROR;
 | ||
| 	}
 | ||
| 
 | ||
| 	return status;
 | ||
| }
 | ||
| 
 | ||
| /* unused function
 | ||
| static ssize_t
 | ||
| kodakaio_rxflush(KodakAio_Scanner *s)
 | ||
| 
 | ||
| Tries to get 64 byte reply
 | ||
| and returns number of bytes read
 | ||
| 
 | ||
| {
 | ||
| 	SANE_Status status;
 | ||
| 	unsigned char rxbuf[64];
 | ||
| 	ssize_t n = 0;
 | ||
| 
 | ||
| 	n = k_recv(s, rxbuf, 64, &status);
 | ||
| 	if (status != SANE_STATUS_GOOD) {
 | ||
| 		DBG(1, "%s: %s gave rx err, %s\n", __func__, "status", sane_strstatus(status));
 | ||
| 	}
 | ||
| 	DBG(5, "%s: flushed, %d bytes\n", __func__,  (int)n);
 | ||
| 	return n;
 | ||
| }
 | ||
| */
 | ||
| 
 | ||
| /*
 | ||
|  *   high-level communication commands
 | ||
| */
 | ||
| 
 | ||
| static SANE_Status
 | ||
| k_hello (KodakAio_Scanner * s)
 | ||
| {
 | ||
| 	SANE_Status status;
 | ||
| 	unsigned char reply[8];
 | ||
| 	char fmt_buf[25];
 | ||
| 
 | ||
| 	DBG(5, "%s\n", __func__);
 | ||
| 
 | ||
| /* check that there is nothing already in the input buffer before starting
 | ||
| kodakaio_rxflush(s);
 | ||
| */
 | ||
| /* preset the reply, so I can see if it gets changed */
 | ||
| reply[0] = 0; reply[1] = 1; reply[2] = 2; reply[3] = 3; reply[4] = 4; reply[5] = 5; reply[6] = 6; reply[7] = 7;
 | ||
| 
 | ||
| 	if((status = kodakaio_txrx(s, KodakEsp_V, reply))!= SANE_STATUS_GOOD) {
 | ||
| 		DBG(1, "%s: KodakEsp_V failure, %s\n", __func__, sane_strstatus(status));
 | ||
| 		return SANE_STATUS_IO_ERROR;
 | ||
| 	}
 | ||
| 
 | ||
| 	if (strncmp((char *) reply, (char *) KodakEsp_v, 3)!=0) {
 | ||
| 		kodakaio_com_str(reply, fmt_buf);
 | ||
| 			DBG(1, "%s: KodakEsp_v err, got %s\n", __func__, fmt_buf);
 | ||
| 			return SANE_STATUS_IO_ERROR;
 | ||
| 	}
 | ||
| 
 | ||
| 
 | ||
| 	DBG(5, "%s: OK %s\n", __func__, sane_strstatus(status));
 | ||
| 	return status;
 | ||
| }
 | ||
| 
 | ||
| /* Start scan command */
 | ||
| static SANE_Status
 | ||
| cmd_start_scan (SANE_Handle handle, size_t expect_total)
 | ||
| /* expect_total is the expected total no of bytes just for info -ve value not a problem? or is it for size_t? */
 | ||
| {
 | ||
| 	KodakAio_Scanner *s = (KodakAio_Scanner *) handle;
 | ||
| 	SANE_Status status = SANE_STATUS_GOOD;
 | ||
| 	unsigned char reply[8];
 | ||
| /*send the start command here */
 | ||
| 	print_status(s, 5);
 | ||
| /*adf added 20/2/12, apparently an extra KodakEsp_F is sent when the adf is used */
 | ||
| 	if (strcmp(source_list[s->val[OPT_SOURCE].w], ADF_STR) == 0) { /* adf is in use */
 | ||
| 		if (! s->adf_loaded) return SANE_STATUS_CANCELLED; /* was SANE_STATUS_NO_DOCS; */
 | ||
| 		if (kodakaio_txrxack(s, KodakEsp_F, reply)!= SANE_STATUS_GOOD) {
 | ||
| 			DBG(1, "%s: Did not get a good reply to KodakEsp_F\n", __func__);
 | ||
| 			return SANE_STATUS_IO_ERROR;
 | ||
| 		}
 | ||
| 	}
 | ||
| 
 | ||
| 	if (kodakaio_txrxack(s, KodakEsp_E, reply)!= SANE_STATUS_GOOD) {
 | ||
| 		DBG(1, "%s: Did not get a good reply to KodakEsp_E\n", __func__);
 | ||
| 		return SANE_STATUS_IO_ERROR;
 | ||
| 	}
 | ||
| 
 | ||
| 	DBG(20, "starting the scan, expected total bytes %lu\n",(unsigned long)expect_total);
 | ||
| 	k_send(s, KodakEsp_Go, 8, &status);
 | ||
| 
 | ||
| 	if (status != SANE_STATUS_GOOD)
 | ||
| 		DBG(1, "%s: KodakEsp_Go command NOT successfully sent\n", __func__);
 | ||
| 	else {
 | ||
| 		DBG(30, "%s: KodakEsp_Go command successfully sent\n", __func__);
 | ||
| 		s->scanning = SANE_TRUE;
 | ||
| 	}
 | ||
| 	return status;
 | ||
| }
 | ||
| 
 | ||
| static SANE_Status
 | ||
| cmd_cancel_scan (SANE_Handle handle)
 | ||
| {
 | ||
| 	KodakAio_Scanner *s = (KodakAio_Scanner *) handle;
 | ||
| 	unsigned char reply[8];
 | ||
| /* adf added 20/2/12 should it be adf? or adf with paper in? */
 | ||
| 	if (strcmp(source_list[s->val[OPT_SOURCE].w], ADF_STR) == 0) { /* adf */
 | ||
| 		if (kodakaio_txrxack(s, KodakEsp_F, reply)!= SANE_STATUS_GOOD)
 | ||
| 		{
 | ||
| 			DBG(1, "%s: KodakEsp_F command failed\n", __func__);
 | ||
| 			return SANE_STATUS_IO_ERROR;
 | ||
| 		}
 | ||
| 		if (kodakaio_txrxack(s, KodakEsp_UnLock, reply)!= SANE_STATUS_GOOD)
 | ||
| 		{
 | ||
| 			DBG(1, "%s: KodakEsp_UnLock command failed\n", __func__);
 | ||
| 			return SANE_STATUS_IO_ERROR;
 | ||
| 		}
 | ||
| 		DBG(5, "%s unlocked the scanner with adf F U\n", __func__);
 | ||
| 	}
 | ||
| 	else { /* no adf */
 | ||
| 		if (kodakaio_txrxack(s, KodakEsp_UnLock, reply)!= SANE_STATUS_GOOD)
 | ||
| 		{
 | ||
| 			DBG(1, "%s: KodakEsp_UnLock command failed\n", __func__);
 | ||
| 			return SANE_STATUS_IO_ERROR;
 | ||
| 		}
 | ||
| 		DBG(5, "%s unlocked the scanner U\n", __func__);
 | ||
| 	}
 | ||
| 	s->scanning = SANE_FALSE;
 | ||
| 	return SANE_STATUS_GOOD;
 | ||
| }
 | ||
| 
 | ||
| static SANE_Status
 | ||
| cmd_get_scanning_parameters(SANE_Handle handle,
 | ||
| 			    SANE_Frame *format, SANE_Int *depth,
 | ||
| 			    SANE_Int *data_pixels, SANE_Int *pixels_per_line,
 | ||
| 			    SANE_Int *lines)
 | ||
| {
 | ||
| /* data_pixels is per line.
 | ||
| Old mc cmd read this stuff from the scanner. I don't think kodak can do that easily */
 | ||
| 
 | ||
| 	KodakAio_Scanner *s = (KodakAio_Scanner *) handle;
 | ||
| 	SANE_Status status = SANE_STATUS_GOOD;
 | ||
| 	NOT_USED (format);
 | ||
| 	NOT_USED (depth);
 | ||
| 
 | ||
| 	DBG(10, "%s\n", __func__);
 | ||
| 
 | ||
| 	/* Calculate returned values */
 | ||
| 	*lines = s->params.lines;
 | ||
| 	*pixels_per_line = s->params.pixels_per_line;
 | ||
| 	*data_pixels = s->params.pixels_per_line;
 | ||
| 
 | ||
| 	DBG (20, "%s: data_pixels = %u, lines = %u, "
 | ||
| 		"pixels_per_line = %u)\n", __func__,
 | ||
| 		*data_pixels, *lines, *pixels_per_line);
 | ||
| 	return status;
 | ||
| }
 | ||
| 
 | ||
| /* Set color curve command, low level, sends commands to the scanner*/
 | ||
| static SANE_Status
 | ||
| cmd_set_color_curve(SANE_Handle handle, unsigned char col)
 | ||
| {
 | ||
| /* sends the color curve data for one color*/
 | ||
| 	KodakAio_Scanner *s = (KodakAio_Scanner *) handle;
 | ||
| 	SANE_Status status = SANE_STATUS_GOOD;
 | ||
| 	unsigned char tx_col[8];
 | ||
| 	unsigned char rx[8];
 | ||
| 	unsigned char tx_curve[256];
 | ||
| 	int i; /* 7/9/14 was unsigned char and that stopped the loop that made the linear curve from going to 255 */
 | ||
| 	DBG(32, "%s: start\n", __func__);
 | ||
| 	tx_col[0]=0x1b; tx_col[1]='S'; tx_col[2]='K'; tx_col[3]=col; tx_col[4]=0; tx_col[5]=0; tx_col[6]=0; tx_col[7]=0;
 | ||
| /* linear curve now but could send tailor made curves in future */
 | ||
| 	for(i=0;i<=255;++i) tx_curve[i]=i; /* 7/9/14 was i<255 the missing elements caused speckles */
 | ||
| 
 | ||
| 	k_send(s, tx_col, 8, &status);
 | ||
| 	if (status != SANE_STATUS_GOOD) {
 | ||
| 		DBG(1, "%s: tx err, %s\n", __func__, "curve command");
 | ||
| 		return status;
 | ||
| 	}
 | ||
| 	k_send(s, tx_curve, 256, &status);
 | ||
| 	if (status != SANE_STATUS_GOOD) {
 | ||
| 		DBG(1, "%s: tx err, %s\n", __func__, "curve data");
 | ||
| 		return status;
 | ||
| 	}
 | ||
| 	if (kodakaio_expect_ack(s, rx) != SANE_STATUS_GOOD) return SANE_STATUS_IO_ERROR;
 | ||
| 		DBG(10, "%s: sent curve OK, \n", __func__);
 | ||
| 		return status;
 | ||
| }
 | ||
| 
 | ||
| /* Set scanning parameters command, low level, sends commands to the scanner*/
 | ||
| static SANE_Status
 | ||
| cmd_set_scanning_parameters(SANE_Handle handle,
 | ||
| 	int resolution,
 | ||
| 	int tl_x, int tl_y, int width, int height, unsigned char source)
 | ||
| 
 | ||
| /* NB. here int tl_x, int tl_y, int width, int height are in DPI units, not optres units! */
 | ||
| /* sends params to scanner, but should  we store them too? */
 | ||
| {
 | ||
| 	KodakAio_Scanner *s = (KodakAio_Scanner *) handle;
 | ||
| 	SANE_Status status = SANE_STATUS_GOOD;
 | ||
| 	unsigned char tx_S[8];
 | ||
| 	unsigned char tx_dpi[8];
 | ||
| 	unsigned char tx_topleft[8];
 | ||
| 	unsigned char tx_widthheight[8];
 | ||
| 	unsigned char bufread[8];
 | ||
| 	int i;
 | ||
| 
 | ||
| /*don't know the purpose of F yet. windows USB repeated 4 x why? does it affect the colour balance?*/
 | ||
| 	DBG(8, "%s\n", __func__);
 | ||
| 	for(i=0;i<4;++i) {
 | ||
| 		kodakaio_txrxack(s, KodakEsp_F, bufread);
 | ||
| 		sleep(1);
 | ||
| 	}
 | ||
| /*	kodakaio_txrxack(s, KodakEsp_F, bufread);  for net, just once */
 | ||
| 
 | ||
| /* Source? bed /ADF */
 | ||
| 	tx_S[0]=0x1b; tx_S[1]='S'; tx_S[2]='S'; tx_S[3]=source; tx_S[4]=0; tx_S[5]=0; tx_S[6]=0; tx_S[7]=0;
 | ||
| 	kodakaio_txrxack(s, tx_S, bufread);
 | ||
| 
 | ||
| /* Compression */
 | ||
| 	kodakaio_txrxack(s, KodakEsp_Comp, bufread);
 | ||
| 
 | ||
| /* DPI resolution */
 | ||
| 	tx_dpi[0]=0x1b;
 | ||
| 	tx_dpi[1]='S';
 | ||
| 	tx_dpi[2]='D';
 | ||
| 	tx_dpi[3]=resolution & 0xff;
 | ||
| 	tx_dpi[4]=(resolution >> 8) & 0xff;
 | ||
| 	tx_dpi[5]=resolution & 0xff;
 | ||
| 	tx_dpi[6]=(resolution >> 8) & 0xff;
 | ||
| 	tx_dpi[7]=0;
 | ||
| 	kodakaio_txrxack(s, tx_dpi, bufread);
 | ||
| 
 | ||
| /* colour curves don't seem to be sent for usb preview
 | ||
| but it seems to do no harm to send them */
 | ||
| 	cmd_set_color_curve(s, 'R');
 | ||
| 	cmd_set_color_curve(s, 'G');
 | ||
| 	cmd_set_color_curve(s, 'B');
 | ||
| 
 | ||
| 
 | ||
| /* Origin top left s->tl_x and s->tl_y are in optres units
 | ||
| this command needs actual DPI units*/
 | ||
| 	DBG(20, "%s: left (DPI)=%d, top (DPI)=%d\n", __func__, tl_x , tl_y);
 | ||
| 
 | ||
| 	tx_topleft[0]=0x1b;
 | ||
| 	tx_topleft[1]='S';
 | ||
| 	tx_topleft[2]='O';
 | ||
| 	tx_topleft[3]=(tl_x) & 0xff;
 | ||
| 	tx_topleft[4]=((tl_x) >> 8) & 0xff;
 | ||
| 	tx_topleft[5]=(tl_y) & 0xff;
 | ||
| 	tx_topleft[6]=((tl_y) >> 8) & 0xff;
 | ||
| 	tx_topleft[7]=0;
 | ||
| 	kodakaio_txrxack(s, tx_topleft, bufread);
 | ||
| 
 | ||
| /* Z width height note the s->width and s->height are in optres units
 | ||
| this command needs actual DPI units*/
 | ||
| 	tx_widthheight[0]=0x1b;
 | ||
| 	tx_widthheight[1]='S';
 | ||
| 	tx_widthheight[2]='Z';
 | ||
| 	tx_widthheight[3]=(width) & 0xff;
 | ||
| 	tx_widthheight[4]=((width) >> 8) & 0xff;
 | ||
| 	tx_widthheight[5]=(height) & 0xff;
 | ||
| 	tx_widthheight[6]=((height) >> 8) & 0xff;
 | ||
| 	tx_widthheight[7]=0;
 | ||
| 	kodakaio_txrxack(s, tx_widthheight, bufread);
 | ||
| 
 | ||
| 	if (status != SANE_STATUS_GOOD)
 | ||
| 		DBG(1, "%s: Data NOT successfully sent\n", __func__);
 | ||
| 	else
 | ||
| 		DBG(20, "%s: Data successfully sent\n", __func__);
 | ||
| 	return status;
 | ||
| }
 | ||
| 
 | ||
| int
 | ||
| cmparray (unsigned char *array1, unsigned char *array2, size_t len)
 | ||
| {
 | ||
| /* compares len bytes of the arrays returns 0 if they match
 | ||
| returns the first mismatch position if they don't match */
 | ||
| unsigned int i;
 | ||
| 	for(i=0; i<len; ++i)
 | ||
| 	{
 | ||
| 		if(array1[i] != array2[i]) return -1;
 | ||
| 	}
 | ||
| 	return 0;
 | ||
| }
 | ||
| 
 | ||
| static SANE_Status
 | ||
| cmd_read_data (SANE_Handle handle, unsigned char *buf, size_t *len)
 | ||
| {
 | ||
| /*
 | ||
| cmd_read_data is only used in k_read. It reads one block of data
 | ||
| read data using k_recv until you get the ackstring
 | ||
| when you get the ackstring return s->ack and do padding if the padding option is selected
 | ||
| if no padding option return EOF
 | ||
| */
 | ||
| 	KodakAio_Scanner *s = (KodakAio_Scanner *) handle;
 | ||
| 	SANE_Status status;
 | ||
| 	int oldtimeout = K_Request_Timeout;
 | ||
| 	size_t bytecount;
 | ||
| 	unsigned char *Last8; /* will point to the last 8 chars in buf */
 | ||
| 	int i, line, lines;
 | ||
| 
 | ||
| 	if (s->ack && s->val[OPT_PADDING].w) {
 | ||
| 		/* do padding of whole block*/
 | ||
| 		/* memset(buf, 0x80, *len);  need to work out the background colour for this */
 | ||
| 		lines = *len / s->params.bytes_per_line;
 | ||
| 		for (line=0; line < lines; ++line) {
 | ||
| 			for (i=0; i< s->params.pixels_per_line; ++i) {
 | ||
| 				buf[line * s->params.bytes_per_line + i] = s->background[0]; /*red */
 | ||
| 				buf[line * s->params.bytes_per_line + s->params.pixels_per_line + i] = s->background[1];  /*green */
 | ||
| 				buf[line * s->params.bytes_per_line + 2 * s->params.pixels_per_line + i] = s->background[2];  /*blue */
 | ||
| 			}
 | ||
| 		}
 | ||
| 		s->bytes_unread -= *len;
 | ||
| 		if (s->bytes_unread < 0)
 | ||
| 			s->bytes_unread = 0;
 | ||
| 		return SANE_STATUS_GOOD;
 | ||
| 	}
 | ||
| 
 | ||
| 	if (s->ack && !s->val[OPT_PADDING].w) {
 | ||
| 		s->bytes_unread = 0;
 | ||
| 		s->eof = SANE_TRUE;
 | ||
| 		return SANE_STATUS_EOF;
 | ||
| 	}
 | ||
| 
 | ||
| 	/* Temporarily set the poll timeout long instead of short,
 | ||
| 	 * because a color scan needs >5 seconds to initialize. Is this needed for kodak? maybe */
 | ||
| 	K_Request_Timeout = K_Scan_Data_Timeout;
 | ||
| 	sanei_usb_set_timeout (K_Scan_Data_Timeout);
 | ||
| 	bytecount = k_recv(s, buf, *len, &status);
 | ||
| 	K_Request_Timeout = oldtimeout;
 | ||
| 	sanei_usb_set_timeout (oldtimeout);
 | ||
| 
 | ||
| /* We may need to do some special thing with the block request size to cope with usb blocks of any length
 | ||
| in order to keep the ack bytes, when using adf, at the end of one block ie not split between blocks.
 | ||
| But it seems that the scanner takes care of that, and gives you the ack as a separate 8 byte block */
 | ||
| 
 | ||
| 	if (bytecount >= 8) {
 | ||
| 		/* it may be the last block from the scanner so look for Ack response in last 8 bytes */
 | ||
| 		Last8 = buf + bytecount - 8;
 | ||
| 
 | ||
| 		/* only compare 4 bytes because we sometimes get escSS02.. or escSS00..
 | ||
| 		is 4 the right number ? */
 | ||
| 		if (cmparray(Last8,KodakEsp_Ack,4) == 0) {
 | ||
| 			DBG(min(10,DBG_READ), "%s: found KodakEsp_Ack at %lu bytes of %lu\n", __func__, (unsigned long) bytecount, (unsigned long) *len);
 | ||
| 			s->ack = SANE_TRUE;
 | ||
| 			*len = bytecount - 8; /* discard the Ack response */
 | ||
| 			s->bytes_unread -= *len; /* return a short block */
 | ||
| 		}
 | ||
| 		else {
 | ||
| 		/* a not full buffer is returned usb does this */
 | ||
| 		DBG(min(10,DBG_READ), "%s: buffer not full, got %lu bytes of %lu\n", __func__, (unsigned long) bytecount, (unsigned long) *len);
 | ||
| 		*len = bytecount;
 | ||
| 		s->bytes_unread -= bytecount;
 | ||
| 		}
 | ||
| 	}
 | ||
| 	else {
 | ||
| 		DBG(min(1,DBG_READ), "%s: tiny read, got %lu bytes of %lu\n", __func__, (unsigned long) bytecount, (unsigned long) *len);
 | ||
| 		return SANE_STATUS_IO_ERROR;
 | ||
| 	}
 | ||
| 	lines = *len / s->params.bytes_per_line;
 | ||
| 	if (lines > 1) {
 | ||
| 		/* store average colour as background. That's not the ideal method but it's easy to implement. What's it used for? */
 | ||
| 		s->background[0] = 0;
 | ||
| 		s->background[1] = 0;
 | ||
| 		s->background[2] = 0;
 | ||
| 
 | ||
| 		for (line=0; line < lines; ++line) {
 | ||
| 			for (i=0; i< s->params.pixels_per_line; ++i) {
 | ||
| 				s->background[0] += buf[line * s->params.bytes_per_line + i]; /*red */
 | ||
| 				s->background[1] += buf[line * s->params.bytes_per_line + s->params.pixels_per_line + i];  /*green */
 | ||
| 				s->background[2] += buf[line * s->params.bytes_per_line + 2 * s->params.pixels_per_line + i];  /*blue */
 | ||
| 			}
 | ||
| 		}
 | ||
| 		s->background[0] = s->background[0] / (lines * s->params.pixels_per_line);
 | ||
| 		s->background[1] = s->background[1] / (lines * s->params.pixels_per_line);
 | ||
| 		s->background[2] = s->background[2] / (lines * s->params.pixels_per_line);
 | ||
| 
 | ||
| 	}
 | ||
| 
 | ||
| 	if (status == SANE_STATUS_GOOD)
 | ||
| 		if (s->bytes_unread <= 0)
 | ||
| 			DBG(min(2,DBG_READ), "%s: Page fully read %d blocks, %ld bytes unread\n", __func__, s->counter, (long) s->bytes_unread);
 | ||
| 		else
 | ||
| 			DBG(min(20,DBG_READ), "%s: Image data successfully read %ld bytes, %ld bytes unread\n", __func__, (long) bytecount, (long) s->bytes_unread);
 | ||
| 	else if  (s->ack) /* was (status == SANE_STATUS_EOF) */
 | ||
| 		DBG(min(2,DBG_READ), "%s: scanner data read ended %d blocks %ld bytes, %ld bytes unread\n", __func__, s->counter, (long) bytecount, (long) s->bytes_unread);
 | ||
| 	else
 | ||
| 		DBG(min(1,DBG_READ), "%s: Image data read stopped with %s after %d blocks %ld bytes, %ld bytes unread\n", __func__, sane_strstatus(status), s->counter, (long) bytecount, (long) s->bytes_unread);
 | ||
| 
 | ||
| 	return status;
 | ||
| }
 | ||
| 
 | ||
| 
 | ||
| 
 | ||
| /****************************************************************************
 | ||
|  *  kodakaio backend high-level operations ****************************************************************************/
 | ||
| 
 | ||
| static void
 | ||
| k_dev_init(Kodak_Device *dev, const char *devname, int conntype)
 | ||
| {
 | ||
| 	DBG(5, "%s for %s\n", __func__,devname);
 | ||
| 
 | ||
| 	dev->name = NULL;
 | ||
| 	dev->model = NULL;
 | ||
| 	dev->connection = conntype;
 | ||
| 	dev->sane.name = devname;
 | ||
| 	dev->sane.model = NULL;
 | ||
| 	dev->sane.type = "flatbed scanner";
 | ||
| 	dev->sane.vendor = "Kodak";
 | ||
| 	dev->cap = &kodakaio_cap[CAP_DEFAULT];
 | ||
| }
 | ||
| 
 | ||
| 
 | ||
| static SANE_Status
 | ||
| k_set_model(KodakAio_Scanner * s, const char *model, size_t len)
 | ||
| {
 | ||
| 	unsigned char *buf;
 | ||
| 	unsigned char *p;
 | ||
| 	struct Kodak_Device *dev = s->hw;
 | ||
| 
 | ||
| 	if (len<1) return SANE_STATUS_INVAL; /* to handle missing model */
 | ||
| 
 | ||
| 	buf = malloc(len + 1);
 | ||
| 	if (buf == NULL)
 | ||
| 		return SANE_STATUS_NO_MEM;
 | ||
| 
 | ||
| 	memcpy(buf, model, len);
 | ||
| 	buf[len] = '\0';
 | ||
| 
 | ||
| 	p = &buf[len - 1];
 | ||
| 
 | ||
| 	while (*p == ' ') {
 | ||
| 		*p = '\0';
 | ||
| 		p--;
 | ||
| 	}
 | ||
| 
 | ||
| 	if (dev->model)
 | ||
| 		free(dev->model);
 | ||
| 
 | ||
| 	dev->model = strndup((const char *) buf, len);
 | ||
| 	dev->sane.model = dev->model;
 | ||
| 	DBG(10, "%s: model is '%s'\n", __func__, dev->model);
 | ||
| 
 | ||
| 	free(buf);
 | ||
| 
 | ||
| 	return SANE_STATUS_GOOD;
 | ||
| }
 | ||
| 
 | ||
| static void
 | ||
| k_set_device (SANE_Handle handle, SANE_Word device)
 | ||
| {
 | ||
| 	KodakAio_Scanner *s = (KodakAio_Scanner *) handle;
 | ||
| 	Kodak_Device *dev = s->hw;
 | ||
| 	int n;
 | ||
| 
 | ||
| 	DBG(10, "%s: 0x%x\n", __func__, device);
 | ||
| 
 | ||
| 	for (n = 0; n < NELEMS (kodakaio_cap); n++) {
 | ||
| 		if (kodakaio_cap[n].id == device)
 | ||
| 			break;
 | ||
| 	}
 | ||
| 	if (n < NELEMS(kodakaio_cap)) {
 | ||
| 		dev->cap = &kodakaio_cap[n];
 | ||
| 	} else {
 | ||
| 		dev->cap = &kodakaio_cap[CAP_DEFAULT];
 | ||
| 		DBG(1, " unknown device 0x%x, using default %s\n",
 | ||
| 		    device, dev->cap->model);
 | ||
| 	}
 | ||
| 	k_set_model (s, dev->cap->model, strlen (dev->cap->model));
 | ||
| 
 | ||
| }
 | ||
| 
 | ||
| static SANE_Status
 | ||
| k_discover_capabilities(KodakAio_Scanner *s)
 | ||
| {
 | ||
| 	SANE_Status status = SANE_STATUS_GOOD;
 | ||
| 	Kodak_Device *dev = s->hw;
 | ||
| 	SANE_String_Const *source_list_add = source_list;
 | ||
| 
 | ||
| 	DBG(10, "%s\n", __func__);
 | ||
| 
 | ||
| 	/* always add flatbed */
 | ||
| 	*source_list_add++ = FBF_STR;
 | ||
| 	/* TODO: How can I check for existence of an ADF??? */
 | ||
| 	if (dev->cap->ADF == SANE_TRUE) {
 | ||
| 		*source_list_add++ = ADF_STR;
 | ||
| 		DBG(10, "%s: added adf to list\n", __func__);
 | ||
| 	}
 | ||
| 
 | ||
| 	/* TODO: Is there any capability that we can extract from the
 | ||
| 	 *       device by some scanner command? So far, it looks like
 | ||
| 	 *       the device does not support any reporting.
 | ||
| 	 */
 | ||
| 
 | ||
| 	dev->x_range = &dev->cap->fbf_x_range;
 | ||
| 	dev->y_range = &dev->cap->fbf_y_range;
 | ||
| 
 | ||
| 	DBG(10, "   x-range: %f %f\n", SANE_UNFIX(dev->x_range->min), SANE_UNFIX(dev->x_range->max));
 | ||
| 	DBG(10, "   y-range: %f %f\n", SANE_UNFIX(dev->y_range->min), SANE_UNFIX(dev->y_range->max));
 | ||
| 
 | ||
| 	DBG(5, "End of %s, status:%s\n", __func__, sane_strstatus(status));
 | ||
| 	*source_list_add = NULL; /* add end marker to source list */
 | ||
| 	return status;
 | ||
| }
 | ||
| 
 | ||
| static SANE_Status
 | ||
| k_setup_block_mode (KodakAio_Scanner *s)
 | ||
| {
 | ||
| /* works for USB and for net changing to make block size  = a number of complete lines 28/12/12 */
 | ||
| 	s->block_len = MAX_BLOCK_SIZE / s->scan_bytes_per_line * s->scan_bytes_per_line;
 | ||
| 	s->bytes_unread = s->data_len;
 | ||
| 	s->counter = 0;
 | ||
| 	s->bytes_read_in_line = 0;
 | ||
| 	if (s->line_buffer)
 | ||
| 		free(s->line_buffer);
 | ||
| 	s->line_buffer = malloc(s->scan_bytes_per_line);
 | ||
| 	if (s->line_buffer == NULL) {
 | ||
| 		DBG(1, "out of memory (line %d)\n", __LINE__);
 | ||
| 		return SANE_STATUS_NO_MEM;
 | ||
| 	}
 | ||
| 
 | ||
| 	DBG (10, " %s: Setup block mode - scan_bytes_per_line=%d, pixels_per_line=%d, depth=%d, data_len=%d, block_len=%d, blocks=%d, last_len=%d\n",
 | ||
| 		__func__, s->scan_bytes_per_line, s->params.pixels_per_line, s->params.depth, s->data_len, s->block_len, s->blocks, s->last_len);
 | ||
| 	return SANE_STATUS_GOOD;
 | ||
| }
 | ||
| 
 | ||
| /* Call the commands to set scanning parameters
 | ||
| In the Kodak Aio the parameters are:
 | ||
| (x1b,"S","F",0,0,0,0,0)
 | ||
| (x1b,"S","S",1,0,0,0,0)
 | ||
| #It looks like the 4th param byte of the C command is compression 1=compress, 0=no compression
 | ||
| #1st (or 3rd) param could be channels, 2nd could be bits per channel
 | ||
| (x1b,"S","C",3,8,3,0,0)  #3,8,3,1,0) was what the kodak software used with compression
 | ||
| (x1b,"S","D",LowByte(Res),HighByte(Res),LowByte(Res),HighByte(Res),0) #resolution in DPI
 | ||
| SendColour(tcpCliSock,"R")
 | ||
| SendColour(tcpCliSock,"G")
 | ||
| SendColour(tcpCliSock,"B")
 | ||
| (x1b,"S","O",LowByte(x0*Res),HighByte(x0*Res),LowByte(y0*Res),HighByte(y0*Res),0) #top left in pixels
 | ||
| (x1b,"S","Z",LowByte(x1*Res),HighByte(x1*Res),LowByte(y1*Res),HighByte(y1*Res),0) #bot right in pixels
 | ||
| (x1b,"S","E",1,0,0,0,0)
 | ||
| 
 | ||
| */
 | ||
| 
 | ||
| static SANE_Status
 | ||
| k_lock_scanner (KodakAio_Scanner * s)
 | ||
| {
 | ||
| 	SANE_Status status;
 | ||
| 	unsigned char reply[8];
 | ||
| 
 | ||
| 	status = k_hello(s);
 | ||
| 	if(status != SANE_STATUS_GOOD) {
 | ||
| 		DBG(1, "%s k_hello failed with %s\n", __func__, sane_strstatus(status));
 | ||
| 		return status;
 | ||
| 	}
 | ||
| 
 | ||
| 	if (kodakaio_txrxack(s, KodakEsp_Lock, reply)!= SANE_STATUS_GOOD) {
 | ||
| 		DBG(1, "%s Could not lock scanner\n", __func__);
 | ||
| 		return SANE_STATUS_IO_ERROR;
 | ||
| 	}
 | ||
| 	if (s->adf_loaded) DBG(5, "%s scanner locked, with docs in adf\n", __func__);
 | ||
| 	else DBG(5, "%s scanner locked, with no docs in adf\n", __func__);
 | ||
| 	return SANE_STATUS_GOOD;
 | ||
| }
 | ||
| 
 | ||
| static SANE_Status
 | ||
| k_set_scanning_parameters(KodakAio_Scanner * s)
 | ||
| {
 | ||
| 	SANE_Status status;
 | ||
| 	unsigned char rs, source;
 | ||
| 	SANE_Int scan_pixels_per_line = 0;
 | ||
| 	int dpi, optres;
 | ||
| 
 | ||
| 	dpi = s->val[OPT_RESOLUTION].w;
 | ||
| 	optres = s->hw->cap->optical_res;
 | ||
| 
 | ||
| 	/* Find the resolution in the res list and assign the index (rs) */
 | ||
| 	for (rs=0; rs < s->hw->cap->res_list_size; rs++ ) {
 | ||
| 		if ( dpi == s->hw->cap->res_list[rs] )
 | ||
| 			break;
 | ||
| 	}
 | ||
| 
 | ||
| 	/* ADF used? */
 | ||
| 	if (strcmp(source_list[s->val[OPT_SOURCE].w], ADF_STR) == 0) {
 | ||
| 		source = 0x00;
 | ||
| 	} else {
 | ||
| 		source = 0x01;
 | ||
| 	}
 | ||
| 
 | ||
| 
 | ||
| 	/* TODO: Any way to set PREVIEW??? */
 | ||
| 
 | ||
| 	/* Remaining bytes unused */
 | ||
| 	status = cmd_set_scanning_parameters(s, dpi,
 | ||
| 		s->left * dpi / optres, s->top * dpi / optres,  /* top/left start (dpi units)*/
 | ||
| 		s->params.pixels_per_line, s->params.lines, /* extent was s->width, s->height*/
 | ||
| 		source); /* source */
 | ||
| 
 | ||
| 	if (status != SANE_STATUS_GOOD)
 | ||
| 		DBG (1, "%s: Command cmd_set_scanning_parameters failed, %s\n",
 | ||
| 		     __func__, sane_strstatus(status));
 | ||
| 
 | ||
| 	/* Now query the scanner for the current image parameters */
 | ||
| 	status = cmd_get_scanning_parameters (s,
 | ||
| 			&s->params.format, &s->params.depth,
 | ||
| 			&scan_pixels_per_line,
 | ||
| 			&s->params.pixels_per_line, &s->params.lines);
 | ||
| 	if (status != SANE_STATUS_GOOD) {
 | ||
| 		DBG (1, "%s: Command cmd_get_scanning_parameters failed, %s\n",
 | ||
| 		     __func__, sane_strstatus(status));
 | ||
| 		return status;
 | ||
| 	}
 | ||
| 
 | ||
| 	/* Calculate how many bytes are really used per line */
 | ||
| 	s->params.bytes_per_line = ceil (s->params.pixels_per_line * s->params.depth / 8.0);
 | ||
| 	if (s->val[OPT_MODE].w == MODE_COLOR)
 | ||
| 		s->params.bytes_per_line *= 3;
 | ||
| 
 | ||
| 	/* Calculate how many bytes per line will be returned by the scanner.
 | ||
| 	magicolor needed this because it uses padding so scan bytes per line != image bytes per line.
 | ||
| 	 * The values needed for this are returned by get_scanning_parameters */
 | ||
| 	s->scan_bytes_per_line = 3 * ceil (scan_pixels_per_line); /* we always scan in colour 8 bit */
 | ||
| 	s->data_len = s->scan_bytes_per_line * floor (s->height * dpi / optres + 0.5); /* NB this is the length for a full scan */
 | ||
| 	DBG (5, "Check: scan_bytes_per_line = %d  s->params.bytes_per_line = %d \n", s->scan_bytes_per_line, s->params.bytes_per_line);
 | ||
| 
 | ||
| /* k_setup_block_mode at the start of each page for adf to work */
 | ||
| 	status = k_setup_block_mode (s);
 | ||
| 	if (status != SANE_STATUS_GOOD)
 | ||
| 		DBG (1, "%s: Command k_setup_block_mode failed, %s\n",
 | ||
| 		     __func__, sane_strstatus(status));
 | ||
| 
 | ||
| 	DBG (18, "%s: bytes_read_in_line: %d\n", __func__, s->bytes_read_in_line);
 | ||
| 	return status;
 | ||
| }
 | ||
| 
 | ||
| static SANE_Status
 | ||
| k_check_adf(KodakAio_Scanner * s)
 | ||
| {
 | ||
| /* 20/2/12  detect paper in the adf? acknowledge esc S S 00 01.. ?*/
 | ||
| 
 | ||
| 	if (! s->adf_loaded) {
 | ||
| 		DBG(5, "%s: NO DOCS\n", __func__);
 | ||
| 		return SANE_STATUS_NO_DOCS;
 | ||
| 	}
 | ||
| 	else {
 | ||
| 
 | ||
| 	/* TODO: Check for jam in ADF */
 | ||
| 		DBG(5, "%s: DOCS IN ADF\n", __func__);
 | ||
| 		return SANE_STATUS_GOOD;
 | ||
| 	}
 | ||
| }
 | ||
| 
 | ||
| static SANE_Status
 | ||
| k_scan_finish(KodakAio_Scanner * s)
 | ||
| {
 | ||
| 	SANE_Status status = SANE_STATUS_GOOD;
 | ||
| 	DBG(10, "%s called\n", __func__);
 | ||
| 
 | ||
| 	/* If we have not yet read all data, cancel the scan */
 | ||
| 	if (s->buf && !s->eof)
 | ||
| 		status = cmd_cancel_scan (s);
 | ||
| 
 | ||
| 	if (s->line_buffer)
 | ||
| 		free (s->line_buffer);
 | ||
| 	s->line_buffer = NULL;
 | ||
| 	free(s->buf);
 | ||
| 	s->buf = s->end = s->ptr = NULL;
 | ||
| 
 | ||
| 	return status;
 | ||
| }
 | ||
| 
 | ||
| static void
 | ||
| k_copy_image_data(KodakAio_Scanner * s, SANE_Byte * data, SANE_Int max_length,
 | ||
| 		   SANE_Int * length)
 | ||
| /* copies the read data from s->line_buffer to the position in data pointer to by s->ptr
 | ||
| uncompressed data is RRRR...GGGG...BBBB  per line */
 | ||
| {
 | ||
| 		SANE_Int bytes_available;
 | ||
| 		SANE_Int threshold;
 | ||
| 
 | ||
| 		DBG (min(18,DBG_READ), "%s: bytes_read  in line: %d\n", __func__, s->bytes_read_in_line);
 | ||
| 		*length = 0;
 | ||
| 
 | ||
| 		threshold = 255 - (int) (SANE_UNFIX(s->val[OPT_THRESHOLD].w) * 255.0 / 100.0 + 0.5); /* 255 - for the grey scale version */
 | ||
| 		DBG (20, "%s: threshold: %d\n", __func__, threshold);
 | ||
| 
 | ||
| 		while ((max_length >= s->params.bytes_per_line) && (s->ptr < s->end)) {
 | ||
| 			SANE_Int bytes_to_copy = s->scan_bytes_per_line - s->bytes_read_in_line;
 | ||
| 			/* First, fill the line buffer for the current line: */
 | ||
| 			bytes_available = (s->end - s->ptr);
 | ||
| 			/* Don't copy more than we have buffer and available */
 | ||
| 			if (bytes_to_copy > bytes_available)
 | ||
| 				bytes_to_copy = bytes_available;
 | ||
| 
 | ||
| 			if (bytes_to_copy > 0) {
 | ||
| 				memcpy (s->line_buffer + s->bytes_read_in_line, s->ptr, bytes_to_copy);
 | ||
| 				s->ptr += bytes_to_copy;
 | ||
| 				s->bytes_read_in_line += bytes_to_copy;
 | ||
| 			}
 | ||
| 
 | ||
| 			/* We have filled as much as possible of the current line
 | ||
| 			 * with data from the scanner. If we have a complete line,
 | ||
| 			 * copy it over.
 | ||
| 			line points to the current byte in the input s->line_buffer
 | ||
| 			data points to the output buffer*/
 | ||
| 			if ((s->bytes_read_in_line >= s->scan_bytes_per_line) &&
 | ||
| 			    (s->params.bytes_per_line <= max_length))
 | ||
| 			{
 | ||
| 				SANE_Int i;
 | ||
| 				SANE_Byte *line = s->line_buffer;
 | ||
| 				*length += s->params.bytes_per_line;
 | ||
| 
 | ||
| 				for (i=0; i< s->params.pixels_per_line; ++i) {
 | ||
| 				/* different behaviour for each mode */
 | ||
| 
 | ||
| 					if (s->val[OPT_MODE].w == MODE_COLOR){
 | ||
| 					/*interlace was subtracting from 255 until 6/9/14 */
 | ||
| 					 	*data++ = 255-line[0]; /*red */
 | ||
| 					 	*data++ = 255-line[s->params.pixels_per_line];  /*green */
 | ||
| 					 	*data++ = 255-line[2 * s->params.pixels_per_line];  /*blue */
 | ||
| 					}
 | ||
| 
 | ||
| 					else if (s->val[OPT_MODE].w == MODE_LINEART) { /* gives 1 bit output  */
 | ||
|         					/*output image location*/
 | ||
|         					int offset = i % 8;
 | ||
|         					unsigned char mask = 0x80 >> offset;
 | ||
| 						/*set if any colour is over the threshold  */
 | ||
| 						if (line[0] < threshold || line[s->params.pixels_per_line] < threshold || line[2 * s->params.pixels_per_line] < threshold)
 | ||
|           						*data &= ~mask;     /* white clear the bit in mask */
 | ||
|         					else
 | ||
|           						*data |= mask;      /* black set the bit in mask */
 | ||
| 
 | ||
|         					if (offset == 7 || i == s->params.pixels_per_line-1)
 | ||
|             						data++; /* move on a byte if the byte is full or the line is complete */
 | ||
| 					}
 | ||
| 
 | ||
| 					else { /* greyscale - Average the 3 colours */
 | ||
| 						*data++ = (255-line[0]
 | ||
| 						+255-line[s->params.pixels_per_line]
 | ||
| 						+255-line[2 * s->params.pixels_per_line])
 | ||
| 						/ 3;
 | ||
| 					}
 | ||
| 						line++;
 | ||
| 				}
 | ||
| /*debug file The same for color or grey because the scan is colour */
 | ||
| 				if (RawScan != NULL) {
 | ||
| 					for (i=0; i< s->scan_bytes_per_line; ++i) fputc(s->line_buffer[i],RawScan);
 | ||
| 				}
 | ||
| 				max_length -= s->params.bytes_per_line;
 | ||
| 				s->bytes_read_in_line -= s->scan_bytes_per_line;
 | ||
| 			}
 | ||
| 		}
 | ||
| }
 | ||
| 
 | ||
| static SANE_Status
 | ||
| k_init_parametersta(KodakAio_Scanner * s)
 | ||
| {
 | ||
| 	int dpi, optres;
 | ||
| 	/* struct mode_param *mparam; */
 | ||
| 
 | ||
| 	DBG(10, "%s\n", __func__);
 | ||
| 
 | ||
| 	memset(&s->params, 0, sizeof(SANE_Parameters));
 | ||
| 
 | ||
| 	dpi = s->val[OPT_RESOLUTION].w;
 | ||
| 	optres = s->hw->cap->optical_res;
 | ||
| 
 | ||
| 	 /* mparam = &mode_params[s->val[OPT_MODE].w];does this get used? */
 | ||
| 
 | ||
| 	if (SANE_UNFIX(s->val[OPT_BR_Y].w) == 0 ||
 | ||
| 		SANE_UNFIX(s->val[OPT_BR_X].w) == 0)
 | ||
| 		return SANE_STATUS_INVAL;
 | ||
| 
 | ||
| 	/* TODO: Use OPT_RESOLUTION or fixed 600dpi for left/top/width/height? */
 | ||
| 	s->left = ((SANE_UNFIX(s->val[OPT_TL_X].w) / MM_PER_INCH) * optres) + 0.5;
 | ||
| 
 | ||
| 	s->top = ((SANE_UNFIX(s->val[OPT_TL_Y].w) / MM_PER_INCH) * optres) + 0.5;
 | ||
| 
 | ||
| 	/* width in pixels */
 | ||
| 	s->width =
 | ||
| 		((SANE_UNFIX(s->val[OPT_BR_X].w -
 | ||
| 			   s->val[OPT_TL_X].w) / MM_PER_INCH) * optres) + 0.5;
 | ||
| 
 | ||
| 	s->height = ((SANE_UNFIX(s->val[OPT_BR_Y].w -
 | ||
| 			   s->val[OPT_TL_Y].w) / MM_PER_INCH) * optres) + 0.5;
 | ||
| 
 | ||
| 	DBG(20, "%s: s->width = %d, s->height = %d optres units\n",
 | ||
| 		__func__, s->width, s->height);
 | ||
| 
 | ||
| 	s->params.pixels_per_line = s->width * dpi / optres + 0.5;
 | ||
| 
 | ||
| 	/* ADF used without padding? added 30/12/12 */
 | ||
| 	if (strcmp(source_list[s->val[OPT_SOURCE].w], ADF_STR) == 0 && !s->val[OPT_PADDING].w)
 | ||
| 		s->params.lines = -1;
 | ||
| 	else
 | ||
| 		s->params.lines = s->height * dpi / optres + 0.5;
 | ||
| 
 | ||
| 
 | ||
| 	DBG(20, "%s: resolution = %d, preview = %d\n",
 | ||
| 		__func__, dpi, s->val[OPT_PREVIEW].w);
 | ||
| 
 | ||
| 	DBG(20, "%s: %p %p tlx %f tly %f brx %f bry %f [mm]\n",
 | ||
| 	    __func__, (void *) s, (void *) s->val,
 | ||
| 	    SANE_UNFIX(s->val[OPT_TL_X].w), SANE_UNFIX(s->val[OPT_TL_Y].w),
 | ||
| 	    SANE_UNFIX(s->val[OPT_BR_X].w), SANE_UNFIX(s->val[OPT_BR_Y].w));
 | ||
| 
 | ||
| 	/*
 | ||
| 	 * The default color depth is stored in mode_params.depth:
 | ||
| 	 */
 | ||
| 	if (mode_params[s->val[OPT_MODE].w].depth == 1)
 | ||
| 		s->params.depth = 1;
 | ||
| 	else {
 | ||
| 		s->params.depth = s->val[OPT_BIT_DEPTH].w;
 | ||
| 	}
 | ||
| 	DBG(20, "%s: bit depth = s->params.depth = %d\n", __func__,s->params.depth);
 | ||
| 	s->params.last_frame = SANE_TRUE;
 | ||
| 	s->params.bytes_per_line = 3 * ceil (s->params.depth * s->params.pixels_per_line / 8.0);
 | ||
| 
 | ||
| /* kodak only scans in color and conversion to grey or lineart is done in the driver
 | ||
| 		s->params.format = SANE_FRAME_RGB; */
 | ||
| 	DBG(20, "%s: s->val[OPT_MODE].w = %d (color is %d)\n", __func__,s->val[OPT_MODE].w, MODE_COLOR);
 | ||
| 	if (s->val[OPT_MODE].w == MODE_COLOR) s->params.format = SANE_FRAME_RGB;
 | ||
| 	else if (s->val[OPT_MODE].w == MODE_LINEART) s->params.format = SANE_FRAME_GRAY;
 | ||
| 	else s->params.format = SANE_FRAME_GRAY;
 | ||
| 
 | ||
| 	DBG(20, "%s: format=%d, bytes_per_line=%d, lines=%d\n", __func__, s->params.format, s->params.bytes_per_line, s->params.lines);
 | ||
| 	return (s->params.lines >= -1) ? SANE_STATUS_GOOD : SANE_STATUS_INVAL;
 | ||
| }
 | ||
| 
 | ||
| static SANE_Status
 | ||
| k_start_scan(KodakAio_Scanner * s)
 | ||
| {
 | ||
| 	SANE_Status status;
 | ||
| 
 | ||
| 	status = cmd_start_scan (s, s->data_len);
 | ||
| 	if (status != SANE_STATUS_GOOD ) {
 | ||
| 		DBG (1, "%s: starting the scan failed (%s)\n", __func__, sane_strstatus(status));
 | ||
| 	}
 | ||
| 	return status;
 | ||
| }
 | ||
| 
 | ||
| 
 | ||
| 
 | ||
| static SANE_Status
 | ||
| k_read(struct KodakAio_Scanner *s)
 | ||
| {
 | ||
| 	unsigned char rx[8];
 | ||
| 
 | ||
| /* monitors progress of blocks and calls cmd_read_data to get each block
 | ||
| you don't know how many blocks there will be in advance because their size may be determined by the scanner*/
 | ||
| 	SANE_Status status = SANE_STATUS_GOOD;
 | ||
| 	size_t buf_len = 0;
 | ||
| 
 | ||
| 	/* have we passed everything we read to sane? */
 | ||
| 	if (s->ptr == s->end) {
 | ||
| 		if (s->eof)
 | ||
| 			return SANE_STATUS_EOF;
 | ||
| 
 | ||
| 		s->counter++;
 | ||
| 		if (s->bytes_unread >= s->block_len)
 | ||
| 			buf_len = s->block_len;
 | ||
| 		else
 | ||
| 			buf_len = s->bytes_unread;
 | ||
| 		DBG(min(20,DBG_READ), "%s: block %d, size %lu\n", __func__,
 | ||
| 			s->counter, (unsigned long) buf_len);
 | ||
| 
 | ||
| 		/* receive image data + error code */
 | ||
| 		status = cmd_read_data (s, s->buf, &buf_len);
 | ||
| 		if (status != SANE_STATUS_GOOD && status != SANE_STATUS_EOF) { /* was just GOOD 20/2/12 */
 | ||
| 			DBG (1, "%s: Receiving image data failed (%s)\n",
 | ||
| 					__func__, sane_strstatus(status));
 | ||
| 			cmd_cancel_scan(s);
 | ||
| 			return status;
 | ||
| 		}
 | ||
| 
 | ||
| 		DBG(min(14,DBG_READ), "%s: success %lu bytes of block %d, %d remain\n", __func__, (unsigned long) buf_len, s->counter, s->bytes_unread);
 | ||
| 
 | ||
| 		if (s->bytes_unread > 0) {
 | ||
| 			if (s->canceling) {
 | ||
| 				cmd_cancel_scan(s);
 | ||
| 				return SANE_STATUS_CANCELLED;
 | ||
| 			}
 | ||
| 			if (status == SANE_STATUS_EOF) {
 | ||
| 				/* page ended prematurely.  */
 | ||
| 			}
 | ||
| 		}
 | ||
| 		else { /* s->bytes_unread <=0 This is the end of a page */
 | ||
| 			s->eof = SANE_TRUE;
 | ||
| 			DBG(min(10,DBG_READ), "%s: set EOF after %d blocks\n=============\n", __func__, s->counter);
 | ||
| /* look for the terminating ack if required */
 | ||
| 			if (!s->ack) {
 | ||
| 				if (kodakaio_expect_ack(s, rx) == SANE_STATUS_GOOD) {
 | ||
| 					s->ack = SANE_TRUE;
 | ||
| 				}
 | ||
| 				else {
 | ||
| 					DBG(min(1,DBG_READ), "%s: Did not get expected ack at end of page\n", __func__);
 | ||
| 					return SANE_STATUS_IO_ERROR;
 | ||
| 				}
 | ||
| 			}
 | ||
| 		}
 | ||
| 		s->end = s->buf + buf_len;
 | ||
| 		s->ptr = s->buf;
 | ||
| 	}
 | ||
| 	else {
 | ||
| 		DBG(min(20,DBG_READ), "%s: data left in buffer\n", __func__);
 | ||
| 	}
 | ||
| 	return status;
 | ||
| }
 | ||
| 
 | ||
| /*
 | ||
|  *   SANE API implementation (high-level functions)
 | ||
| */
 | ||
| 
 | ||
| #if WITH_AVAHI
 | ||
| static struct KodakaioCap *
 | ||
| get_device_from_identification (const char *ident, const char *vid, const char *pid)
 | ||
| {
 | ||
| 	int n;
 | ||
| 	SANE_Word pidnum, vidnum;
 | ||
| 
 | ||
| 	if(sscanf(vid, "%x", (unsigned int *)&vidnum) == EOF) {
 | ||
|     		DBG(5, "could not convert hex vid <%s>\n", vid);
 | ||
|     		return NULL;
 | ||
| 	}
 | ||
| 	if(sscanf(pid, "%x", (unsigned int *)&pidnum) == EOF) {
 | ||
|     		DBG(5, "could not convert hex pid <%s>\n", pid);
 | ||
|     		return NULL;
 | ||
| 	}
 | ||
| 	for (n = 0; n < NELEMS (kodakaio_cap); n++) {
 | ||
| 
 | ||
| 		if (strcmp (kodakaio_cap[n].model, ident)==0) {
 | ||
| 			DBG(20, "matched <%s> & <%s>\n", kodakaio_cap[n].model, ident);
 | ||
| 			return &kodakaio_cap[n];
 | ||
| 		}
 | ||
| 		else
 | ||
| 		if (kodakaio_cap[n].id == pidnum && 0x040A == vidnum) {
 | ||
| 			DBG(20, "matched <%s> & <%s:%s>\n", kodakaio_cap[n].model, vid, pid);
 | ||
| 			return &kodakaio_cap[n];
 | ||
| 		}
 | ||
| 		else {
 | ||
| 			DBG(20, "not found <%s> & <%s>\n", kodakaio_cap[n].model, pid);
 | ||
| 		}
 | ||
| 	}
 | ||
| 	return NULL;
 | ||
| }
 | ||
| #endif /* WITH_AVAHI */
 | ||
| 
 | ||
| /*
 | ||
|  * close_scanner()
 | ||
|  *
 | ||
|  * Close the open scanner. Depending on the connection method, a different
 | ||
|  * close function is called.
 | ||
|  */
 | ||
| static void
 | ||
| close_scanner(KodakAio_Scanner *s)
 | ||
| {
 | ||
| 	DBG(7, "%s: fd = %d\n", __func__, s->fd);
 | ||
| 
 | ||
| 	if (s->fd == -1)
 | ||
| 		return;
 | ||
| 
 | ||
| 	k_scan_finish(s);
 | ||
| 	if (s->hw->connection == SANE_KODAKAIO_NET) {
 | ||
| 		sanei_kodakaio_net_close(s);
 | ||
| 		sanei_tcp_close(s->fd);
 | ||
| 	} else if (s->hw->connection == SANE_KODAKAIO_USB) {
 | ||
| 		sanei_usb_close(s->fd);
 | ||
| 	}
 | ||
| 
 | ||
| 	s->fd = -1;
 | ||
| }
 | ||
| 
 | ||
| static SANE_Bool
 | ||
| split_scanner_name (const char *name, char * IP, unsigned int *model)
 | ||
| {
 | ||
| 	const char *device = name;
 | ||
| 	const char *qm;
 | ||
| 	*model = 0;
 | ||
| 	/* cut off leading net: */
 | ||
| 	if (strncmp(device, "net:", 4) == 0)
 | ||
| 		device = &device[4];
 | ||
| 
 | ||
| 	qm = strchr(device, '?');
 | ||
| 	if (qm != NULL) {
 | ||
| 		size_t len = qm-device;
 | ||
| 		strncpy (IP, device, len);
 | ||
| 		IP[len] = '\0';
 | ||
| 		qm++;
 | ||
| 		if (strncmp(qm, "model=", 6) == 0) {
 | ||
| 			qm += 6;
 | ||
| 			if (!sscanf(qm, "0x%x", model))
 | ||
| 				sscanf(qm, "%x", model);
 | ||
| 		}
 | ||
| 	} else {
 | ||
| 		strcpy (IP, device);
 | ||
| 	}
 | ||
| 	return SANE_TRUE;
 | ||
| }
 | ||
| 
 | ||
| /*
 | ||
|  * open_scanner()
 | ||
|  *
 | ||
|  * Open the scanner device. Depending on the connection method,
 | ||
|  * different open functions are called.
 | ||
|  */
 | ||
| 
 | ||
| static SANE_Status
 | ||
| open_scanner(KodakAio_Scanner *s)
 | ||
| {
 | ||
| 	SANE_Status status = 0;
 | ||
| 
 | ||
| 	DBG(7, "%s: %s\n", __func__, s->hw->sane.name);
 | ||
| 
 | ||
| 	if (s->fd != -1) {
 | ||
| 		DBG(10, "scanner is already open: fd = %d\n", s->fd);
 | ||
| 		return SANE_STATUS_GOOD;	/* no need to open the scanner */
 | ||
| 	}
 | ||
| 
 | ||
| 	if (s->hw->connection == SANE_KODAKAIO_NET) {
 | ||
| 		/* device name has the form net:ipaddr?model=... */
 | ||
| 		char IP[1024];
 | ||
| 		unsigned int model = 0;
 | ||
| 		if (!split_scanner_name (s->hw->sane.name, IP, &model))
 | ||
| 			return SANE_STATUS_INVAL;
 | ||
| 		DBG(10, "split_scanner_name OK model=0x%x\n",model);
 | ||
| /* normal with IP */
 | ||
| 		status = sanei_tcp_open(IP, 9101, &s->fd);  /* (host,port,file pointer) */
 | ||
| 
 | ||
| 		if (status != SANE_STATUS_GOOD ) DBG(1, "Is network scanner switched on?\n");
 | ||
| 
 | ||
| 		if (model>0)
 | ||
| 			k_set_device (s, model);
 | ||
| 		if (status == SANE_STATUS_GOOD) {
 | ||
| 			status = sanei_kodakaio_net_open (s);
 | ||
| 		}
 | ||
| else			DBG(1, "status was not good at net open\n");
 | ||
| 
 | ||
| 
 | ||
| 	} else if (s->hw->connection == SANE_KODAKAIO_USB) {
 | ||
| 			DBG(7, "trying to open usb\n");
 | ||
| 		status = sanei_usb_open(s->hw->sane.name, &s->fd);
 | ||
| 		if (s->hw->cap->out_ep>0)
 | ||
| 			sanei_usb_set_endpoint (s->fd,
 | ||
| 				USB_DIR_OUT | USB_ENDPOINT_TYPE_BULK, s->hw->cap->out_ep);
 | ||
| 		if (s->hw->cap->in_ep>0)
 | ||
| 			sanei_usb_set_endpoint (s->fd,
 | ||
| 				USB_DIR_IN | USB_ENDPOINT_TYPE_BULK, s->hw->cap->in_ep);
 | ||
| 	}
 | ||
| 
 | ||
| 	if (status == SANE_STATUS_ACCESS_DENIED) {
 | ||
| 		DBG(1, "please check that you have permissions on the device.\n");
 | ||
| 		DBG(1, "if this is a multi-function device with a printer,\n");
 | ||
| 		DBG(1, "disable any conflicting driver (like usblp).\n");
 | ||
| 	}
 | ||
| 
 | ||
| 	if (status != SANE_STATUS_GOOD)
 | ||
| 		DBG(1, "%s open failed: %s\n", s->hw->sane.name,
 | ||
| 			sane_strstatus(status));
 | ||
| 	else
 | ||
| 		DBG(3, "scanner opened\n");
 | ||
| /* add check here of usb properties? */
 | ||
| /*sanei_usb_get_descriptor( SANE_Int dn, struct sanei_usb_dev_descriptor *desc );*/
 | ||
| 
 | ||
| 
 | ||
| 	return status;
 | ||
| }
 | ||
| 
 | ||
| static SANE_Status
 | ||
| detect_usb(struct KodakAio_Scanner *s)
 | ||
| {
 | ||
| 	SANE_Status status;
 | ||
| 	SANE_Word vendor, product;
 | ||
| 	int i, numIds;
 | ||
| 	SANE_Bool is_valid;
 | ||
| 
 | ||
| 	/* if the sanei_usb_get_vendor_product call is not supported,
 | ||
| 	 * then we just ignore this and rely on the user to config
 | ||
| 	 * the correct device.
 | ||
| 	 */
 | ||
| 
 | ||
| 	status = sanei_usb_get_vendor_product(s->fd, &vendor, &product);
 | ||
| 	if (status != SANE_STATUS_GOOD) {
 | ||
| 		DBG(1, "the device cannot be verified - will continue\n");
 | ||
| 		return SANE_STATUS_GOOD;
 | ||
| 	}
 | ||
| 
 | ||
| 	/* check the vendor ID to see if we are dealing with a kodak device */
 | ||
| 	if (vendor != SANE_KODAKAIO_VENDOR_ID) {
 | ||
| 		/* this is not a supported vendor ID */
 | ||
| 		DBG(1, "not a Kodak Aio device at %s (vendor id=0x%x)\n",
 | ||
| 		    s->hw->sane.name, vendor);
 | ||
| 		return SANE_STATUS_INVAL;
 | ||
| 	}
 | ||
| 
 | ||
| 	numIds = kodakaio_getNumberOfUSBProductIds();
 | ||
| 	is_valid = SANE_FALSE;
 | ||
| 	i = 0;
 | ||
| 
 | ||
| 	/* check all known product IDs to verify that we know
 | ||
| 	 *	   about the device */
 | ||
| 	while (i != numIds && !is_valid) {
 | ||
| 	/*	if (product == kodakaio_usb_product_ids[i]) */
 | ||
| 		if (product == kodakaio_cap[i].id)
 | ||
| 			is_valid = SANE_TRUE;
 | ||
| 		i++;
 | ||
| 	}
 | ||
| 
 | ||
| 	if (is_valid == SANE_FALSE) {
 | ||
| 		DBG(1, "the device at %s is not a supported (product id=0x%x)\n",
 | ||
| 		    s->hw->sane.name, product);
 | ||
| 		return SANE_STATUS_INVAL;
 | ||
| 	}
 | ||
| 
 | ||
| 	DBG(2, "found valid usb Kodak Aio scanner: 0x%x/0x%x (vendorID/productID)\n",
 | ||
| 	    vendor, product);
 | ||
| 	k_set_device(s, product); /* added 21/12/11 to try and get a name for the device */
 | ||
| 
 | ||
| 	return SANE_STATUS_GOOD;
 | ||
| }
 | ||
| 
 | ||
| /*
 | ||
|  * used by attach* and sane_get_devices
 | ||
|  * a ptr to a single-linked list of Kodak_Device structs
 | ||
|  * a ptr to a null term array of ptrs to SANE_Device structs
 | ||
|  */
 | ||
| static int num_devices;		/* number of scanners attached to backend */
 | ||
| static Kodak_Device *first_dev;	/* first scanner in list */
 | ||
| static const SANE_Device **devlist = NULL;
 | ||
| 
 | ||
| static struct KodakAio_Scanner *
 | ||
| scanner_create(struct Kodak_Device *dev, SANE_Status *status)
 | ||
| {
 | ||
| 	struct KodakAio_Scanner *s;
 | ||
| 
 | ||
| 	s = malloc(sizeof(struct KodakAio_Scanner));
 | ||
| 	if (s == NULL) {
 | ||
| 		*status = SANE_STATUS_NO_MEM;
 | ||
| 		return NULL;
 | ||
| 	}
 | ||
| 
 | ||
| 	memset(s, 0x00, sizeof(struct KodakAio_Scanner));
 | ||
| 
 | ||
| 	s->fd = -1;
 | ||
| 	s->hw = dev;
 | ||
| 
 | ||
| 	return s;
 | ||
| }
 | ||
| 
 | ||
| static struct KodakAio_Scanner *
 | ||
| device_detect(const char *name, int type, SANE_Status *status)
 | ||
| {
 | ||
| 	struct KodakAio_Scanner *s;
 | ||
| 	struct Kodak_Device *dev;
 | ||
| 
 | ||
| 	/* try to find the device in our list */
 | ||
| 	for (dev = first_dev; dev; dev = dev->next) {
 | ||
| 		if (strcmp(dev->sane.name, name) == 0) {
 | ||
| 			dev->missing = 0;
 | ||
| 			DBG (10, "%s: Device %s already attached!\n", __func__,
 | ||
| 			     name);
 | ||
| 			return scanner_create(dev, status);
 | ||
| 		}
 | ||
| 	}
 | ||
| 
 | ||
| 	if (type == SANE_KODAKAIO_NODEV) {
 | ||
| 		*status = SANE_STATUS_INVAL;
 | ||
| 		return NULL;
 | ||
| 	}
 | ||
| 
 | ||
| 	/* alloc and clear our device structure */
 | ||
| 	dev = malloc(sizeof(*dev));
 | ||
| 	if (!dev) {
 | ||
| 		*status = SANE_STATUS_NO_MEM;
 | ||
| 		return NULL;
 | ||
| 	}
 | ||
| 	memset(dev, 0x00, sizeof(struct Kodak_Device));
 | ||
| 
 | ||
| 	s = scanner_create(dev, status);
 | ||
| 	if (s == NULL)
 | ||
| 		return NULL;
 | ||
| 
 | ||
| 	k_dev_init(dev, name, type);
 | ||
| 
 | ||
| 	*status = open_scanner(s);
 | ||
| 	if (*status != SANE_STATUS_GOOD) {
 | ||
| 		free(s);
 | ||
| 		free(dev);
 | ||
| 		return NULL;
 | ||
| 	}
 | ||
| 
 | ||
| 	/* from now on, close_scanner() must be called */
 | ||
| 
 | ||
| 	/* USB requires special care */
 | ||
| 	if (dev->connection == SANE_KODAKAIO_USB) {
 | ||
| 		*status = detect_usb(s);
 | ||
| 	}
 | ||
| 
 | ||
| 	if (*status != SANE_STATUS_GOOD)
 | ||
| 		goto close;
 | ||
| 
 | ||
| 	/* set name and model (if not already set) */
 | ||
| 	if (dev->model == NULL)
 | ||
| 		k_set_model(s, "generic", 7);
 | ||
| 
 | ||
| 	dev->name = strdup(name);
 | ||
| 	dev->sane.name = dev->name;
 | ||
| 
 | ||
| 	/* do we need to discover capabilities here? */
 | ||
| 	*status = k_discover_capabilities(s);
 | ||
| 	if (*status != SANE_STATUS_GOOD)
 | ||
| 		goto close;
 | ||
| 
 | ||
| 	if (source_list[0] == NULL || dev->cap->dpi_range.min == 0) {
 | ||
| 		DBG(1, "something is wrong in the discovery process, aborting.\n");
 | ||
| 		*status = SANE_STATUS_IO_ERROR;
 | ||
| 		goto close;
 | ||
| 	}
 | ||
| 
 | ||
| 	/* add this scanner to the device list */
 | ||
| 	num_devices++;
 | ||
| 	dev->missing = 0;
 | ||
| 	dev->next = first_dev;
 | ||
| 	first_dev = dev;
 | ||
| 
 | ||
| 	return s;
 | ||
| 
 | ||
| 	close:
 | ||
| 	close_scanner(s);
 | ||
| 	free(dev);
 | ||
| 	free(s);
 | ||
| 	return NULL;
 | ||
| }
 | ||
| 
 | ||
| 
 | ||
| 
 | ||
| #if WITH_AVAHI
 | ||
| /* ProcessAvahiDevice is called to process each discovered device in turn */
 | ||
| void
 | ||
| ProcessAvahiDevice(const char *device_id, const char *vid, const char *pid, const char *ip_addr)
 | ||
| {
 | ||
| 	struct KodakaioCap *cap;
 | ||
| 
 | ||
| 	DBG(min(10,DBG_AUTO),"device_id = <%s> vid:pid = <%s:%s>\n", device_id,vid,pid);
 | ||
| 
 | ||
| /* check if it is a model likely to be supported: "KODAK ESP" or "KODAK HERO"
 | ||
| 
 | ||
| 	DBG(min(10,DBG_AUTO),"look up model <%s>\n", device_model); */
 | ||
| 	cap = get_device_from_identification("", vid, pid);
 | ||
| 	if (cap == NULL) {
 | ||
| 		return;
 | ||
| 	}
 | ||
| 
 | ||
| 	DBG(min(10,DBG_AUTO), "%s: Found autodiscovered device: %s (type 0x%x)\n", __func__, cap->model, cap->id);
 | ||
| 		attach_one_net (ip_addr, cap->id);
 | ||
| }
 | ||
| 
 | ||
| 
 | ||
| static void resolve_callback(
 | ||
|     AvahiServiceResolver *r,
 | ||
|     AVAHI_GCC_UNUSED AvahiIfIndex interface,
 | ||
|     AVAHI_GCC_UNUSED AvahiProtocol protocol,
 | ||
|     AvahiResolverEvent event,
 | ||
|     const char *name,
 | ||
|     const char *type,
 | ||
|     const char *domain,
 | ||
|     const char *host_name,
 | ||
|     const AvahiAddress *address,
 | ||
|     uint16_t port,
 | ||
|     AvahiStringList *txt,
 | ||
|     AvahiLookupResultFlags flags,
 | ||
|     AVAHI_GCC_UNUSED void* userdata) {
 | ||
| 
 | ||
| 	AvahiStringList *vid_pair_list = NULL, *pid_pair_list = NULL;
 | ||
| 	char *pidkey, *pidvalue;
 | ||
| 	char *vidkey, *vidvalue;
 | ||
| 	size_t valuesize;
 | ||
| 	NOT_USED (flags);
 | ||
| 
 | ||
|     assert(r);
 | ||
| 
 | ||
|     /* Called whenever a service has been resolved successfully or timed out */
 | ||
| 
 | ||
|     switch (event) {
 | ||
|         case AVAHI_RESOLVER_FAILURE:
 | ||
|             DBG(min(1,DBG_AUTO), "(Resolver) Failed to resolve service '%s' of type '%s' in domain '%s': %s\n", name, type, domain, avahi_strerror(avahi_client_errno(avahi_service_resolver_get_client(r))));
 | ||
|             break;
 | ||
| 
 | ||
|         case AVAHI_RESOLVER_FOUND: {
 | ||
|             char a[AVAHI_ADDRESS_STR_MAX];
 | ||
| 
 | ||
|             avahi_address_snprint(a, sizeof(a), address);
 | ||
| 
 | ||
| /* Output short for Kodak ESP */
 | ||
| 	DBG(min(10,DBG_AUTO), "%s:%u  %s\n", a,port,host_name);
 | ||
| 
 | ||
| 	vid_pair_list = avahi_string_list_find(txt, "vid");
 | ||
| 	if(vid_pair_list != NULL) {
 | ||
| 		avahi_string_list_get_pair(vid_pair_list, &vidkey, &vidvalue, &valuesize);
 | ||
| 		DBG(min(10,DBG_AUTO), "%s=%s  ", vidkey, vidvalue);
 | ||
| 	}
 | ||
| 	else	DBG(min(10,DBG_AUTO), "failed to find key vid\n");
 | ||
| 
 | ||
| 	pid_pair_list = avahi_string_list_find(txt, "pid");
 | ||
| 	if(pid_pair_list != NULL) {
 | ||
| 		avahi_string_list_get_pair(pid_pair_list, &pidkey, &pidvalue, &valuesize);
 | ||
| 		DBG(min(10,DBG_AUTO), "%s=%s\n", pidkey, pidvalue);
 | ||
| 	}
 | ||
| 	else	DBG(min(10,DBG_AUTO), "failed to find key pid\n");
 | ||
| 
 | ||
| 	if(pid_pair_list != NULL && vid_pair_list != NULL) {
 | ||
| 		ProcessAvahiDevice(name, vidvalue, pidvalue, a);
 | ||
| 	}
 | ||
| 	else DBG(min(10,DBG_AUTO), "didn't call ProcessAvahiDevice\n");
 | ||
| 
 | ||
| 	if(vid_pair_list != NULL) {
 | ||
| 		avahi_free(vidkey);
 | ||
| 		avahi_free(vidvalue);
 | ||
| 		DBG(min(15,DBG_AUTO), "vidkey and vidvalue freed\n");
 | ||
| 	}
 | ||
| 	if(pid_pair_list != NULL) {
 | ||
| 		avahi_free(pidkey);
 | ||
| 		avahi_free(pidvalue);
 | ||
| 		DBG(min(15,DBG_AUTO), "pidkey and pidvalue freed\n");
 | ||
| 	}
 | ||
|         }
 | ||
|     }
 | ||
|     DBG(min(10,DBG_AUTO), "ending resolve_callback\n");
 | ||
|     avahi_service_resolver_free(r);
 | ||
| }
 | ||
| 
 | ||
| static void browse_callback(
 | ||
|     AvahiServiceBrowser *b,
 | ||
|     AvahiIfIndex interface,
 | ||
|     AvahiProtocol protocol,
 | ||
|     AvahiBrowserEvent event,
 | ||
|     const char *name,
 | ||
|     const char *type,
 | ||
|     const char *domain,
 | ||
|     AVAHI_GCC_UNUSED AvahiLookupResultFlags flags,
 | ||
|     void* userdata) {
 | ||
|     AvahiSimplePoll *simple_poll = userdata;
 | ||
| 
 | ||
|     AvahiClient *c = avahi_service_browser_get_client (b);
 | ||
| 
 | ||
|     /* Called whenever a new services becomes available on the LAN or is removed from the LAN */
 | ||
|     switch (event) {
 | ||
|         case AVAHI_BROWSER_FAILURE:
 | ||
| 
 | ||
|             DBG(min(1,DBG_AUTO), "(Browser) %s\n", avahi_strerror(avahi_client_errno(avahi_service_browser_get_client(b))));
 | ||
|             avahi_simple_poll_quit(simple_poll);
 | ||
|             return;
 | ||
| 
 | ||
|         case AVAHI_BROWSER_NEW:
 | ||
|             DBG(min(5,DBG_AUTO), "(Browser) NEW: service '%s' of type '%s' in domain '%s'\n", name, type, domain);
 | ||
| 
 | ||
|             /* We ignore the returned resolver object. In the callback
 | ||
|                function we free it. If the server is terminated before
 | ||
|                the callback function is called the server will free
 | ||
|                the resolver for us. */
 | ||
| 
 | ||
|             if (!(avahi_service_resolver_new(c, interface, protocol, name, type, domain, AVAHI_PROTO_UNSPEC, 0, resolve_callback, c)))
 | ||
|                 DBG(min(1,DBG_AUTO), "Failed to resolve service '%s': %s\n", name, avahi_strerror(avahi_client_errno(c)));
 | ||
| 
 | ||
|             break;
 | ||
| 
 | ||
|         case AVAHI_BROWSER_REMOVE:
 | ||
|             DBG(min(1,DBG_AUTO), "(Browser) REMOVE: service '%s' of type '%s' in domain '%s'\n", name, type, domain);
 | ||
|             break;
 | ||
| 
 | ||
|         case AVAHI_BROWSER_ALL_FOR_NOW:
 | ||
|         case AVAHI_BROWSER_CACHE_EXHAUSTED:
 | ||
|             DBG(min(5,DBG_AUTO), "(Browser) %s\n", event == AVAHI_BROWSER_CACHE_EXHAUSTED ? "CACHE_EXHAUSTED" : "ALL_FOR_NOW");
 | ||
|             break;
 | ||
|     }
 | ||
| }
 | ||
| 
 | ||
| static void client_callback(AvahiClient *c, AvahiClientState state, void * userdata) {
 | ||
|     AvahiSimplePoll *simple_poll = userdata;
 | ||
|     assert(c);
 | ||
| 
 | ||
|     /* Called whenever the client or server state changes */
 | ||
| 
 | ||
|     if (state == AVAHI_CLIENT_FAILURE) {
 | ||
|         DBG(min(1,DBG_AUTO), "Server connection failure: %s\n", avahi_strerror(avahi_client_errno(c)));
 | ||
|         avahi_simple_poll_quit(simple_poll);
 | ||
|     }
 | ||
| }
 | ||
| 
 | ||
| 
 | ||
| static int
 | ||
| kodak_network_discovery(const char*host)
 | ||
| /* If host = NULL do autodiscovery. If host != NULL try to verify the model
 | ||
| First version only does autodiscovery */
 | ||
| {
 | ||
|     AvahiSimplePoll *simple_poll;
 | ||
|     AvahiClient *client = NULL;
 | ||
|     AvahiServiceBrowser *sb = NULL;
 | ||
|     int error;
 | ||
|     int i, ret = 1;
 | ||
| 	NOT_USED(host);
 | ||
| 
 | ||
| 	DBG(2, "%s: called\n", __func__);
 | ||
| 
 | ||
|     /* Allocate main loop object */
 | ||
|     if (!(simple_poll = avahi_simple_poll_new())) {
 | ||
|         DBG(min(1,DBG_AUTO), "Failed to create simple poll object.\n");
 | ||
|         goto fail;
 | ||
|     }
 | ||
| 
 | ||
|     /* Allocate a new client */
 | ||
|     client = avahi_client_new(avahi_simple_poll_get(simple_poll), 0, client_callback, simple_poll, &error);
 | ||
| 
 | ||
|     /* Check whether creating the client object succeeded */
 | ||
|     if (!client) {
 | ||
|         DBG(min(1,DBG_AUTO), "Failed to create client: %s\n", avahi_strerror(error));
 | ||
|         goto fail;
 | ||
|     }
 | ||
| 
 | ||
|     /* Create the service browser */
 | ||
|     if (!(sb = avahi_service_browser_new(client, AVAHI_IF_UNSPEC, AVAHI_PROTO_UNSPEC, "_scanner._tcp", NULL, 0, browse_callback, simple_poll))) {
 | ||
|         DBG(min(1,DBG_AUTO), "Failed to create service browser: %s\n", avahi_strerror(avahi_client_errno(client)));
 | ||
|         goto fail;
 | ||
|     }
 | ||
| 
 | ||
|     /* Run the main loop */
 | ||
| 	for(i=1;i<K_SNMP_Timeout/POLL_ITN_MS;++i) {
 | ||
|     		if (avahi_simple_poll_iterate(simple_poll,POLL_ITN_MS) != 0)
 | ||
|     			break;
 | ||
| 	}
 | ||
|     ret = 0;
 | ||
| 
 | ||
| fail:
 | ||
| 
 | ||
| 
 | ||
|     /* Cleanup things  */
 | ||
|         DBG(min(10,DBG_AUTO), "Cleaning up avahi.\n");
 | ||
|     if (sb)
 | ||
|         avahi_service_browser_free(sb);
 | ||
| 
 | ||
|     if (client)
 | ||
|         avahi_client_free(client);
 | ||
| 
 | ||
|     if (simple_poll)
 | ||
|         avahi_simple_poll_free(simple_poll);
 | ||
| 
 | ||
|     return ret;
 | ||
| }
 | ||
| 
 | ||
| #endif
 | ||
| 
 | ||
| 
 | ||
| static SANE_Status
 | ||
| attach(const char *name, int type)
 | ||
| {
 | ||
| 	SANE_Status status;
 | ||
| 	KodakAio_Scanner *s;
 | ||
| 
 | ||
| 	DBG(7, "%s: devname = %s, type = %d\n", __func__, name, type);
 | ||
| 
 | ||
| 	s = device_detect(name, type, &status);
 | ||
| 	if(s == NULL)
 | ||
| 		return status;
 | ||
| 
 | ||
| 	close_scanner(s);
 | ||
| 	free(s);
 | ||
| 	return status;
 | ||
| }
 | ||
| 
 | ||
| SANE_Status
 | ||
| attach_one_usb(const char *dev)
 | ||
| {
 | ||
| 	DBG(7, "%s: dev = %s\n", __func__, dev);
 | ||
| 	return attach(dev, SANE_KODAKAIO_USB);
 | ||
| }
 | ||
| 
 | ||
| static SANE_Status
 | ||
| attach_one_net(const char *dev, unsigned int model)
 | ||
| {
 | ||
| 	char name[1024];
 | ||
| 
 | ||
| 	DBG(7, "%s: dev = %s\n", __func__, dev);
 | ||
| 	if (model > 0) {
 | ||
| 		snprintf(name, 1024, "net:%s?model=0x%x", dev, model);
 | ||
| 	} else {
 | ||
| 		snprintf(name, 1024, "net:%s", dev);
 | ||
| 	}
 | ||
| 
 | ||
| 	return attach(name, SANE_KODAKAIO_NET);
 | ||
| }
 | ||
| 
 | ||
| static SANE_Status
 | ||
| attach_one_config(SANEI_Config __sane_unused__ *config, const char *line,
 | ||
| 		  void *data)
 | ||
| {
 | ||
| 	int vendor, product, timeout;
 | ||
| 	SANE_Bool local_only = *(SANE_Bool*) data;
 | ||
| 	int len = strlen(line);
 | ||
| 
 | ||
| 	DBG(7, "%s: len = %d, line = %s\n", __func__, len, line);
 | ||
| 
 | ||
| 	if (sscanf(line, "usb %i %i", &vendor, &product) == 2) {
 | ||
| 		/* add the vendor and product IDs to the list of
 | ||
| 		 *		   known devices before we call the attach function */
 | ||
| 
 | ||
| 		int numIds = kodakaio_getNumberOfUSBProductIds();
 | ||
| 
 | ||
| 		if (vendor != SANE_KODAKAIO_VENDOR_ID) {
 | ||
| 			DBG(7, "Wrong vendor: numIds = %d, vendor = %d\n", numIds, vendor);
 | ||
| 			return SANE_STATUS_INVAL; /* this is not a Kodak device */
 | ||
| 		}
 | ||
| 		/* kodakaio_usb_product_ids[numIds - 1] = product; */
 | ||
| 		kodakaio_cap[numIds - 1].id = product;
 | ||
| 
 | ||
| 		sanei_usb_attach_matching_devices(line, attach_one_usb);
 | ||
| 
 | ||
| 	} else if (strncmp(line, "usb", 3) == 0 && len == 3) {
 | ||
| 		int i, numIds;
 | ||
| 		/* auto detect ?  */
 | ||
| 		numIds = kodakaio_getNumberOfUSBProductIds();
 | ||
| 
 | ||
| 		for (i = 0; i < numIds; i++) {
 | ||
| /*			sanei_usb_find_devices(SANE_KODAKAIO_VENDOR_ID,
 | ||
| 					       kodakaio_usb_product_ids[i], attach_one_usb); */
 | ||
| 			sanei_usb_find_devices(SANE_KODAKAIO_VENDOR_ID,
 | ||
| 					       kodakaio_cap[i].id, attach_one_usb);
 | ||
| 		}
 | ||
| 
 | ||
| 	} else if (strncmp(line, "net", 3) == 0) {
 | ||
| 
 | ||
| 		if (!local_only) {
 | ||
| 			/* remove the "net" sub string */
 | ||
| 			const char *name =
 | ||
| 				sanei_config_skip_whitespace(line + 3);
 | ||
| 			char IP[1024];
 | ||
| 			unsigned int model = 0;
 | ||
| 
 | ||
| 			if (strncmp(name, "autodiscovery", 13) == 0) {
 | ||
| 
 | ||
| 	#if WITH_AVAHI
 | ||
| 				DBG (30, "%s: Initiating network autodiscovery via avahi\n", __func__);
 | ||
| 				kodak_network_discovery(NULL);
 | ||
| 	#else
 | ||
| 				DBG (20, "%s: Network autodiscovery not done because not configured with avahi.\n", __func__);
 | ||
| 	#endif
 | ||
| 
 | ||
| 			} else if (sscanf(name, "%s %x", IP, &model) == 2) {
 | ||
| 				DBG(30, "%s: Using network device on IP %s, forcing model 0x%x\n", __func__, IP, model);
 | ||
| 				attach_one_net(IP, model);
 | ||
| 			} else {
 | ||
| 				DBG(1, "%s: net entry %s may be a host name?\n", __func__, name);
 | ||
| 				attach_one_net(name, 0);
 | ||
| 			}
 | ||
| 		}
 | ||
| 
 | ||
| 	} else if (sscanf(line, "snmp-timeout %i\n", &timeout)) {
 | ||
| 		/* Timeout for auto network discovery */
 | ||
| 		DBG(50, "%s: network auto-discovery timeout set to %d\n", __func__, timeout);
 | ||
| 		K_SNMP_Timeout = timeout;
 | ||
| 
 | ||
| 	} else if (sscanf(line, "scan-data-timeout %i\n", &timeout)) {
 | ||
| 		/* Timeout for scan data requests */
 | ||
| 		DBG(50, "%s: Scan data timeout set to %d\n", __func__, timeout);
 | ||
| 		K_Scan_Data_Timeout = timeout;
 | ||
| 
 | ||
| 	} else if (sscanf(line, "request-timeout %i\n", &timeout)) {
 | ||
| 		/* Timeout for all other read requests */
 | ||
| 		DBG(50, "%s: Request timeout set to %d\n", __func__, timeout);
 | ||
| 		K_Request_Timeout = timeout;
 | ||
| 
 | ||
| 	} else {
 | ||
| 		/* TODO: Warning about unparsable line! */
 | ||
| 	}
 | ||
| 
 | ||
| 	return SANE_STATUS_GOOD;
 | ||
| }
 | ||
| 
 | ||
| static void
 | ||
| free_devices(void)
 | ||
| {
 | ||
| 	Kodak_Device *dev, *next;
 | ||
| 
 | ||
| 	DBG(5, "%s\n", __func__);
 | ||
| 
 | ||
| 	for (dev = first_dev; dev; dev = next) {
 | ||
| 		next = dev->next;
 | ||
| 		free(dev->name);
 | ||
| 		free(dev->model);
 | ||
| 		free(dev);
 | ||
| 	}
 | ||
| 
 | ||
| 	if (devlist)
 | ||
| 		free(devlist);
 | ||
| 	devlist = NULL;
 | ||
| 	first_dev = NULL;
 | ||
| }
 | ||
| 
 | ||
| SANE_Status
 | ||
| sane_init(SANE_Int *version_code, SANE_Auth_Callback __sane_unused__ authorize)
 | ||
| {
 | ||
| 	DBG_INIT();
 | ||
| 	DBG(1, "========================================== \n");
 | ||
| 	DBG(2, "%s: " PACKAGE " " VERSION "\n", __func__);
 | ||
| 
 | ||
| 	DBG(1, "kodakaio backend, version %i.%i.%i\n",
 | ||
| 	    KODAKAIO_VERSION, KODAKAIO_REVISION, KODAKAIO_BUILD);
 | ||
| 	DBG(2, "%s: called\n", __func__);
 | ||
| 	if (version_code != NULL)
 | ||
| 		*version_code = SANE_VERSION_CODE(SANE_CURRENT_MAJOR, SANE_CURRENT_MINOR,
 | ||
| 						  KODAKAIO_BUILD);
 | ||
| 	sanei_usb_init();
 | ||
| 
 | ||
| #if WITH_AVAHI
 | ||
| 	DBG(min(3,DBG_AUTO), "avahi detected\n");
 | ||
| #else
 | ||
| 	DBG(min(3,DBG_AUTO), "avahi not detected\n");
 | ||
| #endif
 | ||
| 	return SANE_STATUS_GOOD;
 | ||
| }
 | ||
| 
 | ||
| /* Clean up the list of attached scanners. */
 | ||
| void
 | ||
| sane_exit(void)
 | ||
| {
 | ||
| 	DBG(5, "%s\n", __func__);
 | ||
| 	free_devices();
 | ||
| }
 | ||
| 
 | ||
| SANE_Status
 | ||
| sane_get_devices(const SANE_Device ***device_list, SANE_Bool local_only)
 | ||
| {
 | ||
| 	Kodak_Device *dev, *s, *prev=0;
 | ||
| 	int i;
 | ||
| 
 | ||
| 	DBG(2, "%s: called\n", __func__);
 | ||
| 
 | ||
| 	sanei_usb_init();
 | ||
| 
 | ||
| 	/* mark all existing scanners as missing, attach_one will remove mark */
 | ||
| 	for (s = first_dev; s; s = s->next) {
 | ||
| 		s->missing = 1;
 | ||
| 	}
 | ||
| 
 | ||
| 	/* Read the config, mark each device as found, possibly add new devs */
 | ||
| 	sanei_configure_attach(KODAKAIO_CONFIG_FILE, NULL,
 | ||
| 			       attach_one_config, &local_only);
 | ||
| 
 | ||
| 	/*delete missing scanners from list*/
 | ||
| 	for (s = first_dev; s;) {
 | ||
| 		if (s->missing) {
 | ||
| 			DBG (5, "%s: missing scanner %s\n", __func__, s->name);
 | ||
| 
 | ||
| 			/*splice s out of list by changing pointer in prev to next*/
 | ||
| 			if (prev) {
 | ||
| 				prev->next = s->next;
 | ||
| 				free (s);
 | ||
| 				s = prev->next;
 | ||
| 				num_devices--;
 | ||
| 			} else {
 | ||
| 				/*remove s from head of list */
 | ||
| 				first_dev = s->next;
 | ||
| 				free(s);
 | ||
| 				s = first_dev;
 | ||
| 				prev=NULL;
 | ||
| 				num_devices--;
 | ||
| 			}
 | ||
| 		} else {
 | ||
| 			prev = s;
 | ||
| 			s = prev->next;
 | ||
| 		}
 | ||
| 	}
 | ||
| 
 | ||
| 	DBG (15, "%s: found %d scanner(s)\n", __func__, num_devices);
 | ||
| 	for (s = first_dev; s; s=s->next) {
 | ||
| 		DBG (15, "%s: found scanner %s\n", __func__, s->name);
 | ||
| 	}
 | ||
| 
 | ||
| 	if (devlist)
 | ||
| 		free (devlist);
 | ||
| 
 | ||
| 	devlist = malloc((num_devices + 1) * sizeof(devlist[0]));
 | ||
| 	if (!devlist) {
 | ||
| 		DBG(1, "out of memory (line %d)\n", __LINE__);
 | ||
| 		return SANE_STATUS_NO_MEM;
 | ||
| 	}
 | ||
| 
 | ||
| 	DBG(5, "%s - results:\n", __func__);
 | ||
| 
 | ||
| 	for (i = 0, dev = first_dev; i < num_devices && dev; dev = dev->next, i++) {
 | ||
| 		DBG(5, " %d (%d): %s\n", i, dev->connection, dev->model);
 | ||
| 		devlist[i] = &dev->sane;
 | ||
| 	}
 | ||
| 
 | ||
| 	devlist[i] = NULL;
 | ||
| 
 | ||
| 	if(device_list){
 | ||
| 		*device_list = devlist;
 | ||
| 	}
 | ||
| 
 | ||
| 	return SANE_STATUS_GOOD;
 | ||
| }
 | ||
| 
 | ||
| static SANE_Status
 | ||
| init_options(KodakAio_Scanner *s)
 | ||
| {
 | ||
| 	int i;
 | ||
| 	SANE_Word *res_list;
 | ||
| 	DBG(5, "%s: called\n", __func__);
 | ||
| 
 | ||
| 	for (i = 0; i < NUM_OPTIONS; i++) {
 | ||
| 		s->opt[i].size = sizeof(SANE_Word);
 | ||
| 		s->opt[i].cap = SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT;
 | ||
| 	}
 | ||
| 
 | ||
| 	s->opt[OPT_NUM_OPTS].title = SANE_TITLE_NUM_OPTIONS;
 | ||
| 	s->opt[OPT_NUM_OPTS].desc = SANE_DESC_NUM_OPTIONS;
 | ||
| 	s->opt[OPT_NUM_OPTS].type = SANE_TYPE_INT;
 | ||
| 	s->opt[OPT_NUM_OPTS].cap = SANE_CAP_SOFT_DETECT;
 | ||
| 	s->val[OPT_NUM_OPTS].w = NUM_OPTIONS;
 | ||
| 
 | ||
| 	/* "Scan Mode" group: */
 | ||
| 
 | ||
| 	s->opt[OPT_MODE_GROUP].name = SANE_NAME_STANDARD;
 | ||
| 	s->opt[OPT_MODE_GROUP].title = SANE_TITLE_STANDARD;
 | ||
| 	s->opt[OPT_MODE_GROUP].desc = SANE_DESC_STANDARD;
 | ||
| 	s->opt[OPT_MODE_GROUP].type = SANE_TYPE_GROUP;
 | ||
| 	s->opt[OPT_MODE_GROUP].cap = 0;
 | ||
| 
 | ||
| 	/* scan mode */
 | ||
| 	s->opt[OPT_MODE].name = SANE_NAME_SCAN_MODE;
 | ||
| 	s->opt[OPT_MODE].title = SANE_TITLE_SCAN_MODE;
 | ||
| 	s->opt[OPT_MODE].desc = SANE_DESC_SCAN_MODE;
 | ||
| 	s->opt[OPT_MODE].type = SANE_TYPE_STRING;
 | ||
| 	s->opt[OPT_MODE].size = max_string_size(mode_list);
 | ||
| 	s->opt[OPT_MODE].constraint_type = SANE_CONSTRAINT_STRING_LIST;
 | ||
| 	s->opt[OPT_MODE].constraint.string_list = mode_list;
 | ||
| 	s->val[OPT_MODE].w = MODE_COLOR;	/* default */
 | ||
| 	DBG(20, "%s: mode_list has first entry %s, default mode is %s\n", __func__, mode_list[0],mode_list[s->val[OPT_MODE].w]);
 | ||
| 
 | ||
| 	/* threshold the sane std says should be SANE_TYPE_FIXED 0..100 but all other backends seem to use INT 0..255 */
 | ||
| 	s->opt[OPT_THRESHOLD].name = SANE_NAME_THRESHOLD;
 | ||
| 	s->opt[OPT_THRESHOLD].title = SANE_TITLE_THRESHOLD;
 | ||
| 	s->opt[OPT_THRESHOLD].desc = SANE_DESC_THRESHOLD;
 | ||
| 	s->opt[OPT_THRESHOLD].type = SANE_TYPE_FIXED;
 | ||
| 	s->opt[OPT_THRESHOLD].unit = SANE_UNIT_PERCENT;
 | ||
| 	s->opt[OPT_THRESHOLD].size = sizeof(SANE_Word);
 | ||
| 	s->opt[OPT_THRESHOLD].constraint_type = SANE_CONSTRAINT_RANGE;
 | ||
| 	s->opt[OPT_THRESHOLD].constraint.range = &percent_range_fixed;
 | ||
| 	s->val[OPT_THRESHOLD].w = SANE_FIX(50.0);
 | ||
| 	DBG(20, "%s: threshold initialised to fixed %f\n", __func__, SANE_UNFIX(s->val[OPT_THRESHOLD].w));
 | ||
| 
 | ||
| 	/* threshold the sane std says should be SANE_TYPE_FIXED 0..100 but all other backends seem to use INT 0..255
 | ||
| 	s->opt[OPT_THRESHOLD].name = SANE_NAME_THRESHOLD;
 | ||
| 	s->opt[OPT_THRESHOLD].title = SANE_TITLE_THRESHOLD;
 | ||
| 	s->opt[OPT_THRESHOLD].desc = SANE_DESC_THRESHOLD;
 | ||
| 	s->opt[OPT_THRESHOLD].type = SANE_TYPE_INT;
 | ||
| 	s->opt[OPT_THRESHOLD].unit = SANE_UNIT_PERCENT;
 | ||
| 	s->opt[OPT_THRESHOLD].size = sizeof(SANE_Word);
 | ||
| 	s->opt[OPT_THRESHOLD].constraint_type = SANE_CONSTRAINT_RANGE;
 | ||
| 	s->opt[OPT_THRESHOLD].constraint.range = &percent_range_int;
 | ||
| 	s->val[OPT_THRESHOLD].w = 51;
 | ||
| 	DBG(20, "%s: threshold initialised to int %d\n", __func__, s->val[OPT_THRESHOLD].w); */
 | ||
| 
 | ||
| 	/* bit depth */
 | ||
| 	s->opt[OPT_BIT_DEPTH].name = SANE_NAME_BIT_DEPTH;
 | ||
| 	s->opt[OPT_BIT_DEPTH].title = SANE_TITLE_BIT_DEPTH;
 | ||
| 	s->opt[OPT_BIT_DEPTH].desc = SANE_DESC_BIT_DEPTH;
 | ||
| 	s->opt[OPT_BIT_DEPTH].type = SANE_TYPE_INT;
 | ||
| 	s->opt[OPT_BIT_DEPTH].unit = SANE_UNIT_NONE;
 | ||
| 	s->opt[OPT_BIT_DEPTH].constraint_type = SANE_CONSTRAINT_WORD_LIST;
 | ||
| 	s->opt[OPT_BIT_DEPTH].constraint.word_list = s->hw->cap->depth_list;
 | ||
| 	s->opt[OPT_BIT_DEPTH].cap |= SANE_CAP_INACTIVE;
 | ||
| 	s->val[OPT_BIT_DEPTH].w = s->hw->cap->depth_list[1];	/* the first "real" element is the default */
 | ||
| 
 | ||
| 	DBG(20, "%s: depth list has depth_list[0] = %d entries\n", __func__, s->hw->cap->depth_list[0]);
 | ||
| 	if (s->hw->cap->depth_list[0] == 1) {	/* only one element in the list -> hide the option */
 | ||
| 		s->opt[OPT_BIT_DEPTH].cap |= SANE_CAP_INACTIVE;
 | ||
| 		DBG(20, "%s: Only one depth in list so inactive option\n", __func__);
 | ||
| 	}
 | ||
| 
 | ||
| 	/* resolution */
 | ||
| 	s->opt[OPT_RESOLUTION].name = SANE_NAME_SCAN_RESOLUTION;
 | ||
| 	s->opt[OPT_RESOLUTION].title = SANE_TITLE_SCAN_RESOLUTION;
 | ||
| 	s->opt[OPT_RESOLUTION].desc = SANE_DESC_SCAN_RESOLUTION;
 | ||
| 	s->opt[OPT_RESOLUTION].type = SANE_TYPE_INT;
 | ||
| 	s->opt[OPT_RESOLUTION].unit = SANE_UNIT_DPI;
 | ||
| 	s->opt[OPT_RESOLUTION].constraint_type = SANE_CONSTRAINT_WORD_LIST;
 | ||
| 	res_list = malloc((s->hw->cap->res_list_size + 1) * sizeof(SANE_Word));
 | ||
| 	if (res_list == NULL) {
 | ||
| 		return SANE_STATUS_NO_MEM;
 | ||
| 	}
 | ||
| 	*(res_list) = s->hw->cap->res_list_size;
 | ||
| 	memcpy(&(res_list[1]), s->hw->cap->res_list, s->hw->cap->res_list_size * sizeof(SANE_Word));
 | ||
| 	s->opt[OPT_RESOLUTION].constraint.word_list = res_list;
 | ||
| 	s->val[OPT_RESOLUTION].w = s->hw->cap->dpi_range.min;
 | ||
| 
 | ||
| 
 | ||
| 	/* trial option for debugging
 | ||
| 	s->opt[OPT_TRIALOPT].name = "trialoption";
 | ||
| 	s->opt[OPT_TRIALOPT].title = "trialoption";
 | ||
| 	s->opt[OPT_TRIALOPT].desc = "trialoption";
 | ||
| 	s->opt[OPT_TRIALOPT].type = SANE_TYPE_INT;
 | ||
| 	s->opt[OPT_TRIALOPT].unit = SANE_UNIT_NONE;
 | ||
| 	s->opt[OPT_TRIALOPT].size = sizeof(SANE_Word);
 | ||
| 	s->opt[OPT_TRIALOPT].constraint_type = SANE_CONSTRAINT_RANGE;
 | ||
| 	s->opt[OPT_TRIALOPT].constraint.range = &percent_range_int;
 | ||
| 	s->val[OPT_TRIALOPT].w = 1; */
 | ||
| 
 | ||
| 	/* preview */
 | ||
| 	s->opt[OPT_PREVIEW].name = SANE_NAME_PREVIEW;
 | ||
| 	s->opt[OPT_PREVIEW].title = SANE_TITLE_PREVIEW;
 | ||
| 	s->opt[OPT_PREVIEW].desc = SANE_DESC_PREVIEW;
 | ||
| 	s->opt[OPT_PREVIEW].type = SANE_TYPE_BOOL;
 | ||
| 	s->val[OPT_PREVIEW].w = SANE_FALSE;
 | ||
| 
 | ||
| 	for(i=0;source_list[i]!=NULL;++i)
 | ||
| 		DBG(18, "source_list: %s\n",source_list[i]);
 | ||
| 
 | ||
| 	/* source */
 | ||
| 	s->opt[OPT_SOURCE].name = SANE_NAME_SCAN_SOURCE;
 | ||
| 	s->opt[OPT_SOURCE].title = SANE_TITLE_SCAN_SOURCE;
 | ||
| 	s->opt[OPT_SOURCE].desc = SANE_DESC_SCAN_SOURCE;
 | ||
| 	s->opt[OPT_SOURCE].type = SANE_TYPE_STRING;
 | ||
| 	s->opt[OPT_SOURCE].size = max_string_size(source_list);
 | ||
| 	s->opt[OPT_SOURCE].constraint_type = SANE_CONSTRAINT_STRING_LIST;
 | ||
| 	s->opt[OPT_SOURCE].constraint.string_list = source_list;
 | ||
| 	s->val[OPT_SOURCE].w = 0;	/* always use Flatbed as default */
 | ||
| 
 | ||
| 	if ((!s->hw->cap->ADF)) {
 | ||
| 		DBG(9, "device with no adf detected source option inactive\n");
 | ||
| 		s->opt[OPT_SOURCE].cap |= SANE_CAP_INACTIVE;
 | ||
| 	}
 | ||
| 
 | ||
| /* Are there any ESP scanners that are duplex? */
 | ||
| 	s->opt[OPT_ADF_MODE].name = "adf-mode";
 | ||
| 	s->opt[OPT_ADF_MODE].title = SANE_I18N("ADF Mode");
 | ||
| 	s->opt[OPT_ADF_MODE].desc =
 | ||
| 	SANE_I18N("Selects the ADF mode (simplex/duplex)");
 | ||
| 	s->opt[OPT_ADF_MODE].type = SANE_TYPE_STRING;
 | ||
| 	s->opt[OPT_ADF_MODE].size = max_string_size(adf_mode_list);
 | ||
| 	s->opt[OPT_ADF_MODE].constraint_type = SANE_CONSTRAINT_STRING_LIST;
 | ||
| 	s->opt[OPT_ADF_MODE].constraint.string_list = adf_mode_list;
 | ||
| 	s->val[OPT_ADF_MODE].w = 0;	/* simplex */
 | ||
| 	if ((!s->hw->cap->ADF) || (!s->hw->cap->adf_duplex))
 | ||
| 		s->opt[OPT_ADF_MODE].cap |= SANE_CAP_INACTIVE;
 | ||
| 
 | ||
| 
 | ||
| 	/* "Geometry" group: */
 | ||
| 	s->opt[OPT_GEOMETRY_GROUP].name = SANE_NAME_GEOMETRY;
 | ||
| 	s->opt[OPT_GEOMETRY_GROUP].title = SANE_TITLE_GEOMETRY;
 | ||
| 	s->opt[OPT_GEOMETRY_GROUP].desc = SANE_DESC_GEOMETRY;
 | ||
| 	s->opt[OPT_GEOMETRY_GROUP].type = SANE_TYPE_GROUP;
 | ||
| 	s->opt[OPT_GEOMETRY_GROUP].cap = SANE_CAP_ADVANCED;
 | ||
| 
 | ||
| 	/* top-left x */
 | ||
| 	s->opt[OPT_TL_X].name = SANE_NAME_SCAN_TL_X;
 | ||
| 	s->opt[OPT_TL_X].title = SANE_TITLE_SCAN_TL_X;
 | ||
| 	s->opt[OPT_TL_X].desc = SANE_DESC_SCAN_TL_X;
 | ||
| 	s->opt[OPT_TL_X].type = SANE_TYPE_FIXED;
 | ||
| 	s->opt[OPT_TL_X].unit = SANE_UNIT_MM;
 | ||
| 	s->opt[OPT_TL_X].constraint_type = SANE_CONSTRAINT_RANGE;
 | ||
| 	s->opt[OPT_TL_X].constraint.range = s->hw->x_range;
 | ||
| 	s->val[OPT_TL_X].w = 0;
 | ||
| 
 | ||
| 	/* top-left y */
 | ||
| 	s->opt[OPT_TL_Y].name = SANE_NAME_SCAN_TL_Y;
 | ||
| 	s->opt[OPT_TL_Y].title = SANE_TITLE_SCAN_TL_Y;
 | ||
| 	s->opt[OPT_TL_Y].desc = SANE_DESC_SCAN_TL_Y;
 | ||
| 	s->opt[OPT_TL_Y].type = SANE_TYPE_FIXED;
 | ||
| 	s->opt[OPT_TL_Y].unit = SANE_UNIT_MM;
 | ||
| 	s->opt[OPT_TL_Y].constraint_type = SANE_CONSTRAINT_RANGE;
 | ||
| 	s->opt[OPT_TL_Y].constraint.range = s->hw->y_range;
 | ||
| 	s->val[OPT_TL_Y].w = 0;
 | ||
| 
 | ||
| 	/* bottom-right x */
 | ||
| 	s->opt[OPT_BR_X].name = SANE_NAME_SCAN_BR_X;
 | ||
| 	s->opt[OPT_BR_X].title = SANE_TITLE_SCAN_BR_X;
 | ||
| 	s->opt[OPT_BR_X].desc = SANE_DESC_SCAN_BR_X;
 | ||
| 	s->opt[OPT_BR_X].type = SANE_TYPE_FIXED;
 | ||
| 	s->opt[OPT_BR_X].unit = SANE_UNIT_MM;
 | ||
| 	s->opt[OPT_BR_X].constraint_type = SANE_CONSTRAINT_RANGE;
 | ||
| 	s->opt[OPT_BR_X].constraint.range = s->hw->x_range;
 | ||
| 	s->val[OPT_BR_X].w = s->hw->x_range->max;
 | ||
| 
 | ||
| 	/* bottom-right y */
 | ||
| 	s->opt[OPT_BR_Y].name = SANE_NAME_SCAN_BR_Y;
 | ||
| 	s->opt[OPT_BR_Y].title = SANE_TITLE_SCAN_BR_Y;
 | ||
| 	s->opt[OPT_BR_Y].desc = SANE_DESC_SCAN_BR_Y;
 | ||
| 	s->opt[OPT_BR_Y].type = SANE_TYPE_FIXED;
 | ||
| 	s->opt[OPT_BR_Y].unit = SANE_UNIT_MM;
 | ||
| 	s->opt[OPT_BR_Y].constraint_type = SANE_CONSTRAINT_RANGE;
 | ||
| 	s->opt[OPT_BR_Y].constraint.range = s->hw->y_range;
 | ||
| 	s->val[OPT_BR_Y].w = s->hw->y_range->max;
 | ||
| 
 | ||
| 	/* padding short pages in adf */
 | ||
| 	s->opt[OPT_PADDING].name = "adf-padding";
 | ||
| 	s->opt[OPT_PADDING].title = "pad short adf pages";
 | ||
| 	s->opt[OPT_PADDING].desc = "Selects whether to make short pages up to full length";
 | ||
| 	s->opt[OPT_PADDING].type = SANE_TYPE_BOOL;
 | ||
| 	s->val[OPT_PADDING].w = SANE_FALSE;
 | ||
| 	if ((!s->hw->cap->ADF) || (strcmp(source_list[s->val[OPT_SOURCE].w], ADF_STR) != 0))
 | ||
| 	{
 | ||
| 		DBG(9, "adf not source so padding option off and inactive\n");
 | ||
| 		s->opt[OPT_PADDING].cap |= SANE_CAP_INACTIVE;
 | ||
| 	}
 | ||
| 
 | ||
| 	return SANE_STATUS_GOOD;
 | ||
| }
 | ||
| 
 | ||
| SANE_Status
 | ||
| sane_open(SANE_String_Const name, SANE_Handle *handle)
 | ||
| {
 | ||
| 	SANE_Status status;
 | ||
| 	KodakAio_Scanner *s = NULL;
 | ||
| 
 | ||
| 	int l = strlen(name);
 | ||
| 
 | ||
| 	DBG(2, "%s: name = %s\n", __func__, name);
 | ||
| 
 | ||
| 	/* probe if empty device name provided */
 | ||
| 	if (l == 0) {
 | ||
| 
 | ||
| 		status = sane_get_devices(NULL,0);
 | ||
| 		if (status != SANE_STATUS_GOOD) {
 | ||
| 			return status;
 | ||
| 		}
 | ||
| 
 | ||
| 		if (first_dev == NULL) {
 | ||
| 			DBG(1, "no device detected\n");
 | ||
| 			return SANE_STATUS_INVAL;
 | ||
| 		}
 | ||
| 
 | ||
| 		s = device_detect(first_dev->sane.name, first_dev->connection,
 | ||
| 					&status);
 | ||
| 		if (s == NULL) {
 | ||
| 			DBG(1, "cannot open a perfectly valid device (%s),"
 | ||
| 				" please report to the authors\n", name);
 | ||
| 			return SANE_STATUS_INVAL;
 | ||
| 		}
 | ||
| 
 | ||
| 	} else {
 | ||
| 
 | ||
| 		if (strncmp(name, "net:", 4) == 0) {
 | ||
| 			s = device_detect(name, SANE_KODAKAIO_NET, &status);
 | ||
| 			if (s == NULL)
 | ||
| 				return status;
 | ||
| 		} else if (strncmp(name, "libusb:", 7) == 0) {
 | ||
| 			s = device_detect(name, SANE_KODAKAIO_USB, &status);
 | ||
| 			if (s == NULL)
 | ||
| 				return status;
 | ||
| 		} else {
 | ||
| 
 | ||
| 			/* as a last resort, check for a match
 | ||
| 			 * in the device list. This should handle platforms without libusb.
 | ||
| 			 */
 | ||
| 			if (first_dev == NULL) {
 | ||
| 				status = sane_get_devices(NULL,0);
 | ||
| 				if (status != SANE_STATUS_GOOD) {
 | ||
| 					return status;
 | ||
| 				}
 | ||
| 			}
 | ||
| 
 | ||
| 			s = device_detect(name, SANE_KODAKAIO_NODEV, &status);
 | ||
| 			if (s == NULL) {
 | ||
| 				DBG(1, "invalid device name: %s\n", name);
 | ||
| 				return SANE_STATUS_INVAL;
 | ||
| 			}
 | ||
| 		}
 | ||
| 	}
 | ||
| 
 | ||
| 
 | ||
| 	/* s is always valid here */
 | ||
| 
 | ||
| 	DBG(10, "handle obtained\n");
 | ||
| 	status = k_discover_capabilities(s); /* added 27/12/11 to fix source list problem
 | ||
| maybe we should only be rebuilding the source list here? */
 | ||
| 	if (status != SANE_STATUS_GOOD)
 | ||
| 		return status;
 | ||
| 
 | ||
| 	init_options(s);
 | ||
| 
 | ||
| 	*handle = (SANE_Handle) s;
 | ||
| 
 | ||
| /* moving the open scanner section below to sane_start 27/12/14
 | ||
| 	status = open_scanner(s);
 | ||
| 	if (status != SANE_STATUS_GOOD) {
 | ||
| 		free(s);
 | ||
| 		return status;
 | ||
| 	}
 | ||
| */
 | ||
| 	return status;
 | ||
| }
 | ||
| 
 | ||
| void
 | ||
| sane_close(SANE_Handle handle)
 | ||
| {
 | ||
| 	KodakAio_Scanner *s;
 | ||
| 
 | ||
| 	/*
 | ||
| 	 * XXX Test if there is still data pending from
 | ||
| 	 * the scanner. If so, then do a cancel
 | ||
| 	 */
 | ||
| 
 | ||
| 	s = (KodakAio_Scanner *) handle;
 | ||
| 	DBG(2, "%s: called\n", __func__);
 | ||
| 
 | ||
| /* moving the close scanner section below to sane_cancel 27/12/14 */
 | ||
| 	if (s->fd != -1)
 | ||
| 		close_scanner(s);
 | ||
| /* end of section */
 | ||
| 
 | ||
| 	if(RawScan != NULL)
 | ||
| 		fclose(RawScan);
 | ||
| 	RawScan = NULL;
 | ||
| 	free(s);
 | ||
| }
 | ||
| 
 | ||
| const SANE_Option_Descriptor *
 | ||
| sane_get_option_descriptor(SANE_Handle handle, SANE_Int option)
 | ||
| {
 | ||
| /* this may be a sane call, but it happens way too often to have DBG level 2 */
 | ||
| 	KodakAio_Scanner *s = (KodakAio_Scanner *) handle;
 | ||
| 
 | ||
| 	DBG(30, "%s: called for option %d\n", __func__, option);
 | ||
| 
 | ||
| 	if (option < 0 || option >= NUM_OPTIONS)
 | ||
| 		return NULL;
 | ||
| 
 | ||
| 	return s->opt + option;
 | ||
| }
 | ||
| 
 | ||
| static const SANE_String_Const *
 | ||
| search_string_list(const SANE_String_Const *list, SANE_String value)
 | ||
| {
 | ||
| 	while (*list != NULL && strcmp(value, *list) != 0)
 | ||
| 		list++;
 | ||
| 
 | ||
| 	return ((*list == NULL) ? NULL : list);
 | ||
| }
 | ||
| 
 | ||
| /*
 | ||
|     Activate, deactivate an option. Subroutines so we can add
 | ||
|     debugging info if we want. The change flag is set to TRUE
 | ||
|     if we changed an option. If we did not change an option,
 | ||
|     then the value of the changed flag is not modified.
 | ||
| */
 | ||
| 
 | ||
| static void
 | ||
| activateOption(KodakAio_Scanner *s, SANE_Int option, SANE_Bool *change)
 | ||
| {
 | ||
| 	if (!SANE_OPTION_IS_ACTIVE(s->opt[option].cap)) {
 | ||
| 		s->opt[option].cap &= ~SANE_CAP_INACTIVE;
 | ||
| 		*change = SANE_TRUE;
 | ||
| 	}
 | ||
| }
 | ||
| 
 | ||
| static void
 | ||
| deactivateOption(KodakAio_Scanner *s, SANE_Int option, SANE_Bool *change)
 | ||
| {
 | ||
| 	if (SANE_OPTION_IS_ACTIVE(s->opt[option].cap)) {
 | ||
| 		s->opt[option].cap |= SANE_CAP_INACTIVE;
 | ||
| 		*change = SANE_TRUE;
 | ||
| 	}
 | ||
| }
 | ||
| 
 | ||
| static SANE_Status
 | ||
| getvalue(SANE_Handle handle, SANE_Int option, void *value)
 | ||
| {
 | ||
| 	KodakAio_Scanner *s = (KodakAio_Scanner *) handle;
 | ||
| 	SANE_Option_Descriptor *sopt = &(s->opt[option]);
 | ||
| 	Option_Value *sval = &(s->val[option]);
 | ||
| 
 | ||
| 	DBG(17, "%s: option = %d\n", __func__, option);
 | ||
| 
 | ||
| 	switch (option) {
 | ||
| 
 | ||
| 	case OPT_NUM_OPTS:
 | ||
| 	case OPT_BIT_DEPTH:
 | ||
| 	/* case OPT_TRIALOPT: */
 | ||
| 	case OPT_RESOLUTION:
 | ||
| 	case OPT_PREVIEW:
 | ||
| 	case OPT_TL_X:
 | ||
| 	case OPT_TL_Y:
 | ||
| 	case OPT_BR_X:
 | ||
| 	case OPT_BR_Y:
 | ||
| 		*((SANE_Word *) value) = sval->w;
 | ||
| 		DBG(20, "%s: got option %d as %d\n", __func__, option, *((SANE_Word *) value));
 | ||
| 		break;
 | ||
| 
 | ||
| 	case OPT_THRESHOLD:
 | ||
| 		*((SANE_Word *) value) = sval->w;
 | ||
| 		DBG(20, "%s: got option %d as %f\n", __func__, option, SANE_UNFIX(*((SANE_Word *) value)));
 | ||
| 		/*DBG(20, "%s: got option %d as %d\n", __func__, option, *((SANE_Word *) value));*/
 | ||
| 		break;
 | ||
| 
 | ||
| 	case OPT_MODE:
 | ||
| 	case OPT_SOURCE:
 | ||
| 	case OPT_ADF_MODE:
 | ||
| 		strcpy((char *) value, sopt->constraint.string_list[sval->w]);
 | ||
| 		break;
 | ||
| 	case OPT_PADDING:
 | ||
| 		*((SANE_Bool *) value) = sval->w;
 | ||
| 		break;
 | ||
| 
 | ||
| 	default:
 | ||
| 		DBG(20, "%s: returning inval\n", __func__);
 | ||
| 		return SANE_STATUS_INVAL;
 | ||
| 	}
 | ||
| 
 | ||
| 	DBG(20, "%s: returning good\n", __func__);
 | ||
| 	return SANE_STATUS_GOOD;
 | ||
| }
 | ||
| 
 | ||
| 
 | ||
| /*
 | ||
|  * Handles setting the source (flatbed, or auto document feeder (ADF)).
 | ||
|  *
 | ||
|  */
 | ||
| 
 | ||
| static void
 | ||
| change_source(KodakAio_Scanner *s, SANE_Int optindex, char *value)
 | ||
| {
 | ||
| 	int force_max = SANE_FALSE;
 | ||
| 	SANE_Bool dummy;
 | ||
| 
 | ||
| 	DBG(5, "%s: optindex = %d, source = '%s'\n", __func__, optindex,
 | ||
| 	    value);
 | ||
| 
 | ||
| 	if (s->val[OPT_SOURCE].w == optindex)
 | ||
| 		return;
 | ||
| 
 | ||
| 	s->val[OPT_SOURCE].w = optindex;
 | ||
| 
 | ||
| 	if (s->val[OPT_TL_X].w == s->hw->x_range->min
 | ||
| 	    && s->val[OPT_TL_Y].w == s->hw->y_range->min
 | ||
| 	    && s->val[OPT_BR_X].w == s->hw->x_range->max
 | ||
| 	    && s->val[OPT_BR_Y].w == s->hw->y_range->max) {
 | ||
| 		force_max = SANE_TRUE;
 | ||
| 	}
 | ||
| 
 | ||
| 	if (strcmp(ADF_STR, value) == 0) {
 | ||
| 		s->hw->x_range = &s->hw->cap->adf_x_range;
 | ||
| 		s->hw->y_range = &s->hw->cap->adf_y_range;
 | ||
| 		if (s->hw->cap->adf_duplex) {
 | ||
| 			activateOption(s, OPT_ADF_MODE, &dummy);
 | ||
| 		} else {
 | ||
| 			deactivateOption(s, OPT_ADF_MODE, &dummy);
 | ||
| 			s->val[OPT_ADF_MODE].w = 0;
 | ||
| 		}
 | ||
| 		activateOption(s, OPT_PADDING, &dummy);
 | ||
| 
 | ||
| 		DBG(5, "adf activated flag = %d\n",s->hw->cap->adf_duplex);
 | ||
| 
 | ||
| 	} else {
 | ||
| 		/* ADF not active */
 | ||
| 		s->hw->x_range = &s->hw->cap->fbf_x_range;
 | ||
| 		s->hw->y_range = &s->hw->cap->fbf_y_range;
 | ||
| 
 | ||
| 		deactivateOption(s, OPT_ADF_MODE, &dummy);
 | ||
| 		deactivateOption(s, OPT_PADDING, &dummy);
 | ||
| 	}
 | ||
| 
 | ||
| 	s->opt[OPT_BR_X].constraint.range = s->hw->x_range;
 | ||
| 	s->opt[OPT_BR_Y].constraint.range = s->hw->y_range;
 | ||
| 
 | ||
| 	if (s->val[OPT_TL_X].w < s->hw->x_range->min || force_max)
 | ||
| 		s->val[OPT_TL_X].w = s->hw->x_range->min;
 | ||
| 
 | ||
| 	if (s->val[OPT_TL_Y].w < s->hw->y_range->min || force_max)
 | ||
| 		s->val[OPT_TL_Y].w = s->hw->y_range->min;
 | ||
| 
 | ||
| 	if (s->val[OPT_BR_X].w > s->hw->x_range->max || force_max)
 | ||
| 		s->val[OPT_BR_X].w = s->hw->x_range->max;
 | ||
| 
 | ||
| 	if (s->val[OPT_BR_Y].w > s->hw->y_range->max || force_max)
 | ||
| 		s->val[OPT_BR_Y].w = s->hw->y_range->max;
 | ||
| 
 | ||
| }
 | ||
| 
 | ||
| static SANE_Status
 | ||
| setvalue(SANE_Handle handle, SANE_Int option, void *value, SANE_Int *info)
 | ||
| {
 | ||
| 	KodakAio_Scanner *s = (KodakAio_Scanner *) handle;
 | ||
| 	SANE_Option_Descriptor *sopt = &(s->opt[option]);
 | ||
| 	Option_Value *sval = &(s->val[option]);
 | ||
| 
 | ||
| 	SANE_Status status;
 | ||
| 	const SANE_String_Const *optval = NULL;
 | ||
| 	int optindex = 0;
 | ||
| 	SANE_Bool reload = SANE_FALSE;
 | ||
| 
 | ||
| 	DBG(17, "%s: option = %d, value = %p, as word: %d\n", __func__, option, value, *(SANE_Word *) value);
 | ||
| 
 | ||
| 	status = sanei_constrain_value(sopt, value, info);
 | ||
| 	if (status != SANE_STATUS_GOOD)
 | ||
| 		return status;
 | ||
| 
 | ||
| 	if (info && value && (*info & SANE_INFO_INEXACT)
 | ||
| 	    && sopt->type == SANE_TYPE_INT)
 | ||
| 		DBG(17, "%s: constrained val = %d\n", __func__,
 | ||
| 		    *(SANE_Word *) value);
 | ||
| 
 | ||
| 	if (sopt->constraint_type == SANE_CONSTRAINT_STRING_LIST) {
 | ||
| 		optval = search_string_list(sopt->constraint.string_list,
 | ||
| 					    (char *) value);
 | ||
| 		if (optval == NULL)
 | ||
| 			return SANE_STATUS_INVAL;
 | ||
| 		optindex = optval - sopt->constraint.string_list;
 | ||
| 	}
 | ||
| 
 | ||
| 	switch (option) {
 | ||
| 
 | ||
| 	case OPT_MODE:
 | ||
| 	{
 | ||
| 		sval->w = optindex;
 | ||
| 		/* if binary, then disable the bit depth selection and enable threshold */
 | ||
| 		if (optindex == MODE_LINEART) {
 | ||
| 	DBG(17, "%s: binary mode setting depth to 1\n", __func__);
 | ||
| 			s->val[OPT_BIT_DEPTH].w = 1;
 | ||
| 			s->opt[OPT_BIT_DEPTH].cap |= SANE_CAP_INACTIVE;
 | ||
| 			s->opt[OPT_THRESHOLD].cap &= ~SANE_CAP_INACTIVE;
 | ||
| 		} else {
 | ||
| 			if (s->hw->cap->depth_list[0] == 1) { /* only one entry in the list ? */
 | ||
| 	DBG(17, "%s: non-binary mode but only one depth available\n", __func__);
 | ||
| 				s->val[OPT_BIT_DEPTH].w = s->hw->cap->depth_list[1];
 | ||
| 				s->opt[OPT_BIT_DEPTH].cap |= SANE_CAP_INACTIVE;
 | ||
| 				s->opt[OPT_THRESHOLD].cap |= SANE_CAP_INACTIVE;
 | ||
| 			} else { /* there is a list to choose from ? */
 | ||
| 	DBG(17, "%s: non-binary mode and depth list available\n", __func__);
 | ||
| 				s->opt[OPT_BIT_DEPTH].cap &= ~SANE_CAP_INACTIVE;
 | ||
| 				s->val[OPT_BIT_DEPTH].w = mode_params[optindex].depth;
 | ||
| 				s->opt[OPT_THRESHOLD].cap |= SANE_CAP_INACTIVE; /* does not work in xsane ? */
 | ||
| 			}
 | ||
| 		}
 | ||
| 		reload = SANE_TRUE;
 | ||
| 		break;
 | ||
| 	}
 | ||
| 
 | ||
| 	case OPT_BIT_DEPTH:
 | ||
| 		sval->w = *((SANE_Word *) value);
 | ||
| 		mode_params[s->val[OPT_MODE].w].depth = sval->w;
 | ||
| 		reload = SANE_TRUE;
 | ||
| 		break;
 | ||
| 
 | ||
| 	case OPT_THRESHOLD:
 | ||
| 		sval->w = *((SANE_Word *) value);
 | ||
| 		DBG(17, "setting threshold to %f\n", SANE_UNFIX(sval->w));
 | ||
| 		/*DBG(17, "setting threshold to %d\n", sval->w);*/
 | ||
| 		/*reload = SANE_TRUE; what does this do?*/
 | ||
| 		break;
 | ||
| 
 | ||
| 	case OPT_RESOLUTION:
 | ||
| 		sval->w = *((SANE_Word *) value);
 | ||
| 		DBG(17, "setting resolution to %d\n", sval->w);
 | ||
| 		reload = SANE_TRUE;
 | ||
| 		break;
 | ||
| 
 | ||
| 	case OPT_BR_X:
 | ||
| 	case OPT_BR_Y:
 | ||
| 		if (SANE_UNFIX(*((SANE_Word *) value)) == 0) {
 | ||
| 			DBG(17, "invalid br-x or br-y\n");
 | ||
| 			return SANE_STATUS_INVAL;
 | ||
| 		}
 | ||
|                 // fall through
 | ||
| 	case OPT_TL_X:
 | ||
| 	case OPT_TL_Y:
 | ||
| 		sval->w = *((SANE_Word *) value);
 | ||
| 		DBG(17, "setting size to %f\n", SANE_UNFIX(sval->w));
 | ||
| 		if (NULL != info)
 | ||
| 			*info |= SANE_INFO_RELOAD_PARAMS;
 | ||
| 		break;
 | ||
| 
 | ||
| 	case OPT_SOURCE:
 | ||
| 		change_source(s, optindex, (char *) value);
 | ||
| 		reload = SANE_TRUE;
 | ||
| 		break;
 | ||
| 
 | ||
| 	case OPT_ADF_MODE:
 | ||
| 		sval->w = optindex;	/* Simple lists */
 | ||
| 		break;
 | ||
| 
 | ||
| 	case OPT_PADDING:
 | ||
| 		sval->w = *((SANE_Word *) value);
 | ||
| 		break;
 | ||
| 
 | ||
| 	/* case OPT_TRIALOPT: */
 | ||
| 	case OPT_PREVIEW:	/* needed? */
 | ||
| 		sval->w = *((SANE_Word *) value);
 | ||
| 		break;
 | ||
| 
 | ||
| 	default:
 | ||
| 		return SANE_STATUS_INVAL;
 | ||
| 	}
 | ||
| 
 | ||
| 	if (reload && info != NULL)
 | ||
| 		*info |= SANE_INFO_RELOAD_OPTIONS | SANE_INFO_RELOAD_PARAMS;
 | ||
| 
 | ||
| 	DBG(17, "%s: end\n", __func__);
 | ||
| 
 | ||
| 	return SANE_STATUS_GOOD;
 | ||
| }
 | ||
| 
 | ||
| SANE_Status
 | ||
| sane_control_option(SANE_Handle handle, SANE_Int option, SANE_Action action,
 | ||
| 		    void *value, SANE_Int *info)
 | ||
| {
 | ||
| 	KodakAio_Scanner *s = (KodakAio_Scanner *) handle;
 | ||
| 	if (option < 0 || option >= NUM_OPTIONS)
 | ||
| 	{
 | ||
| 		DBG(1, "%s: option num = %d out of range (0..%d)\n", __func__, option, NUM_OPTIONS - 1);
 | ||
| 		return SANE_STATUS_INVAL;
 | ||
| 	}
 | ||
| 
 | ||
| 	DBG(5, "%s: action = %x, option = %d %s\n", __func__, action, option, s->opt[option].name);
 | ||
| 
 | ||
| 	if (info != NULL)
 | ||
| 		*info = 0;
 | ||
| 
 | ||
| 	switch (action) {
 | ||
| 	case SANE_ACTION_GET_VALUE:
 | ||
| 		return getvalue(handle, option, value);
 | ||
| 
 | ||
| 	case SANE_ACTION_SET_VALUE:
 | ||
| 		return setvalue(handle, option, value, info);
 | ||
| 
 | ||
| 	default:
 | ||
| 		return SANE_STATUS_INVAL;
 | ||
| 	}
 | ||
| 
 | ||
| 	return SANE_STATUS_INVAL;
 | ||
| }
 | ||
| 
 | ||
| SANE_Status
 | ||
| sane_get_parameters(SANE_Handle handle, SANE_Parameters *params)
 | ||
| {
 | ||
| 	KodakAio_Scanner *s = (KodakAio_Scanner *) handle;
 | ||
| 
 | ||
| 	DBG(2, "%s: called\n", __func__);
 | ||
| 
 | ||
| 	if (params == NULL)
 | ||
| 		DBG(1, "%s: params is NULL\n", __func__);
 | ||
| 
 | ||
| 	/*
 | ||
| 	 * If sane_start was already called, then just retrieve the parameters
 | ||
| 	 * from the scanner data structure
 | ||
| 	 */
 | ||
| 
 | ||
| 	if (!s->eof && s->ptr != NULL) {
 | ||
| 		DBG(5, "scan in progress, returning saved params structure\n");
 | ||
| 	} else {
 | ||
| 		/* otherwise initialize the params structure and gather the data */
 | ||
| 		k_init_parametersta(s);
 | ||
| 	}
 | ||
| 
 | ||
| 	if (params != NULL)
 | ||
| 		*params = s->params;
 | ||
| 
 | ||
| 	print_params(s->params,20);
 | ||
| 
 | ||
| 	return SANE_STATUS_GOOD;
 | ||
| }
 | ||
| 
 | ||
| /*
 | ||
|  * This function is part of the SANE API and gets called from the front end to
 | ||
|  * start the scan process.
 | ||
|  */
 | ||
| 
 | ||
| SANE_Status
 | ||
| sane_start(SANE_Handle handle)
 | ||
| {
 | ||
| 	KodakAio_Scanner *s = (KodakAio_Scanner *) handle;
 | ||
| 	SANE_Status status;
 | ||
| 
 | ||
| 	DBG(2, "%s: called\n", __func__);
 | ||
| 	if(! s->scanning) {
 | ||
| 		/* calc scanning parameters */
 | ||
| 		status = k_init_parametersta(s);
 | ||
| 		if (status != SANE_STATUS_GOOD)
 | ||
| 			return status;
 | ||
| 
 | ||
| 	/* set scanning parameters; also query the current image
 | ||
| 	 * parameters from the sanner and save
 | ||
| 	 * them to s->params
 | ||
| Only set scanning params the first time, or after a cancel
 | ||
| try change 22/2/12 take lock scanner out of k_set_scanning_parameters */
 | ||
| 
 | ||
| /* moved open_scanner here 27/12/14 from sane_open */
 | ||
| 	status = open_scanner(s);
 | ||
| 	if (status != SANE_STATUS_GOOD) {
 | ||
| 		free(s);
 | ||
| 		return status;
 | ||
| 	}
 | ||
| /* end of open scanner section */
 | ||
| 
 | ||
| 
 | ||
| 		status = k_lock_scanner(s);
 | ||
| 		if (status != SANE_STATUS_GOOD) {
 | ||
| 			DBG(1, "could not lock scanner\n");
 | ||
| 			return status;
 | ||
| 		}
 | ||
| 
 | ||
| 	}
 | ||
| 
 | ||
| 	status = k_set_scanning_parameters(s);
 | ||
| 	if (status != SANE_STATUS_GOOD)
 | ||
| 		return status;
 | ||
| 
 | ||
| 	print_params(s->params, 5);
 | ||
| 	/* if we scan from ADF, check if it is loaded */
 | ||
| 	if (strcmp(source_list[s->val[OPT_SOURCE].w], ADF_STR) == 0) {
 | ||
| 		status = k_check_adf(s);
 | ||
| 		if (status != SANE_STATUS_GOOD) {
 | ||
| /* returning SANE_STATUS_NO_DOCS seems not to cause simple-scan to end the adf scan, so we cancel */
 | ||
| 			status = SANE_STATUS_CANCELLED;
 | ||
| 			DBG(10, "%s: returning %s\n", __func__, sane_strstatus(status));
 | ||
| 			return status;
 | ||
| 		}
 | ||
| 	}
 | ||
| 
 | ||
| 	/* prepare buffer here so that a memory allocation failure
 | ||
| 	 * will leave the scanner in a sane state.
 | ||
| 	 */
 | ||
| 	s->buf = realloc(s->buf, s->block_len);
 | ||
| 	if (s->buf == NULL)
 | ||
| 		return SANE_STATUS_NO_MEM;
 | ||
| 
 | ||
| 	s->eof = SANE_FALSE; /* page not finished */
 | ||
| 	s->ack = SANE_FALSE; /* page from scanner not finished */
 | ||
| 	s->ptr = s->end = s->buf;
 | ||
| 	s->canceling = SANE_FALSE;
 | ||
| 
 | ||
| 	if (strlen(RawScanPath) > 0 && s->params.lines > 0)
 | ||
| 		RawScan = fopen(RawScanPath, "wb");/* open the debug file if it has a name */
 | ||
| 	if(RawScan) fprintf(RawScan, "P5\n%d %d\n%d\n",s->scan_bytes_per_line, s->params.lines, 255);
 | ||
| 
 | ||
| 	/* start scanning */
 | ||
| 	DBG(2, "%s: scanning...\n", __func__);
 | ||
| 	status = k_start_scan(s);
 | ||
| 
 | ||
| 	if (status != SANE_STATUS_GOOD) {
 | ||
| 		DBG(1, "%s: start failed: %s\n", __func__,
 | ||
| 		    sane_strstatus(status));
 | ||
| 
 | ||
| 		return status;
 | ||
| 	}
 | ||
| 
 | ||
| 	return status;
 | ||
| }
 | ||
| 
 | ||
| /* this moves data from our buffers to SANE */
 | ||
| 
 | ||
| SANE_Status
 | ||
| sane_read(SANE_Handle handle, SANE_Byte *data, SANE_Int max_length,
 | ||
| 	  SANE_Int *length)
 | ||
| {
 | ||
| 	SANE_Status status;
 | ||
| 	KodakAio_Scanner *s = (KodakAio_Scanner *) handle;
 | ||
| 
 | ||
| 	if (s->buf == NULL || s->canceling)
 | ||
| 		return SANE_STATUS_CANCELLED;
 | ||
| 
 | ||
| 	*length = 0;
 | ||
| 	DBG(18, "sane-read, bytes unread %d\n",s->bytes_unread);
 | ||
| 
 | ||
| 	status = k_read(s);
 | ||
| 
 | ||
| 	if (status == SANE_STATUS_CANCELLED) {
 | ||
| 		k_scan_finish(s);
 | ||
| 		return status;
 | ||
| 	}
 | ||
| 
 | ||
| 	k_copy_image_data(s, data, max_length, length);
 | ||
| 
 | ||
| 	DBG(18, "%d lines read, status: %s\n",
 | ||
| 		*length / s->params.bytes_per_line, sane_strstatus(status));
 | ||
| 
 | ||
| 	/* continue reading if appropriate */
 | ||
| 	if (status == SANE_STATUS_GOOD)
 | ||
| 		return status;
 | ||
| 
 | ||
| /* not sure if we want to finish (unlock scanner) here or in sane_close */
 | ||
| 	/* k_scan_finish(s); */
 | ||
| 	return status;
 | ||
| }
 | ||
| 
 | ||
| 
 | ||
| void
 | ||
| sane_cancel(SANE_Handle handle)
 | ||
| {
 | ||
| 	SANE_Status status;
 | ||
| 	KodakAio_Scanner *s = (KodakAio_Scanner *) handle;
 | ||
| 	DBG(2, "%s: called\n", __func__);
 | ||
| 
 | ||
| 	status = cmd_cancel_scan(s);
 | ||
| 	if (status != SANE_STATUS_GOOD)
 | ||
| 		DBG(1, "%s: cmd_cancel_scan failed: %s\n", __func__,
 | ||
| 		    sane_strstatus(status));
 | ||
| 
 | ||
| /* moved from close scanner section 27/12/14 */
 | ||
| 	if (s->fd != -1)
 | ||
| 		close_scanner(s);
 | ||
| /* end of section */
 | ||
| 
 | ||
| }
 | ||
| 
 | ||
| /*
 | ||
|  * SANE_Status sane_set_io_mode()
 | ||
|  *
 | ||
|  * not supported - for asynchronous I/O
 | ||
|  */
 | ||
| 
 | ||
| SANE_Status
 | ||
| sane_set_io_mode(SANE_Handle __sane_unused__ handle,
 | ||
| 	SANE_Bool __sane_unused__ non_blocking)
 | ||
| {
 | ||
| 	return SANE_STATUS_UNSUPPORTED;
 | ||
| }
 | ||
| 
 | ||
| /*
 | ||
|  * SANE_Status sane_get_select_fd()
 | ||
|  *
 | ||
|  * not supported - for asynchronous I/O
 | ||
|  */
 | ||
| 
 | ||
| SANE_Status
 | ||
| sane_get_select_fd(SANE_Handle __sane_unused__ handle,
 | ||
| 	SANE_Int __sane_unused__ *fd)
 | ||
| {
 | ||
| 	return SANE_STATUS_UNSUPPORTED;
 | ||
| }
 |