1141cc406Sopenharmony_ci/* 2141cc406Sopenharmony_ci * epson2_net.c - SANE library for Epson scanners. 3141cc406Sopenharmony_ci * 4141cc406Sopenharmony_ci * Copyright (C) 2006 Tower Technologies 5141cc406Sopenharmony_ci * Author: Alessandro Zummo <a.zummo@towertech.it> 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, version 2. 12141cc406Sopenharmony_ci */ 13141cc406Sopenharmony_ci 14141cc406Sopenharmony_ci#define DEBUG_DECLARE_ONLY 15141cc406Sopenharmony_ci 16141cc406Sopenharmony_ci#include "sane/config.h" 17141cc406Sopenharmony_ci 18141cc406Sopenharmony_ci#ifdef HAVE_SYS_SELECT_H 19141cc406Sopenharmony_ci#include <sys/select.h> 20141cc406Sopenharmony_ci#endif 21141cc406Sopenharmony_ci 22141cc406Sopenharmony_ci#include "sane/sane.h" 23141cc406Sopenharmony_ci#include "sane/saneopts.h" 24141cc406Sopenharmony_ci#include "sane/sanei_tcp.h" 25141cc406Sopenharmony_ci#include "sane/sanei_config.h" 26141cc406Sopenharmony_ci#include "sane/sanei_backend.h" 27141cc406Sopenharmony_ci 28141cc406Sopenharmony_ci#include "epson2.h" 29141cc406Sopenharmony_ci#include "epson2_net.h" 30141cc406Sopenharmony_ci 31141cc406Sopenharmony_ci#include "byteorder.h" 32141cc406Sopenharmony_ci 33141cc406Sopenharmony_ci#include "sane/sanei_debug.h" 34141cc406Sopenharmony_ci 35141cc406Sopenharmony_cistatic ssize_t 36141cc406Sopenharmony_cisanei_epson_net_read_raw(Epson_Scanner *s, unsigned char *buf, ssize_t wanted, 37141cc406Sopenharmony_ci SANE_Status *status) 38141cc406Sopenharmony_ci{ 39141cc406Sopenharmony_ci int ready; 40141cc406Sopenharmony_ci ssize_t read = -1; 41141cc406Sopenharmony_ci fd_set readable; 42141cc406Sopenharmony_ci struct timeval tv; 43141cc406Sopenharmony_ci 44141cc406Sopenharmony_ci tv.tv_sec = 10; 45141cc406Sopenharmony_ci tv.tv_usec = 0; 46141cc406Sopenharmony_ci 47141cc406Sopenharmony_ci FD_ZERO(&readable); 48141cc406Sopenharmony_ci FD_SET(s->fd, &readable); 49141cc406Sopenharmony_ci 50141cc406Sopenharmony_ci ready = select(s->fd + 1, &readable, NULL, NULL, &tv); 51141cc406Sopenharmony_ci if (ready > 0) { 52141cc406Sopenharmony_ci read = sanei_tcp_read(s->fd, buf, wanted); 53141cc406Sopenharmony_ci } else { 54141cc406Sopenharmony_ci DBG(15, "%s: select failed: %d\n", __func__, ready); 55141cc406Sopenharmony_ci } 56141cc406Sopenharmony_ci 57141cc406Sopenharmony_ci *status = SANE_STATUS_GOOD; 58141cc406Sopenharmony_ci 59141cc406Sopenharmony_ci if (read < wanted) { 60141cc406Sopenharmony_ci *status = SANE_STATUS_IO_ERROR; 61141cc406Sopenharmony_ci } 62141cc406Sopenharmony_ci 63141cc406Sopenharmony_ci return read; 64141cc406Sopenharmony_ci} 65141cc406Sopenharmony_ci 66141cc406Sopenharmony_cistatic ssize_t 67141cc406Sopenharmony_cisanei_epson_net_read_buf(Epson_Scanner *s, unsigned char *buf, ssize_t wanted, 68141cc406Sopenharmony_ci SANE_Status * status) 69141cc406Sopenharmony_ci{ 70141cc406Sopenharmony_ci ssize_t read = 0; 71141cc406Sopenharmony_ci 72141cc406Sopenharmony_ci DBG(23, "%s: reading up to %lu from buffer at %p, %lu available\n", 73141cc406Sopenharmony_ci __func__, (u_long) wanted, (void *) s->netptr, (u_long) s->netlen); 74141cc406Sopenharmony_ci 75141cc406Sopenharmony_ci if ((size_t) wanted > s->netlen) { 76141cc406Sopenharmony_ci *status = SANE_STATUS_IO_ERROR; 77141cc406Sopenharmony_ci wanted = s->netlen; 78141cc406Sopenharmony_ci } 79141cc406Sopenharmony_ci 80141cc406Sopenharmony_ci memcpy(buf, s->netptr, wanted); 81141cc406Sopenharmony_ci read = wanted; 82141cc406Sopenharmony_ci 83141cc406Sopenharmony_ci s->netptr += read; 84141cc406Sopenharmony_ci s->netlen -= read; 85141cc406Sopenharmony_ci 86141cc406Sopenharmony_ci if (s->netlen == 0) { 87141cc406Sopenharmony_ci DBG(23, "%s: freeing %p\n", __func__, (void *) s->netbuf); 88141cc406Sopenharmony_ci free(s->netbuf); 89141cc406Sopenharmony_ci s->netbuf = s->netptr = NULL; 90141cc406Sopenharmony_ci s->netlen = 0; 91141cc406Sopenharmony_ci } 92141cc406Sopenharmony_ci 93141cc406Sopenharmony_ci return read; 94141cc406Sopenharmony_ci} 95141cc406Sopenharmony_ci 96141cc406Sopenharmony_cissize_t 97141cc406Sopenharmony_cisanei_epson_net_read(Epson_Scanner *s, unsigned char *buf, ssize_t wanted, 98141cc406Sopenharmony_ci SANE_Status * status) 99141cc406Sopenharmony_ci{ 100141cc406Sopenharmony_ci if (wanted < 0) { 101141cc406Sopenharmony_ci *status = SANE_STATUS_INVAL; 102141cc406Sopenharmony_ci return 0; 103141cc406Sopenharmony_ci } 104141cc406Sopenharmony_ci 105141cc406Sopenharmony_ci size_t size; 106141cc406Sopenharmony_ci ssize_t read = 0; 107141cc406Sopenharmony_ci unsigned char header[12]; 108141cc406Sopenharmony_ci 109141cc406Sopenharmony_ci /* read from remainder of buffer */ 110141cc406Sopenharmony_ci if (s->netptr) { 111141cc406Sopenharmony_ci return sanei_epson_net_read_buf(s, buf, wanted, status); 112141cc406Sopenharmony_ci } 113141cc406Sopenharmony_ci 114141cc406Sopenharmony_ci /* receive net header */ 115141cc406Sopenharmony_ci read = sanei_epson_net_read_raw(s, header, 12, status); 116141cc406Sopenharmony_ci if (read != 12) { 117141cc406Sopenharmony_ci return 0; 118141cc406Sopenharmony_ci } 119141cc406Sopenharmony_ci 120141cc406Sopenharmony_ci /* validate header */ 121141cc406Sopenharmony_ci if (header[0] != 'I' || header[1] != 'S') { 122141cc406Sopenharmony_ci DBG(1, "header mismatch: %02X %02x\n", header[0], header[1]); 123141cc406Sopenharmony_ci *status = SANE_STATUS_IO_ERROR; 124141cc406Sopenharmony_ci return 0; 125141cc406Sopenharmony_ci } 126141cc406Sopenharmony_ci 127141cc406Sopenharmony_ci /* parse payload size */ 128141cc406Sopenharmony_ci size = be32atoh(&header[6]); 129141cc406Sopenharmony_ci 130141cc406Sopenharmony_ci *status = SANE_STATUS_GOOD; 131141cc406Sopenharmony_ci 132141cc406Sopenharmony_ci if (!s->netbuf) { 133141cc406Sopenharmony_ci DBG(15, "%s: direct read\n", __func__); 134141cc406Sopenharmony_ci DBG(23, "%s: wanted = %lu, available = %lu\n", __func__, 135141cc406Sopenharmony_ci (u_long) wanted, (u_long) size); 136141cc406Sopenharmony_ci 137141cc406Sopenharmony_ci if ((size_t) wanted > size) { 138141cc406Sopenharmony_ci wanted = size; 139141cc406Sopenharmony_ci } 140141cc406Sopenharmony_ci 141141cc406Sopenharmony_ci read = sanei_epson_net_read_raw(s, buf, wanted, status); 142141cc406Sopenharmony_ci } else { 143141cc406Sopenharmony_ci DBG(15, "%s: buffered read\n", __func__); 144141cc406Sopenharmony_ci DBG(23, "%s: bufferable = %lu, available = %lu\n", __func__, 145141cc406Sopenharmony_ci (u_long) s->netlen, (u_long) size); 146141cc406Sopenharmony_ci 147141cc406Sopenharmony_ci if (s->netlen > size) { 148141cc406Sopenharmony_ci s->netlen = size; 149141cc406Sopenharmony_ci } 150141cc406Sopenharmony_ci 151141cc406Sopenharmony_ci /* fill buffer */ 152141cc406Sopenharmony_ci read = sanei_epson_net_read_raw(s, s->netbuf, s->netlen, status); 153141cc406Sopenharmony_ci s->netptr = s->netbuf; 154141cc406Sopenharmony_ci s->netlen = (read > 0 ? read : 0); 155141cc406Sopenharmony_ci 156141cc406Sopenharmony_ci /* copy wanted part */ 157141cc406Sopenharmony_ci read = sanei_epson_net_read_buf(s, buf, wanted, status); 158141cc406Sopenharmony_ci } 159141cc406Sopenharmony_ci 160141cc406Sopenharmony_ci return read; 161141cc406Sopenharmony_ci} 162141cc406Sopenharmony_ci 163141cc406Sopenharmony_cisize_t 164141cc406Sopenharmony_cisanei_epson_net_write(Epson_Scanner *s, unsigned int cmd, const unsigned char *buf, 165141cc406Sopenharmony_ci size_t buf_size, size_t reply_len, SANE_Status *status) 166141cc406Sopenharmony_ci{ 167141cc406Sopenharmony_ci unsigned char *h1, *h2, *payload; 168141cc406Sopenharmony_ci unsigned char *packet = malloc(12 + 8 + buf_size); 169141cc406Sopenharmony_ci 170141cc406Sopenharmony_ci if (!packet) { 171141cc406Sopenharmony_ci *status = SANE_STATUS_NO_MEM; 172141cc406Sopenharmony_ci return 0; 173141cc406Sopenharmony_ci } 174141cc406Sopenharmony_ci 175141cc406Sopenharmony_ci h1 = packet; 176141cc406Sopenharmony_ci h2 = packet + 12; 177141cc406Sopenharmony_ci payload = packet + 12 + 8; 178141cc406Sopenharmony_ci 179141cc406Sopenharmony_ci if (reply_len) { 180141cc406Sopenharmony_ci if (s->netbuf) { 181141cc406Sopenharmony_ci DBG(23, "%s, freeing %p, %ld bytes unprocessed\n", 182141cc406Sopenharmony_ci __func__, (void *) s->netbuf, (u_long) s->netlen); 183141cc406Sopenharmony_ci free(s->netbuf); 184141cc406Sopenharmony_ci s->netbuf = s->netptr = NULL; 185141cc406Sopenharmony_ci s->netlen = 0; 186141cc406Sopenharmony_ci } 187141cc406Sopenharmony_ci s->netbuf = malloc(reply_len); 188141cc406Sopenharmony_ci if (!s->netbuf) { 189141cc406Sopenharmony_ci free(packet); 190141cc406Sopenharmony_ci *status = SANE_STATUS_NO_MEM; 191141cc406Sopenharmony_ci return 0; 192141cc406Sopenharmony_ci } 193141cc406Sopenharmony_ci s->netlen = reply_len; 194141cc406Sopenharmony_ci DBG(24, "%s: allocated %lu bytes at %p\n", __func__, 195141cc406Sopenharmony_ci (u_long) s->netlen, (void *) s->netbuf); 196141cc406Sopenharmony_ci } 197141cc406Sopenharmony_ci 198141cc406Sopenharmony_ci DBG(24, "%s: cmd = %04x, buf = %p, buf_size = %lu, reply_len = %lu\n", 199141cc406Sopenharmony_ci __func__, cmd, (void *) buf, (u_long) buf_size, (u_long) reply_len); 200141cc406Sopenharmony_ci 201141cc406Sopenharmony_ci memset(h1, 0x00, 12); 202141cc406Sopenharmony_ci memset(h2, 0x00, 8); 203141cc406Sopenharmony_ci 204141cc406Sopenharmony_ci h1[0] = 'I'; 205141cc406Sopenharmony_ci h1[1] = 'S'; 206141cc406Sopenharmony_ci 207141cc406Sopenharmony_ci h1[2] = cmd >> 8; 208141cc406Sopenharmony_ci h1[3] = cmd; 209141cc406Sopenharmony_ci 210141cc406Sopenharmony_ci h1[4] = 0x00; 211141cc406Sopenharmony_ci h1[5] = 0x0C; /* Don't know what's that */ 212141cc406Sopenharmony_ci 213141cc406Sopenharmony_ci DBG(24, "H1[0]: %02x %02x %02x %02x\n", h1[0], h1[1], h1[2], h1[3]); 214141cc406Sopenharmony_ci 215141cc406Sopenharmony_ci if((cmd >> 8) == 0x20) { 216141cc406Sopenharmony_ci htobe32a(&h1[6], buf_size + 8); 217141cc406Sopenharmony_ci 218141cc406Sopenharmony_ci htobe32a(&h2[0], buf_size); 219141cc406Sopenharmony_ci htobe32a(&h2[4], reply_len); 220141cc406Sopenharmony_ci 221141cc406Sopenharmony_ci DBG(24, "H1[6]: %02x %02x %02x %02x (%lu)\n", h1[6], h1[7], h1[8], h1[9], (u_long) (buf_size + 8)); 222141cc406Sopenharmony_ci DBG(24, "H2[0]: %02x %02x %02x %02x (%lu)\n", h2[0], h2[1], h2[2], h2[3], (u_long) buf_size); 223141cc406Sopenharmony_ci DBG(24, "H2[4]: %02x %02x %02x %02x (%lu)\n", h2[4], h2[5], h2[6], h2[7], (u_long) reply_len); 224141cc406Sopenharmony_ci } 225141cc406Sopenharmony_ci 226141cc406Sopenharmony_ci if ((cmd >> 8) == 0x20 && (buf_size || reply_len)) { 227141cc406Sopenharmony_ci if (buf_size) 228141cc406Sopenharmony_ci memcpy(payload, buf, buf_size); 229141cc406Sopenharmony_ci 230141cc406Sopenharmony_ci sanei_tcp_write(s->fd, packet, 12 + 8 + buf_size); 231141cc406Sopenharmony_ci } 232141cc406Sopenharmony_ci else 233141cc406Sopenharmony_ci sanei_tcp_write(s->fd, packet, 12); 234141cc406Sopenharmony_ci 235141cc406Sopenharmony_ci free(packet); 236141cc406Sopenharmony_ci 237141cc406Sopenharmony_ci *status = SANE_STATUS_GOOD; 238141cc406Sopenharmony_ci return buf_size; 239141cc406Sopenharmony_ci} 240141cc406Sopenharmony_ci 241141cc406Sopenharmony_ciSANE_Status 242141cc406Sopenharmony_cisanei_epson_net_lock(struct Epson_Scanner *s) 243141cc406Sopenharmony_ci{ 244141cc406Sopenharmony_ci SANE_Status status; 245141cc406Sopenharmony_ci unsigned char buf[1]; 246141cc406Sopenharmony_ci 247141cc406Sopenharmony_ci DBG(1, "%s\n", __func__); 248141cc406Sopenharmony_ci 249141cc406Sopenharmony_ci sanei_epson_net_write(s, 0x2100, NULL, 0, 0, &status); 250141cc406Sopenharmony_ci sanei_epson_net_read(s, buf, 1, &status); 251141cc406Sopenharmony_ci return status; 252141cc406Sopenharmony_ci} 253141cc406Sopenharmony_ci 254141cc406Sopenharmony_ciSANE_Status 255141cc406Sopenharmony_cisanei_epson_net_unlock(struct Epson_Scanner *s) 256141cc406Sopenharmony_ci{ 257141cc406Sopenharmony_ci SANE_Status status; 258141cc406Sopenharmony_ci 259141cc406Sopenharmony_ci DBG(1, "%s\n", __func__); 260141cc406Sopenharmony_ci 261141cc406Sopenharmony_ci sanei_epson_net_write(s, 0x2101, NULL, 0, 0, &status); 262141cc406Sopenharmony_ci/* sanei_epson_net_read(s, buf, 1, &status); */ 263141cc406Sopenharmony_ci return status; 264141cc406Sopenharmony_ci} 265