[sane-devel] Proposal: SANE standard additions/fixes

Matto Marjanovic maddog@mir.com
Sun, 6 Oct 2002 13:01:52 -0400


 >While I'm working on this topic some more small issues that got lost
 >somehow after older discussions. These are proposals for SANE 1. From
 >TODO:

Hi --- I hadn't replied to this yet, but it was still in my inbox, so
 I had intended to get back to it when I had more time.  Here I go:

 >1) What happens when sane_init returns a status other than
 >   SANE_STATUS_GOOD?
 >
 >That's not defined but we should state that explicitely.
 >
 >The standard reads:
 >
 >| 4.3.1 sane_init
 >| This function must be called before any other SANE function can be
 >| called. The behavior of a SANE backend is undefined if this function
 >| is not called first. The version code of the backend is returned in
 >| the value pointed to by version_code. If that pointer is NULL, no
 >| version code is returned. Argument authorize is either a pointer to a
 >| function that is invoked when the backend requires authentication for
 >| a specific resource or NULL if the frontend does not support
 >| authentication.
 >
 >I propose to add "or if the returned status code is different from
 >SANE_STATUS_GOOD" after the second sentence resulting in:
 >
 >"This function must be called before any other SANE function can be
 >called. The behavior of a SANE backend is undefined if this function
 >is not called first or if the returned status code is different from
 >SANE_STATUS_GOOD. The version code of the backend is returned in the
 >value pointed to by version_code. If that pointer is NULL, no version
 >code is returned. Argument authorize is either a pointer to a function
 >that is invoked when the backend requires authentication for a
 >specific resource or NULL if the frontend does not support
 >authentication."

Sounds good.  (That was an easy one.)

 >2) Concerning sane_get_select_fd: It's not that easy to implement the
 >   select fd correctly in frontends and backends. For frontends the
 >   problem is, that not only the readable status has to be cheked but
 >   also if the fd was closed. E.g. using a gdk_input will not work
 >   because it won't detect the closing of the file descriptor by the
 >   backend and waits forever.
 >   
 >   So if you use select you have to check the return value of select
 >   if the fd was closed (that means EOF in the next call to SANE_READ)
 >   and so you can call sane_cancel. If no error occured, check if the
 >   fd is readable. If yes, run sane_read, otherwise wait.
 >   
 >   Maybe we can add a "frontend implementation note" for that one.
 >   I don't know how to write this exactly, maybe Oliver?

Well, I was the guy who thought it might be a good idea to get rid of this
 mode of operation altogether, so I'm not the best one to comment.  (Feel
 free to skip ahead; somehow it turned into thoughts on the semantics of
 sane_cancel(), until (e) and (f)....)

The standard does seem to be unclear on what happens when sane_cancel()
 is called:

 a) If you are in the middle of another sane call, and sane_cancel() is
    called (via a signal handler), the spec is clear:  the scan is officially
    cancelled once the current call returns with SANE_CANCELLED.

 b) If you are *not* in the middle of another sane call, what happens?
    If I call sane_cancel() in between calls to sane_read(), is the scan
    cancelled immediately upon returning from sane_cancel(), or are you
    allowed or required to call sane_read() once more so that you get a
    return value of SANE_CANCELLED?

 c) The above behavior would give everything an overall consistent behavior:
      1) An image acquisition cycle begins when sane_start() is called.
      2) An image acquisition cycle ends if sane_start() returns a value
          which is not SANE_STATUS_GOOD, or when sane_read() returns a
          value which is not SANE_STATUS_GOOD.
    In this model, one must call sane_read() one last time to finish the
    scan, and that is when any file descriptors should be cleaned up.

    But this conflicts with the requirement that sane_cancel() be called
    at the end of a scan.  It seems to me that sane_cancel() is actually
    being overloaded; it shouldn't serve as both a post-scan clean-up
    function and as the 'stop now' signalling function.

    (Someone will say enforcing such a model would break almost all of
    the current backends.  Oh well, maybe for version 2.0....)

    If sane_read() or sane_start() return SANE_STATUS_CANCELLED, does 
    sane_cancel() *still* need to be called?  The strict reading of the
    specification would say "yes".


 d) Anyhow, all that aside, it seems to me that if select() is waiting
     on a file descriptor fd, then it is bad asynchronous behavior for
     a call to sane_cancel() in a signal handler to close that fd.
     (Presumably the fd is connected to a pipe connecting to a reader
     process spawned by the backend.  The far-end of that pipe should
     be closed, causing the select() to see a pending EOF on the fd.)
    However, select() should return an EINTR if it is hit by a signal,
     and calling select() again should then return EBADF if the fd is
     gone....

 e) Maybe using the "IOChannel" facilities of GDK instead of gdk_input
     would work better?  (Just looked at the manpages; seems to be able
     to do stuff in the case of other error conditions.)


 f) There are *no* return codes listed for sane_get_parameters().
    One of the possible return values should be SANE_STATUS_CANCELLED,
     in case the scan has been cancelled between the sane_start() and
     the sane_get_parameters() calls.



 >3) Defining the meaning of SANE_CAP_ADVANCED for option groups.
 >   The current usage of SANE_CAP_ADVANCED for option groups is that
 >   all the options are advanced even if it's not mentioned in the
 >   standard. At least xsane has this behaviour.
 >
 >   Should we state this explicitely? What happens if some options in a
 >   group are adavanced an some are not? Shall the backend display two
 >   groups?
 >   
 >   Or should only groups be allowed to use SANE_CAP_ADVANCED? Or only
 >   normal options?
 >   
 >   Or all the options in a group and the group itsself must be either
 >   advanced or not but not mixed?

