I know this may be too late for 1.0.16 - but thought I'd submit it anyway.

This patch adds usb functionality on OS/2 using the usbcalls interface 
from http://projects.netlabs.org/?category_id=13

I still need to patch configure.in to detect usbcalls.h and add a 
#define and link against usbcalls..

This shouldn't break anything on other platforms....

This isn't perfect yet, but works on quite a few usb scanners - see 
http://smedley.info/sane.html for details.

Cheers,

Paul.
-------------- next part --------------
--- sanei_usb-cvs.c     Sat Apr 16 06:18:24 2005
+++ sanei_usb.c Mon Jul 18 20:03:58 2005
@@ -1,5 +1,5 @@
 /* sane - Scanner Access Now Easy.
-   Copyright (C) 2003 Rene Rebe (sanei_read_int)
+   Copyright (C) 2003 Rene Rebe (sanei_read_int,sanei_set_timeout)
    Copyright (C) 2001 - 2003 Henning Meier-Geinitz
    Copyright (C) 2001 Frank Zago (sanei_usb_control_msg)
    This file is part of the SANE package.
@@ -62,6 +62,30 @@
 #include <usb.h>
 #endif /* HAVE_LIBUSB */
 
+#ifdef HAVE_USBCALLS
+#include <usb.h>
+#include <os2.h>
+#include <usbcalls.h>
+#define MAX_RW 64000
+static int usbcalls_timeout = 30 * 1000;       /* 30 seconds */
+USBHANDLE dh;
+HEV UsbIrqStartHev;
+
+static
+struct usb_descriptor_header *GetNextDescriptor( struct usb_descriptor_header 
*currHead, UCHAR  *lastBytePtr)
+{
+  UCHAR    *currBytePtr, *nextBytePtr;
+
+  if (!currHead->bLength)
+     return (NULL);
+  currBytePtr=(UCHAR *)currHead;
+  nextBytePtr=currBytePtr+currHead->bLength;
+  if (nextBytePtr>=lastBytePtr)
+     return (NULL);
+  return ((struct usb_descriptor_header*)nextBytePtr);
+}
+#endif /* HAVE_USBCALLS */
+
 #define BACKEND_NAME   sanei_usb
 #include "../include/sane/sane.h"
 #include "../include/sane/sanei_debug.h"
@@ -72,7 +96,9 @@
 {
   sanei_usb_method_scanner_driver = 0, /* kernel scanner driver 
                                           (Linux, BSD) */
-  sanei_usb_method_libusb
+  sanei_usb_method_libusb,
+
+  sanei_usb_method_usbcalls
 }
 sanei_usb_access_method_type;
 
@@ -138,6 +164,9 @@
   void *data;
 }
 cmsg;
+#elif defined(__BEOS__)
+#include <drivers/USB_scanner.h>
+#include <kernel/OS.h>
 #endif /* __linux__ */
 
 static SANE_Bool inited = SANE_FALSE;
@@ -202,7 +231,20 @@
        DBG (3, "sanei_usb_get_vendor_product: ioctl (product) "
             "of device %d failed: %s\n", fd, strerror (errno));
     }
-#endif /* defined (__linux__) */
+#elif defined(__BEOS__)
+  {
+    uint16 vendor, product;
+    if (ioctl (fd, B_SCANNER_IOCTL_VENDOR, &vendor) != B_OK)
+      DBG (3, "kernel_get_vendor_product: ioctl (vendor) "
+          "of device %d failed: %s\n", fd, strerror (errno));
+    if (ioctl (fd, B_SCANNER_IOCTL_PRODUCT, &product) != B_OK)
+      DBG (3, "sanei_usb_get_vendor_product: ioctl (product) "
+          "of device %d failed: %s\n", fd, strerror (errno));
+    /* copy from 16 to 32 bit value */
+    *vendorID = vendor;
+    *productID = product;
+  }
+#endif /* defined (__linux__), defined(__BEOS__) */
   /* put more os-dependant stuff ... */
 }
 
