1141cc406Sopenharmony_ci/* sane - Scanner Access Now Easy. 2141cc406Sopenharmony_ci 3141cc406Sopenharmony_ci pieusb_buffer.c 4141cc406Sopenharmony_ci 5141cc406Sopenharmony_ci Copyright (C) 2012-2015 Jan Vleeshouwers, Michael Rickmann, Klaus Kaempf 6141cc406Sopenharmony_ci 7141cc406Sopenharmony_ci This file is part of the SANE package. 8141cc406Sopenharmony_ci 9141cc406Sopenharmony_ci This program is free software; you can redistribute it and/or 10141cc406Sopenharmony_ci modify it under the terms of the GNU General Public License as 11141cc406Sopenharmony_ci published by the Free Software Foundation; either version 2 of the 12141cc406Sopenharmony_ci License, or (at your option) any later version. 13141cc406Sopenharmony_ci 14141cc406Sopenharmony_ci This program is distributed in the hope that it will be useful, but 15141cc406Sopenharmony_ci WITHOUT ANY WARRANTY; without even the implied warranty of 16141cc406Sopenharmony_ci MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 17141cc406Sopenharmony_ci General Public License for more details. 18141cc406Sopenharmony_ci 19141cc406Sopenharmony_ci You should have received a copy of the GNU General Public License 20141cc406Sopenharmony_ci along with this program. If not, see <https://www.gnu.org/licenses/>. 21141cc406Sopenharmony_ci 22141cc406Sopenharmony_ci As a special exception, the authors of SANE give permission for 23141cc406Sopenharmony_ci additional uses of the libraries contained in this release of SANE. 24141cc406Sopenharmony_ci 25141cc406Sopenharmony_ci The exception is that, if you link a SANE library with other files 26141cc406Sopenharmony_ci to produce an executable, this does not by itself cause the 27141cc406Sopenharmony_ci resulting executable to be covered by the GNU General Public 28141cc406Sopenharmony_ci License. Your use of that executable is in no way restricted on 29141cc406Sopenharmony_ci account of linking the SANE library code into it. 30141cc406Sopenharmony_ci 31141cc406Sopenharmony_ci This exception does not, however, invalidate any other reasons why 32141cc406Sopenharmony_ci the executable file might be covered by the GNU General Public 33141cc406Sopenharmony_ci License. 34141cc406Sopenharmony_ci 35141cc406Sopenharmony_ci If you submit changes to SANE to the maintainers to be included in 36141cc406Sopenharmony_ci a subsequent release, you agree by submitting the changes that 37141cc406Sopenharmony_ci those changes may be distributed with this exception intact. 38141cc406Sopenharmony_ci 39141cc406Sopenharmony_ci If you write modifications of your own for SANE, it is your choice 40141cc406Sopenharmony_ci whether to permit this exception to apply to your modifications. 41141cc406Sopenharmony_ci If you do not wish that, delete this exception notice. */ 42141cc406Sopenharmony_ci 43141cc406Sopenharmony_ci/* ========================================================================= 44141cc406Sopenharmony_ci * 45141cc406Sopenharmony_ci * Read buffer 46141cc406Sopenharmony_ci * 47141cc406Sopenharmony_ci * Data obtained from the scanner cannot be presented to the frontend immediately. 48141cc406Sopenharmony_ci * The scanner returns data in the 'index' or 'line' color format, which means it 49141cc406Sopenharmony_ci * returns data in batches which contain a single color of a scan line. 50141cc406Sopenharmony_ci * 51141cc406Sopenharmony_ci * These must finally be converted into the SANE data format (data for a single 52141cc406Sopenharmony_ci * pixel in consecutive bytes). Apart from that, sane_read() must be able to 53141cc406Sopenharmony_ci * return any amount of data bytes. 54141cc406Sopenharmony_ci * 55141cc406Sopenharmony_ci * In between, data processing may be necessary, usually requiring the whole 56141cc406Sopenharmony_ci * image to be available. 57141cc406Sopenharmony_ci * 58141cc406Sopenharmony_ci * To accommodate all this, the buffer stores all samples as 16-bit values, even 59141cc406Sopenharmony_ci * if the original values are 8-bit or even 1 bit. This is a waste of space, but 60141cc406Sopenharmony_ci * makes processing much easier, and it is only temporary. 61141cc406Sopenharmony_ci * 62141cc406Sopenharmony_ci * The read buffer is constructed by a call to buffer_create(), which initializes 63141cc406Sopenharmony_ci * the buffer based on width, height, number of colors and depth. The buffer 64141cc406Sopenharmony_ci * contains data organized in color planes, with each plane consisting of lines, 65141cc406Sopenharmony_ci * each line of a fixed number of (single color) pixels, and each pixel of a fixed 66141cc406Sopenharmony_ci * number of bits (or bytes). 67141cc406Sopenharmony_ci * 68141cc406Sopenharmony_ci * The buffer maintains read and write pointers. 69141cc406Sopenharmony_ci * 70141cc406Sopenharmony_ci * Multi-color data with a bit depth of 1 are packed in single color bytes, so 71141cc406Sopenharmony_ci * the data obtained from the scanner does not need conversion. 72141cc406Sopenharmony_ci * 73141cc406Sopenharmony_ci * ========================================================================= */ 74141cc406Sopenharmony_ci 75141cc406Sopenharmony_ci#define DEBUG_DECLARE_ONLY 76141cc406Sopenharmony_ci 77141cc406Sopenharmony_ci/* Configuration defines */ 78141cc406Sopenharmony_ci#include "../include/sane/config.h" 79141cc406Sopenharmony_ci 80141cc406Sopenharmony_ci/* SANE includes */ 81141cc406Sopenharmony_ci#include "../include/sane/sane.h" 82141cc406Sopenharmony_ci#include "../include/sane/saneopts.h" 83141cc406Sopenharmony_ci#include "../include/sane/sanei_usb.h" 84141cc406Sopenharmony_ci#include "../include/sane/sanei_config.h" 85141cc406Sopenharmony_ci 86141cc406Sopenharmony_ci/* Backend includes */ 87141cc406Sopenharmony_ci#define BACKEND_NAME pieusb 88141cc406Sopenharmony_ci#include "../include/sane/sanei_backend.h" 89141cc406Sopenharmony_ci#include "pieusb.h" 90141cc406Sopenharmony_ci 91141cc406Sopenharmony_ci#include "pieusb_specific.h" 92141cc406Sopenharmony_ci#include "pieusb_buffer.h" 93141cc406Sopenharmony_ci 94141cc406Sopenharmony_ci#ifdef HAVE_ALLOCA_H 95141cc406Sopenharmony_ci#include <alloca.h> 96141cc406Sopenharmony_ci#endif 97141cc406Sopenharmony_ci 98141cc406Sopenharmony_ci#include <stdio.h> 99141cc406Sopenharmony_ci#include <fcntl.h> 100141cc406Sopenharmony_ci#include <sys/mman.h> 101141cc406Sopenharmony_ci 102141cc406Sopenharmony_ci#include "byteorder.h" 103141cc406Sopenharmony_ci 104141cc406Sopenharmony_cistatic void buffer_update_read_index(struct Pieusb_Read_Buffer* buffer, int increment); 105141cc406Sopenharmony_ci 106141cc406Sopenharmony_ci/* READER */ 107141cc406Sopenharmony_ci 108141cc406Sopenharmony_ci/** 109141cc406Sopenharmony_ci * Initialize the buffer. 110141cc406Sopenharmony_ci * A scanner has a Pieusb_Read_Buffer struct as one of its members. 111141cc406Sopenharmony_ci * 112141cc406Sopenharmony_ci * @param buffer the buffer to initialize 113141cc406Sopenharmony_ci * @param width number of pixels on a line (row) 114141cc406Sopenharmony_ci * @param height number of lines in the buffer (pixels in a column) 115141cc406Sopenharmony_ci * @param colors bitmap specifying the colors in the scanned data (bitmap: 0000 IBGR) 116141cc406Sopenharmony_ci * @param depth number of bits of a color 117141cc406Sopenharmony_ci * @param bigendian how to store multi-byte values: bigendian if true 118141cc406Sopenharmony_ci * @param maximum_size maximum size of buffer (-1 = size of image) 119141cc406Sopenharmony_ci */ 120141cc406Sopenharmony_ci 121141cc406Sopenharmony_ciSANE_Status 122141cc406Sopenharmony_cisanei_pieusb_buffer_create(struct Pieusb_Read_Buffer* buffer, SANE_Int width, SANE_Int height, SANE_Byte color_spec, SANE_Byte depth) 123141cc406Sopenharmony_ci{ 124141cc406Sopenharmony_ci int k, result; 125141cc406Sopenharmony_ci unsigned int buffer_size_bytes; 126141cc406Sopenharmony_ci unsigned char g; 127141cc406Sopenharmony_ci 128141cc406Sopenharmony_ci /* Base parameters */ 129141cc406Sopenharmony_ci buffer->width = width; 130141cc406Sopenharmony_ci buffer->height = height; 131141cc406Sopenharmony_ci buffer->colors = 0; 132141cc406Sopenharmony_ci if (color_spec & 0x01) { buffer->color_index_red = 0; buffer->colors++; } else { buffer->color_index_red = -1; } 133141cc406Sopenharmony_ci if (color_spec & 0x02) { buffer->color_index_green = 1; buffer->colors++; } else { buffer->color_index_green = -1; } 134141cc406Sopenharmony_ci if (color_spec & 0x04) { buffer->color_index_blue = 2; buffer->colors++; } else { buffer->color_index_blue = -1; } 135141cc406Sopenharmony_ci if (color_spec & 0x08) { buffer->color_index_infrared = 3; buffer->colors++; } else { buffer->color_index_infrared = -1; } 136141cc406Sopenharmony_ci if (buffer->colors == 0) { 137141cc406Sopenharmony_ci DBG(DBG_error, "sanei_pieusb_buffer_create(): no colors specified\n"); 138141cc406Sopenharmony_ci return SANE_STATUS_INVAL; 139141cc406Sopenharmony_ci } 140141cc406Sopenharmony_ci buffer->depth = depth; 141141cc406Sopenharmony_ci if (depth < 1 || depth > 16) { 142141cc406Sopenharmony_ci DBG(DBG_error, "sanei_pieusb_buffer_create(): unsupported depth %d\n", depth); 143141cc406Sopenharmony_ci return SANE_STATUS_INVAL; 144141cc406Sopenharmony_ci } 145141cc406Sopenharmony_ci buffer->packing_density = (depth == 1) ? 8 : 1; /* These are all the situations we have */ 146141cc406Sopenharmony_ci 147141cc406Sopenharmony_ci /* Derived*/ 148141cc406Sopenharmony_ci buffer->packet_size_bytes = (buffer->depth * buffer->packing_density + 7) / 8; 149141cc406Sopenharmony_ci buffer->line_size_packets = (buffer->width + buffer->packing_density -1) / buffer->packing_density; 150141cc406Sopenharmony_ci buffer->line_size_bytes = buffer->line_size_packets * buffer->packet_size_bytes; 151141cc406Sopenharmony_ci buffer->image_size_bytes = buffer->colors * buffer->height * buffer->line_size_bytes; 152141cc406Sopenharmony_ci 153141cc406Sopenharmony_ci /* Create empty file */ 154141cc406Sopenharmony_ci snprintf(buffer->buffer_name, L_tmpnam, "/tmp/sane.XXXXXX"); 155141cc406Sopenharmony_ci if (buffer->data_file != 0) /* might still be open from previous invocation */ 156141cc406Sopenharmony_ci close(buffer->data_file); 157141cc406Sopenharmony_ci buffer->data_file = mkstemp(buffer->buffer_name); 158141cc406Sopenharmony_ci if (buffer->data_file == -1) { 159141cc406Sopenharmony_ci buffer->data_file = 0; 160141cc406Sopenharmony_ci buffer->data = NULL; 161141cc406Sopenharmony_ci perror("sanei_pieusb_buffer_create(): error opening image buffer file"); 162141cc406Sopenharmony_ci return SANE_STATUS_IO_ERROR; 163141cc406Sopenharmony_ci } 164141cc406Sopenharmony_ci /* Stretch the file size */ 165141cc406Sopenharmony_ci buffer_size_bytes = buffer->width * buffer->height * buffer->colors * sizeof(SANE_Uint); 166141cc406Sopenharmony_ci if (buffer_size_bytes == 0) { 167141cc406Sopenharmony_ci close(buffer->data_file); 168141cc406Sopenharmony_ci buffer->data_file = 0; 169141cc406Sopenharmony_ci DBG(DBG_error, "sanei_pieusb_buffer_create(): buffer_size is zero: width %d, height %d, colors %d\n", buffer->width, buffer->height, buffer->colors); 170141cc406Sopenharmony_ci return SANE_STATUS_INVAL; 171141cc406Sopenharmony_ci } 172141cc406Sopenharmony_ci result = lseek(buffer->data_file, buffer_size_bytes-1, SEEK_SET); 173141cc406Sopenharmony_ci if (result == -1) { 174141cc406Sopenharmony_ci close(buffer->data_file); 175141cc406Sopenharmony_ci buffer->data_file = 0; 176141cc406Sopenharmony_ci buffer->data = NULL; 177141cc406Sopenharmony_ci DBG(DBG_error, "sanei_pieusb_buffer_create(): error calling lseek() to 'stretch' the file to %d bytes\n", buffer_size_bytes-1); 178141cc406Sopenharmony_ci perror("sanei_pieusb_buffer_create(): error calling lseek()"); 179141cc406Sopenharmony_ci return SANE_STATUS_INVAL; 180141cc406Sopenharmony_ci } 181141cc406Sopenharmony_ci /* Write one byte at the end */ 182141cc406Sopenharmony_ci g = 0x00; 183141cc406Sopenharmony_ci result = write(buffer->data_file, &g, 1); 184141cc406Sopenharmony_ci if (result < 0) { 185141cc406Sopenharmony_ci close(buffer->data_file); 186141cc406Sopenharmony_ci buffer->data_file = 0; 187141cc406Sopenharmony_ci buffer->data = NULL; 188141cc406Sopenharmony_ci perror("sanei_pieusb_buffer_create(): error writing a byte at the end of the file"); 189141cc406Sopenharmony_ci return SANE_STATUS_IO_ERROR; 190141cc406Sopenharmony_ci } 191141cc406Sopenharmony_ci#ifdef HAVE_MMAP 192141cc406Sopenharmony_ci /* Create memory map */ 193141cc406Sopenharmony_ci buffer->data = mmap(NULL, buffer_size_bytes, PROT_WRITE | PROT_READ, MAP_SHARED, buffer->data_file, 0); 194141cc406Sopenharmony_ci if (buffer->data == MAP_FAILED) { 195141cc406Sopenharmony_ci close(buffer->data_file); 196141cc406Sopenharmony_ci buffer->data = NULL; 197141cc406Sopenharmony_ci perror("sanei_pieusb_buffer_create(): error mapping file"); 198141cc406Sopenharmony_ci return SANE_STATUS_INVAL; 199141cc406Sopenharmony_ci } 200141cc406Sopenharmony_ci#else 201141cc406Sopenharmony_ci#error mmap(2) not available, aborting 202141cc406Sopenharmony_ci#endif 203141cc406Sopenharmony_ci buffer->data_size = buffer_size_bytes; 204141cc406Sopenharmony_ci /* Reading and writing */ 205141cc406Sopenharmony_ci buffer->p_read = calloc(buffer->colors, sizeof(SANE_Uint*)); 206141cc406Sopenharmony_ci if (buffer->p_read == NULL) 207141cc406Sopenharmony_ci return SANE_STATUS_NO_MEM; 208141cc406Sopenharmony_ci buffer->p_write = calloc(buffer->colors, sizeof(SANE_Uint*)); 209141cc406Sopenharmony_ci if (buffer->p_write == NULL) 210141cc406Sopenharmony_ci return SANE_STATUS_NO_MEM; 211141cc406Sopenharmony_ci for (k = 0; k < buffer->colors; k++) { 212141cc406Sopenharmony_ci buffer->p_write[k] = buffer->data + k * buffer->height * buffer->width; 213141cc406Sopenharmony_ci buffer->p_read[k] = buffer->p_write[k]; 214141cc406Sopenharmony_ci } 215141cc406Sopenharmony_ci buffer->read_index[0] = 0; 216141cc406Sopenharmony_ci buffer->read_index[1] = 0; 217141cc406Sopenharmony_ci buffer->read_index[2] = 0; 218141cc406Sopenharmony_ci buffer->read_index[3] = 0; 219141cc406Sopenharmony_ci 220141cc406Sopenharmony_ci /* Statistics */ 221141cc406Sopenharmony_ci buffer->bytes_read = 0; 222141cc406Sopenharmony_ci buffer->bytes_written = 0; 223141cc406Sopenharmony_ci buffer->bytes_unread = 0; 224141cc406Sopenharmony_ci 225141cc406Sopenharmony_ci DBG(DBG_info,"pieusb: Read buffer created: w=%d h=%d ncol=%d depth=%d in file %s\n", 226141cc406Sopenharmony_ci buffer->width, buffer->height, buffer->colors, buffer->depth, buffer->buffer_name); 227141cc406Sopenharmony_ci return SANE_STATUS_GOOD; 228141cc406Sopenharmony_ci} 229141cc406Sopenharmony_ci 230141cc406Sopenharmony_ci/** 231141cc406Sopenharmony_ci * Delete buffer and free its resources 232141cc406Sopenharmony_ci * 233141cc406Sopenharmony_ci * @param buffer 234141cc406Sopenharmony_ci */ 235141cc406Sopenharmony_civoid 236141cc406Sopenharmony_cisanei_pieusb_buffer_delete(struct Pieusb_Read_Buffer* buffer) 237141cc406Sopenharmony_ci{ 238141cc406Sopenharmony_ci#ifdef HAVE_MMAP 239141cc406Sopenharmony_ci munmap(buffer->data, buffer->data_size); 240141cc406Sopenharmony_ci#else 241141cc406Sopenharmony_ci#error mmap(2) not available, aborting 242141cc406Sopenharmony_ci#endif 243141cc406Sopenharmony_ci /* ftruncate(buffer->data_file,0); Can we delete given a file-descriptor? */ 244141cc406Sopenharmony_ci close(buffer->data_file); 245141cc406Sopenharmony_ci /* remove fs entry */ 246141cc406Sopenharmony_ci unlink(buffer->buffer_name); 247141cc406Sopenharmony_ci buffer->data_file = 0; 248141cc406Sopenharmony_ci buffer->data_size = 0; 249141cc406Sopenharmony_ci free(buffer->p_read); 250141cc406Sopenharmony_ci free(buffer->p_write); 251141cc406Sopenharmony_ci buffer->data = 0; 252141cc406Sopenharmony_ci buffer->width = 0; 253141cc406Sopenharmony_ci buffer->height = 0; 254141cc406Sopenharmony_ci buffer->depth = 0; 255141cc406Sopenharmony_ci buffer->colors = 0; 256141cc406Sopenharmony_ci buffer->packing_density = 0; 257141cc406Sopenharmony_ci 258141cc406Sopenharmony_ci DBG(DBG_info,"pieusb: Read buffer deleted\n"); 259141cc406Sopenharmony_ci} 260141cc406Sopenharmony_ci 261141cc406Sopenharmony_ci/** 262141cc406Sopenharmony_ci * Add a line to the reader buffer, for the given color. 263141cc406Sopenharmony_ci * The buffer checks and decides how to interpret the data. 264141cc406Sopenharmony_ci * 265141cc406Sopenharmony_ci * @param buffer 266141cc406Sopenharmony_ci * @param color Color code for line 267141cc406Sopenharmony_ci * @param line 268141cc406Sopenharmony_ci * @param size Number of bytes in line 269141cc406Sopenharmony_ci * @return 1 if successful, 0 if not 270141cc406Sopenharmony_ci */ 271141cc406Sopenharmony_ciSANE_Int 272141cc406Sopenharmony_cisanei_pieusb_buffer_put_single_color_line(struct Pieusb_Read_Buffer* buffer, SANE_Byte color, void* line, SANE_Int size) 273141cc406Sopenharmony_ci{ 274141cc406Sopenharmony_ci 275141cc406Sopenharmony_ci SANE_Int c, k, m, n; 276141cc406Sopenharmony_ci 277141cc406Sopenharmony_ci /* Check index code */ 278141cc406Sopenharmony_ci c = -1; 279141cc406Sopenharmony_ci switch (color) { 280141cc406Sopenharmony_ci case 'R': 281141cc406Sopenharmony_ci c = buffer->color_index_red; 282141cc406Sopenharmony_ci break; 283141cc406Sopenharmony_ci case 'G': 284141cc406Sopenharmony_ci c = buffer->color_index_green; 285141cc406Sopenharmony_ci break; 286141cc406Sopenharmony_ci case 'B': 287141cc406Sopenharmony_ci c = buffer->color_index_blue; 288141cc406Sopenharmony_ci break; 289141cc406Sopenharmony_ci case 'I': 290141cc406Sopenharmony_ci c = buffer->color_index_infrared; 291141cc406Sopenharmony_ci break; 292141cc406Sopenharmony_ci } 293141cc406Sopenharmony_ci if (c == -1) { 294141cc406Sopenharmony_ci DBG(DBG_error, "sanei_pieusb_buffer_put_single_color_line(): color '%c' not specified when buffer was created\n", color); 295141cc406Sopenharmony_ci return 0; 296141cc406Sopenharmony_ci } 297141cc406Sopenharmony_ci DBG(DBG_info_buffer, "sanei_pieusb_buffer_put_single_color_line() line color = %d (0=R, 1=G, 2=B, 3=I)\n",c); 298141cc406Sopenharmony_ci 299141cc406Sopenharmony_ci /* Check line size (for a line with a single color) */ 300141cc406Sopenharmony_ci if (buffer->line_size_bytes != size) { 301141cc406Sopenharmony_ci DBG(DBG_error, "sanei_pieusb_buffer_put_single_color_line(): incorrect line size, expecting %d, got %d\n", buffer->line_size_bytes, size); 302141cc406Sopenharmony_ci return 0; 303141cc406Sopenharmony_ci } 304141cc406Sopenharmony_ci 305141cc406Sopenharmony_ci /* The general approach for all densities and packet sizes 306141cc406Sopenharmony_ci * - process packet_size_bytes at a time 307141cc406Sopenharmony_ci * - use packing_density to decode the full packet into separate values 308141cc406Sopenharmony_ci * - now save these values as neighbouring pixels on the current line 309141cc406Sopenharmony_ci * Use custom code for the 1-byte and 2-byte single sample cases, 310141cc406Sopenharmony_ci * because the general approach is a bit overkill for them. 311141cc406Sopenharmony_ci */ 312141cc406Sopenharmony_ci 313141cc406Sopenharmony_ci if (buffer->packet_size_bytes == 1 && buffer->packing_density == 1) { 314141cc406Sopenharmony_ci uint8_t* p_packet = (uint8_t*)line; 315141cc406Sopenharmony_ci n = 0; 316141cc406Sopenharmony_ci while (n < size) { 317141cc406Sopenharmony_ci /* Get next packet data & store in buffer */ 318141cc406Sopenharmony_ci *buffer->p_write[c]++ = *p_packet++; 319141cc406Sopenharmony_ci n++; 320141cc406Sopenharmony_ci } 321141cc406Sopenharmony_ci } else if (buffer->packet_size_bytes == 2 && buffer->packing_density == 1) { 322141cc406Sopenharmony_ci uint16_t* p_packet = (uint16_t*)line; 323141cc406Sopenharmony_ci n = 0; 324141cc406Sopenharmony_ci while (n < size) { 325141cc406Sopenharmony_ci /* Get next packet data & store in buffer */ 326141cc406Sopenharmony_ci *buffer->p_write[c]++ = le16toh (*p_packet++); 327141cc406Sopenharmony_ci n += 2; 328141cc406Sopenharmony_ci } 329141cc406Sopenharmony_ci } else { 330141cc406Sopenharmony_ci uint8_t* p_packet = (uint8_t*)line; 331141cc406Sopenharmony_ci uint8_t *packet = (uint8_t *)alloca(buffer->packet_size_bytes * sizeof(uint8_t)); 332141cc406Sopenharmony_ci SANE_Uint val; 333141cc406Sopenharmony_ci uint8_t mask = ~(0xFF >> buffer->depth); /* byte with depth most significant bits set */ 334141cc406Sopenharmony_ci n = 0; 335141cc406Sopenharmony_ci while (n < size) { 336141cc406Sopenharmony_ci /* Get next packet data */ 337141cc406Sopenharmony_ci for (k = 0; k < buffer->packet_size_bytes; k++) packet[k] = *p_packet++; 338141cc406Sopenharmony_ci /* Unpack packing_density samples from packet. Of course, 339141cc406Sopenharmony_ci * buffer->depth * packing_density <= # bits in packet. 340141cc406Sopenharmony_ci * That is checked at buffer creation. */ 341141cc406Sopenharmony_ci for (k = 0; k < buffer->packing_density; k++) { 342141cc406Sopenharmony_ci /* Take 1st depth bits and store in val */ 343141cc406Sopenharmony_ci val = (packet[0] & mask) >> (8-buffer->depth); 344141cc406Sopenharmony_ci /* Now shift packet bytes depth bits left */ 345141cc406Sopenharmony_ci for (m = 0; m < buffer->packet_size_bytes; m++) { 346141cc406Sopenharmony_ci /* Shift left one sample */ 347141cc406Sopenharmony_ci packet[m] <<= buffer->depth; 348141cc406Sopenharmony_ci if (m < buffer->packet_size_bytes-1) { 349141cc406Sopenharmony_ci /* If there are more bytes, insert 1st depth bits of next byte */ 350141cc406Sopenharmony_ci packet[m] |= (packet[m+1] >> (8-buffer->depth)); 351141cc406Sopenharmony_ci } 352141cc406Sopenharmony_ci } 353141cc406Sopenharmony_ci /* Store in buffer */ 354141cc406Sopenharmony_ci *buffer->p_write[c]++ = val; 355141cc406Sopenharmony_ci } 356141cc406Sopenharmony_ci n += buffer->packet_size_bytes; 357141cc406Sopenharmony_ci } 358141cc406Sopenharmony_ci } 359141cc406Sopenharmony_ci 360141cc406Sopenharmony_ci /* Update state & statistics */ 361141cc406Sopenharmony_ci buffer->bytes_written += size; 362141cc406Sopenharmony_ci buffer->bytes_unread += size; 363141cc406Sopenharmony_ci 364141cc406Sopenharmony_ci /* Output current buffer state */ 365141cc406Sopenharmony_ci /* buffer_output_state(buffer); */ 366141cc406Sopenharmony_ci 367141cc406Sopenharmony_ci return 1; 368141cc406Sopenharmony_ci} 369141cc406Sopenharmony_ci 370141cc406Sopenharmony_ci/** 371141cc406Sopenharmony_ci * Write line of full color pixels to the buffer. 372141cc406Sopenharmony_ci * 373141cc406Sopenharmony_ci * @param buffer Read buffer 374141cc406Sopenharmony_ci * @param pixel array of full color pixel data 375141cc406Sopenharmony_ci * @param size Number of bytes in the line 376141cc406Sopenharmony_ci * @return 1 if successful, 0 if not 377141cc406Sopenharmony_ci */ 378141cc406Sopenharmony_ci/** 379141cc406Sopenharmony_ci * 380141cc406Sopenharmony_ci */ 381141cc406Sopenharmony_ciSANE_Int 382141cc406Sopenharmony_cisanei_pieusb_buffer_put_full_color_line(struct Pieusb_Read_Buffer* buffer, void* line, int size) 383141cc406Sopenharmony_ci{ 384141cc406Sopenharmony_ci int k, c, m, n; 385141cc406Sopenharmony_ci 386141cc406Sopenharmony_ci DBG(DBG_info_buffer, "sanei_pieusb_buffer_put_full_color_line() entered\n"); 387141cc406Sopenharmony_ci 388141cc406Sopenharmony_ci /* Check line size */ 389141cc406Sopenharmony_ci if (buffer->line_size_bytes * buffer->colors != size) { 390141cc406Sopenharmony_ci DBG(DBG_error, "sanei_pieusb_buffer_put_full_color_line(): incorrect line size, expecting %d, got %d\n", buffer->line_size_bytes * buffer->colors, size); 391141cc406Sopenharmony_ci return 0; 392141cc406Sopenharmony_ci } 393141cc406Sopenharmony_ci 394141cc406Sopenharmony_ci /* The general approach for all densities and packet sizes 395141cc406Sopenharmony_ci * - process packet_size_bytes at a time 396141cc406Sopenharmony_ci * - use packing_density to decode the full packet into separate values 397141cc406Sopenharmony_ci * - now save these values as neighbouring pixels on the current line 398141cc406Sopenharmony_ci * Use custom code for the 1-byte and 2-byte single sample cases, 399141cc406Sopenharmony_ci * because the general approach is a bit overkill for them. 400141cc406Sopenharmony_ci */ 401141cc406Sopenharmony_ci 402141cc406Sopenharmony_ci if (buffer->packet_size_bytes == 1 && buffer->packing_density == 1) { 403141cc406Sopenharmony_ci uint8_t* p_packet = (uint8_t*)line; 404141cc406Sopenharmony_ci n = 0; 405141cc406Sopenharmony_ci while (n < size) { 406141cc406Sopenharmony_ci /* Get next packet data & store in buffer */ 407141cc406Sopenharmony_ci for (c = 0; c < buffer->colors; c++) { 408141cc406Sopenharmony_ci *buffer->p_write[c]++ = *p_packet++; 409141cc406Sopenharmony_ci n++; 410141cc406Sopenharmony_ci } 411141cc406Sopenharmony_ci } 412141cc406Sopenharmony_ci } else if (buffer->packet_size_bytes == 2 && buffer->packing_density == 1) { 413141cc406Sopenharmony_ci uint16_t* p_packet = (uint16_t*)line; 414141cc406Sopenharmony_ci n = 0; 415141cc406Sopenharmony_ci while (n < size) { 416141cc406Sopenharmony_ci /* Get next packet data & store in buffer */ 417141cc406Sopenharmony_ci for (c = 0; c < buffer->colors; c++) { 418141cc406Sopenharmony_ci *buffer->p_write[c]++ = le16toh (*p_packet++); 419141cc406Sopenharmony_ci n += 2; 420141cc406Sopenharmony_ci } 421141cc406Sopenharmony_ci } 422141cc406Sopenharmony_ci } else { 423141cc406Sopenharmony_ci uint8_t* p_packet = (uint8_t*)line; 424141cc406Sopenharmony_ci uint8_t *packet = (uint8_t *)alloca(buffer->packet_size_bytes * sizeof(uint8_t)); 425141cc406Sopenharmony_ci SANE_Uint val; 426141cc406Sopenharmony_ci uint8_t mask = ~(0xFF >> buffer->depth); /* byte with depth most significant bits set */ 427141cc406Sopenharmony_ci /* DBG(DBG_info,"buffer_put_full_color_line(): mask %02x\n",mask); */ 428141cc406Sopenharmony_ci n = 0; 429141cc406Sopenharmony_ci while (n < size) { 430141cc406Sopenharmony_ci /* Get next packet data */ 431141cc406Sopenharmony_ci for (c = 0; c < buffer->colors; c++) { 432141cc406Sopenharmony_ci for (k = 0; k < buffer->packet_size_bytes; k++) { 433141cc406Sopenharmony_ci packet[k] = *p_packet++; 434141cc406Sopenharmony_ci /* DBG(DBG_info,"buffer_put_full_color_line(): packet[%d] = %02x\n",k,packet[k]); */ 435141cc406Sopenharmony_ci } 436141cc406Sopenharmony_ci /* Unpack packing_density samples from packet. Of course, 437141cc406Sopenharmony_ci * buffer->depth * packing_density <= # bits in packet. 438141cc406Sopenharmony_ci * That is checked at buffer creation. */ 439141cc406Sopenharmony_ci for (k = 0; k < buffer->packing_density; k++) { 440141cc406Sopenharmony_ci /* Take 1st depth bits and store in val */ 441141cc406Sopenharmony_ci val = (packet[0] & mask) >> (8-buffer->depth); 442141cc406Sopenharmony_ci /* DBG(DBG_info,"buffer_put_full_color_line(): val[%d] = %02x\n",k,val); */ 443141cc406Sopenharmony_ci /* Now shift packet bytes depth bits left */ 444141cc406Sopenharmony_ci for (m = 0; m < buffer->packet_size_bytes; m++) { 445141cc406Sopenharmony_ci /* Shift left one sample */ 446141cc406Sopenharmony_ci packet[m] <<= buffer->depth; 447141cc406Sopenharmony_ci /* DBG(DBG_info,"buffer_put_full_color_line(): shift packet[%d] = %02x\n",m,packet[m]); */ 448141cc406Sopenharmony_ci if (m < buffer->packet_size_bytes-1) { 449141cc406Sopenharmony_ci /* If there are more bytes, insert 1st depth bits of next byte */ 450141cc406Sopenharmony_ci packet[m] |= (packet[m+1] >> (8-buffer->depth)); 451141cc406Sopenharmony_ci /* DBG(DBG_info,"buffer_put_full_color_line(): shift packet[%d] = %02x\n",m,packet[m]); */ 452141cc406Sopenharmony_ci } 453141cc406Sopenharmony_ci } 454141cc406Sopenharmony_ci /* Store in buffer */ 455141cc406Sopenharmony_ci *buffer->p_write[c]++ = val; 456141cc406Sopenharmony_ci } 457141cc406Sopenharmony_ci n += buffer->packet_size_bytes; 458141cc406Sopenharmony_ci } 459141cc406Sopenharmony_ci } 460141cc406Sopenharmony_ci } 461141cc406Sopenharmony_ci 462141cc406Sopenharmony_ci /* Update state & statistics */ 463141cc406Sopenharmony_ci buffer->bytes_written += size; 464141cc406Sopenharmony_ci buffer->bytes_unread += size; 465141cc406Sopenharmony_ci 466141cc406Sopenharmony_ci /* Output current buffer state */ 467141cc406Sopenharmony_ci /* buffer_output_state(buffer); */ 468141cc406Sopenharmony_ci 469141cc406Sopenharmony_ci return 1; 470141cc406Sopenharmony_ci} 471141cc406Sopenharmony_ci 472141cc406Sopenharmony_ci/** 473141cc406Sopenharmony_ci * Return bytes from the buffer. Do not mind pixel boundaries. 474141cc406Sopenharmony_ci * Since the image data is organized in color planes, return bytes from the 475141cc406Sopenharmony_ci * planes in the defined order. Take care to return multi-byte values after 476141cc406Sopenharmony_ci * each other. Pack unpacked values. 477141cc406Sopenharmony_ci * 478141cc406Sopenharmony_ci * @param buffer Buffer to return bytes from. 479141cc406Sopenharmony_ci * @param data Byte array to return bytes in 480141cc406Sopenharmony_ci * @param max_len Maximum number of bytes returned 481141cc406Sopenharmony_ci * @param len Actual number of bytes returned 482141cc406Sopenharmony_ci */ 483141cc406Sopenharmony_civoid 484141cc406Sopenharmony_cisanei_pieusb_buffer_get(struct Pieusb_Read_Buffer* buffer, SANE_Byte* data, SANE_Int max_len, SANE_Int* len) 485141cc406Sopenharmony_ci{ 486141cc406Sopenharmony_ci SANE_Byte *pdata; 487141cc406Sopenharmony_ci SANE_Int n, i, n_bits, N; 488141cc406Sopenharmony_ci 489141cc406Sopenharmony_ci DBG(DBG_info_buffer, "sanei_pieusb_buffer_get() entered\n"); 490141cc406Sopenharmony_ci 491141cc406Sopenharmony_ci /* Read from the p_read locations */ 492141cc406Sopenharmony_ci pdata = data; 493141cc406Sopenharmony_ci n = 0; 494141cc406Sopenharmony_ci N = buffer->width * buffer->height; 495141cc406Sopenharmony_ci /* Determine bytes to return */ 496141cc406Sopenharmony_ci if (buffer->packet_size_bytes == 1 && buffer->packing_density == 1) { 497141cc406Sopenharmony_ci /* Single byte values in buffer */ 498141cc406Sopenharmony_ci while (n < max_len && buffer->bytes_read < buffer->image_size_bytes) { 499141cc406Sopenharmony_ci /* Return byte*/ 500141cc406Sopenharmony_ci *pdata++ = *(buffer->data + N*buffer->read_index[0] + buffer->width*buffer->read_index[1] + buffer->read_index[2]) & 0xFF; 501141cc406Sopenharmony_ci /* Update read indices */ 502141cc406Sopenharmony_ci buffer_update_read_index(buffer,1); 503141cc406Sopenharmony_ci /* Update number of bytes read */ 504141cc406Sopenharmony_ci buffer->bytes_read++; 505141cc406Sopenharmony_ci n++; 506141cc406Sopenharmony_ci } 507141cc406Sopenharmony_ci } else if (buffer->packet_size_bytes == 1 && buffer->packing_density == 8) { 508141cc406Sopenharmony_ci /* Unpacked bits in buffer: repack */ 509141cc406Sopenharmony_ci while (n < max_len && buffer->bytes_read < buffer->image_size_bytes) { 510141cc406Sopenharmony_ci uint8_t val = 0; 511141cc406Sopenharmony_ci /* How many bits to pack? At the end of a line it may be less than 8 */ 512141cc406Sopenharmony_ci n_bits = 8; 513141cc406Sopenharmony_ci if (buffer->width - buffer->read_index[2] < 8) { 514141cc406Sopenharmony_ci n_bits = buffer->width - buffer->read_index[2]; 515141cc406Sopenharmony_ci } 516141cc406Sopenharmony_ci /* Pack n_bits samples from same color plane */ 517141cc406Sopenharmony_ci for (i = 0; i < n_bits; i++) { 518141cc406Sopenharmony_ci if (*(buffer->data + N*buffer->read_index[0] + buffer->width*buffer->read_index[1] + buffer->read_index[2] + i) > 0) { 519141cc406Sopenharmony_ci val |= (0x80 >> i); 520141cc406Sopenharmony_ci } 521141cc406Sopenharmony_ci } 522141cc406Sopenharmony_ci /* Return byte */ 523141cc406Sopenharmony_ci *pdata++ = val; 524141cc406Sopenharmony_ci /* Update read indices */ 525141cc406Sopenharmony_ci buffer_update_read_index(buffer,n_bits); 526141cc406Sopenharmony_ci /* Update number of bytes read */ 527141cc406Sopenharmony_ci buffer->bytes_read++; 528141cc406Sopenharmony_ci n++; 529141cc406Sopenharmony_ci } 530141cc406Sopenharmony_ci } else if (buffer->packet_size_bytes == 2) { 531141cc406Sopenharmony_ci /* Two-byte values in buffer */ 532141cc406Sopenharmony_ci while (n < max_len && buffer->bytes_read < buffer->image_size_bytes) { 533141cc406Sopenharmony_ci /* Pointer to byte to return */ 534141cc406Sopenharmony_ci SANE_Uint val = *(buffer->data + N*buffer->read_index[0] + buffer->width*buffer->read_index[1] + buffer->read_index[2]); 535141cc406Sopenharmony_ci /* Return byte */ 536141cc406Sopenharmony_ci if (buffer->read_index[3] == 0) { 537141cc406Sopenharmony_ci *pdata++ = *((SANE_Byte*)(&val)); 538141cc406Sopenharmony_ci } else { 539141cc406Sopenharmony_ci *pdata++ = *((SANE_Byte*)(&val)+1); 540141cc406Sopenharmony_ci } 541141cc406Sopenharmony_ci /* Update read indices */ 542141cc406Sopenharmony_ci buffer_update_read_index(buffer,1); 543141cc406Sopenharmony_ci /* Update number of bytes read */ 544141cc406Sopenharmony_ci buffer->bytes_read++; 545141cc406Sopenharmony_ci n++; 546141cc406Sopenharmony_ci } 547141cc406Sopenharmony_ci } else { 548141cc406Sopenharmony_ci /* not implemented */ 549141cc406Sopenharmony_ci DBG(DBG_error, "buffer_put(): paccket size & density of %d/%d not implemented\n", buffer->packet_size_bytes, buffer->packing_density); 550141cc406Sopenharmony_ci return; 551141cc406Sopenharmony_ci } 552141cc406Sopenharmony_ci *len = n; 553141cc406Sopenharmony_ci 554141cc406Sopenharmony_ci /* Update statistics */ 555141cc406Sopenharmony_ci buffer->bytes_unread -= n; 556141cc406Sopenharmony_ci 557141cc406Sopenharmony_ci /* Output current buffer state */ 558141cc406Sopenharmony_ci /* buffer_output_state(buffer); */ 559141cc406Sopenharmony_ci} 560141cc406Sopenharmony_ci 561141cc406Sopenharmony_ci/** 562141cc406Sopenharmony_ci * Update read index to point a given number of bytes past the current position. 563141cc406Sopenharmony_ci * 564141cc406Sopenharmony_ci * @param buffer the buffer to initialize 565141cc406Sopenharmony_ci * @param increment the amount of bytes to move the index 566141cc406Sopenharmony_ci */ 567141cc406Sopenharmony_cistatic void buffer_update_read_index(struct Pieusb_Read_Buffer* buffer, int increment) 568141cc406Sopenharmony_ci{ 569141cc406Sopenharmony_ci /* Update read indices 570141cc406Sopenharmony_ci * [3] = byte-index in 2-byte value: increased first, if we have 2-byte data 571141cc406Sopenharmony_ci * [2] = index of pixel on line: increased after color plane 572141cc406Sopenharmony_ci * [1] = index of line: increased after line is complete 573141cc406Sopenharmony_ci * [0] = color index: increased first since SANE requires full color pixels */ 574141cc406Sopenharmony_ci if (buffer->read_index[3] == 0 && buffer->packet_size_bytes == 2) { 575141cc406Sopenharmony_ci buffer->read_index[3] = 1; 576141cc406Sopenharmony_ci } else { 577141cc406Sopenharmony_ci buffer->read_index[3] = 0; 578141cc406Sopenharmony_ci buffer->read_index[0]++; 579141cc406Sopenharmony_ci if (buffer->read_index[0] == buffer->colors) { 580141cc406Sopenharmony_ci buffer->read_index[0] = 0; 581141cc406Sopenharmony_ci buffer->read_index[2] += increment; 582141cc406Sopenharmony_ci if (buffer->read_index[2] >= buffer->width) { 583141cc406Sopenharmony_ci buffer->read_index[2] = 0; 584141cc406Sopenharmony_ci buffer->read_index[1]++; 585141cc406Sopenharmony_ci } 586141cc406Sopenharmony_ci } 587141cc406Sopenharmony_ci } 588141cc406Sopenharmony_ci} 589141cc406Sopenharmony_ci 590141cc406Sopenharmony_ci#if 0 591141cc406Sopenharmony_ci/** 592141cc406Sopenharmony_ci * Display the buffer state. 593141cc406Sopenharmony_ci * 594141cc406Sopenharmony_ci * @param buffer the buffer to initialize 595141cc406Sopenharmony_ci */ 596141cc406Sopenharmony_ci 597141cc406Sopenharmony_cistatic void buffer_output_state(struct Pieusb_Read_Buffer* buffer) 598141cc406Sopenharmony_ci{ 599141cc406Sopenharmony_ci SANE_Int line_size; 600141cc406Sopenharmony_ci SANE_Int N, k, loc[4]; 601141cc406Sopenharmony_ci 602141cc406Sopenharmony_ci line_size = buffer->line_size_bytes * buffer->colors; /* Full line size in bytes */ 603141cc406Sopenharmony_ci 604141cc406Sopenharmony_ci DBG(DBG_info_buffer, "Buffer data\n"); 605141cc406Sopenharmony_ci DBG(DBG_info_buffer," width/height/colors/depth = %d %d %d %d (buffer size %d)\n", 606141cc406Sopenharmony_ci buffer->width, buffer->height, buffer->colors, buffer->depth, buffer->image_size_bytes); 607141cc406Sopenharmony_ci 608141cc406Sopenharmony_ci /* Summary */ 609141cc406Sopenharmony_ci N = buffer->width * buffer->height; 610141cc406Sopenharmony_ci for (k = 0; k < buffer->colors; k++) { 611141cc406Sopenharmony_ci loc[k] = buffer->p_read[k] - buffer->data - k*N; 612141cc406Sopenharmony_ci } 613141cc406Sopenharmony_ci for (k = buffer->colors; k < 4; k++) { 614141cc406Sopenharmony_ci loc[k] = 0; 615141cc406Sopenharmony_ci } 616141cc406Sopenharmony_ci DBG(DBG_info_buffer, " reading at: lines = %d:%d:%d:%d\n", loc[0], loc[1], loc[2], loc[3]); 617141cc406Sopenharmony_ci for (k = 0; k < buffer->colors; k++) { 618141cc406Sopenharmony_ci loc[k] = buffer->p_write[k] - buffer->data - k*N; 619141cc406Sopenharmony_ci } 620141cc406Sopenharmony_ci for (k = buffer->colors; k < 4; k++) { 621141cc406Sopenharmony_ci loc[k] = 0; 622141cc406Sopenharmony_ci } 623141cc406Sopenharmony_ci DBG(DBG_info_buffer, " writing at: lines = %d:%d:%d:%d\n", loc[0], loc[1], loc[2], loc[3]); 624141cc406Sopenharmony_ci 625141cc406Sopenharmony_ci /* Progress */ 626141cc406Sopenharmony_ci double fdata = (double)buffer->bytes_unread/buffer->image_size_bytes*100; 627141cc406Sopenharmony_ci double fread = (double)buffer->bytes_read/buffer->image_size_bytes*100; 628141cc406Sopenharmony_ci double fwritten = (double)buffer->bytes_written/buffer->image_size_bytes*100; 629141cc406Sopenharmony_ci DBG(DBG_info_buffer, " byte counts: image = %d, data = %d (%.0f%%), read = %d (%.0f%%), written = %d (%.0f%%)\n", 630141cc406Sopenharmony_ci buffer->image_size_bytes, buffer->bytes_unread, fdata, buffer->bytes_read, fread, buffer->bytes_written, fwritten); 631141cc406Sopenharmony_ci DBG(DBG_info_buffer, " line counts: image = %.1f, data = %.1f, read = %.1f, written = %.1f\n", 632141cc406Sopenharmony_ci (double)buffer->image_size_bytes/line_size, (double)buffer->bytes_unread/line_size, (double)buffer->bytes_read/line_size, (double)buffer->bytes_written/line_size); 633141cc406Sopenharmony_ci 634141cc406Sopenharmony_ci} 635141cc406Sopenharmony_ci#endif 636