Subject: Re: more usb oddness...
To: Lennart Augustsson <lennart@augustsson.net>
From: Alfred Perlstein <bright@mu.org>
List: tech-kern
Date: 02/27/2002 01:33:44
* Lennart Augustsson <lennart@augustsson.net> [020226 14:02] wrote:
> Alfred Perlstein wrote:
> 
> > Ok, I'm stumped.
> >
> > It seems like everything works ok (device open/ioctl/etc) the first
> > two times I open the device, after that the device starts timeing
> > out on requests.
> >
> > Any suggestions for debugging this?
> 
> Do you have access to a USB protocol analyzer?

No, do you know how much they are and/or if I can get a loaner in
the San Fransico Bay Area?

> There are some weird scanner devices that don't reset the data
> toggle when you perform a CLEAR STALL (which open does),
> so then you can get out of sync.  That's the only thing I can think
> of.

Is there a workaround?

Are there any diagnostics to make sure I'm doing the right thing?

What I'm basically aiming to do is emulate in some form or another
the ioctls that the HP printer guy wants.  He has it implemented
for linux (but they're ignoring him as usual. :)) here:

http://hpoj.sourceforge.net/download/experimental/linux-usb/

Can you look at the attached delta and let me know if/how I may have
gone wrong?

I get this output:

ulptopen: 488
ulptopen: 515
/usr/src/sys/arch/i386/compile/BRAZZEN_TINY/../../../../dev/usb/ohci.c:1690 using timeout! 0xc04fbb00 (ms 5000, ticks 500, hz 100)
ulpt_openpipes: 762
ulpt_openpipes: 765
/usr/src/sys/arch/i386/compile/BRAZZEN_TINY/../../../../dev/usb/ohci.c:1690 using timeout! 0xc04fbb00 (ms 5000, ticks 500, hz 100)
ulpt_openpipes: 774
ulpt_openpipes: 793
ulpt_openpipes: 797
ulpt_openpipes: 801
USB_LP_GET_PROTOCOL -> 3
ulpt ioctl cmd = 40045597, error = 0
ulpt_getdescriptbyproto: found proto: 2, altno = 1
ulptclose
ulptclose closing out_pipe
ulptclose aborting in_pipe
ulptclose closing in_pipe
ulptclose free xfer 1
ulptclose free xfer 1
ulptclose done
/usr/src/sys/arch/i386/compile/BRAZZEN_TINY/../../../../dev/usb/ohci.c:1690 using timeout! 0xc05b0680 (ms 5000, ticks 500, hz 100)
ohci_timeout called!
ioctl, usbd_set_interface said: 15 'TIMEOUT'
ulpt ioctl cmd = 80045598, error = 22
ulptclose
ulptclose:566 sc_state != ULPT_OPEN

This is my current delta:

Index: ulpt.c
===================================================================
RCS file: /home/netcvs/syssrc/sys/dev/usb/ulpt.c,v
retrieving revision 1.49
diff -u -r1.49 ulpt.c
--- ulpt.c	2002/02/25 22:39:01	1.49
+++ ulpt.c	2002/02/27 02:58:49
@@ -155,12 +155,18 @@
 };
 #endif
 
-void ulpt_disco(void *);
+Static int ulpt_openpipes(struct ulpt_softc *);
+Static int ulpt_primeendpoints(struct ulpt_softc *);
+Static int ulpt_do_close(struct ulpt_softc *);
+Static int ulpt_do_write(struct ulpt_softc *, struct uio *uio, int);
+Static int ulpt_status(struct ulpt_softc *);
+Static void ulpt_reset(struct ulpt_softc *);
+Static int ulpt_statusmsg(u_char, struct ulpt_softc *);
+Static int ulpt_get_id(dev_t, char *, int);
+Static int ulpt_getdescriptbyproto(struct ulpt_softc *, int,
+    usb_interface_descriptor_t **, int *);
+	
 