@@ -216,6 +258,8 @@
     "/dev/usb/", "scanner",
 #elif defined(__FreeBSD__) || defined(__NetBSD__) || defined (__OpenBSD__)
     "/dev/", "uscanner",
+#elif defined(__BEOS__)
+    "/dev/scanner/usb/", "",
 #endif
     0, 0
   };
@@ -272,6 +316,10 @@
 
       while ((dir_entry = readdir (dir)) != 0)
        {
+         /* skip standard dir entries */
+         if (strcmp (dir_entry->d_name, ".") == 0 || strcmp 
(dir_entry->d_name, "..") == 0)
+               continue;
+                       
          if (strncmp (base_name, dir_entry->d_name, strlen (base_name)) == 0)
            {
              if (strlen (dir_name) + strlen (dir_entry->d_name) + 1 >
@@ -414,6 +462,81 @@
        }
     }
 #endif /* HAVE_LIBUSB */
+#ifdef HAVE_USBCALLS
+  /* Check for devices using OS/2 USBCALLS Interface */
+
+   CHAR ucData[2048];
+   struct usb_device_descriptor *pDevDesc;
+   struct usb_config_descriptor   *pCfgDesc;
+   struct usb_interface_descriptor *intf;
+   struct usb_endpoint_descriptor  *ep;
+   struct usb_descriptor_header    *pDescHead;
+
+   APIRET rc;
+   ULONG ulNumDev, ulDev, ulBufLen;
+
+   ulBufLen = sizeof(ucData);
+   memset(&ucData,0,sizeof(ucData));
+   rc = UsbQueryNumberDevices( &ulNumDev);
+
+   if(rc==0 && ulNumDev)
+   {
+       for (ulDev=1; ulDev<=ulNumDev; ulDev++)
+       {
+         rc = UsbQueryDeviceReport( ulDev,
+                                  &ulBufLen,
+                                  ucData);
+
+         pDevDesc = (struct usb_device_descriptor*)ucData;
+         pCfgDesc = (struct usb_config_descriptor*) (ucData+sizeof(struct 
usb_device_descriptor));
+         int interface=0;
+         SANE_Bool found;
+         if (!pCfgDesc->bConfigurationValue)
+           {
+             DBG (1, "sanei_usb_init: device 0x%04x/0x%04x is not 
configured\n",
+                  pDevDesc->idVendor, pDevDesc->idProduct);
+             continue;
+           }
+         if (pDevDesc->idVendor == 0 || pDevDesc->idProduct == 0)
+           {
+             DBG (5, "sanei_usb_init: device 0x%04x/0x%04x looks like a root 
hub\n",
+                  pDevDesc->idVendor, pDevDesc->idProduct);
+             continue;
+           }
+         found = SANE_FALSE;
+          
+          if (pDevDesc->bDeviceClass = USB_CLASS_VENDOR_SPEC)
+           {
+             found = SANE_TRUE;
+           }
+
+         if (!found)
+           {
+             DBG (5, "sanei_usb_init: device 0x%04x/0x%04x: no suitable 
interfaces\n",
+                  pDevDesc->idVendor, pDevDesc->idProduct);
+             continue;
+           }
+
+         snprintf (devname, sizeof (devname), "usbcalls:%d",
+                   ulDev);
+         devices[dn].devname = strdup (devname);
+          devices[dn].fd = ulDev; /* store usbcalls device number */
+         devices[dn].vendor = pDevDesc->idVendor;
+         devices[dn].product = pDevDesc->idProduct;
+         devices[dn].method = sanei_usb_method_usbcalls;
+         devices[dn].open = SANE_FALSE;
+         devices[dn].interface_nr = interface;
+         DBG (4, "sanei_usb_init: found usbcalls device (0x%04x/0x%04x) as 
device number %s\n",
+              pDevDesc->idVendor, pDevDesc->idProduct,devices[dn].devname);
+          dn++;
+          if (dn >= MAX_DEVICES)
+           return;
+
+       }
+   }
+
+#endif /* HAVE_USBCALLS */
+
   DBG (5, "sanei_usb_init: found %d devices\n", dn);
 }
 
