summaryrefslogtreecommitdiff
path: root/backend/artec_eplus48u.h
blob: cc30214e8fe934bffc612d228b78aec34d3526f4 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
#ifndef ARTEC48U_H
#define ARTEC48U_H

#include "../include/sane/sane.h"
#include "../include/sane/sanei.h"
#include "../include/sane/saneopts.h"
#include <sys/types.h>
#ifdef HAVE_SYS_IPC_H
#include <sys/ipc.h>
#endif
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>

#include "../include/sane/sanei_usb.h"
#include "../include/sane/sanei_thread.h"

#define _MAX_ID_LEN 20

/*Uncomment next line for button support. This
  actually isn't supported by the frontends. */
/*#define ARTEC48U_USE_BUTTONS 1*/

#define ARTEC48U_PACKET_SIZE 64
#define DECLARE_FUNCTION_NAME(name)     \
  IF_DBG ( static const char function_name[] = name; )

typedef SANE_Byte Artec48U_Packet[ARTEC48U_PACKET_SIZE];
#define XDBG(args)           do { IF_DBG ( DBG args ); } while (0)

/* calculate the minimum/maximum values */
#define MIN(a, b) (((a) < (b)) ? (a) : (b))
#define MAX(a, b) (((a) > (b)) ? (a) : (b))

/* return the lower/upper 8 bits of a 16 bit word */
#define HIBYTE(w) ((SANE_Byte)(((SANE_Word)(w) >> 8) & 0xFF))
#define LOBYTE(w) ((SANE_Byte)(w))


#define CHECK_DEV_NOT_NULL(dev, func_name)                              \
  do {                                                                  \
    if (!(dev))                                                         \
      {                                                                 \
        XDBG ((3, "%s: BUG: NULL device\n", (func_name)));              \
        return SANE_STATUS_INVAL;                                       \
      }                                                                 \
  } while (SANE_FALSE)

/** Check that the device is open.
 *
 * @param dev       Pointer to the device object (Artec48U_Device).
 * @param func_name Function name (for use in debug messages).
 */
#define CHECK_DEV_OPEN(dev, func_name)                                  \
  do {                                                                  \
    CHECK_DEV_NOT_NULL ((dev), (func_name));                            \
    if ((dev)->fd == -1)                                                \
      {                                                                 \
        XDBG ((3, "%s: BUG: device %p not open\n", (func_name), (void*)(dev)));\
        return SANE_STATUS_INVAL;                                       \
      }                                                                 \
  } while (SANE_FALSE)

#define CHECK_DEV_ACTIVE(dev,func_name)                                \
  do {                                                                  \
    CHECK_DEV_OPEN ((dev), (func_name));                                \
    if (!(dev)->active)                                                 \
      {                                                                 \
        XDBG ((3, "%s: BUG: device %p not active\n",                    \
               (func_name), (void*)(dev)));                                    \
        return SANE_STATUS_INVAL;                                       \
      }                                                                 \
  } while (SANE_FALSE)

typedef struct Artec48U_Device Artec48U_Device;
typedef struct Artec48U_Scan_Request Artec48U_Scan_Request;
typedef struct Artec48U_Scanner Artec48U_Scanner;
typedef struct Artec48U_Scan_Parameters Artec48U_Scan_Parameters;
typedef struct Artec48U_AFE_Parameters Artec48U_AFE_Parameters;
typedef struct Artec48U_Exposure_Parameters Artec48U_Exposure_Parameters;
typedef struct Artec48U_Line_Reader Artec48U_Line_Reader;
typedef struct Artec48U_Delay_Buffer Artec48U_Delay_Buffer;

enum artec_options
{
  OPT_NUM_OPTS = 0,
  OPT_MODE_GROUP,
  OPT_SCAN_MODE,
  OPT_BIT_DEPTH,
  OPT_BLACK_LEVEL,
  OPT_RESOLUTION,
  OPT_ENHANCEMENT_GROUP,
  OPT_BRIGHTNESS,
  OPT_CONTRAST,
  OPT_GAMMA,
  OPT_GAMMA_R,
  OPT_GAMMA_G,
  OPT_GAMMA_B,
  OPT_DEFAULT_ENHANCEMENTS,
  OPT_GEOMETRY_GROUP,
  OPT_TL_X,
  OPT_TL_Y,
  OPT_BR_X,
  OPT_BR_Y,
  OPT_CALIBRATION_GROUP,
  OPT_CALIBRATE,
  OPT_CALIBRATE_SHADING,
#ifdef ARTEC48U_USE_BUTTONS
  OPT_BUTTON_STATE,
#endif
  /* must come last: */
  NUM_OPTIONS
};

