Hello,

I would like to propose adding a ulptread call to the ulpt(4).

This diff adds ulptread and ulpt_do_read functions, similar to
ultpwrite and ulpt_do_write (essentially copy/paste/edit), as well
as looking at ugen_do_read (for BULK).


One thing to note is the current ultp driver runs two continuous
transfers and stashes any data into sc_junk. This was added in:

| revision 1.7
| date: 2001/05/03 02:20:34;  author: aaron;  state: Exp;  lines: +165 -40;
| branches:  1.7.2;
| Sync with NetBSD. Tested with a USB keyboard, USB mouse, and three different
| kue(4) Ethernet devices.

I think this matches revision 1.42 on NetBSD.

I am not sure of the original reason for this continuous read.
Therefore, to minimize any potential fallout, this diff checks
the flag to ulptopen call for FREAD, and if set, it doesn't
start the continuous transfers to sc_junk.


Looking at NetBSD source history now, they added read to their driver
in revision 1.60:

| Several changes:
| * Implement read for ulpt.
| * If the device is not opened for reading, occasionally drain any
|   data the printer might have (but don't hammer the printer with reads).
| * Lower the buffer size to one page.
|   The driver seems to work with more printers now.


They similarly check for FREAD in their open, and if "it's not
opened for read the [sic] set up a reader."


The reason for the proposal is that I have a USB thermal printer
which attaches to ulpt and for me to "drive" the printer, I need
the status messages the printer sends back.

I initially got the device working with ulpt disabled and using
libusb1 from ports. It would be much more convenient not to bother
with disabling ulpt.


Comments?

--patrick




Index: sys/conf.h
===================================================================
RCS file: /cvs/obsd/src/sys/sys/conf.h,v
retrieving revision 1.143
diff -u -p -u -p -r1.143 conf.h
--- sys/conf.h  4 Sep 2016 10:51:24 -0000       1.143
+++ sys/conf.h  19 May 2017 01:39:18 -0000
@@ -356,9 +356,9 @@ extern struct cdevsw cdevsw[];
        (dev_type_stop((*))) enodev, 0, selfalse, \
        (dev_type_mmap((*))) enodev }
 
-/* open, close, write */
+/* open, close, read, write */
 #define cdev_ulpt_init(c,n) { \
-       dev_init(c,n,open), dev_init(c,n,close), (dev_type_read((*))) enodev, \
+       dev_init(c,n,open), dev_init(c,n,close), dev_init(c,n,read), \
        dev_init(c,n,write), (dev_type_ioctl((*))) enodev, \
        (dev_type_stop((*))) enodev, 0, selfalse, (dev_type_mmap((*))) enodev }
 
Index: dev/usb/ulpt.c
===================================================================
RCS file: /cvs/obsd/src/sys/dev/usb/ulpt.c,v
retrieving revision 1.54
diff -u -p -u -p -r1.54 ulpt.c
--- dev/usb/ulpt.c      26 Mar 2017 15:31:15 -0000      1.54
+++ dev/usb/ulpt.c      19 May 2017 01:39:18 -0000
@@ -42,6 +42,7 @@
 #include <sys/device.h>
 #include <sys/uio.h>
 #include <sys/conf.h>
+#include <sys/fcntl.h>
 #include <sys/vnode.h>
 #include <sys/syslog.h>
 #include <sys/types.h>
@@ -486,7 +487,7 @@ ulptopen(dev_t dev, int flag, int mode, 
                if (usbd_is_dying(sc->sc_udev)) {
                        error = ENXIO;
                        sc->sc_state = 0;
-                       goto done;
+                       goto bad;
                }
        }
 