@@ -486,13 +609,22 @@
       return SANE_STATUS_UNSUPPORTED;
 #endif /* HAVE_LIBUSB */
     }
+  else if (devices[dn].method == sanei_usb_method_usbcalls)
+   {
+#ifdef HAVE_USBCALLS
+     vendorID = devices[dn].vendor;
+     productID = devices[dn].product;
+#else
+      DBG (1, "sanei_usb_get_vendor_product: usbcalls support missing\n");
+      return SANE_STATUS_UNSUPPORTED;
+#endif /* HAVE_USBCALLS */
+   }
   else
     {
       DBG (1, "sanei_usb_get_vendor_product: access method %d not "
           "implemented\n", devices[dn].method);
       return SANE_STATUS_INVAL;
     }
-
   if (vendor)
     *vendor = vendorID;
   if (product)
@@ -858,6 +990,153 @@
                 devname, strerror (errno));
        }
     }
+  else if (devices[devcount].method == sanei_usb_method_usbcalls)
+    {
+#ifdef HAVE_USBCALLS
+      CHAR ucData[2048];
+      struct usb_device_descriptor *pDevDesc;
+      struct usb_config_descriptor   *pCfgDesc;
+      struct usb_interface_descriptor *interface;
+      struct usb_endpoint_descriptor  *endpoint;
+      struct usb_descriptor_header    *pDescHead;
+
+      ULONG  ulBufLen;
+      ulBufLen = sizeof(ucData);
+      memset(&ucData,0,sizeof(ucData));
+
+      int result, num,rc;
+      int address, direction, transfer_type;
+
+      DBG (5, "devname = %s, devcount = 
%d\n",devices[devcount].devname,devcount);
+      DBG (5, "USBCalls device number to open = %d\n",devices[devcount].fd);
+      DBG (5, "USBCalls Vendor/Product to open = 0x%04x/0x%04x\n",
+               devices[devcount].vendor,devices[devcount].product);
+      
+      rc = UsbOpen (&dh, 
+                       devices[devcount].vendor,
+                       devices[devcount].product,
+                       USB_ANY_PRODUCTVERSION,
+                       USB_OPEN_FIRST_UNUSED);
+      DBG (1, "sanei_usb_open: UsbOpen rc = %d\n",rc);
+      if (rc!=0)
+       {
+         SANE_Status status = SANE_STATUS_INVAL;
+         DBG (1, "sanei_usb_open: can't open device `%s': %s\n",
+              devname, strerror (rc));
+         return status;
+       }
+      rc = UsbQueryDeviceReport( devices[devcount].fd,
+                                  &ulBufLen,
+                                  ucData);
+      DBG (1, "sanei_usb_open: UsbQueryDeviceReport rc = %d\n",rc);
+      pDevDesc = (struct usb_device_descriptor*)ucData;
+      pCfgDesc = (struct usb_config_descriptor*) (ucData+sizeof(struct 
usb_device_descriptor));
+      UCHAR *pCurPtr = (UCHAR*) pCfgDesc;
+      UCHAR *pEndPtr = pCurPtr+ pCfgDesc->wTotalLength;
+      pDescHead = (struct usb_descriptor_header *) (pCurPtr+pCfgDesc->bLength);
+      /* Set the configuration */
+      if (pDevDesc->bNumConfigurations > 1)
+       {
+         DBG (3, "sanei_usb_open: more than one "
+              "configuration (%d), choosing first config (%d)\n",
+              pDevDesc->bNumConfigurations, 
+              pCfgDesc->bConfigurationValue);
+       }
+      DBG (5, "UsbDeviceSetConfiguration parameters: dh = %p, 
bConfigurationValue = %d\n",
+               dh,pCfgDesc->bConfigurationValue);
+      result = UsbDeviceSetConfiguration (dh,
+                                     pCfgDesc->bConfigurationValue);
+      DBG (1, "sanei_usb_open: UsbDeviceSetConfiguration rc = %d\n",result);
+      if (result)
+       {
+         SANE_Status status = SANE_STATUS_INVAL;
+         DBG (1, "sanei_usb_open: usbcalls complained on 
UsbDeviceSetConfiguration, rc= %d\n", result);
+         status = SANE_STATUS_ACCESS_DENIED;
+         UsbClose (dh);
+         return status;
+       }
+      
+      /* Now we look for usable endpoints */
+      
+      for (pDescHead = (struct usb_descriptor_header *) 
(pCurPtr+pCfgDesc->bLength);
+            pDescHead;pDescHead = GetNextDescriptor(pDescHead,pEndPtr) )
+       {
+          switch(pDescHead->bDescriptorType)
+          {
+            case USB_DT_INTERFACE:
+              interface = (struct usb_interface_descriptor *) pDescHead;
+              DBG (5, "Found %d endpoints\n",interface->bNumEndpoints);
+              break;
+            case USB_DT_ENDPOINT:
+             endpoint = (struct usb_endpoint_descriptor*)pDescHead;
+              address = endpoint->bEndpointAddress;
+             //address = endpoint->bEndpointAddress & 
USB_ENDPOINT_ADDRESS_MASK;
+             direction = endpoint->bEndpointAddress & USB_ENDPOINT_DIR_MASK;
+             transfer_type = endpoint->bmAttributes & USB_ENDPOINT_TYPE_MASK;
+             /* save the endpoints we need later */
+             if (transfer_type == USB_ENDPOINT_TYPE_INTERRUPT)
+             {
+              DBG (5, "sanei_usb_open: found interupt-%s endpoint (address 
%2x)\n",
+                   direction ? "in" : "out", address);
+              if (direction)   /* in */
+              {
+                if (devices[devcount].int_in_ep)
+                  DBG (3, "sanei_usb_open: we already have a int-in endpoint "
+                       "(address: %d), ignoring the new one\n",
+                       devices[devcount].int_in_ep);
+                else
+                  devices[devcount].int_in_ep = endpoint->bEndpointAddress;
+              }
+              else
+                if (devices[devcount].int_out_ep)
+                  DBG (3, "sanei_usb_open: we already have a int-out endpoint "
+                       "(address: %d), ignoring the new one\n",
+                       devices[devcount].int_out_ep);
+                else
+                  devices[devcount].int_out_ep = endpoint->bEndpointAddress;
+            }
+            else if (transfer_type == USB_ENDPOINT_TYPE_BULK)
+            {
+              DBG (5, "sanei_usb_open: found bulk-%s endpoint (address %2x)\n",
+                   direction ? "in" : "out", address);
+              if (direction)   /* in */
+                {
+                  if (devices[devcount].bulk_in_ep)
+                    DBG (3, "sanei_usb_open: we already have a bulk-in 
endpoint "
+                         "(address: %d), ignoring the new one\n",
+                         devices[devcount].bulk_in_ep);
+                  else
+                    devices[devcount].bulk_in_ep = endpoint->bEndpointAddress;
+                }
+              else
+                {
+                  if (devices[devcount].bulk_out_ep)
+                    DBG (3, "sanei_usb_open: we already have a bulk-out 
endpoint "
+                         "(address: %d), ignoring the new one\n",
+                         devices[devcount].bulk_out_ep);
+                  else
+                    devices[devcount].bulk_out_ep = endpoint->bEndpointAddress;
+                }
+              }
+            /* ignore currently unsupported endpoints */
+            else {
+                DBG (5, "sanei_usb_open: ignoring %s-%s endpoint "
+                     "(address: %d)\n",
+                     transfer_type == USB_ENDPOINT_TYPE_CONTROL ? "control" :
+                     transfer_type == USB_ENDPOINT_TYPE_ISOCHRONOUS
+                     ? "isochronous" : "interrupt",
+                     direction ? "in" : "out", address);
+                continue;
+                 }
+          break;
+          }
+        }
+#else
+      DBG (1, "sanei_usb_open: can't open device `%s': "
+          "usbcalls support missing\n", devname);
+      return SANE_STATUS_UNSUPPORTED;
+#endif /* HAVE_USBCALLS */
+    }
   else
     {
       DBG (1, "sanei_usb_open: access method %d not implemented\n",
@@ -889,6 +1168,16 @@
     }
   if (devices[dn].method == sanei_usb_method_scanner_driver)
     close (devices[dn].fd);
+  else if (devices[dn].method == sanei_usb_method_usbcalls)
+    {
+#ifdef HAVE_USBCALLS
+      int rc;
+      rc=UsbClose (dh);
+      DBG (5,"rc of UsbClose = %d\n",rc);
+#else
+    DBG (1, "sanei_usb_close: usbcalls support missing\n");
+#endif
+    }
   else
 #ifdef HAVE_LIBUSB
     {
@@ -913,6 +1202,16 @@
   return;
 }
 
+void
+sanei_usb_set_timeout (SANE_Int timeout)
+{
+#ifdef HAVE_LIBUSB
+  libusb_timeout = timeout;
+#else
+  DBG (1, "sanei_usb_close: libusb support missing\n");
+#endif /* HAVE_LIBUSB */
+}
+
 SANE_Status
 sanei_usb_read_bulk (SANE_Int dn, SANE_Byte * buffer, size_t * size)
 {
@@ -954,6 +1253,41 @@
       return SANE_STATUS_UNSUPPORTED;
     }
 #endif /* not HAVE_LIBUSB */
+  else if (devices[dn].method == sanei_usb_method_usbcalls)
+  {
+#ifdef HAVE_USBCALLS
+    int rc;
+    while (*size)
+    {
+      ULONG ulToRead = (*size>MAX_RW)?MAX_RW:*size;
+      ULONG ulNum = ulToRead;
+      DBG (5, "Entered usbcalls UsbBulkRead with dn = %d\n",dn);
+      DBG (5, "Entered usbcalls UsbBulkRead with dh = %p\n",dh);
+      DBG (5, "Entered usbcalls UsbBulkRead with bulk_in_ep = 
0x%02x\n",devices[dn].bulk_in_ep);
+      DBG (5, "Entered usbcalls UsbBulkRead with interface_nr = 
%d\n",devices[dn].interface_nr);
+      DBG (5, "Entered usbcalls UsbBulkRead with usbcalls_timeout = 
%d\n",usbcalls_timeout);
+
+      if (devices[dn].bulk_in_ep){
+        rc = UsbBulkRead (dh, devices[dn].bulk_in_ep, devices[dn].interface_nr,
+                               &ulToRead, (char *) buffer, usbcalls_timeout);
+        DBG (1, "sanei_usb_read_bulk: rc = %d\n",rc);}
+      else
+      {
+          DBG (1, "sanei_usb_read_bulk: can't read without a bulk-in 
endpoint\n");
+          return SANE_STATUS_INVAL;
+      }
+      if (rc || (ulNum!=ulToRead)) return SANE_STATUS_INVAL;
+      *size -=ulToRead;
+      buffer += ulToRead;
+      read_size += ulToRead;
+    }
+#else /* not HAVE_USBCALLS */
+    {
+      DBG (1, "sanei_usb_read_bulk: usbcalls support missing\n");
+      return SANE_STATUS_UNSUPPORTED;
+    }
+#endif /* not HAVE_USBCALLS */
+  }
   else
     {
       DBG (1, "sanei_usb_read_bulk: access method %d not implemented\n",
@@ -1030,6 +1364,42 @@
       return SANE_STATUS_UNSUPPORTED;
     }
 #endif /* not HAVE_LIBUSB */
+  else if (devices[dn].method == sanei_usb_method_usbcalls)
+  {
+#ifdef HAVE_USBCALLS
+    int rc;
+    DBG (5, "Entered usbcalls UsbBulkWrite with dn = %d\n",dn);
+    DBG (5, "Entered usbcalls UsbBulkWrite with dh = %p\n",dh);
+    DBG (5, "Entered usbcalls UsbBulkWrite with bulk_out_ep = 
0x%02x\n",devices[dn].bulk_out_ep);
+    DBG (5, "Entered usbcalls UsbBulkWrite with interface_nr = 
%d\n",devices[dn].interface_nr);
+    DBG (5, "Entered usbcalls UsbBulkWrite with usbcalls_timeout = 
%d\n",usbcalls_timeout);
+    while (*size)
+    {
+      ULONG ulToWrite = (*size>MAX_RW)?MAX_RW:*size;
+
+      DBG (5, "size requested to write = %lu, ulToWrite = %lu\n",(unsigned 
long) *size,ulToWrite);
+      if (devices[dn].bulk_out_ep){
+        rc = UsbBulkWrite (dh, devices[dn].bulk_out_ep, 
devices[dn].interface_nr,
+                               ulToWrite, (char*) buffer, usbcalls_timeout);
+        DBG (1, "sanei_usb_write_bulk: rc = %d\n",rc);}
+      else
+      {
+          DBG (1, "sanei_usb_write_bulk: can't read without a bulk-out 
endpoint\n");
+          return SANE_STATUS_INVAL;
+      }
+      if (rc) return SANE_STATUS_INVAL;
+      *size -=ulToWrite;
+      buffer += ulToWrite;
+      write_size += ulToWrite;
+      DBG (5, "size = %d, write_size = %d\n",*size, write_size);
+    }
+#else /* not HAVE_USBCALLS */
+    {
+      DBG (1, "sanei_usb_write_bulk: usbcalls support missing\n");
+      return SANE_STATUS_UNSUPPORTED;
+    }
+#endif /* not HAVE_USBCALLS */
+  }
   else
     {
       DBG (1, "sanei_usb_write_bulk: access method %d not implemented\n",
@@ -1091,6 +1461,26 @@
       if ((rtype & 0x80) && debug_level > 10)
        print_buffer (data, len);
       return SANE_STATUS_GOOD;
+#elif defined(__BEOS__)
+      struct usb_scanner_ioctl_ctrlmsg c;
+
+      c.req.request_type = rtype;
+      c.req.request = req;
+      c.req.value = value;
+      c.req.index = index;
+      c.req.length = len;
+      c.data = data;
+
+      if (ioctl (devices[dn].fd, B_SCANNER_IOCTL_CTRLMSG, &c) < 0)
+       {
+         DBG (5, "sanei_usb_control_msg: SCANNER_IOCTL_CTRLMSG error - %s\n",
+              strerror (errno));
+         return SANE_STATUS_IO_ERROR;
+       }
+       if ((rtype & 0x80) && debug_level > 10)
+               print_buffer (data, len);
+       
+       return SANE_STATUS_GOOD;
 #else /* not __linux__ */
       DBG (5, "sanei_usb_control_msg: not supported on this OS\n");
       return SANE_STATUS_UNSUPPORTED;
@@ -1120,6 +1510,30 @@
       return SANE_STATUS_UNSUPPORTED;
     }
 #endif /* not HAVE_LIBUSB */
+  else if (devices[dn].method == sanei_usb_method_usbcalls)
+     {
+#ifdef HAVE_USBCALLS
+      int result;
+
+      result = UsbCtrlMessage (dh, rtype, req,
+                               value, index, len, (char *) data, 
+                               usbcalls_timeout);
+      DBG (5, "rc of usb_control_msg = %d\n",result);
+      if (result < 0)
+       {
+         DBG (1, "sanei_usb_control_msg: usbcalls complained: %d\n",result);
+         return SANE_STATUS_INVAL;
+       }
+      if ((rtype & 0x80) && debug_level > 10)
+       print_buffer (data, len);
+      return SANE_STATUS_GOOD;
+#else /* not HAVE_USBCALLS */
+    {
+      DBG (1, "sanei_usb_control_msg: usbcalls support missing\n");
+      return SANE_STATUS_UNSUPPORTED;
+    }
+#endif /* not HAVE_USBCALLS */
+     }
   else
     {
       DBG (1, "sanei_usb_control_msg: access method %d not implemented\n",
@@ -1174,6 +1588,35 @@
       return SANE_STATUS_UNSUPPORTED;
     }
 #endif /* not HAVE_LIBUSB */
+  else if (devices[dn].method == sanei_usb_method_usbcalls)
+    {
+#ifdef HAVE_USBCALLS
+      int rc;
+      USHORT usNumBytes=*size; 
+      DBG (5, "Entered usbcalls UsbBulkWrite with dn = %d\n",dn);
+      DBG (5, "Entered usbcalls UsbBulkWrite with dh = %p\n",dh);
+      DBG (5, "Entered usbcalls UsbBulkWrite with int_in_ep = 
0x%02x\n",devices[dn].int_in_ep);
+      DBG (5, "Entered usbcalls UsbBulkWrite with interface_nr = 
%d\n",devices[dn].interface_nr);
+      DBG (5, "Entered usbcalls UsbBulkWrite with bytes to read = 
%u\n",usNumBytes);
+
+      if (devices[dn].int_in_ep){
+         rc = UsbIrqStart (dh,devices[dn].int_in_ep,devices[dn].interface_nr,
+                       usNumBytes, (char *) buffer, (HEV *) UsbIrqStartHev);
+         DBG (5, "rc of UsbIrqStart = %d\n",rc);
+        }
+      else
+       {
+         DBG (1, "sanei_usb_read_int: can't read without an int "
+              "endpoint\n");
+         return SANE_STATUS_INVAL;
+       }
+      if (rc) return SANE_STATUS_INVAL;
+      read_size += usNumBytes;
+#else
+      DBG (1, "sanei_usb_read_int: usbcalls support missing\n");
+      return SANE_STATUS_UNSUPPORTED;
+#endif /* HAVE_USBCALLS */
+    }
   else
     {
       DBG (1, "sanei_usb_read_int: access method %d not implemented\n",
From lists.ix.sane-de...@gregjohnson.com  Mon Jul 18 12:13:41 2005
From: lists.ix.sane-de...@gregjohnson.com (Gregory C. Johnson)
Date: Mon Jul 18 12:20:29 2005
Subject: [sane-devel] Color depth upsampling and compressibility
In-Reply-To: <20050717105203.6b7328d...@mailwash5.pair.com>
References: <20050717105203.6b7328d...@mailwash5.pair.com>
Message-ID: <2502.69.40.28.111.1121688821.squir...@webmail3.pair.com>

> On Mon, Jul 11, 2005 at 05:11:48PM +0200, Mattias Ellert wrote:
>> Even better would be:
>>
>>               *dst-- = ((*src << 4) & 0xf0) + ((*src)        & 0x0f);
>>               *dst-- = ((*src)      & 0xf0) + ((*src-- >> 4) & 0x0f);
>>
>> Then 0 would map to 0 and 15 to 255, i.e. white is white and black is
>> black.
>
> You're right. I've changed taht in sp15c.c in CVS.

Some quick Googling doesn't provide dispositive information on this
strategy's impact on compressibility.  However I suspect that introducing
pseudo-random data in the low nybble will reduce compressibility beyond
simply squaring the symbol table.  (Hence, my initial ponderings on
tweaking the constant)

This might be a good candidate for specification in the SANE 2 standard,
as there are clearly multiple strategies for getting from 4 to 8 bits, and
each has different tradeoffs.

Still, I can't imagine this dragon hasn't been slain many times before... 
Anyone know of a dispositive reference that we can just point to?  
Alternately, this should be trivial to explore exhaustively through
brute-force.

Thanks,
-Greg

Reply via email to