-int ulpt_do_write(struct ulpt_softc *, struct uio *uio, int);
-int ulpt_status(struct ulpt_softc *);
-void ulpt_reset(struct ulpt_softc *);
-int ulpt_statusmsg(u_char, struct ulpt_softc *);
 
 #if 0
 void ieee1284_print_id(char *);
@@ -197,13 +203,10 @@
 	usbd_device_handle dev = uaa->device;
 	usbd_interface_handle iface = uaa->iface;
 	usb_interface_descriptor_t *ifcd = usbd_get_interface_descriptor(iface);
-	usb_interface_descriptor_t *id, *iend;
-	usb_config_descriptor_t *cdesc;
+	usb_interface_descriptor_t *id;
 	usbd_status err;
 	char devinfo[1024];
-	usb_endpoint_descriptor_t *ed;
-	u_int8_t epcount;
-	int i, altno;
+	int altno;
 	
 	DPRINTFN(10,("ulpt_attach: sc=%p\n", sc));
 	usbd_devinfo(dev, 0, devinfo);
@@ -211,38 +214,16 @@
 	printf("%s: %s, iclass %d/%d\n", USBDEVNAME(sc->sc_dev),
 	       devinfo, ifcd->bInterfaceClass, ifcd->bInterfaceSubClass);
 
-	/* XXX 
-	 * Stepping through the alternate settings needs to be abstracted out.
-	 */
-	cdesc = usbd_get_config_descriptor(dev);
-	if (cdesc == NULL) {
-		printf("%s: failed to get configuration descriptor\n",
-		       USBDEVNAME(sc->sc_dev));
-		USB_ATTACH_ERROR_RETURN;
-	}
-	iend = (usb_interface_descriptor_t *)
-		   ((char *)cdesc + UGETW(cdesc->wTotalLength));
-#ifdef DIAGNOSTIC
-	if (ifcd < (usb_interface_descriptor_t *)cdesc ||
-	    ifcd >= iend)
-		panic("ulpt: iface desc out of range\n");
-#endif
-	/* Step through all the descriptors looking for bidir mode */
-	for (id = ifcd, altno = 0;
-	     id < iend;
-	     id = (void *)((char *)id + id->bLength)) {
-		if (id->bDescriptorType == UDESC_INTERFACE &&
-		    id->bInterfaceNumber == ifcd->bInterfaceNumber) {
-			if (id->bInterfaceClass == UICLASS_PRINTER &&
-			    id->bInterfaceSubClass == UISUBCLASS_PRINTER &&
-			    (id->bInterfaceProtocol == UIPROTO_PRINTER_BI ||
-			     id->bInterfaceProtocol == UIPROTO_PRINTER_1284))
-				goto found;
-			altno++;
-		}
-	}
-	id = ifcd;		/* not found, use original */
- found:
+	sc->sc_iface = iface;
+	sc->sc_ifaceno = id->bInterfaceNumber;
+	sc->sc_udev = dev;
+
+	err = ulpt_getdescriptbyproto(sc, UIPROTO_PRINTER_1284, &id, &altno);
+	if (err)
+		err = ulpt_getdescriptbyproto(sc, UIPROTO_PRINTER_BI,
+		    &id, &altno);
+	if (err)
+		id = ifcd;	/* not found, use original */
 	if (id != ifcd) {
 		/* Found a new bidir setting */
 		DPRINTF(("ulpt_attach: set altno = %d\n", altno));
@@ -254,28 +235,8 @@
 			USB_ATTACH_ERROR_RETURN;
 		}
 	}
-
-	epcount = 0;
-	(void)usbd_endpoint_count(iface, &epcount);
 
