diff options
| author | Jörg Frings-Fürst <debian@jff-webhosting.net> | 2020-03-30 21:30:45 +0200 | 
|---|---|---|
| committer | Jörg Frings-Fürst <debian@jff-webhosting.net> | 2020-03-30 21:30:45 +0200 | 
| commit | ee770c2346eb37e0dcb8b6cf3eaacf3d8efd6bbc (patch) | |
| tree | 58f05092be1a17a939e861f8cadcda1b6ca2ecef /backend/pixma/pixma_io_sanei.c | |
| parent | 0da9e21872802cfc6e975b1ebaf9efb9e5934d84 (diff) | |
| parent | fef76e17ed4c607ea73b81279f9ef1d7121be900 (diff) | |
Merge branch 'release/experimental/1.0.29-1_experimental1'experimental/1.0.29-1_experimental1
Diffstat (limited to 'backend/pixma/pixma_io_sanei.c')
| -rw-r--r-- | backend/pixma/pixma_io_sanei.c | 556 | 
1 files changed, 556 insertions, 0 deletions
| diff --git a/backend/pixma/pixma_io_sanei.c b/backend/pixma/pixma_io_sanei.c new file mode 100644 index 0000000..c30b404 --- /dev/null +++ b/backend/pixma/pixma_io_sanei.c @@ -0,0 +1,556 @@ +/* SANE - Scanner Access Now Easy. + * For limitations, see function sanei_usb_get_vendor_product(). + +   Copyright (C) 2011-2019 Rolf Bensch <rolf at bensch hyphen online dot de> +   Copyright (C) 2006-2007 Wittawat Yamwong <wittawat@web.de> + +   This file is part of the SANE package. + +   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; either version 2 of the +   License, or (at your option) any later version. + +   This program is distributed in the hope that it will be useful, but +   WITHOUT ANY WARRANTY; without even the implied warranty of +   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU +   General Public License for more details. + +   You should have received a copy of the GNU General Public License +   along with this program; if not, write to the Free Software +   Foundation, Inc., 59 Temple Place - Suite 330, Boston, +   MA 02111-1307, USA. + +   As a special exception, the authors of SANE give permission for +   additional uses of the libraries contained in this release of SANE. + +   The exception is that, if you link a SANE library with other files +   to produce an executable, this does not by itself cause the +   resulting executable to be covered by the GNU General Public +   License.  Your use of that executable is in no way restricted on +   account of linking the SANE library code into it. + +   This exception does not, however, invalidate any other reasons why +   the executable file might be covered by the GNU General Public +   License. + +   If you submit changes to SANE to the maintainers to be included in +   a subsequent release, you agree by submitting the changes that +   those changes may be distributed with this exception intact. + +   If you write modifications of your own for SANE, it is your choice +   whether to permit this exception to apply to your modifications. +   If you do not wish that, delete this exception notice. + */ +#include "../include/sane/config.h" + +#include <string.h> +#include <stdlib.h> +#include <stdio.h> +#include <limits.h>		/* INT_MAX */ + +#include "pixma_rename.h" +#include "pixma_common.h" +#include "pixma_io.h" +#include "pixma_bjnp.h" + +#include "../include/sane/sanei_usb.h" +#include "../include/sane/sane.h" + + +#ifdef __GNUC__ +# define UNUSED(v) (void) v +#else +# define UNUSED(v) +#endif + +/* MAC OS X does not support timeouts in darwin/libusb interrupt reads + * This is a very basic turnaround for MAC OS X + * Button scan will not work with this wrapper */ +#ifdef __APPLE__ +# define sanei_usb_read_int sanei_usb_read_bulk +#endif + + +struct pixma_io_t +{ +  pixma_io_t *next; +  int interface; +  SANE_Int dev; +}; + +typedef struct scanner_info_t +{ +  struct scanner_info_t *next; +  char *devname; +  int interface; +  const pixma_config_t *cfg; +  char serial[PIXMA_MAX_ID_LEN + 1];	/* "xxxxyyyy_zzzzzzz..." +					   x = vid, y = pid, z = serial */ +} scanner_info_t; + +#define INT_USB 0 +#define INT_BJNP 1 + +static scanner_info_t *first_scanner = NULL; +static pixma_io_t *first_io = NULL; +static unsigned nscanners; + + +static scanner_info_t * +get_scanner_info (unsigned devnr) +{ +  scanner_info_t *si; +  for (si = first_scanner; si && devnr != 0; --devnr, si = si->next) +    { +    } +  return si; +} + +static SANE_Status +attach (SANE_String_Const devname) +{ +  scanner_info_t *si; + +  si = (scanner_info_t *) calloc (1, sizeof (*si)); +  if (!si) +    return SANE_STATUS_NO_MEM; +  si->devname = strdup (devname); +  if (!si->devname) +    return SANE_STATUS_NO_MEM; +  si -> interface = INT_USB; +  si->next = first_scanner; +  first_scanner = si; +  nscanners++; +  return SANE_STATUS_GOOD; +} + + +static SANE_Status +attach_bjnp (SANE_String_Const devname, +             SANE_String_Const serial, +             const struct pixma_config_t *cfg) +{ +  scanner_info_t *si; + +  si = (scanner_info_t *) calloc (1, sizeof (*si)); +  if (!si) +    return SANE_STATUS_NO_MEM; +  si->devname = strdup (devname); +  if (!si->devname) +    return SANE_STATUS_NO_MEM; + +  si->cfg = cfg; +  sprintf(si->serial, "%s_%s", cfg->model, serial); +  si -> interface = INT_BJNP; +  si->next = first_scanner; +  first_scanner = si; +  nscanners++; +  return SANE_STATUS_GOOD; +} + +static void +clear_scanner_list (void) +{ +  scanner_info_t *si = first_scanner; +  while (si) +    { +      scanner_info_t *temp = si; +      free (si->devname); +      si = si->next; +      free (temp); +    } +  nscanners = 0; +  first_scanner = NULL; +} + +static SANE_Status +get_descriptor (SANE_Int dn, SANE_Int type, SANE_Int descidx, +		SANE_Int index, SANE_Int length, SANE_Byte * data) +{ +  return sanei_usb_control_msg (dn, 0x80, USB_REQ_GET_DESCRIPTOR, +				((type & 0xff) << 8) | (descidx & 0xff), +				index, length, data); +} + +static SANE_Status +get_string_descriptor (SANE_Int dn, SANE_Int index, SANE_Int lang, +		       SANE_Int length, SANE_Byte * data) +{ +  return get_descriptor (dn, USB_DT_STRING, index, lang, length, data); +} + +static void +u16tohex (uint16_t x, char *str) +{ +  static const char hdigit[16] = +    { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', +    'E', 'F' +    }; +  str[0] = hdigit[(x >> 12) & 0xf]; +  str[1] = hdigit[(x >> 8) & 0xf]; +  str[2] = hdigit[(x >> 4) & 0xf]; +  str[3] = hdigit[x & 0xf]; +  str[4] = '\0'; +} + +static void +read_serial_number (scanner_info_t * si) +{ +  uint8_t unicode[2 * (PIXMA_MAX_ID_LEN - 9) + 2]; +  uint8_t ddesc[18]; +  int iSerialNumber; +  SANE_Int usb; +  char *serial = si->serial; + +  u16tohex (si->cfg->vid, serial); +  u16tohex (si->cfg->pid, serial + 4); + +  if (SANE_STATUS_GOOD != sanei_usb_open (si->devname, &usb)) +    return; +  if (get_descriptor (usb, USB_DT_DEVICE, 0, 0, 18, ddesc) +      != SANE_STATUS_GOOD) +    goto done; +  iSerialNumber = ddesc[16]; +  if (iSerialNumber != 0) +    { +      int i, len; +      SANE_Status status; + +      /*int iSerialNumber = ddesc[16];*/ +      /* Read the first language code. Assumed that there is at least one. */ +      if (get_string_descriptor (usb, 0, 0, 4, unicode) != SANE_STATUS_GOOD) +        goto done; +      /* Read the serial number string. */ +      status = get_string_descriptor (usb, iSerialNumber, +                                      unicode[3] * 256 + unicode[2], +                                      sizeof (unicode), unicode); +      if (status != SANE_STATUS_GOOD) +        goto done; +      /* Assumed charset: Latin1 */ +      len = unicode[0]; +      if (len > (int) sizeof (unicode)) +        { +          len = sizeof (unicode); +          PDBG (pixma_dbg (1, "WARNING:Truncated serial number\n")); +        } +            serial[8] = '_'; +            for (i = 2; i < len; i += 2) +        { +          serial[9 + i / 2 - 1] = unicode[i]; +        } +      serial[9 + i / 2 - 1] = '\0'; +    } +  else +    { +      PDBG (pixma_dbg (1, "WARNING:No serial number\n")); +    } +done: +  sanei_usb_close (usb); +} + +static int +map_error (SANE_Status ss) +{ +  switch (ss) +    { +    case SANE_STATUS_GOOD: +      return 0; +    case SANE_STATUS_UNSUPPORTED: +      return PIXMA_ENODEV; +    case SANE_STATUS_DEVICE_BUSY: +      return PIXMA_EBUSY; +    case SANE_STATUS_INVAL: +      return PIXMA_EINVAL; +    case SANE_STATUS_IO_ERROR: +      return PIXMA_EIO; +    case SANE_STATUS_NO_MEM: +      return PIXMA_ENOMEM; +    case SANE_STATUS_ACCESS_DENIED: +      return PIXMA_EACCES; +    case SANE_STATUS_CANCELLED: +      return PIXMA_ECANCELED; +    case SANE_STATUS_JAMMED: +       return PIXMA_EPAPER_JAMMED; +    case SANE_STATUS_COVER_OPEN: +       return PIXMA_ECOVER_OPEN; +    case SANE_STATUS_NO_DOCS: +       return PIXMA_ENO_PAPER; +    case SANE_STATUS_EOF: +       return PIXMA_EOF; +#ifdef SANE_STATUS_HW_LOCKED +    case SANE_STATUS_HW_LOCKED:       /* unused by pixma */ +#endif +#ifdef SANE_STATUS_WARMING_UP +    case SANE_STATUS_WARMING_UP:      /* unused by pixma */ +#endif +      break; +    } +  PDBG (pixma_dbg (1, "BUG:Unmapped SANE Status code %d\n", ss)); +  return PIXMA_EIO;		/* should not happen */ +} + + +int +pixma_io_init (void) +{ +  sanei_usb_init (); +  sanei_bjnp_init(); +  nscanners = 0; +  return 0; +} + +void +pixma_io_cleanup (void) +{ +  while (first_io) +    pixma_disconnect (first_io); +  clear_scanner_list (); +} + +unsigned +pixma_collect_devices (const char **conf_devices, +                       const struct pixma_config_t *const pixma_devices[], SANE_Bool local_only) +{ +  unsigned i, j; +  struct scanner_info_t *si; +  const struct pixma_config_t *cfg; + +  clear_scanner_list (); +  j = 0; +  for (i = 0; pixma_devices[i]; i++) +    { +      for (cfg = pixma_devices[i]; cfg->name; cfg++) +        { +          sanei_usb_find_devices (cfg->vid, cfg->pid, attach); +          si = first_scanner; +          while (j < nscanners) +            { +              PDBG (pixma_dbg (3, "pixma_collect_devices() found %s at %s\n", +                   cfg->name, si->devname)); +              si->cfg = cfg; +              read_serial_number (si); +              si = si->next; +              j++; +            } +        } +    } +  if (! local_only) +    sanei_bjnp_find_devices(conf_devices, attach_bjnp, pixma_devices); + +  si = first_scanner; +  while (j < nscanners) +    { +      PDBG (pixma_dbg (3, "pixma_collect_devices() found %s at %s\n", +               si->cfg->name, si->devname)); +      si = si->next; +      j++; + +    } +  return nscanners; +} + +const pixma_config_t * +pixma_get_device_config (unsigned devnr) +{ +  const scanner_info_t *si = get_scanner_info (devnr); +  return (si) ? si->cfg : NULL; +} + +const char * +pixma_get_device_id (unsigned devnr) +{ +  const scanner_info_t *si = get_scanner_info (devnr); +  return (si) ? si->serial : NULL; +} + +int +pixma_connect (unsigned devnr, pixma_io_t ** handle) +{ +  pixma_io_t *io; +  SANE_Int dev; +  const scanner_info_t *si; +  int error; + +  *handle = NULL; +  si = get_scanner_info (devnr); +  if (!si) +    return PIXMA_EINVAL; +  if (si-> interface == INT_BJNP) +    error = map_error (sanei_bjnp_open (si->devname, &dev)); +  else +    error = map_error (sanei_usb_open (si->devname, &dev)); + +  if (error < 0) +    return error; +  io = (pixma_io_t *) calloc (1, sizeof (*io)); +  if (!io) +    { +      if (si -> interface == INT_BJNP) +        sanei_bjnp_close (dev); +      else +        sanei_usb_close (dev); +      return PIXMA_ENOMEM; +    } +  io->next = first_io; +  first_io = io; +  io->dev = dev; +  io->interface = si->interface; +  *handle = io; +  return 0; +} + + +void +pixma_disconnect (pixma_io_t * io) +{ +  pixma_io_t **p; + +  if (!io) +    return; +  for (p = &first_io; *p && *p != io; p = &((*p)->next)) +    { +    } +  PASSERT (*p); +  if (!(*p)) +    return; +  if (io-> interface == INT_BJNP) +    sanei_bjnp_close (io->dev); +  else +    sanei_usb_close (io->dev); +  *p = io->next; +  free (io); +} + +int pixma_activate (pixma_io_t * io) +{ +  int error; +  if (io->interface == INT_BJNP) +    { +      error = map_error(sanei_bjnp_activate (io->dev)); +    } +  else +    /* noop for USB interface */ +    error = 0; +  return error; +} + +int pixma_deactivate (pixma_io_t * io) +{ +  int error; +  if (io->interface == INT_BJNP) +    { +      error = map_error(sanei_bjnp_deactivate (io->dev)); +    } +  else +    /* noop for USB interface */ +    error = 0; +  return error; + +} + +int +pixma_reset_device (pixma_io_t * io) +{ +  UNUSED (io); +  return PIXMA_ENOTSUP; +} + +int +pixma_write (pixma_io_t * io, const void *cmd, unsigned len) +{ +  size_t count = len; +  int error; + +  if (io->interface == INT_BJNP) +    { +    sanei_bjnp_set_timeout (io->dev, PIXMA_BULKOUT_TIMEOUT); +    error = map_error (sanei_bjnp_write_bulk (io->dev, cmd, &count)); +    } +  else +    { +#ifdef HAVE_SANEI_USB_SET_TIMEOUT +    sanei_usb_set_timeout (PIXMA_BULKOUT_TIMEOUT); +#endif +    error = map_error (sanei_usb_write_bulk (io->dev, cmd, &count)); +    } +  if (error == PIXMA_EIO) +    error = PIXMA_ETIMEDOUT;	/* FIXME: SANE doesn't have ETIMEDOUT!! */ +  if (count != len) +    { +      PDBG (pixma_dbg (1, "WARNING:pixma_write(): count(%u) != len(%u)\n", +		       (unsigned) count, len)); +      error = PIXMA_EIO; +    } +  if (error >= 0) +    error = count; +  PDBG (pixma_dump (10, "OUT ", cmd, error, len, 128)); +  return error; +} + +int +pixma_read (pixma_io_t * io, void *buf, unsigned size) +{ +  size_t count = size; +  int error; + +  if (io-> interface == INT_BJNP) +    { +    sanei_bjnp_set_timeout (io->dev, PIXMA_BULKIN_TIMEOUT); +    error = map_error (sanei_bjnp_read_bulk (io->dev, buf, &count)); +    } +  else +    { +#ifdef HAVE_SANEI_USB_SET_TIMEOUT +      sanei_usb_set_timeout (PIXMA_BULKIN_TIMEOUT); +#endif +      error = map_error (sanei_usb_read_bulk (io->dev, buf, &count)); +    } + +  if (error == PIXMA_EIO) +    error = PIXMA_ETIMEDOUT;	/* FIXME: SANE doesn't have ETIMEDOUT!! */ +  if (error >= 0) +    error = count; +  PDBG (pixma_dump (10, "IN  ", buf, error, -1, 128)); +  return error; +} + +int +pixma_wait_interrupt (pixma_io_t * io, void *buf, unsigned size, int timeout) +{ +  size_t count = size; +  int error; + +  /* FIXME: What is the meaning of "timeout" in sanei_usb? */ +  if (timeout < 0) +    timeout = INT_MAX; +  else if (timeout < 100) +    timeout = 100; +  if (io-> interface == INT_BJNP) +    { +      sanei_bjnp_set_timeout (io->dev, timeout); +      error = map_error (sanei_bjnp_read_int (io->dev, buf, &count)); +    } +  else +    { +#ifdef HAVE_SANEI_USB_SET_TIMEOUT +      sanei_usb_set_timeout (timeout); +#endif +      error = map_error (sanei_usb_read_int (io->dev, buf, &count)); +    } +  if (error == PIXMA_EIO || +      (io->interface == INT_BJNP && error == PIXMA_EOF))     /* EOF is a bjnp timeout error! */ +    error = PIXMA_ETIMEDOUT;	/* FIXME: SANE doesn't have ETIMEDOUT!! */ +  if (error == 0) +    error = count; +  if (error != PIXMA_ETIMEDOUT) +    PDBG (pixma_dump (10, "INTR", buf, error, -1, -1)); +  return error; +} + +int +pixma_set_interrupt_mode (pixma_io_t * s, int background) +{ +  UNUSED (s); +  return (background) ? PIXMA_ENOTSUP : 0; +} | 