I say make the current behavior explicit:

 a) If an option group is tagged with SANE_CAP_ADVANCED, then all of the
     options within it are considered advanced options, and the frontend
     should display, or not display, the whole group depending on the user's
     preference.
    The constituent options in the group inherit the ADVANCED tag from the
     group, and it does not matter whether they have the tag or not.

 b) If an option group is _not_ tagged with SANE_CAP_ADVANCED, then the
     options within it may individually be tagged as ADVANCED options, and
     the frontend should display them as such.

 >4) Return status of sane_start:
 >
 >The standard reads:
 >
 >| 4.3.9 sane_start
 >| This function initiates aquisition of an image from the device
 >| represented by handle h.
 >| 
 >| SANE_Status sane_start (SANE_Handle h);
 >| 
 >| This function may fail with one of the following status codes.
 >|
 >| SANE_STATUS_CANCELLED:
 >| The operation was cancelled through a call to sane_cancel.
 >| 
 >| SANE_STATUS_DEVICE_BUSY:
 >| The device is busy. The operation should be retried later.
 >| 
 >| SANE_STATUS_JAMMED:
 >| The document feeder is jammed.
 >|
 >| SANE_STATUS_NO_DOCS:
 >| The document feeder is out of documents.
 >| 
 >| SANE_STATUS_COVER_OPEN:
 >| The scanner cover is open.
 >| 
 >| SANE_STATUS_IO_ERROR:
 >| An error occurred while communicating with the device.
 >| 
 >| SANE_STATUS_NO_MEM:
 >| An insufficent amount of memory is available.
 >
 >I propose to add:
 >
 >" SANE_STATUS_INVAL
 >The scan can't be started with the current set of options."
 >
 >The reason is, that this is the only way to handle case whe TL_X >
 >BR_X without breaking graphical frontends. Other reasons may be that
 >the TA was turned off in the meantime or similar.

Sounds good.
Since one reason for this return value is that the scanner capabilities
 may have somehow changed, perhaps we should also add:

   "The frontend should reload the device option descriptors, as if
    SANE_INFO_RELOAD_OPTIONS had been returned from a call to
    sane_control_option(), since the device's capabilities may have 
    changed."

I would also change "can't" to "cannot".


 >5) sane_set_io_mode
 >
 >The description is unclear concerning the meaning of
 >SANE_STATUS_UNSUPPORTED and the time when it's allowed to call it.
 >
 >The standard reads:
 >
 >| 4.3.12 sane_set_io_mode
 >| 
 >| This function is used to set the I/O mode of handle h. The I/O mode
 >| can be either blocking or non-blocking. If argument m is SANE_TRUE,
 >| the mode is set to non-blocking mode, otherwise it's set to blocking
 >| mode.
 >
 >[...]
 >
 >| This function may fail with one of the following status codes:
 >|
 >| SANE_STATUS_INVAL:
 >| No image acquisition is pending.
 >|
 >| SANE_STATUS_UNSUPPORTED:
 >| The backend does not support this operation.
 >
 >I propose the following changes:
 >
 >"This function is used to set the I/O mode of handle h. The I/O mode
 >can be either blocking or non-blocking. If argument m is SANE_TRUE,
 >the mode is set to non-blocking mode, otherwise it's set to blocking
 >mode. This function can be called only after a call to sane_start()
 >has been performed."
 >
 >[...]
 >
 >"This function may fail with one of the following status codes:
 >
 >SANE_STATUS_INVAL:
 >No image acquisition is pending.
 >
 >SANE_STATUS_UNSUPPORTED:
 >The backend does not support the requested I/O mode."

Sounds good.


-matt m.