-	sc->sc_in = -1;
-	sc->sc_out = -1;
-	for (i = 0; i < epcount; i++) {
-		ed = usbd_interface2endpoint_descriptor(iface, i);
-		if (ed == NULL) {
-			printf("%s: couldn't get ep %d\n",
-			    USBDEVNAME(sc->sc_dev), i);
-			USB_ATTACH_ERROR_RETURN;
-		}
-		if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_IN &&
-		    UE_GET_XFERTYPE(ed->bmAttributes) == UE_BULK) {
-			sc->sc_in = ed->bEndpointAddress;
-		} else if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_OUT &&
-			   UE_GET_XFERTYPE(ed->bmAttributes) == UE_BULK) {
-			sc->sc_out = ed->bEndpointAddress;
-		}
-	}
-	if (sc->sc_out == -1) {
+	if (ulpt_primeendpoints(sc) == -1) {
 		printf("%s: could not find bulk endpoint\n",
 		    USBDEVNAME(sc->sc_dev));
 		sc->sc_dying = 1;
@@ -291,46 +252,6 @@
 
 	DPRINTFN(10, ("ulpt_attach: bulk=%d\n", sc->sc_out));
 
-	sc->sc_iface = iface;
-	sc->sc_ifaceno = id->bInterfaceNumber;
-	sc->sc_udev = dev;
-
-#if 0
-/*
- * This code is disabled because for some mysterious reason it causes
- * printing not to work.  But only sometimes, and mostly with
- * UHCI and less often with OHCI.  *sigh*
- */
-	{
-	usb_config_descriptor_t *cd = usbd_get_config_descriptor(dev);
-	usb_device_request_t req;
-	int len, alen;
-
-	req.bmRequestType = UT_READ_CLASS_INTERFACE;
-	req.bRequest = UR_GET_DEVICE_ID;
-	USETW(req.wValue, cd->bConfigurationValue);
-	USETW2(req.wIndex, id->bInterfaceNumber, id->bAlternateSetting);
-	USETW(req.wLength, sizeof devinfo - 1);
-	err = usbd_do_request_flags(dev, &req, devinfo, USBD_SHORT_XFER_OK,
-		  &alen, USBD_DEFAULT_TIMEOUT);
-	if (err) {
-		printf("%s: cannot get device id\n", USBDEVNAME(sc->sc_dev));
-	} else if (alen <= 2) {
-		printf("%s: empty device id, no printer connected?\n",
-		       USBDEVNAME(sc->sc_dev));
-	} else {
-		/* devinfo now contains an IEEE-1284 device ID */
-		len = ((devinfo[0] & 0xff) << 8) | (devinfo[1] & 0xff);
-		if (len > sizeof devinfo - 3)
-			len = sizeof devinfo - 3;
-		devinfo[len] = 0;
-		printf("%s: device id <", USBDEVNAME(sc->sc_dev));
-		ieee1284_print_id(devinfo+2);
-		printf(">\n");
-	}
-	}
-#endif
-
 #if defined(__FreeBSD__)
 	sc->dev = make_dev(&ulpt_cdevsw, device_get_unit(self),
 		UID_ROOT, GID_OPERATOR, 0644, "ulpt%d", device_get_unit(self));
@@ -338,13 +259,47 @@
 		device_get_unit(self)|ULPT_NOPRIME,
 		UID_ROOT, GID_OPERATOR, 0644, "unlpt%d", device_get_unit(self));
 #endif
-
+#ifndef __FreeBSD__
 	usbd_add_drv_event(USB_EVENT_DRIVER_ATTACH, sc->sc_udev,
 			   USBDEV(sc->sc_dev));
+#endif
 
 	USB_ATTACH_SUCCESS_RETURN;
 }
 