/** Artec48U analog front-end (AFE) parameters.
 */
struct Artec48U_AFE_Parameters
{
  SANE_Byte r_offset;	/**< Red channel offset */
  SANE_Byte r_pga;	/**< Red channel PGA gain */
  SANE_Byte g_offset;	/**< Green channel offset (also used for mono) */
  SANE_Byte g_pga;	/**< Green channel PGA gain (also used for mono) */
  SANE_Byte b_offset;	/**< Blue channel offset */
  SANE_Byte b_pga;	/**< Blue channel PGA gain */
};

/** TV9693 exposure time parameters.
 */
struct Artec48U_Exposure_Parameters
{
  SANE_Int r_time;     /**< Red exposure time */
  SANE_Int g_time;     /**< Red exposure time */
  SANE_Int b_time;     /**< Red exposure time */
};

struct Artec48U_Device
{
  Artec48U_Device *next;
  /** Device file descriptor. */
  int fd;
  /** Device activation flag. */
  SANE_Bool active;
  SANE_String_Const name;
  SANE_Device sane;		 /** Scanner model data. */
  SANE_String_Const firmware_path;
  double gamma_master;
  double gamma_r;
  double gamma_g;
  double gamma_b;
  Artec48U_Exposure_Parameters exp_params;
  Artec48U_AFE_Parameters afe_params;
  Artec48U_AFE_Parameters artec_48u_afe_params;
  Artec48U_Exposure_Parameters artec_48u_exposure_params;

  SANE_Int optical_xdpi;
  SANE_Int optical_ydpi;
  SANE_Int base_ydpi;
  SANE_Int xdpi_offset;		/* in optical_xdpi units */
  SANE_Int ydpi_offset;		/* in optical_ydpi units */
  SANE_Int x_size;		/* in optical_xdpi units */
  SANE_Int y_size;		/* in optical_ydpi units */
/* the number of lines, that we move forward before we start reading the
   shading lines */
  int shading_offset;
/* the number of lines we read for the black shading buffer */
  int shading_lines_b;
/* the number of lines we read for the white shading buffer */
  int shading_lines_w;

  SANE_Fixed x_offset, y_offset;
  SANE_Bool read_active;
  SANE_Byte *read_buffer;
  size_t requested_buffer_size;
  size_t read_pos;
  size_t read_bytes_in_buffer;
  size_t read_bytes_left;
  unsigned int is_epro;
  unsigned int epro_mult;
};

/** Scan parameters for artec48u_device_setup_scan().
 *
 * These parameters describe a low-level scan request; many such requests are
 * executed during calibration, and they need to have parameters separate from
 * the main request (Artec48U_Scan_Request).  E.g., on the BearPaw 2400 TA the
 * scan to find the home position is always done at 300dpi 8-bit mono with
 * fixed width and height, regardless of the high-level scan parameters.
 */
struct Artec48U_Scan_Parameters
{
  SANE_Int xdpi;	/**< Horizontal resolution */
  SANE_Int ydpi;	/**< Vertical resolution */
  SANE_Int depth;	/**< Number of bits per channel */
  SANE_Bool color;	/**< Color mode flag */

  SANE_Int pixel_xs;		/**< Logical width in pixels */
  SANE_Int pixel_ys;		/**< Logical height in pixels */
  SANE_Int scan_xs;		/**< Physical width in pixels */
  SANE_Int scan_ys;		/**< Physical height in pixels */
  SANE_Int scan_bpl;		/**< Number of bytes per scan line */
  SANE_Bool lineart;		/**<Lineart is not really supported by device*/
};


/** Parameters for the high-level scan request.
 *
 * These parameters describe the scan request sent by the SANE frontend.
 */
struct Artec48U_Scan_Request
{
  SANE_Fixed x0;	/**< Left boundary  */
  SANE_Fixed y0;	/**< Top boundary */
  SANE_Fixed xs;	/**< Width */
  SANE_Fixed ys;	/**< Height */
  SANE_Int xdpi;	/**< Horizontal resolution */
  SANE_Int ydpi;	/**< Vertical resolution */
  SANE_Int depth;	/**< Number of bits per channel */
  SANE_Bool color;	/**< Color mode flag */
};
/** Scan action code (purpose of the scan).
 *
 * The scan action code affects various scanning mode fields in the setup
 * command.
 */
