diff options
Diffstat (limited to 'sanei')
| -rw-r--r-- | sanei/sanei_init_debug.c | 4 | ||||
| -rw-r--r-- | sanei/sanei_pio.c | 6 | ||||
| -rw-r--r-- | sanei/sanei_usb.c | 182 | 
3 files changed, 167 insertions, 25 deletions
| diff --git a/sanei/sanei_init_debug.c b/sanei/sanei_init_debug.c index 3cde74e..d5d64f2 100644 --- a/sanei/sanei_init_debug.c +++ b/sanei/sanei_init_debug.c @@ -118,7 +118,7 @@ is_socket (int fd)  #if defined(S_ISSOCK)    return S_ISSOCK(sbuf.st_mode); -#elif defined (S_IFMT) && defined(S_IFMT) +#elif defined (S_IFMT) && defined(S_IFSOCK)    return (sbuf.st_mode & S_IFMT) == S_IFSOCK;  #else    return 0; @@ -133,6 +133,7 @@ sanei_debug_msg    if (max_level >= level)      { +#if defined(LOG_DEBUG)        if (is_socket(fileno(stderr)))  	{  	  msg = (char *)malloc (sizeof(char) * (strlen(be) + strlen(fmt) + 4)); @@ -149,6 +150,7 @@ sanei_debug_msg  	    }  	}        else +#endif  	{            struct timeval tv;            struct tm *t; diff --git a/sanei/sanei_pio.c b/sanei/sanei_pio.c index 3290704..8b67093 100644 --- a/sanei/sanei_pio.c +++ b/sanei/sanei_pio.c @@ -495,7 +495,7 @@ sanei_pio_close (int fd)  {    Port p = port + fd; -  if ((0 > fd) && (NELEMS (port) <= fd)) +  if ((0 > fd) || (NELEMS (port) <= fd))      return;    if (!p->in_use) @@ -515,7 +515,7 @@ sanei_pio_close (int fd)  int  sanei_pio_read (int fd, u_char * buf, int n)  { -  if ((0 > fd) && (NELEMS (port) <= fd)) +  if ((0 > fd) || (NELEMS (port) <= fd))      return -1;    if (!port[fd].in_use) @@ -527,7 +527,7 @@ sanei_pio_read (int fd, u_char * buf, int n)  int  sanei_pio_write (int fd, const u_char * buf, int n)  { -  if ((0 > fd) && (NELEMS (port) <= fd)) +  if ((0 > fd) || (NELEMS (port) <= fd))      return -1;    if (!port[fd].in_use) diff --git a/sanei/sanei_usb.c b/sanei/sanei_usb.c index db0f452..4b49b11 100644 --- a/sanei/sanei_usb.c +++ b/sanei/sanei_usb.c @@ -48,6 +48,9 @@  #include "../include/sane/config.h" +#ifdef HAVE_STDINT_H +# include <stdint.h> +#endif  #include <stdlib.h>  #include <ctype.h>  #include <sys/types.h> @@ -195,15 +198,16 @@ static sanei_usb_testing_mode testing_mode = sanei_usb_testing_mode_disabled;  #if WITH_USB_RECORD_REPLAY  static int testing_development_mode = 0; -int testing_known_commands_input_failed = 0; -unsigned testing_last_known_seq = 0; -SANE_String testing_record_backend = NULL; -xmlNode* testing_append_commands_node = NULL; +static int testing_already_opened = 0; +static int testing_known_commands_input_failed = 0; +static unsigned testing_last_known_seq = 0; +static SANE_String testing_record_backend = NULL; +static xmlNode* testing_append_commands_node = NULL;  // XML file from which we read testing data -SANE_String testing_xml_path = NULL; -xmlDoc* testing_xml_doc = NULL; -xmlNode* testing_xml_next_tx_node = NULL; +static SANE_String testing_xml_path = NULL; +static xmlDoc* testing_xml_doc = NULL; +static xmlNode* testing_xml_next_tx_node = NULL;  #endif // WITH_USB_RECORD_REPLAY  #if defined(HAVE_LIBUSB_LEGACY) || defined(HAVE_LIBUSB) @@ -214,6 +218,14 @@ static int libusb_timeout = 30 * 1000;	/* 30 seconds */  static libusb_context *sanei_usb_ctx;  #endif /* HAVE_LIBUSB */ +#if defined (__APPLE__) +/* macOS won't configure several USB scanners (i.e. ScanSnap 300M) because their + * descriptors are vendor specific.  As a result the device will get configured + * later during sanei_usb_open making it safe to ignore the configuration check + * on these platforms. */ +#define SANEI_ALLOW_UNCONFIGURED_DEVICES +#endif +  #if defined (__linux__)  /* From /usr/src/linux/driver/usb/scanner.h */  #define SCANNER_IOCTL_VENDOR _IOR('U', 0x20, int) @@ -587,9 +599,8 @@ static void sanei_xml_print_seq_if_any(xmlNode* node, const char* parent_fun)    xmlFree(attr);  } -// Checks whether transaction should be ignored. We ignore get_descriptor and -// set_configuration transactions. The latter is ignored because -// set_configuration is called in sanei_usb_open outside test path. +// Checks whether transaction should be ignored. We ignore set_configuration +// transactions, because set_configuration is called in sanei_usb_open outside test path.  static int sanei_xml_is_transaction_ignored(xmlNode* node)  {    if (xmlStrcmp(node->name, (const xmlChar*)"control_tx") != 0) @@ -627,7 +638,8 @@ static int sanei_xml_is_transaction_ignored(xmlNode* node)  static xmlNode* sanei_xml_skip_non_tx_nodes(xmlNode* node)  {    const char* known_node_names[] = { -    "control_tx", "bulk_tx", "interrupt_tx", "debug", "known_commands_end" +    "control_tx", "bulk_tx", "interrupt_tx", +    "get_descriptor", "debug", "known_commands_end"    };    while (node != NULL) @@ -660,13 +672,11 @@ static int sanei_xml_is_known_commands_end(xmlNode* node)    return xmlStrcmp(node->name, (const xmlChar*)"known_commands_end") == 0;  } -// returns next transaction node that is not get_descriptor  static xmlNode* sanei_xml_peek_next_tx_node()  {    return testing_xml_next_tx_node;  } -// returns next transaction node that is not get_descriptor  static xmlNode* sanei_xml_get_next_tx_node()  {    xmlNode* next = testing_xml_next_tx_node; @@ -1200,7 +1210,7 @@ static SANE_Status sanei_usb_testing_init()            memset(&device, 0, sizeof(device));            device.devname = strdup(testing_xml_path); -          // other code shouldn't depend on methon because testing_mode is +          // other code shouldn't depend on method because testing_mode is            // sanei_usb_testing_mode_replay            device.method = sanei_usb_method_libusb;            device.vendor = device_id; @@ -1303,6 +1313,18 @@ static void sanei_usb_testing_exit()    xmlFreeDoc(testing_xml_doc);    free(testing_xml_path);    xmlCleanupParser(); + +  // reset testing-related all data to initial values +  testing_development_mode = 0; +  testing_already_opened = 0; +  testing_known_commands_input_failed = 0; +  testing_last_known_seq = 0; +  testing_record_backend = NULL; +  testing_append_commands_node = NULL; + +  testing_xml_path = NULL; +  testing_xml_doc = NULL; +  testing_xml_next_tx_node = NULL;  }  #else // WITH_USB_RECORD_REPLAY  SANE_Status sanei_usb_testing_enable_replay(SANE_String_Const path, @@ -1848,6 +1870,7 @@ static void libusb_scan_devices(void)  	  continue;  	} +#if !defined(SANEI_ALLOW_UNCONFIGURED_DEVICES)        if (config == 0)  	{  	  DBG (1, @@ -1855,6 +1878,7 @@ static void libusb_scan_devices(void)  	       vid, pid, busno, address);  	  continue;  	} +#endif        ret = libusb_get_config_descriptor (dev, 0, &config0);        if (ret < 0) @@ -2288,22 +2312,43 @@ sanei_usb_get_endpoint (SANE_Int dn, SANE_Int ep_type)  }  #if WITH_USB_RECORD_REPLAY +static void sanei_xml_indent_child(xmlNode* parent, unsigned indent_count) +{ +  indent_count *= 4; + +  xmlChar* indent_str = malloc(indent_count + 2); +  indent_str[0] = '\n'; +  memset(indent_str + 1, ' ', indent_count); +  indent_str[indent_count + 1] = '\0'; + +  xmlAddChild(parent, xmlNewText(indent_str)); +  free(indent_str); +} +  static void sanei_usb_record_open(SANE_Int dn)  { +  if (testing_already_opened) +    return; +    xmlNode* e_root = xmlNewNode(NULL, (const xmlChar*) "device_capture");    xmlDocSetRootElement(testing_xml_doc, e_root);    xmlNewProp(e_root, (const xmlChar*)"backend", (const xmlChar*) testing_record_backend); +  sanei_xml_indent_child(e_root, 1);    xmlNode* e_description = xmlNewChild(e_root, NULL, (const xmlChar*) "description", NULL);    sanei_xml_set_hex_attr(e_description, "id_vendor", devices[dn].vendor);    sanei_xml_set_hex_attr(e_description, "id_product", devices[dn].product); +  sanei_xml_indent_child(e_description, 2);    xmlNode* e_configurations = xmlNewChild(e_description, NULL,                                            (const xmlChar*) "configurations", NULL); + +  sanei_xml_indent_child(e_configurations, 3);    xmlNode* e_configuration = xmlNewChild(e_configurations, NULL,                                           (const xmlChar*) "configuration", NULL);    sanei_xml_set_uint_attr(e_configuration, "number", 1); +  sanei_xml_indent_child(e_configuration, 4);    xmlNode* e_interface = xmlNewChild(e_configuration, NULL, (const xmlChar*) "interface", NULL);    sanei_xml_set_uint_attr(e_interface, "number", devices[dn].interface_nr); @@ -2329,6 +2374,7 @@ static void sanei_usb_record_open(SANE_Int dn)      {        if (endpoints[i].ep_address)          { +          sanei_xml_indent_child(e_interface, 5);            xmlNode* e_endpoint = xmlNewChild(e_interface, NULL, (const xmlChar*)"endpoint", NULL);            xmlNewProp(e_endpoint, (const xmlChar*)"transfer_type",                       (const xmlChar*) endpoints[i].transfer_type); @@ -2338,10 +2384,17 @@ static void sanei_usb_record_open(SANE_Int dn)            sanei_xml_set_hex_attr(e_endpoint, "address", endpoints[i].ep_address);          }      } +  sanei_xml_indent_child(e_interface, 4); +  sanei_xml_indent_child(e_configuration, 3); +  sanei_xml_indent_child(e_configurations, 2); +  sanei_xml_indent_child(e_description, 1); + +  sanei_xml_indent_child(e_root, 1);    xmlNode* e_transactions = xmlNewChild(e_root, NULL, (const xmlChar*)"transactions", NULL);    // add an empty node so that we have something to append to -  testing_append_commands_node =  xmlAddChild(e_transactions, xmlNewText((const xmlChar*)""));; +  testing_append_commands_node = xmlAddChild(e_transactions, xmlNewText((const xmlChar*)"")); +  testing_already_opened = 1;  }  #endif // WITH_USB_RECORD_REPLAY @@ -2574,11 +2627,13 @@ sanei_usb_open (SANE_String_Const devname, SANE_Int * dn)  	  return SANE_STATUS_INVAL;  	} +#if !defined(SANEI_ALLOW_UNCONFIGURED_DEVICES)        if (config == 0)  	{  	  DBG (1, "sanei_usb_open: device `%s' not configured?\n", devname);  	  return SANE_STATUS_INVAL;  	} +#endif        result = libusb_get_device_descriptor (dev, &desc);        if (result < 0) @@ -3851,7 +3906,7 @@ sanei_usb_replay_control_msg(SANE_Int dn, SANE_Int rtype, SANE_Int req,    (void) dn;    if (testing_known_commands_input_failed) -    return -1; +    return SANE_STATUS_IO_ERROR;    xmlNode* node = sanei_xml_get_next_tx_node();    if (node == NULL) @@ -4184,6 +4239,11 @@ static int sanei_usb_replay_read_int(SANE_Int dn, SANE_Byte* buffer,        return -1;      } +  if (sanei_usb_check_attr(node, "error", "timeout", __func__)) +    { +      return -1; +    } +    size_t tx_data_size = 0;    char* tx_data = sanei_xml_get_hex_data(node, &tx_data_size); @@ -4723,14 +4783,66 @@ sanei_usb_set_altinterface (SANE_Int dn, SANE_Int alternate)      }  } +#if WITH_USB_RECORD_REPLAY +  static SANE_Status  sanei_usb_replay_get_descriptor(SANE_Int dn,                                  struct sanei_usb_dev_descriptor *desc)  {    (void) dn; -  (void) desc; -  return SANE_STATUS_UNSUPPORTED; -  // ZZTODO + +  if (testing_known_commands_input_failed) +    return SANE_STATUS_IO_ERROR; + +  xmlNode* node = sanei_xml_get_next_tx_node(); +  if (node == NULL) +    { +      FAIL_TEST(__func__, "no more transactions\n"); +      return SANE_STATUS_IO_ERROR; +    } + +  if (sanei_xml_is_known_commands_end(node)) +    { +      testing_known_commands_input_failed = 1; +      return SANE_STATUS_IO_ERROR; +    } + +  sanei_xml_record_seq(node); +  sanei_xml_break_if_needed(node); + +  if (xmlStrcmp(node->name, (const xmlChar*)"get_descriptor") != 0) +    { +      FAIL_TEST_TX(__func__, node, "unexpected transaction type %s\n", +                   (const char*) node->name); +      testing_known_commands_input_failed = 1; +      return SANE_STATUS_IO_ERROR; +    } + +  int desc_type = sanei_xml_get_prop_uint(node, "descriptor_type"); +  int bcd_usb = sanei_xml_get_prop_uint(node, "bcd_usb"); +  int bcd_dev = sanei_xml_get_prop_uint(node, "bcd_device"); +  int dev_class = sanei_xml_get_prop_uint(node, "device_class"); +  int dev_sub_class = sanei_xml_get_prop_uint(node, "device_sub_class"); +  int dev_protocol = sanei_xml_get_prop_uint(node, "device_protocol"); +  int max_packet_size = sanei_xml_get_prop_uint(node, "max_packet_size"); + +  if (desc_type < 0 || bcd_usb < 0 || bcd_dev < 0 || dev_class < 0 || +      dev_sub_class < 0 || dev_protocol < 0 || max_packet_size < 0) +  { +      FAIL_TEST_TX(__func__, node, "get_descriptor recorded block is missing attributes\n"); +      testing_known_commands_input_failed = 1; +      return SANE_STATUS_IO_ERROR; +  } + +  desc->desc_type = desc_type; +  desc->bcd_usb = bcd_usb; +  desc->bcd_dev = bcd_dev; +  desc->dev_class = dev_class; +  desc->dev_sub_class = dev_sub_class; +  desc->dev_protocol = dev_protocol; +  desc->max_packet_size = max_packet_size; + +  return SANE_STATUS_GOOD;  }  static void @@ -4738,10 +4850,28 @@ sanei_usb_record_get_descriptor(SANE_Int dn,                                  struct sanei_usb_dev_descriptor *desc)  {    (void) dn; -  (void) desc; -  // ZZTODO + +  xmlNode* node = testing_append_commands_node; + +  xmlNode* e_tx = xmlNewNode(NULL, (const xmlChar*)"get_descriptor"); + +  xmlNewProp(e_tx, (const xmlChar*)"time_usec", (const xmlChar*)"0"); +  sanei_xml_set_uint_attr(node, "seq", ++testing_last_known_seq); + +  sanei_xml_set_hex_attr(e_tx, "descriptor_type", desc->desc_type); +  sanei_xml_set_hex_attr(e_tx, "bcd_usb", desc->bcd_usb); +  sanei_xml_set_hex_attr(e_tx, "bcd_device", desc->bcd_dev); +  sanei_xml_set_hex_attr(e_tx, "device_class", desc->dev_class); +  sanei_xml_set_hex_attr(e_tx, "device_sub_class", desc->dev_sub_class); +  sanei_xml_set_hex_attr(e_tx, "device_protocol", desc->dev_protocol); +  sanei_xml_set_hex_attr(e_tx, "max_packet_size", desc->max_packet_size); + +  node = sanei_xml_append_command(node, 1, e_tx); +  testing_append_commands_node = node;  } +#endif // WITH_USB_RECORD_REPLAY +  extern SANE_Status  sanei_usb_get_descriptor( SANE_Int dn,                            struct sanei_usb_dev_descriptor __sane_unused__ @@ -4757,7 +4887,12 @@ sanei_usb_get_descriptor( SANE_Int dn,    if (testing_mode == sanei_usb_testing_mode_replay)      { +#if WITH_USB_RECORD_REPLAY        return sanei_usb_replay_get_descriptor(dn, desc); +#else +      DBG (1, "USB record-replay mode support is missing\n"); +      return SANE_STATUS_UNSUPPORTED; +#endif      }    DBG (5, "sanei_usb_get_descriptor\n"); @@ -4808,7 +4943,12 @@ sanei_usb_get_descriptor( SANE_Int dn,    if (testing_mode == sanei_usb_testing_mode_record)      { +#if WITH_USB_RECORD_REPLAY        sanei_usb_record_get_descriptor(dn, desc); +#else +      DBG (1, "USB record-replay mode support is missing\n"); +      return SANE_STATUS_UNSUPPORTED; +#endif      }    return SANE_STATUS_GOOD; | 