+
+static int
+ulpt_get_id(dev_t dev, char *buf, int length)
+{
+	struct ulpt_softc *sc;
+
+	usb_interface_descriptor_t *id;
+	usb_config_descriptor_t *cd;
+	usb_device_request_t req;
+	int err;
+
+	printf("ulpt_get_id\n");
+	USB_GET_SC(ulpt, ULPTUNIT(dev), sc);
+	
+	printf("ulpt_get_id usbd_get_config_descriptor\n");
+	cd = usbd_get_config_descriptor(sc->sc_udev);
+	printf("ulpt_get_id usbd_get_interface_descriptor\n");
+	id = usbd_get_interface_descriptor(sc->sc_iface);
+
+	req.bmRequestType = UT_READ_CLASS_INTERFACE;
+	req.bRequest = UR_GET_DEVICE_ID;
+
+	USETW(req.wValue, cd->bConfigurationValue);
+	USETW2(req.wIndex, id->bInterfaceNumber, id->bAlternateSetting);
+	USETW(req.wLength, length);
+
+	printf("ulpt_get_id usbd_do_request_flags\n");
+	err = usbd_do_request_flags(sc->sc_udev, &req, buf, USBD_SHORT_XFER_OK,
+		  &length, USBD_DEFAULT_TIMEOUT);
+	printf("ulpt_get_id returning %d\n", err);
+	return (err);
+}
+
 #if defined(__NetBSD__) || defined(__OpenBSD__)
 int
 ulpt_activate(device_ptr_t self, enum devact act)
@@ -374,7 +329,11 @@
 	struct vnode *vp;
 #endif
 
+#if defined(__NetBSD__) || defined(__OpenBSD__)
+	DPRINTF(("ulpt_detach: sc=%p flags=%d\n", sc, flags));
+#elif defined(__FreeBSD__)
 	DPRINTF(("ulpt_detach: sc=%p\n", sc));
+#endif
 
 	sc->sc_dying = 1;
 	if (sc->sc_out_pipe != NULL)
@@ -411,8 +370,10 @@
 	destroy_dev(sc->dev_noprime);
 #endif
 
+#ifndef __FreeBSD__
 	usbd_add_drv_event(USB_EVENT_DRIVER_DETACH, sc->sc_udev,
 			   USBDEV(sc->sc_dev));
+#endif
 
 	return (0);
 }
@@ -456,8 +417,12 @@
 	 */
 	req.bmRequestType = UT_WRITE_CLASS_OTHER;
 	if (usbd_do_request(sc->sc_udev, &req, 0)) {	/* 1.0 */
+		printf("UT_WRITE_CLASS_OTHER failed, "
+			"trying UT_WRITE_CLASS_INTERFACE!\n");
 		req.bmRequestType = UT_WRITE_CLASS_INTERFACE;
 		(void)usbd_do_request(sc->sc_udev, &req, 0); /* 1.1 */
+	} else {
+		printf("UT_WRITE_CLASS_OTHER ok!\n");
 	}
 }
 
@@ -484,8 +449,10 @@
 {
 	u_char flags = ULPTFLAGS(dev);
 	struct ulpt_softc *sc;
-	usbd_status err;
-	int spin, error;
+	int error;
+#if 0
+	int spin;
+#endif
 
 	USB_GET_SC_OPEN(ulpt, ULPTUNIT(dev), sc);
 
@@ -510,9 +477,11 @@
 	error = 0;
 	sc->sc_refcnt++;
 
+	printf("ulptopen: %d\n", __LINE__);
 	if ((flags & ULPT_NOPRIME) == 0)
 		ulpt_reset(sc);
-
+#if 0
+	printf("ulptopen: %d\n", __LINE__);
 	for (spin = 0; (ulpt_status(sc) & LPS_SELECT) == 0; spin += STEP) {
 		DPRINTF(("ulpt_open: waiting a while\n"));
 		if (spin >= TIMEOUT) {
@@ -534,54 +503,17 @@
 			goto done;
 		}
 	}
-
-	err = usbd_open_pipe(sc->sc_iface, sc->sc_out, 0, &sc->sc_out_pipe);
-	if (err) {
-		sc->sc_state = 0;
-		error = EIO;
-		goto done;
-	}
-	if (ulptusein && sc->sc_in != -1) {
-		DPRINTF(("ulpt_open: 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;
-		}
-		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) {
-			error = ENOMEM;
-			if (sc->sc_in_xfer1 != NULL) {
-				usbd_free_xfer(sc->sc_in_xfer1);
-				sc->sc_in_xfer1 = NULL;
-			}
-			if (sc->sc_in_xfer2 != NULL) {
-				usbd_free_xfer(sc->sc_in_xfer2);
-				sc->sc_in_xfer2 = NULL;
-			}
-			usbd_close_pipe(sc->sc_out_pipe);
-			sc->sc_out_pipe = NULL;
-			usbd_close_pipe(sc->sc_in_pipe);
-			sc->sc_in_pipe = NULL;
-			sc->sc_state = 0;
-			goto done;
-		}
-		usbd_setup_xfer(sc->sc_in_xfer1, sc->sc_in_pipe, sc,
-		    sc->sc_junk, sizeof sc->sc_junk, USBD_SHORT_XFER_OK,
-		    USBD_NO_TIMEOUT, ulpt_input);
-		usbd_setup_xfer(sc->sc_in_xfer2, sc->sc_in_pipe, sc,
-		    sc->sc_junk, sizeof sc->sc_junk, USBD_SHORT_XFER_OK,
-		    USBD_NO_TIMEOUT, ulpt_input);
-		usbd_transfer(sc->sc_in_xfer1); /* ignore failed start */
-	}
+#endif
+	printf("ulptopen: %d\n", __LINE__);
 
-	sc->sc_state = ULPT_OPEN;
+	
+	error = ulpt_openpipes(sc);
+	if (error == 0)
+		sc->sc_state = ULPT_OPEN;
 
+#if 0
  done:
+#endif
 	if (--sc->sc_refcnt < 0)
 		usb_detach_wakeup(USBDEV(sc->sc_dev));
 
@@ -614,24 +546,38 @@
 	struct ulpt_softc *sc;
 
 	USB_GET_SC(ulpt, ULPTUNIT(dev), sc);
+	return (ulpt_do_close(sc));
+}
 