typedef enum Artec48U_Scan_Action
{
  SA_CALIBRATE_SCAN_WHITE,	/**< Scan white shading buffer           */
  SA_CALIBRATE_SCAN_BLACK,	/**< Scan black shading buffer           */
  SA_CALIBRATE_SCAN_OFFSET_1,	/**< First scan to determin offset       */
  SA_CALIBRATE_SCAN_OFFSET_2,	/**< Second scan to determine offset     */
  SA_CALIBRATE_SCAN_EXPOSURE_1,	  /**< First scan to determin offset       */
  SA_CALIBRATE_SCAN_EXPOSURE_2,	  /**< Second scan to determine offset     */
  SA_SCAN			/**< Normal scan */
}
Artec48U_Scan_Action;


struct Artec48U_Delay_Buffer
{
  SANE_Int line_count;
  SANE_Int read_index;
  SANE_Int write_index;
  unsigned int **lines;
  SANE_Byte *mem_block;
};

struct Artec48U_Line_Reader
{
  Artec48U_Device *dev;			  /**< Low-level interface object */
  Artec48U_Scan_Parameters params;	  /**< Scan parameters */

  /** Number of pixels in the returned scanlines */
  SANE_Int pixels_per_line;

  SANE_Byte *pixel_buffer;

  Artec48U_Delay_Buffer r_delay;
  Artec48U_Delay_Buffer g_delay;
  Artec48U_Delay_Buffer b_delay;
  SANE_Bool delays_initialized;

    SANE_Status (*read) (Artec48U_Line_Reader * reader,
			 unsigned int **buffer_pointers_return);
};

#ifndef SANE_OPTION
typedef union
{
  SANE_Word w;
  SANE_Word *wa;		/* word array */
  SANE_String s;
}
Option_Value;
#endif

struct Artec48U_Scanner
{
  Artec48U_Scanner *next;
  Artec48U_Scan_Parameters params;
  Artec48U_Scan_Request request;
  Artec48U_Device *dev;
  Artec48U_Line_Reader *reader;
  FILE *pipe_handle;
  SANE_Pid reader_pid;
  int pipe;
  int reader_pipe;
  SANE_Option_Descriptor opt[NUM_OPTIONS];
  Option_Value val[NUM_OPTIONS];
  SANE_Status exit_code;
  SANE_Parameters sane_params;
  SANE_Bool scanning;
  SANE_Bool eof;
  SANE_Bool calibrated;
  SANE_Word gamma_array[4][65536];
  SANE_Word contrast_array[65536];
  SANE_Word brightness_array[65536];
  SANE_Byte *line_buffer;
  SANE_Byte *lineart_buffer;
  SANE_Word lines_to_read;
  unsigned int temp_shading_buffer[3][10240]; /*epro*/
  unsigned int *buffer_pointers[3];
  unsigned char *shading_buffer_w;
  unsigned char *shading_buffer_b;
  unsigned int *shading_buffer_white[3];
  unsigned int *shading_buffer_black[3];
  unsigned long byte_cnt;
};


/** Create a new Artec48U_Device object.
 *
 * The newly created device object is in the closed state.
 *
 * @param dev_return Returned pointer to the created device object.
 *
 * @return
 * - #SANE_STATUS_GOOD   - the device object was created.
 * - #SANE_STATUS_NO_MEM - not enough system resources to create the object.
 */
static SANE_Status artec48u_device_new (Artec48U_Device ** dev_return);

/** Destroy the device object and release all associated resources.
 *
 * If the device was active, it will be deactivated; if the device was open, it
 * will be closed.
 *
 * @param dev Device object.
 *
 * @return
 * - #SANE_STATUS_GOOD  - success.
 */
static SANE_Status artec48u_device_free (Artec48U_Device * dev);

/** Open the scanner device.
 *
 * This function opens the device special file @a dev_name and tries to detect
 * the device model by its USB ID.
 *
 * If the device is detected successfully (its USB ID is found in the supported
 * device list), this function sets the appropriate model parameters.
 *
 * If the USB ID is not recognized, the device remains unconfigured; an attempt
 * to activate it will fail unless artec48u_device_set_model() is used to force
 * the parameter set.  Note that the open is considered to be successful in
 * this case.
 *
 * @param dev Device object.
 * @param dev_name Scanner device name.
 *
 * @return
 * - #SANE_STATUS_GOOD - the device was opened successfully (it still may be
 *   unconfigured).
 */
