As scanbuttond author seems unresponsive on his SF mail address, I'm
posting the patch for scanbuttond (applies over CVS version) here.

Hope someone finds it useful.

Best regards,
-- 
 Ilia Sotnikov

diff -Nur --exclude CVS scanbuttond.orig/backends/hp5590.c
scanbuttond/backends/hp5590.c
--- scanbuttond.orig/backends/hp5590.c  1970-01-01 03:00:00.000000000 +0300
+++ scanbuttond/backends/hp5590.c       2008-09-15 18:28:24.000000000 +0300
@@ -0,0 +1,583 @@
+/* hp5590.c: HP4570/5550/5590/7650 backend
+ * This file is part of scanbuttond.
+ * Copyleft )c( 2008 by Ilia Sotnikov <hostcc at gmail.com>
+ *
+ * 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <string.h>
+#include <syslog.h>
+#include <errno.h>
+#include <netinet/in.h> /* For htons() */
+#include "scanbuttond/scanbuttond.h"
+#include "scanbuttond/libusbi.h"
+#include "hp5590.h"
+
+static char* backend_name = "HP5590 USB";
+
+#define NUM_SUPPORTED_USB_DEVICES 4
+
+static int supported_usb_devices[NUM_SUPPORTED_USB_DEVICES][3] =
+{
+       /* vendor, product, num_buttons */
+       { 0x03f0, 0x1305, 5 },  /* HP Scanjet 4570 */
+       { 0x03f0, 0x1305, 5 },  /* HP Scanjet 5550 */
+       { 0x03f0, 0x1705, 5 },  /* HP Scanjet 5590 */
+       { 0x03f0, 0x1805, 5 },  /* HP Scanjet 7650 */
+};
+
+static char* usb_device_descriptions[NUM_SUPPORTED_USB_DEVICES][2] =
+{
+       { "Hewlett-Packard", "ScanJet 4570" },
+       { "Hewlett-Packard", "ScanJet 5550" },
+       { "Hewlett-Packard", "Scanjet 5590" },
+       { "Hewlett-Packard", "Scanjet 7650" },
+};
+
+static libusb_handle_t* libusb_handle;
+static scanner_t* hp5590_scanners = NULL;
+
+/* returns -1 if the scanner is unsupported, or the index of the
+ * corresponding vendor-product pair in the supported_usb_devices array.
+ */
+static int
+hp5590_match_libusb_scanner(libusb_device_t* device)
+{
+       int index;
+
+       for (index = 0; index < NUM_SUPPORTED_USB_DEVICES; index++)
+       {
+               if (supported_usb_devices[index][0] == device->vendorID &&
+                       supported_usb_devices[index][1] == device->productID)
+                       break;
+       }
+
+       if (index >= NUM_SUPPORTED_USB_DEVICES)
+               return -1;
+
+       return index;
+}
+
+static void
+hp5590_attach_libusb_scanner (libusb_device_t* device)
+{
+       const char* descriptor_prefix = "hp5590:libusb:";
+       int             index;
+
+       index = hp5590_match_libusb_scanner(device);
+       /* Unsupported */
+       if (index < 0)
+               return;
+
+       scanner_t* scanner = (scanner_t*) malloc (sizeof(scanner_t));
+       scanner->vendor = usb_device_descriptions[index][0];
+       scanner->product = usb_device_descriptions[index][1];
+       scanner->connection = CONNECTION_LIBUSB;
+       scanner->internal_dev_ptr = (void*) device;
+       scanner->lastbutton = 0;
+       scanner->sane_device = (char*) malloc (strlen (device->location) +
+                                                  strlen (descriptor_prefix) + 
1);
+       strcpy (scanner->sane_device, descriptor_prefix);
+       strcat (scanner->sane_device, device->location);
+       scanner->num_buttons = supported_usb_devices[index][2];
+       scanner->is_open = 0;
+       scanner->next = hp5590_scanners;
+       hp5590_scanners = scanner;
+}
+
+static void
+hp5590_detach_scanners (void)
+{
+       scanner_t* next;
+       while (hp5590_scanners != NULL)
+       {
+               next = hp5590_scanners->next;
+               free (hp5590_scanners->sane_device);
+               free (hp5590_scanners);
+               hp5590_scanners = next;
+       }
+}
+
+static void
+hp5590_scan_devices (libusb_device_t* devices)
+{
+       int index;
+       libusb_device_t* device = devices;
+       while (device != NULL)
+       {
+               index = hp5590_match_libusb_scanner (device);
+               if (index >= 0)
+                       hp5590_attach_libusb_scanner (device);
+               device = device->next;
+       }
+}
+
+static int
+hp5590_init_libusb (void)
+{
+       libusb_device_t* devices;
+
+       libusb_handle = libusb_init ();
+       devices = libusb_get_devices (libusb_handle);
+       hp5590_scan_devices (devices);
+       return 0;
+}
+
+static void
+hp5590_flush (scanner_t* scanner)
+{
+       switch (scanner->connection)
+       {
+               case CONNECTION_LIBUSB:
+                       libusb_flush ((libusb_device_t*) 
scanner->internal_dev_ptr);
+                       break;
+       }
+}
+
+const char*
+scanbtnd_get_backend_name (void)
+{
+       return backend_name;
+}
+
+int
+scanbtnd_init (void)
+{
+       hp5590_scanners = NULL;
+
+       syslog (LOG_INFO, "hp5590-backend: init");
+       return hp5590_init_libusb ();
+}
+
+int
+scanbtnd_rescan (void)
+{
+       libusb_device_t* devices;
+
+       hp5590_detach_scanners ();
+       hp5590_scanners = NULL;
+       libusb_rescan (libusb_handle);
+       devices = libusb_get_devices (libusb_handle);
+       hp5590_scan_devices (devices);
+
+       return 0;
+}
+
+const scanner_t*
+scanbtnd_get_supported_devices (void)
+{
+       return hp5590_scanners;
+}
+
+int
+scanbtnd_open (scanner_t* scanner)
+{
+       int result = -ENOSYS;
+
+       if (scanner->is_open)
+               return -EINVAL;
+
+       switch (scanner->connection)
+       {
+               case CONNECTION_LIBUSB:
+                       /* if devices have been added/removed, return -ENODEV to
+                        * make scanbuttond update its device list
+                        */
+                       if (libusb_get_changed_device_count () != 0)
+                               return -ENODEV;
+                       result = libusb_open ((libusb_device_t*) 
scanner->internal_dev_ptr);
+                       break;
+       }
+
+       if (result == 0)
+               scanner->is_open = 1;
+
+       return result;
+}
+
+int
+scanbtnd_close(scanner_t* scanner)
+{
+       int result = -ENOSYS;
+
+       if (!scanner->is_open)
+               return -EINVAL;
+
+       switch (scanner->connection)
+       {
+               case CONNECTION_LIBUSB:
+                       result = libusb_close ((libusb_device_t*) 
scanner->internal_dev_ptr);
+                       break;
+       }
+
+       if (result == 0)
+               scanner->is_open = 0;
+
+       return result;
+}
+
+/* Taken from sane-backends/include/sane/sanei_usb.h */
+
+#define USB_DIR_OUT                    0x00
+#define USB_DIR_IN                     0x80
+
+/* Taken from sane-backends/backends/hp5590_cmds.c */
+
+/* Button flags */
+#define BUTTON_FLAG_EMAIL      1 << 15
+#define BUTTON_FLAG_COPY       1 << 14
+#define BUTTON_FLAG_DOWN       1 << 13
+#define BUTTON_FLAG_MODE       1 << 12
+#define BUTTON_FLAG_UP         1 << 11
+#define BUTTON_FLAG_FILE       1 << 9
+#define BUTTON_FLAG_POWER      1 << 5
+#define BUTTON_FLAG_SCAN       1 << 2
+#define BUTTON_FLAG_COLLECT    1 << 1
+#define BUTTON_FLAG_CANCEL     1 << 0
+
+#define CMD_BUTTON_STATUS      0x0020
+
+/* Taken from sane-backends/backends/hp5590_low.c */
+
+/* Flags for hp5590_cmd() */
+#define CMD_IN                         1 << 0  /* Indicates IN direction, 
otherwise - OUT */
+#define CMD_VERIFY                     1 << 1  /* Requests last command 
verification */
+
+/* Core flags for hp5590_cmd() - they indicate so called CORE commands */
+#define CORE_NONE                       0      /* No CORE operation */
+#define CORE_DATA                      1 << 0  /* Operate on CORE data */
+
+/* CORE status flag - ready or not */
+#define CORE_FLAG_NOT_READY    1 << 1
+
+/* Structure describing control URB */
+struct usb_in_usb_ctrl_setup
+{
+       u_int8_t  bRequestType;
+       u_int8_t  bRequest;
+       u_int16_t wValue;
+       u_int16_t wIndex;
+       u_int16_t wLength;
+} __attribute__ ((packed));
+
+static int
+hp5590_get_ack (scanner_t *scanner)
+{
+       u_int8_t        status;
+       int                     ret;
+
+       /* Check if USB-in-USB operation was accepted */
+       ret = libusb_control_msg ((libusb_device_t *) scanner->internal_dev_ptr,
+                                                         USB_DIR_IN | 
USB_TYPE_VENDOR,
+                                                         0x0c, 0x8e, 0x20,
+                                                         &status, sizeof 
(status));
+       if (ret <= 0)
+       {
+      syslog (LOG_ERR, "hp5590-backend: USB-in-USB: error getting
acknowledge");
+      return -1;
+    }
+
+       /* Check if we received correct acknowledgement */
+       if (status != 0x01)
+       {
+               syslog (LOG_ERR, "hp5590-backend: USB-in-USB: not accepted 
(status
%u)", status);
+               return -1;
+       }
+
+       return 0;
+}
+
+static int
+hp5590_control_msg (scanner_t *scanner,
+                               int requesttype, int request,
+                                       int value, int index, unsigned char 
*bytes,
+                               int size, int core_flags)
+{
+       struct usb_in_usb_ctrl_setup    ctrl;
+       int                                                             ret;
+       unsigned int                                    len;
+       unsigned char                                   *ptr;
+       u_int8_t                                                ack;
+       u_int8_t                                                response;
+
+       /* IN (read) operation will be performed */
+       if (requesttype & USB_DIR_IN)
+       {
+               /* Prepare USB-in-USB control message */
+               memset (&ctrl, 0, sizeof (ctrl));
+               ctrl.bRequestType = 0xc0;
+               ctrl.bRequest = request;
+               ctrl.wValue = htons (value);
+               ctrl.wIndex = htons (index);
+               ctrl.wLength = size;
+
+               /* Send USB-in-USB control message */
+               ret = libusb_control_msg ((libusb_device_t *) 
scanner->internal_dev_ptr,
+                                                                 USB_DIR_OUT | 
USB_TYPE_VENDOR,
+                                                                 0x04, 0x8f, 
0x00,
+                                                                 (unsigned 
char *) &ctrl, sizeof (ctrl));
+               if (ret <= 0)
+               {
+                       syslog (LOG_ERR, "hp5590-backend: USB-in-USB: error 
sending
control message");
+                       return -1;
+               }
+
+               ret = hp5590_get_ack (scanner);
+               if (ret != 0)
+                       return ret;
+
+               len = size;
+               ptr = bytes;
+               /* Data is read in 8 byte portions */
+               while (len)
+               {
+                       unsigned int next_packet_size;
+                       next_packet_size = 8;
+                       if (len < 8)
+                               next_packet_size = len;
+
+                       /* Read USB-in-USB data */
+                       ret = libusb_control_msg ((libusb_device_t *) 
scanner->internal_dev_ptr,
+                                                                         
USB_DIR_IN | USB_TYPE_VENDOR,
+                                                                         
core_flags & CORE_DATA ? 0x0c : 0x04,
+                                                                         0x90, 
0x00,
+                                                                         ptr, 
next_packet_size);
+                       if (ret <= 0)
+                       {
+                               syslog (LOG_ERR, "hp5590-backend: USB-in-USB: 
error reading data");
+                               return -1;
+                       }
+
+                       ptr += next_packet_size;
+                       len -= next_packet_size;
+               }
+
+               /* Confirm data reception */
+               ack = 0;
+               ret = libusb_control_msg ((libusb_device_t *) 
scanner->internal_dev_ptr,
+                                                                 USB_DIR_OUT | 
USB_TYPE_VENDOR,
+                                                                 0x0c, 0x8f, 
0x00,
+                                                                 &ack, sizeof 
(ack));
+               if (ret <= 0)
+               {
+                       syslog (LOG_ERR, "hp5590-backend: USB-in-USB: error 
confirming
data reception");
+                       return -1;
+               }
+
+               ret = hp5590_get_ack (scanner);
+               if (ret != 0)
+                       return ret;
+       }
+
+       /* OUT (write) operation will be performed */
+       if (!(requesttype & USB_DIR_IN))
+       {
+               /* Prepare USB-in-USB control message */
+               memset (&ctrl, 0, sizeof (ctrl));
+               ctrl.bRequestType = 0x40;
+               ctrl.bRequest = request;
+               ctrl.wValue = htons (value);
+               ctrl.wIndex = htons (index);
+               ctrl.wLength = size;
+
+               /* Send USB-in-USB control message */
+               ret = libusb_control_msg ((libusb_device_t *) 
scanner->internal_dev_ptr,
+                                                                 USB_DIR_OUT | 
USB_TYPE_VENDOR,
+                                                                 0x04, 0x8f, 
0x00,
+                                                                 (unsigned 
char *) &ctrl, sizeof (ctrl));
+               if (ret <= 0)
+               {
+                       syslog (LOG_ERR, "hp5590-backend: USB-in-USB: error 
sending
control message");
+                       return -1;
+               }
+
+               ret = hp5590_get_ack (scanner);
+               if (ret != 0)
+                       return ret;
+
+               len = size;
+               ptr = bytes;
+               /* Data is sent in 8 byte portions */
+               while (len)
+               {
+                       unsigned int next_packet_size;
+                       next_packet_size = 8;
+                       if (len < 8)
+                               next_packet_size = len;
+
+                       /* Send USB-in-USB data */
+                       ret = libusb_control_msg ((libusb_device_t *) 
scanner->internal_dev_ptr,
+                                                                         
USB_DIR_OUT | USB_TYPE_VENDOR,
+                                                                         
core_flags & CORE_DATA ? 0x04 : 0x0c,
+                                                                         0x8f, 
0x00, ptr, next_packet_size);
+                       if (ret <= 0)
+                       {
+                               syslog (LOG_ERR, "hp5590-backend: USB-in-USB: 
error sending data");
+                               return -1;
+                       }
+
+                       /* CORE data is acknowledged packet by packet */
+                       if (core_flags & CORE_DATA)
+                       {
+                               ret = hp5590_get_ack (scanner);
+                               if (ret != 0)
+                                       return ret;
+                       }
+
+                       ptr += next_packet_size;
+                       len -= next_packet_size;
+               }
+
+               /* Normal (non-CORE) data is acknowledged after its full 
transmission */
+               if (!(core_flags & CORE_DATA))
+               {
+                       ret = hp5590_get_ack (scanner);
+                       if (ret != 0)
+                               return ret;
+               }
+
+               /* Getting  response after data transmission */
+               ret = libusb_control_msg ((libusb_device_t *) 
scanner->internal_dev_ptr,
+                                                                 USB_DIR_IN | 
USB_TYPE_VENDOR,
+                                                                 0x0c, 0x90, 
0x00,
+                                                                 &response, 
sizeof (response));
+               if (ret <= 0)
+               {
+                       syslog (LOG_ERR, "hp5590-backend: USB-in-USB: error 
getting response");
+                       return -1;
+               }
+
+               /* Necessary response after normal (non-CORE) data is 0x00 */
+               if (response != 0x00)
+               {
+                       syslog (LOG_ERR, "hp5590-backend: USB-in-USB: invalid 
response received "
+                               "(needed 0x00, got %04x)", response);
+
+                       return -1;
+               }
+       }
+
+       return 0;
+}
+
+static int
+hp5590_verify_last_cmd (scanner_t *scanner, unsigned int cmd)
+{
+       u_int16_t               verify_cmd;
+       unsigned int    last_cmd;
+       unsigned int    core_status;
+       int                             ret;
+
+       /* Read last command along with CORE status */
+       ret = hp5590_control_msg (scanner,
+                                                         USB_DIR_IN,
+                                                         0x04, 0xc5, 0x00,
+                                                         (unsigned char *) 
&verify_cmd,
+                                                         sizeof (verify_cmd), 
CORE_NONE);
+       if (ret != 0)
+               return ret;
+
+       /* Last command - minor byte */
+       last_cmd = verify_cmd & 0xff;
+       /* CORE status - major byte */
+       core_status = (verify_cmd & 0xff00) >> 8;
+
+       /* Verify last command */
+       if ((cmd & 0x00ff) != last_cmd)
+       {
+               syslog (LOG_ERR, "hp5590-backend: USB-in-USB: command 
verification failed: "
+                               "expected 0x%04x, got 0x%04x", cmd, last_cmd);
+               return -1;
+       }
+
+       /* Return value depends on CORE status */
+       return core_status & CORE_FLAG_NOT_READY ? -1 : 0;
+}
+
+static int
+hp5590_cmd (scanner_t *scanner, unsigned int flags,
+                       unsigned int cmd, unsigned char *data, unsigned int 
size,
+                       unsigned int core_flags)
+{
+       int ret;
+
+       ret = hp5590_control_msg (scanner,
+                                                         flags & CMD_IN ? 
USB_DIR_IN : USB_DIR_OUT,
+                                                         0x04, cmd, 0x00, 
data, size, core_flags);
+       if (ret != 0)
+               return ret;
+
+       ret = 0;
+       /* Verify last command if requested */
+       if (flags & CMD_VERIFY)
+               ret = hp5590_verify_last_cmd (scanner, cmd);
+
+       return ret;
+}
+
+int
+scanbtnd_get_button(scanner_t* scanner)
+{
+       int             button = 0;
+       u_int16_t       button_status;
+       int                     ret;
+
+       if (!scanner->is_open)
+               return -EINVAL;
+       
+       ret = hp5590_cmd (scanner, CMD_IN | CMD_VERIFY,
+                                         CMD_BUTTON_STATUS,
+                                         (unsigned char *) &button_status,
+                                         sizeof (button_status), CORE_NONE);
+       if (ret != 0) {
+               hp5590_flush (scanner);
+               return 0;
+       }
+
+       /* Network order */
+       button_status = ntohs (button_status);
+
+       if (button_status & BUTTON_FLAG_SCAN)
+               button = 1;
+
+       if (button_status & BUTTON_FLAG_COLLECT)
+               button = 2;
+
+       if (button_status & BUTTON_FLAG_FILE)
+               button = 3;
+
+       if (button_status & BUTTON_FLAG_EMAIL)
+               button = 4;
+
+       if (button_status & BUTTON_FLAG_COPY)
+               button = 5;
+
+       return button;
+}
+
+const char*
+scanbtnd_get_sane_device_descriptor (scanner_t* scanner)
+{
+       return scanner->sane_device;
+}
+
+int
+scanbtnd_exit (void)
+{
+       syslog (LOG_INFO, "hp5590-backend: exit");
+       hp5590_detach_scanners ();
+       libusb_exit (libusb_handle);
+       return 0;
+}
diff -Nur --exclude CVS scanbuttond.orig/backends/hp5590.h
scanbuttond/backends/hp5590.h
--- scanbuttond.orig/backends/hp5590.h  1970-01-01 03:00:00.000000000 +0300
+++ scanbuttond/backends/hp5590.h       2008-09-13 13:43:02.000000000 +0300
@@ -0,0 +1,25 @@
+/* hp5590.c: HP4570/5550/5590/7650 backend
+ * This file is part of scanbuttond.
+ * Copyleft )c( 2008 by Ilia Sotnikov <hostcc at gmail.com>
+ *
+ * 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifndef __HP5590_H_INCLUDED
+#define __HP5590_H_INCLUDED
+
+#include "scanbuttond/backend.h"
+
+#endif
diff -Nur --exclude CVS scanbuttond.orig/backends/Makefile.am
scanbuttond/backends/Makefile.am
--- scanbuttond.orig/backends/Makefile.am       2008-08-21 03:54:56.000000000 
+0300
+++ scanbuttond/backends/Makefile.am    2008-09-13 11:09:49.000000000 +0300
@@ -8,7 +8,8 @@
                        libscanbtnd-backend_artec_eplus48u.la \
                        libscanbtnd-backend_hp3900.la \
                        libscanbtnd-backend_hp3500.la \
-                       libscanbtnd-backend_genesys.la
+                       libscanbtnd-backend_genesys.la \
+                       libscanbtnd-backend_hp5590.la

 libscanbtnd_backend_epson_la_SOURCES = epson.c epson.h
 libscanbtnd_backend_epson_la_LIBADD = ../interface/libscanbtnd-interface_usb.la
@@ -43,6 +44,9 @@
 libscanbtnd_backend_genesys_la_SOURCES = genesys.c genesys.h
 libscanbtnd_backend_genesys_la_LIBADD =
../interface/libscanbtnd-interface_usb.la
 libscanbtnd_backend_genesys_la_LDFLAGS = -module -version-info 1:0:0
+libscanbtnd_backend_hp5590_la_SOURCES = hp5590.c hp5590.h
+libscanbtnd_backend_hp5590_la_LIBADD =
../interface/libscanbtnd-interface_usb.la
+libscanbtnd_backend_hp5590_la_LDFLAGS = -module -version-info 1:0:0

 pkgsysconfdir = $(sysconfdir)/$(PACKAGE)
 pkgsysconf_DATA = meta.conf
diff -Nur --exclude CVS scanbuttond.orig/backends/meta.conf
scanbuttond/backends/meta.conf
--- scanbuttond.orig/backends/meta.conf 2006-10-02 02:03:04.000000000 +0300
+++ scanbuttond/backends/meta.conf      2008-09-13 11:57:32.000000000 +0300
@@ -7,3 +7,4 @@
 libscanbtnd-backend_artec_eplus48u
 libscanbtnd-backend_hp3900
 libscanbtnd-backend_genesys
+libscanbtnd-backend_hp5590

Reply via email to