-	if (sc->sc_state != ULPT_OPEN)
+int
+ulpt_do_close(struct ulpt_softc *sc)
+{
+
+	printf("ulptclose\n");
+	if (sc->sc_state != ULPT_OPEN) {
+		printf("ulptclose:%d sc_state != ULPT_OPEN\n", __LINE__);
 		/* We are being forced to close before the open completed. */
 		return (0);
+	}
 
 	if (sc->sc_out_pipe != NULL) {
+		printf("ulptclose closing out_pipe\n");
 		usbd_close_pipe(sc->sc_out_pipe);
 		sc->sc_out_pipe = NULL;
 	}
 	if (sc->sc_in_pipe != NULL) {
+		printf("ulptclose aborting in_pipe\n");
 		usbd_abort_pipe(sc->sc_in_pipe);
+		printf("ulptclose closing in_pipe\n");
 		usbd_close_pipe(sc->sc_in_pipe);
 		sc->sc_in_pipe = NULL;
 		if (sc->sc_in_xfer1 != NULL) {
+			printf("ulptclose free xfer 1\n");
 			usbd_free_xfer(sc->sc_in_xfer1);
 			sc->sc_in_xfer1 = NULL;
 		}
 		if (sc->sc_in_xfer2 != NULL) {
+			printf("ulptclose free xfer 1\n");
 			usbd_free_xfer(sc->sc_in_xfer2);
 			sc->sc_in_xfer2 = NULL;
 		}
@@ -639,6 +585,7 @@
 
 	sc->sc_state = 0;
 
+	printf("ulptclose done\n");
 	DPRINTF(("ulptclose: closed\n"));
 	return (0);
 }
@@ -701,14 +648,190 @@
 int
 ulptioctl(dev_t dev, u_long cmd, caddr_t data, int flag, usb_proc_ptr p)
 {
-	int error = 0;
+	struct ulpt_softc *sc;
+	usb_interface_descriptor_t *id, *oid;
+	char devinfo[1024];
+	int altno, len, error;
+	usbd_status err;
+	
+	error = 0;
+	USB_GET_SC(ulpt, ULPTUNIT(dev), sc);
 
 	switch (cmd) {
+	case USB_LP_GET_DEVICE_ID:
+		error = ulpt_get_id(dev, devinfo, sizeof(devinfo) - 1);
+		if (error == 0)
+			break;
+		len = ((devinfo[0] & 0xff) << 8) | (devinfo[1] & 0xff);
+		if (len > sizeof(devinfo))
+			len = sizeof(devinfo);
+		devinfo[len - 1] = '\0';
+		error = copyout(devinfo, *(char **)data, len);
+		break;
+	case USB_LP_GET_PROTOCOL:
+		id = usbd_get_interface_descriptor(sc->sc_iface);
+		*(int *)data = id->bInterfaceProtocol;
+		printf("USB_LP_GET_PROTOCOL -> %d\n", id->bInterfaceProtocol);
+		break;
+	case USB_LP_SET_PROTOCOL:
+		oid = usbd_get_interface_descriptor(sc->sc_iface);
+		error = ulpt_getdescriptbyproto(sc, *(int *)data, &id, &altno);
+		if (error) {
+			printf("ioctl, ulpt_getdescriptbyproto returned %d\n",
+			    error);
+			break;
+		}
+		if (id == oid)
+			break;
+		(void)ulpt_do_close(sc);
+		err = usbd_set_interface(sc->sc_iface, altno);
+		if (err) {
+			printf("ioctl, usbd_set_interface said: %d '%s'\n",
+			    err, usbd_errstr(err));
+			error = EINVAL;	/* map usb error to errno error */
+			break;
+		}
+		(void)ulpt_primeendpoints(sc);
+		error = ulpt_openpipes(sc);
+		if (error) {
+			printf("ioctl, ulpt_openpipes failed.\n");
+			break;
+		}
+		sc->sc_state = ULPT_OPEN;
+		sc->sc_ifaceno = id->bInterfaceNumber;
+		printf("USB_LP_SET_PROTOCOL -> %d\n", id->bInterfaceNumber);
+		break;
 	default:
 		error = ENODEV;
 	}
 
+	printf("ulpt ioctl cmd = %08lx, error = %d\n", cmd, error);
 	return (error);
+}
+
+int
+ulpt_primeendpoints(sc)
+	struct ulpt_softc *sc;
+{
+	usb_endpoint_descriptor_t *ed;
+	u_int8_t epcount;
+	int i;
+
+	epcount = 0;
+	(void)usbd_endpoint_count(sc->sc_iface, &epcount);
+
+	sc->sc_in = -1;
+	sc->sc_out = -1;
+	for (i = 0; i < epcount; i++) {
+		ed = usbd_interface2endpoint_descriptor(sc->sc_iface, i);
+		if (ed == NULL) {
+			printf("%s: couldn't get ep %d\n",
+			    USBDEVNAME(sc->sc_dev), i);
+			return (-1);
+		}
+		if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_IN &&
+		    UE_GET_XFERTYPE(ed->bmAttributes) == UE_BULK) {
+			sc->sc_in = ed->bEndpointAddress;
+		} else if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_OUT &&
+			   UE_GET_XFERTYPE(ed->bmAttributes) == UE_BULK) {
+			sc->sc_out = ed->bEndpointAddress;
+		}
+	}
+	return (sc->sc_out == -1 ? -1 : 0);
+}
+
+int
+ulpt_openpipes(sc)
+	struct ulpt_softc *sc;
+{
+	int err;
+
+	err = usbd_open_pipe(sc->sc_iface, sc->sc_out, 0, &sc->sc_out_pipe);
+	if (err) {
+		sc->sc_state = 0;
+		return (EIO);
+	}
+	printf("ulpt_openpipes: %d\n", __LINE__);
+	if (ulptusein && sc->sc_in != -1) {
+		DPRINTF(("ulpt_open: open input pipe\n"));
+		printf("ulpt_openpipes: %d\n", __LINE__);
+		err = usbd_open_pipe(sc->sc_iface, sc->sc_in, 0,
+		    &sc->sc_in_pipe);
+		if (err) {
+			usbd_close_pipe(sc->sc_out_pipe);
+			sc->sc_out_pipe = NULL;
+			sc->sc_state = 0;
+			return (EIO);
+		}
+		printf("ulpt_openpipes: %d\n", __LINE__);
+		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) {
+			if (sc->sc_in_xfer1 != NULL) {
+				usbd_free_xfer(sc->sc_in_xfer1);
+				sc->sc_in_xfer1 = NULL;
+			}
+			if (sc->sc_in_xfer2 != NULL) {
+				usbd_free_xfer(sc->sc_in_xfer2);
+				sc->sc_in_xfer2 = NULL;
+			}
+			usbd_close_pipe(sc->sc_out_pipe);
+			sc->sc_out_pipe = NULL;
+			usbd_close_pipe(sc->sc_in_pipe);
+			sc->sc_in_pipe = NULL;
+			sc->sc_state = 0;
+			return (ENOMEM);
+		}
+		printf("ulpt_openpipes: %d\n", __LINE__);
+		usbd_setup_xfer(sc->sc_in_xfer1, sc->sc_in_pipe, sc,
+		    sc->sc_junk, sizeof sc->sc_junk, USBD_SHORT_XFER_OK,
+		    USBD_NO_TIMEOUT, ulpt_input);
+		printf("ulpt_openpipes: %d\n", __LINE__);
+		usbd_setup_xfer(sc->sc_in_xfer2, sc->sc_in_pipe, sc,
+		    sc->sc_junk, sizeof sc->sc_junk, USBD_SHORT_XFER_OK,
+		    USBD_NO_TIMEOUT, ulpt_input);
+		printf("ulpt_openpipes: %d\n", __LINE__);
+		usbd_transfer(sc->sc_in_xfer1); /* ignore failed start */
+	}
+	return (0);
+}
+
+int
+ulpt_getdescriptbyproto(sc, proto, idret, altnoret)
+	struct ulpt_softc *sc;
+	int proto;
+	usb_interface_descriptor_t **idret;
+	int *altnoret;
+{
+	usb_config_descriptor_t *cdesc;
+	usb_interface_descriptor_t *id, *ifcd, *iend;
+	int altno;
+
+	ifcd = usbd_get_interface_descriptor(sc->sc_iface);
+	cdesc = usbd_get_config_descriptor(sc->sc_udev);
+	iend = (usb_interface_descriptor_t *)
+	    ((char *)cdesc + UGETW(cdesc->wTotalLength));
+
+	for (id = ifcd, altno = 0;
+	     id < iend;
+	     id = (void *)((char *)id + id->bLength)) {
+		if (id->bDescriptorType == UDESC_INTERFACE &&
+		    id->bInterfaceNumber == ifcd->bInterfaceNumber) {
+			if (id->bInterfaceClass == UICLASS_PRINTER &&
+			    id->bInterfaceSubClass == UISUBCLASS_PRINTER &&
+			    id->bInterfaceProtocol == proto)
+				goto found;
+			altno++;
+		}
+	}
+	printf("ulpt_getdescriptbyproto: couldn't find proto: %d\n", proto);
+	return (ENOENT);
+found:
+	printf("ulpt_getdescriptbyproto: found proto: %d, altno = %d\n", proto,
+	    altno);
+	*altnoret = altno;
+	*idret = id;
+	return (0);
 }
 
 #if 0
Index: usb.h
===================================================================
RCS file: /home/netcvs/syssrc/sys/dev/usb/usb.h,v
retrieving revision 1.65
diff -u -r1.65 usb.h
--- usb.h	2002/02/26 10:27:49	1.65
+++ usb.h	2002/02/27 02:58:49
@@ -672,4 +672,10 @@
 #define USB_GET_CM_OVER_DATA	_IOR ('U', 130, int)
 #define USB_SET_CM_OVER_DATA	_IOW ('U', 131, int)
 
+/* Printer device */    
+#define USB_LP_GET_DEVICE_ID	_IO ('U', 150)
+#define USB_LP_GET_PROTOCOL	_IOR ('U', 151, int)
+#define USB_LP_SET_PROTOCOL	_IOW ('U', 152, int)
+
+
 #endif /* _USB_H_ */