static SANE_Status artec48u_device_open (Artec48U_Device * dev);

/** Close the scanner device.
 *
 * @param dev Device object.
 */
static SANE_Status artec48u_device_close (Artec48U_Device * dev);

/** Activate the device.
 *
 * The device must be activated before performing any I/O operations with it.
 * All device model parameters must be configured before activation; it is
 * impossible to change them after the device is active.
 *
 * This function might need to acquire resources (it calls
 * Artec48U_Command_Set::activate).  These resources will be released when
 * artec48u_device_deactivate() is called.
 *
 * @param dev Device object.
 *
 * @return
 * - #SANE_STATUS_GOOD  - device activated successfully.
 * - #SANE_STATUS_INVAL - invalid request (attempt to activate a closed or
 *   unconfigured device).
 */
static SANE_Status artec48u_device_activate (Artec48U_Device * dev);

/** Deactivate the device.
 *
 * This function reverses the action of artec48u_device_activate().
 *
 * @param dev Device object.
 *
 * @return
 * - #SANE_STATUS_GOOD  - device deactivated successfully.
 * - #SANE_STATUS_INVAL - invalid request (the device was not activated).
 */
static SANE_Status artec48u_device_deactivate (Artec48U_Device * dev);

/** Write a data block to the TV9693 memory.
 *
 * @param dev  Device object.
 * @param addr Start address in the TV9693 memory.
 * @param size Size of the data block in bytes.
 * @param data Data block to write.
 *
 * @return
 * - #SANE_STATUS_GOOD     - success.
 * - #SANE_STATUS_IO_ERROR - a communication error occured.
 *
 * @warning
 * @a size must be a multiple of 64 (at least with TV9693), otherwise the
 * scanner (and possibly the entire USB bus) will lock up.
 */
static SANE_Status
artec48u_device_memory_write (Artec48U_Device * dev, SANE_Word addr,
			      SANE_Word size, SANE_Byte * data);

/** Read a data block from the TV9693 memory.
 *
 * @param dev  Device object.
 * @param addr Start address in the TV9693 memory.
 * @param size Size of the data block in bytes.
 * @param data Buffer for the read data.
 *
 * @return
 * - #SANE_STATUS_GOOD     - success.
 * - #SANE_STATUS_IO_ERROR - a communication error occured.
 *
 * @warning
 * @a size must be a multiple of 64 (at least with TV9693), otherwise the
 * scanner (and possibly the entire USB bus) will lock up.
 */
static SANE_Status
artec48u_device_memory_read (Artec48U_Device * dev, SANE_Word addr,
			     SANE_Word size, SANE_Byte * data);

/** Execute a control command.
 *
 * @param dev Device object.
 * @param cmd Command packet.
 * @param res Result packet (may point to the same buffer as @a cmd).
 *
 * @return
 * - #SANE_STATUS_GOOD     - success.
 * - #SANE_STATUS_IO_ERROR - a communication error occured.
 */
static SANE_Status
artec48u_device_req (Artec48U_Device * dev, Artec48U_Packet cmd,
		     Artec48U_Packet res);

/** Execute a "small" control command.
 *
 * @param dev Device object.
 * @param cmd Command packet; only first 8 bytes are used.
 * @param res Result packet (may point to the same buffer as @a cmd).
 *
 * @return
 * - #SANE_STATUS_GOOD     - success.
 * - #SANE_STATUS_IO_ERROR - a communication error occured.
 */
static SANE_Status
artec48u_device_small_req (Artec48U_Device * dev, Artec48U_Packet cmd,
			   Artec48U_Packet res);

/** Read raw data from the bulk-in scanner pipe.
 *
 * @param dev Device object.
 * @param buffer Buffer for the read data.
 * @param size Pointer to the variable which must be set to the requested data
 * size before call.  After completion this variable will hold the number of
 * bytes actually read.
 *
 * @return
 * - #SANE_STATUS_GOOD - success.
 * - #SANE_STATUS_IO_ERROR - a communication error occured.
 */
static SANE_Status
artec48u_device_read_raw (Artec48U_Device * dev, SANE_Byte * buffer,
			  size_t * size);

static SANE_Status
artec48u_device_set_read_buffer_size (Artec48U_Device * dev,
				      size_t buffer_size);