@@ -494,18 +495,20 @@ ulptopen(dev_t dev, int flag, int mode, 
        if (err) {
                sc->sc_state = 0;
                error = EIO;
-               goto done;
+               goto bad;
        }
        if (ulptusein && sc->sc_in != -1) {
-               DPRINTF(("ulpt_open: open input pipe\n"));
+               DPRINTF(("ulptopen: open input pipe\n"));
                err = usbd_open_pipe(sc->sc_iface, sc->sc_in,0,&sc->sc_in_pipe);
                if (err) {
                        error = EIO;
                        usbd_close_pipe(sc->sc_out_pipe);
                        sc->sc_out_pipe = NULL;
                        sc->sc_state = 0;
-                       goto done;
+                       goto bad;
                }
+               if ((flag & FREAD) == FREAD)
+                       goto done;
                sc->sc_in_xfer1 = usbd_alloc_xfer(sc->sc_udev);
                sc->sc_in_xfer2 = usbd_alloc_xfer(sc->sc_udev);
                if (sc->sc_in_xfer1 == NULL || sc->sc_in_xfer2 == NULL) {
@@ -534,9 +537,10 @@ ulptopen(dev_t dev, int flag, int mode, 
                usbd_transfer(sc->sc_in_xfer1); /* ignore failed start */
        }
 
+ done:
        sc->sc_state = ULPT_OPEN;
 
- done:
+ bad:
        if (--sc->sc_refcnt < 0)
                usb_detach_wakeup(&sc->sc_dev);
 
@@ -596,6 +600,71 @@ ulptclose(dev_t dev, int flag, int mode,
 
        DPRINTF(("ulptclose: closed\n"));
        return (0);
+}
+
+int
+ulpt_do_read(struct ulpt_softc *sc, struct uio *uio, int flags)
+{
+       size_t n;
+       int error = 0;
+       uint32_t bytes;
+       void *bufp;
+       struct usbd_xfer *xfer;
+       usbd_status err;
+
+       DPRINTF(("ulptread\n"));
+       xfer = usbd_alloc_xfer(sc->sc_udev);
+       if (xfer == NULL)
+               return (ENOMEM);
+       bufp = usbd_alloc_buffer(xfer, ULPT_BSIZE);
+       if (bufp == NULL) {
+               usbd_free_xfer(xfer);
+               return (ENOMEM);
+       }
+       while ((n = ulmin(ULPT_BSIZE, uio->uio_resid)) != 0) {
+               ulpt_statusmsg(ulpt_status(sc), sc);
+               DPRINTFN(1, ("ulptread: transfer %zu bytes\n", n));
+               usbd_setup_xfer(xfer, sc->sc_in_pipe, 0, bufp, n,
+                   USBD_NO_COPY | USBD_SYNCHRONOUS | USBD_CATCH |
+                   USBD_SHORT_XFER_OK, 0, NULL);
+               err = usbd_transfer(xfer);
+               if (err) {
+                       usbd_clear_endpoint_stall(sc->sc_in_pipe);
+                       DPRINTF(("ulptread: error=%d\n", err));
+                       error = EIO;
+                       break;
+               }
+               usbd_get_xfer_status(xfer, NULL, NULL, &bytes, NULL);
+               if (bytes == 0)
+                       break;
+               error = uiomove(bufp, bytes, uio);
+               if (error)
+                       break;
+       }
+       usbd_free_xfer(xfer);
+
+       return (error);
+}
+
+int
+ulptread(dev_t dev, struct uio *uio, int flags)
+{
+       struct ulpt_softc *sc;
+       int error;
+
+       sc = ulpt_cd.cd_devs[ULPTUNIT(dev)];
+
+       if (usbd_is_dying(sc->sc_udev) || (sc->sc_flags & ULPT_EFIRMWARE))
+               return (EIO);
+
+       if (sc->sc_in == -1)
+               return (ENODEV);
+
+       sc->sc_refcnt++;
+       error = ulpt_do_read(sc, uio, flags);
+       if (--sc->sc_refcnt < 0)
+               usb_detach_wakeup(&sc->sc_dev);
+       return (error);
 }
 
 int

Reply via email to