Subject: ioctls for dev/usb/uscanner.c
To: None <current-users@NetBSD.org>
From: None <brook@biology.nmsu.edu>
List: current-users
Date: 06/23/2004 12:59:30
SANE needs to obtain information from the uscanner kernel driver about
the vendor and product IDs for USB scanners.  Currently, there are no
ioctls defined for this (or any other) purpose in
sys/dev/usb/uscanner.c.  For this limited purpose, it is sufficient to
implement the USB_GET_DEVICEINFO ioctl, though perhaps a more complete
interface would be preferable.  The patch below is patterned from the
way the ugen driver handles ioctls, with only one actually implemented
(someone more familiar with the usb code may with to extend this
framework, for example to define USCANNERENDPOINT).

I have tested this on a -current kernel and have a patch for SANE that
will use this ioctl successfully.  I am pretty confident that the SANE
folks will accept the patch, as they have already accepted another for
a different part of their code that doesn't require the ioctl
interface.

Would someone please review this patch and commit it (or an
improvement on it)?  Once that is done, I will contact the SANE folks
with the follow-on patch for their code.

Thank you very much.

Cheers,
Brook

===========================================================================
--- sys/dev/usb/uscanner.c.orig
+++ sys/dev/usb/uscanner.c
@@ -300,6 +300,8 @@
 Static int uscanner_do_read(struct uscanner_softc *, struct uio *, int);
 Static int uscanner_do_write(struct uscanner_softc *, struct uio *, int);
 Static void uscanner_do_close(struct uscanner_softc *);
+Static int uscanner_do_ioctl(struct uscanner_softc *, int, u_long,
+			     caddr_t, int, usb_proc_ptr);
 
 #define USCANNERUNIT(n) (minor(n))
 
@@ -765,10 +767,43 @@
 	return (0);
 }
 
+Static int
+uscanner_do_ioctl(struct uscanner_softc *sc, int endpt, u_long cmd,
+		  caddr_t addr, int flag, usb_proc_ptr p)
+{
+	DPRINTFN(5, ("uscannerioctl: cmd=%08lx\n", cmd));
+	if (sc->sc_dying)
+		return (EIO);
+
+	switch (cmd) {
+	case FIONBIO:
+		/* All handled in the upper FS layer. */
+		return (0);
+	case USB_GET_DEVICEINFO:
+		usbd_fill_deviceinfo(sc->sc_udev,
+				     (struct usb_device_info *)addr, 1);
+		break;
+	default:
+		return (EINVAL);
+	}
+	return (0);
+}
+
 int
 uscannerioctl(dev_t dev, u_long cmd, caddr_t addr, int flag, usb_proc_ptr p)
 {
-	return (EINVAL);
+			/* XXX - need macro, but not used above for now */
+	int endpt = 0; /* USCANNERENDPOINT(dev); */
+	struct uscanner_softc *sc;
+	int error;
+
+	USB_GET_SC(uscanner, USCANNERUNIT(dev), sc);
+
+	sc->sc_refcnt++;
+	error = uscanner_do_ioctl(sc, endpt, cmd, addr, flag, p);
+	if (--sc->sc_refcnt < 0)
+		usb_detach_wakeup(USBDEV(sc->sc_dev));
+	return (error);
 }
 
 #if defined(__FreeBSD__)