static SANE_Status
artec48u_device_read_prepare (Artec48U_Device * dev, size_t expected_count);

static SANE_Status
artec48u_device_read (Artec48U_Device * dev, SANE_Byte * buffer,
		      size_t * size);

static SANE_Status artec48u_device_read_finish (Artec48U_Device * dev);


/**
 * Create a new Artec48U_Line_Reader object.
 *
 * @param dev           The low-level scanner interface object.
 * @param params        Scan parameters prepared by artec48u_device_setup_scan().
 * @param reader_return Location for the returned object.
 *
 * @return
 * - SANE_STATUS_GOOD   - on success
 * - SANE_STATUS_NO_MEM - cannot allocate memory for object or buffers
 * - other error values - failure of some internal functions
 */
static SANE_Status
artec48u_line_reader_new (Artec48U_Device * dev,
			  Artec48U_Scan_Parameters * params,
			  Artec48U_Line_Reader ** reader_return);

/**
 * Destroy the Artec48U_Line_Reader object.
 *
 * @param reader  The Artec48U_Line_Reader object to destroy.
 */
static SANE_Status artec48u_line_reader_free (Artec48U_Line_Reader * reader);

/**
 * Read a scanline from the Artec48U_Line_Reader object.
 *
 * @param reader      The Artec48U_Line_Reader object.
 * @param buffer_pointers_return Array of pointers to image lines (1 or 3
 * elements)
 *
 * This function reads a full scanline from the device, unpacks it to internal
 * buffers and returns pointer to these buffers in @a
 * buffer_pointers_return[i].  For monochrome scan, only @a
 * buffer_pointers_return[0] is filled; for color scan, elements 0, 1, 2 are
 * filled with pointers to red, green, and blue data.  The returned pointers
 * are valid until the next call to artec48u_line_reader_read(), or until @a
 * reader is destroyed.
 *
 * @return
 * - SANE_STATUS_GOOD  - read completed successfully
 * - other error value - an error occured
 */
static SANE_Status
artec48u_line_reader_read (Artec48U_Line_Reader * reader,
			   unsigned int **buffer_pointers_return);

static SANE_Status
artec48u_download_firmware (Artec48U_Device * dev,
			    SANE_Byte * data, SANE_Word size);

static SANE_Status
artec48u_is_moving (Artec48U_Device * dev, SANE_Bool * moving);

static SANE_Status artec48u_carriage_home (Artec48U_Device * dev);

static SANE_Status artec48u_stop_scan (Artec48U_Device * dev);

static SANE_Status
artec48u_setup_scan (Artec48U_Scanner * s,
		     Artec48U_Scan_Request * request,
		     Artec48U_Scan_Action action,
		     SANE_Bool calculate_only,
		     Artec48U_Scan_Parameters * params);

static SANE_Status
artec48u_scanner_new (Artec48U_Device * dev,
		      Artec48U_Scanner ** scanner_return);

static SANE_Status artec48u_scanner_free (Artec48U_Scanner * scanner);

static SANE_Status
artec48u_scanner_start_scan (Artec48U_Scanner * scanner,
			     Artec48U_Scan_Request * request,
			     Artec48U_Scan_Parameters * params);

static SANE_Status
artec48u_scanner_read_line (Artec48U_Scanner * scanner,
			    unsigned int **buffer_pointers,
			    SANE_Bool shading);

static SANE_Status artec48u_scanner_stop_scan (Artec48U_Scanner * scanner);

static SANE_Status
artec48u_calculate_shading_buffer (Artec48U_Scanner * s, int start, int end,
				   int resolution, SANE_Bool color);

static SANE_Status download_firmware_file (Artec48U_Device * chip);

static SANE_Status
artec48u_generic_set_exposure_time (Artec48U_Device * dev,
				    Artec48U_Exposure_Parameters * params);

static SANE_Status
artec48u_generic_set_afe (Artec48U_Device * dev,
			  Artec48U_AFE_Parameters * params);

static SANE_Status artec48u_generic_start_scan (Artec48U_Device * dev);

static SANE_Status
artec48u_generic_read_scanned_data (Artec48U_Device * dev, SANE_Bool * ready);

static SANE_Status init_options (Artec48U_Scanner * s);

static SANE_Status load_calibration_data (Artec48U_Scanner * s);

static SANE_Status save_calibration_data (Artec48U_Scanner * s);
#endif