xref: /openbsd-src/sys/dev/usb/ulpt.c (revision 3a3fbb3f2e2521ab7c4a56b7ff7462ebd9095ec5)
1 /*	$OpenBSD: ulpt.c,v 1.9 2001/10/31 04:24:44 nate Exp $ */
2 /*	$NetBSD: ulpt.c,v 1.43 2001/10/19 15:30:25 nathanw Exp $	*/
3 /*	$FreeBSD: src/sys/dev/usb/ulpt.c,v 1.24 1999/11/17 22:33:44 n_hibma Exp $	*/
4 
5 /*
6  * Copyright (c) 1998 The NetBSD Foundation, Inc.
7  * All rights reserved.
8  *
9  * This code is derived from software contributed to The NetBSD Foundation
10  * by Lennart Augustsson (lennart@augustsson.net) at
11  * Carlstedt Research & Technology.
12  *
13  * Redistribution and use in source and binary forms, with or without
14  * modification, are permitted provided that the following conditions
15  * are met:
16  * 1. Redistributions of source code must retain the above copyright
17  *    notice, this list of conditions and the following disclaimer.
18  * 2. Redistributions in binary form must reproduce the above copyright
19  *    notice, this list of conditions and the following disclaimer in the
20  *    documentation and/or other materials provided with the distribution.
21  * 3. All advertising materials mentioning features or use of this software
22  *    must display the following acknowledgement:
23  *        This product includes software developed by the NetBSD
24  *        Foundation, Inc. and its contributors.
25  * 4. Neither the name of The NetBSD Foundation nor the names of its
26  *    contributors may be used to endorse or promote products derived
27  *    from this software without specific prior written permission.
28  *
29  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
30  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
31  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
32  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
33  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
34  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
35  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
36  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
37  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
38  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
39  * POSSIBILITY OF SUCH DAMAGE.
40  */
41 
42 /*
43  * Printer Class spec: http://www.usb.org/developers/data/devclass/usbprint11.pdf
44  */
45 
46 #include <sys/param.h>
47 #include <sys/systm.h>
48 #include <sys/proc.h>
49 #include <sys/kernel.h>
50 #if defined(__NetBSD__) || defined(__OpenBSD__)
51 #include <sys/device.h>
52 #include <sys/ioctl.h>
53 #elif defined(__FreeBSD__)
54 #include <sys/ioccom.h>
55 #include <sys/module.h>
56 #include <sys/bus.h>
57 #endif
58 #include <sys/uio.h>
59 #include <sys/conf.h>
60 #include <sys/vnode.h>
61 #include <sys/syslog.h>
62 
63 #include <dev/usb/usb.h>
64 #include <dev/usb/usbdi.h>
65 #include <dev/usb/usbdi_util.h>
66 #include <dev/usb/usbdevs.h>
67 #include <dev/usb/usb_quirks.h>
68 
69 #define	TIMEOUT		hz*16	/* wait up to 16 seconds for a ready */
70 #define	STEP		hz/4
71 
72 #define	LPTPRI		(PZERO+8)
73 #define	ULPT_BSIZE	16384
74 
75 #ifdef ULPT_DEBUG
76 #define DPRINTF(x)	if (ulptdebug) logprintf x
77 #define DPRINTFN(n,x)	if (ulptdebug>(n)) logprintf x
78 int	ulptdebug = 0;
79 #else
80 #define DPRINTF(x)
81 #define DPRINTFN(n,x)
82 #endif
83 
84 #define UR_GET_DEVICE_ID 0
85 #define UR_GET_PORT_STATUS 1
86 #define UR_SOFT_RESET 2
87 
88 #define	LPS_NERR		0x08	/* printer no error */
89 #define	LPS_SELECT		0x10	/* printer selected */
90 #define	LPS_NOPAPER		0x20	/* printer out of paper */
91 #define LPS_INVERT      (LPS_SELECT|LPS_NERR)
92 #define LPS_MASK        (LPS_SELECT|LPS_NERR|LPS_NOPAPER)
93 
94 struct ulpt_softc {
95 	USBBASEDEVICE sc_dev;
96 	usbd_device_handle sc_udev;	/* device */
97 	usbd_interface_handle sc_iface;	/* interface */
98 	int sc_ifaceno;
99 
100 	int sc_out;
101 	usbd_pipe_handle sc_out_pipe;	/* bulk out pipe */
102 
103 	int sc_in;
104 	usbd_pipe_handle sc_in_pipe;	/* bulk in pipe */
105 	usbd_xfer_handle sc_in_xfer1;
106 	usbd_xfer_handle sc_in_xfer2;
107 	u_char sc_junk[64];	/* somewhere to dump input */
108 
109 	u_char sc_state;
110 #define	ULPT_OPEN	0x01	/* device is open */
111 #define	ULPT_OBUSY	0x02	/* printer is busy doing output */
112 #define	ULPT_INIT	0x04	/* waiting to initialize for open */
113 	u_char sc_flags;
114 #define	ULPT_NOPRIME	0x40	/* don't prime on open */
115 	u_char sc_laststatus;
116 
117 	int sc_refcnt;
118 	u_char sc_dying;
119 
120 #if defined(__FreeBSD__)
121 	dev_t dev;
122 	dev_t dev_noprime;
123 #endif
124 };
125 
126 #if defined(__NetBSD__) || defined(__OpenBSD__)
127 cdev_decl(ulpt);
128 #elif defined(__FreeBSD__)
129 Static d_open_t ulptopen;
130 Static d_close_t ulptclose;
131 Static d_write_t ulptwrite;
132 Static d_ioctl_t ulptioctl;
133 
134 #define ULPT_CDEV_MAJOR 113
135 
136 Static struct cdevsw ulpt_cdevsw = {
137 	/* open */	ulptopen,
138 	/* close */	ulptclose,
139 	/* read */	noread,
140 	/* write */	ulptwrite,
141 	/* ioctl */	ulptioctl,
142 	/* poll */	nopoll,
143 	/* mmap */	nommap,
144 	/* strategy */	nostrategy,
145 	/* name */	"ulpt",
146 	/* maj */	ULPT_CDEV_MAJOR,
147 	/* dump */	nodump,
148 	/* psize */	nopsize,
149 	/* flags */	0,
150 	/* bmaj */	-1
151 };
152 #endif
153 
154 void ulpt_disco(void *);
155 
156 int ulpt_do_write(struct ulpt_softc *, struct uio *uio, int);
157 int ulpt_status(struct ulpt_softc *);
158 void ulpt_reset(struct ulpt_softc *);
159 int ulpt_statusmsg(u_char, struct ulpt_softc *);
160 
161 #if 0
162 void ieee1284_print_id(char *);
163 #endif
164 
165 #define	ULPTUNIT(s)	(minor(s) & 0x1f)
166 #define	ULPTFLAGS(s)	(minor(s) & 0xe0)
167 
168 
169 USB_DECLARE_DRIVER(ulpt);
170 
171 USB_MATCH(ulpt)
172 {
173 	USB_MATCH_START(ulpt, uaa);
174 	usb_interface_descriptor_t *id;
175 
176 	DPRINTFN(10,("ulpt_match\n"));
177 	if (uaa->iface == NULL)
178 		return (UMATCH_NONE);
179 	id = usbd_get_interface_descriptor(uaa->iface);
180 	if (id != NULL &&
181 	    id->bInterfaceClass == UICLASS_PRINTER &&
182 	    id->bInterfaceSubClass == UISUBCLASS_PRINTER &&
183 	    ((id->bInterfaceProtocol == UIPROTO_PRINTER_UNI) ||
184 	     (id->bInterfaceProtocol == UIPROTO_PRINTER_BI) ||
185 	     (id->bInterfaceProtocol == UIPROTO_PRINTER_1284)))
186 		return (UMATCH_IFACECLASS_IFACESUBCLASS_IFACEPROTO);
187 	return (UMATCH_NONE);
188 }
189 
190 USB_ATTACH(ulpt)
191 {
192 	USB_ATTACH_START(ulpt, sc, uaa);
193 	usbd_device_handle dev = uaa->device;
194 	usbd_interface_handle iface = uaa->iface;
195 	usb_interface_descriptor_t *ifcd = usbd_get_interface_descriptor(iface);
196 	usb_interface_descriptor_t *id, *iend;
197 	usb_config_descriptor_t *cdesc;
198 	usbd_status err;
199 	char devinfo[1024];
200 	usb_endpoint_descriptor_t *ed;
201 	u_int8_t epcount;
202 	int i, altno;
203 
204 	DPRINTFN(10,("ulpt_attach: sc=%p\n", sc));
205 	usbd_devinfo(dev, 0, devinfo);
206 	USB_ATTACH_SETUP;
207 	printf("%s: %s, iclass %d/%d\n", USBDEVNAME(sc->sc_dev),
208 	       devinfo, ifcd->bInterfaceClass, ifcd->bInterfaceSubClass);
209 
210 	/* XXX
211 	 * Stepping through the alternate settings needs to be abstracted out.
212 	 */
213 	cdesc = usbd_get_config_descriptor(dev);
214 	if (cdesc == NULL) {
215 		printf("%s: failed to get configuration descriptor\n",
216 		       USBDEVNAME(sc->sc_dev));
217 		USB_ATTACH_ERROR_RETURN;
218 	}
219 	iend = (usb_interface_descriptor_t *)
220 		   ((char *)cdesc + UGETW(cdesc->wTotalLength));
221 #ifdef DIAGNOSTIC
222 	if (ifcd < (usb_interface_descriptor_t *)cdesc ||
223 	    ifcd >= iend)
224 		panic("ulpt: iface desc out of range\n");
225 #endif
226 	/* Step through all the descriptors looking for bidir mode */
227 	for (id = ifcd, altno = 0;
228 	     id < iend;
229 	     id = (void *)((char *)id + id->bLength)) {
230 		if (id->bDescriptorType == UDESC_INTERFACE &&
231 		    id->bInterfaceNumber == ifcd->bInterfaceNumber) {
232 			if (id->bInterfaceClass == UICLASS_PRINTER &&
233 			    id->bInterfaceSubClass == UISUBCLASS_PRINTER &&
234 			    (id->bInterfaceProtocol == UIPROTO_PRINTER_BI ||
235 			     id->bInterfaceProtocol == UIPROTO_PRINTER_1284))
236 				goto found;
237 			altno++;
238 		}
239 	}
240 	id = ifcd;		/* not found, use original */
241  found:
242 	if (id != ifcd) {
243 		/* Found a new bidir setting */
244 		DPRINTF(("ulpt_attach: set altno = %d\n", altno));
245 		err = usbd_set_interface(iface, altno);
246 		if (err) {
247 			printf("%s: setting alternate interface failed\n",
248 			       USBDEVNAME(sc->sc_dev));
249 			sc->sc_dying = 1;
250 			USB_ATTACH_ERROR_RETURN;
251 		}
252 	}
253 
254 	epcount = 0;
255 	(void)usbd_endpoint_count(iface, &epcount);
256 
257 	sc->sc_in = -1;
258 	sc->sc_out = -1;
259 	for (i = 0; i < epcount; i++) {
260 		ed = usbd_interface2endpoint_descriptor(iface, i);
261 		if (ed == NULL) {
262 			printf("%s: couldn't get ep %d\n",
263 			    USBDEVNAME(sc->sc_dev), i);
264 			USB_ATTACH_ERROR_RETURN;
265 		}
266 		if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_IN &&
267 		    UE_GET_XFERTYPE(ed->bmAttributes) == UE_BULK) {
268 			sc->sc_in = ed->bEndpointAddress;
269 		} else if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_OUT &&
270 			   UE_GET_XFERTYPE(ed->bmAttributes) == UE_BULK) {
271 			sc->sc_out = ed->bEndpointAddress;
272 		}
273 	}
274 	if (sc->sc_out == -1) {
275 		printf("%s: could not find bulk endpoint\n",
276 		    USBDEVNAME(sc->sc_dev));
277 		sc->sc_dying = 1;
278 		USB_ATTACH_ERROR_RETURN;
279 	}
280 	printf("%s: using %s-directional mode\n", USBDEVNAME(sc->sc_dev),
281 	       sc->sc_in >= 0 ? "bi" : "uni");
282 
283 	if (usbd_get_quirks(dev)->uq_flags & UQ_BROKEN_BIDIR) {
284 		/* This device doesn't handle reading properly. */
285 		sc->sc_in = -1;
286 	}
287 
288 	DPRINTFN(10, ("ulpt_attach: bulk=%d\n", sc->sc_out));
289 
290 	sc->sc_iface = iface;
291 	sc->sc_ifaceno = id->bInterfaceNumber;
292 	sc->sc_udev = dev;
293 
294 #if 0
295 /*
296  * This code is disabled because for some mysterious reason it causes
297  * printing not to work.  But only sometimes, and mostly with
298  * UHCI and less often with OHCI.  *sigh*
299  */
300 	{
301 	usb_config_descriptor_t *cd = usbd_get_config_descriptor(dev);
302 	usb_device_request_t req;
303 	int len, alen;
304 
305 	req.bmRequestType = UT_READ_CLASS_INTERFACE;
306 	req.bRequest = UR_GET_DEVICE_ID;
307 	USETW(req.wValue, cd->bConfigurationValue);
308 	USETW2(req.wIndex, id->bInterfaceNumber, id->bAlternateSetting);
309 	USETW(req.wLength, sizeof devinfo - 1);
310 	err = usbd_do_request_flags(dev, &req, devinfo,USBD_SHORT_XFER_OK,
311 		  &alen);
312 	if (err) {
313 		printf("%s: cannot get device id\n", USBDEVNAME(sc->sc_dev));
314 	} else if (alen <= 2) {
315 		printf("%s: empty device id, no printer connected?\n",
316 		       USBDEVNAME(sc->sc_dev));
317 	} else {
318 		/* devinfo now contains an IEEE-1284 device ID */
319 		len = ((devinfo[0] & 0xff) << 8) | (devinfo[1] & 0xff);
320 		if (len > sizeof devinfo - 3)
321 			len = sizeof devinfo - 3;
322 		devinfo[len] = 0;
323 		printf("%s: device id <", USBDEVNAME(sc->sc_dev));
324 		ieee1284_print_id(devinfo+2);
325 		printf(">\n");
326 	}
327 	}
328 #endif
329 
330 #if defined(__FreeBSD__)
331 	sc->dev = make_dev(&ulpt_cdevsw, device_get_unit(self),
332 		UID_ROOT, GID_OPERATOR, 0644, "ulpt%d", device_get_unit(self));
333 	sc->dev_noprime = make_dev(&ulpt_cdevsw,
334 		device_get_unit(self)|ULPT_NOPRIME,
335 		UID_ROOT, GID_OPERATOR, 0644, "unlpt%d", device_get_unit(self));
336 #endif
337 
338 	usbd_add_drv_event(USB_EVENT_DRIVER_ATTACH, sc->sc_udev,
339 			   USBDEV(sc->sc_dev));
340 
341 	USB_ATTACH_SUCCESS_RETURN;
342 }
343 
344 #if defined(__NetBSD__) || defined(__OpenBSD__)
345 int
346 ulpt_activate(device_ptr_t self, enum devact act)
347 {
348 	struct ulpt_softc *sc = (struct ulpt_softc *)self;
349 
350 	switch (act) {
351 	case DVACT_ACTIVATE:
352 		return (EOPNOTSUPP);
353 		break;
354 
355 	case DVACT_DEACTIVATE:
356 		sc->sc_dying = 1;
357 		break;
358 	}
359 	return (0);
360 }
361 #endif
362 
363 USB_DETACH(ulpt)
364 {
365 	USB_DETACH_START(ulpt, sc);
366 	int s;
367 #if defined(__NetBSD__) || defined(__OpenBSD__)
368 	int maj, mn;
369 
370 	DPRINTF(("ulpt_detach: sc=%p flags=%d\n", sc, flags));
371 #elif defined(__FreeBSD__)
372 	DPRINTF(("ulpt_detach: sc=%p\n", sc));
373 #endif
374 
375 	sc->sc_dying = 1;
376 	if (sc->sc_out_pipe != NULL)
377 		usbd_abort_pipe(sc->sc_out_pipe);
378 	if (sc->sc_in_pipe != NULL)
379 		usbd_abort_pipe(sc->sc_in_pipe);
380 
381 	s = splusb();
382 	if (--sc->sc_refcnt >= 0) {
383 		/* There is noone to wake, aborting the pipe is enough */
384 		/* Wait for processes to go away. */
385 		usb_detach_wait(USBDEV(sc->sc_dev));
386 	}
387 	splx(s);
388 
389 #if defined(__NetBSD__) || defined(__OpenBSD__)
390 	/* locate the major number */
391 	for (maj = 0; maj < nchrdev; maj++)
392 		if (cdevsw[maj].d_open == ulptopen)
393 			break;
394 
395 	/* Nuke the vnodes for any open instances (calls close). */
396 	mn = self->dv_unit;
397 	vdevgone(maj, mn, mn, VCHR);
398 #elif defined(__FreeBSD__)
399 	/* XXX not implemented yet */
400 
401 	destroy_dev(sc->dev);
402 	destroy_dev(sc->dev_noprime);
403 #endif
404 
405 	usbd_add_drv_event(USB_EVENT_DRIVER_DETACH, sc->sc_udev,
406 			   USBDEV(sc->sc_dev));
407 
408 	return (0);
409 }
410 
411 int
412 ulpt_status(struct ulpt_softc *sc)
413 {
414 	usb_device_request_t req;
415 	usbd_status err;
416 	u_char status;
417 
418 	req.bmRequestType = UT_READ_CLASS_INTERFACE;
419 	req.bRequest = UR_GET_PORT_STATUS;
420 	USETW(req.wValue, 0);
421 	USETW(req.wIndex, sc->sc_ifaceno);
422 	USETW(req.wLength, 1);
423 	err = usbd_do_request(sc->sc_udev, &req, &status);
424 	DPRINTFN(1, ("ulpt_status: status=0x%02x err=%d\n", status, err));
425 	if (!err)
426 		return (status);
427 	else
428 		return (0);
429 }
430 
431 void
432 ulpt_reset(struct ulpt_softc *sc)
433 {
434 	usb_device_request_t req;
435 
436 	DPRINTFN(1, ("ulpt_reset\n"));
437 	req.bmRequestType = UT_WRITE_CLASS_OTHER;
438 	req.bRequest = UR_SOFT_RESET;
439 	USETW(req.wValue, 0);
440 	USETW(req.wIndex, sc->sc_ifaceno);
441 	USETW(req.wLength, 0);
442 
443 	/*
444 	 * There was a mistake in the USB printer 1.0 spec that gave the
445 	 * request type as UT_WRITE_CLASS_OTHER; it should have been
446 	 * UT_WRITE_CLASS_INTERFACE.  Many printers use the old one,
447 	 * so we try both.
448 	 */
449 	if (usbd_do_request(sc->sc_udev, &req, 0)) {	/* 1.0 */
450 		req.bmRequestType = UT_WRITE_CLASS_INTERFACE;
451 		(void)usbd_do_request(sc->sc_udev, &req, 0); /* 1.1 */
452 	}
453 }
454 
455 static void
456 ulpt_input(usbd_xfer_handle xfer, usbd_private_handle priv, usbd_status status)
457 {
458 	struct ulpt_softc *sc = priv;
459 
460 	DPRINTFN(2,("ulpt_input: got some data\n"));
461 	/* Do it again. */
462 	if (xfer == sc->sc_in_xfer1)
463 		usbd_transfer(sc->sc_in_xfer2);
464 	else
465 		usbd_transfer(sc->sc_in_xfer1);
466 }
467 
468 int ulptusein = 1;
469 
470 /*
471  * Reset the printer, then wait until it's selected and not busy.
472  */
473 int
474 ulptopen(dev_t dev, int flag, int mode, struct proc *p)
475 {
476 	u_char flags = ULPTFLAGS(dev);
477 	struct ulpt_softc *sc;
478 	usbd_status err;
479 	int spin, error;
480 
481 	USB_GET_SC_OPEN(ulpt, ULPTUNIT(dev), sc);
482 
483 	if (sc == NULL || sc->sc_iface == NULL || sc->sc_dying)
484 		return (ENXIO);
485 
486 	if (sc->sc_state)
487 		return (EBUSY);
488 
489 	sc->sc_state = ULPT_INIT;
490 	sc->sc_flags = flags;
491 	DPRINTF(("ulptopen: flags=0x%x\n", (unsigned)flags));
492 
493 #if defined(ULPT_DEBUG) && defined(__FreeBSD__)
494 	/* Ignoring these flags might not be a good idea */
495 	if ((flags & ~ULPT_NOPRIME) != 0)
496 		printf("ulptopen: flags ignored: %b\n", flags,
497 			"\20\3POS_INIT\4POS_ACK\6PRIME_OPEN\7AUTOLF\10BYPASS");
498 #endif
499 
500 
501 	error = 0;
502 	sc->sc_refcnt++;
503 
504 	if ((flags & ULPT_NOPRIME) == 0)
505 		ulpt_reset(sc);
506 
507 	for (spin = 0; (ulpt_status(sc) & LPS_SELECT) == 0; spin += STEP) {
508 		DPRINTF(("ulpt_open: waiting a while\n"));
509 		if (spin >= TIMEOUT) {
510 			error = EBUSY;
511 			sc->sc_state = 0;
512 			goto done;
513 		}
514 
515 		/* wait 1/4 second, give up if we get a signal */
516 		error = tsleep((caddr_t)sc, LPTPRI | PCATCH, "ulptop", STEP);
517 		if (error != EWOULDBLOCK) {
518 			sc->sc_state = 0;
519 			goto done;
520 		}
521 
522 		if (sc->sc_dying) {
523 			error = ENXIO;
524 			sc->sc_state = 0;
525 			goto done;
526 		}
527 	}
528 
529 	err = usbd_open_pipe(sc->sc_iface, sc->sc_out, 0, &sc->sc_out_pipe);
530 	if (err) {
531 		sc->sc_state = 0;
532 		error = EIO;
533 		goto done;
534 	}
535 	if (ulptusein && sc->sc_in != -1) {
536 		DPRINTF(("ulpt_open: open input pipe\n"));
537 		err = usbd_open_pipe(sc->sc_iface, sc->sc_in,0,&sc->sc_in_pipe);
538 		if (err) {
539 			error = EIO;
540 			usbd_close_pipe(sc->sc_out_pipe);
541 			sc->sc_out_pipe = NULL;
542 			sc->sc_state = 0;
543 			goto done;
544 		}
545 		sc->sc_in_xfer1 = usbd_alloc_xfer(sc->sc_udev);
546 		sc->sc_in_xfer2 = usbd_alloc_xfer(sc->sc_udev);
547 		if (sc->sc_in_xfer1 == NULL || sc->sc_in_xfer2 == NULL) {
548 			error = ENOMEM;
549 			usbd_close_pipe(sc->sc_out_pipe);
550 			sc->sc_out_pipe = NULL;
551 			sc->sc_state = 0;
552 			goto done;
553 		}
554 		usbd_setup_xfer(sc->sc_in_xfer1, sc->sc_in_pipe, sc,
555 		    sc->sc_junk, sizeof sc->sc_junk, USBD_SHORT_XFER_OK,
556 		    USBD_NO_TIMEOUT, ulpt_input);
557 		usbd_setup_xfer(sc->sc_in_xfer2, sc->sc_in_pipe, sc,
558 		    sc->sc_junk, sizeof sc->sc_junk, USBD_SHORT_XFER_OK,
559 		    USBD_NO_TIMEOUT, ulpt_input);
560 		usbd_transfer(sc->sc_in_xfer1); /* ignore failed start */
561 	}
562 
563 	sc->sc_state = ULPT_OPEN;
564 
565  done:
566 	if (--sc->sc_refcnt < 0)
567 		usb_detach_wakeup(USBDEV(sc->sc_dev));
568 
569 	DPRINTF(("ulptopen: done, error=%d\n", error));
570 	return (error);
571 }
572 
573 int
574 ulpt_statusmsg(u_char status, struct ulpt_softc *sc)
575 {
576 	u_char new;
577 
578 	status = (status ^ LPS_INVERT) & LPS_MASK;
579 	new = status & ~sc->sc_laststatus;
580 	sc->sc_laststatus = status;
581 
582 	if (new & LPS_SELECT)
583 		log(LOG_NOTICE, "%s: offline\n", USBDEVNAME(sc->sc_dev));
584 	else if (new & LPS_NOPAPER)
585 		log(LOG_NOTICE, "%s: out of paper\n", USBDEVNAME(sc->sc_dev));
586 	else if (new & LPS_NERR)
587 		log(LOG_NOTICE, "%s: output error\n", USBDEVNAME(sc->sc_dev));
588 
589 	return (status);
590 }
591 
592 int
593 ulptclose(dev_t dev, int flag, int mode, struct proc *p)
594 {
595 	struct ulpt_softc *sc;
596 
597 	USB_GET_SC(ulpt, ULPTUNIT(dev), sc);
598 
599 	if (sc->sc_state != ULPT_OPEN)
600 		/* We are being forced to close before the open completed. */
601 		return (0);
602 
603 	if (sc->sc_out_pipe != NULL) {
604 		usbd_close_pipe(sc->sc_out_pipe);
605 		sc->sc_out_pipe = NULL;
606 	}
607 	if (sc->sc_in_pipe != NULL) {
608 		usbd_abort_pipe(sc->sc_in_pipe);
609 		usbd_close_pipe(sc->sc_in_pipe);
610 		sc->sc_in_pipe = NULL;
611 		if (sc->sc_in_xfer1 != NULL) {
612 			usbd_free_xfer(sc->sc_in_xfer1);
613 			sc->sc_in_xfer1 = NULL;
614 		}
615 		if (sc->sc_in_xfer2 != NULL) {
616 			usbd_free_xfer(sc->sc_in_xfer2);
617 			sc->sc_in_xfer2 = NULL;
618 		}
619 	}
620 
621 	sc->sc_state = 0;
622 
623 	DPRINTF(("ulptclose: closed\n"));
624 	return (0);
625 }
626 
627 int
628 ulpt_do_write(struct ulpt_softc *sc, struct uio *uio, int flags)
629 {
630 	u_int32_t n;
631 	int error = 0;
632 	void *bufp;
633 	usbd_xfer_handle xfer;
634 	usbd_status err;
635 
636 	DPRINTF(("ulptwrite\n"));
637 	xfer = usbd_alloc_xfer(sc->sc_udev);
638 	if (xfer == NULL)
639 		return (ENOMEM);
640 	bufp = usbd_alloc_buffer(xfer, ULPT_BSIZE);
641 	if (bufp == NULL) {
642 		usbd_free_xfer(xfer);
643 		return (ENOMEM);
644 	}
645 	while ((n = min(ULPT_BSIZE, uio->uio_resid)) != 0) {
646 		ulpt_statusmsg(ulpt_status(sc), sc);
647 		error = uiomove(bufp, n, uio);
648 		if (error)
649 			break;
650 		DPRINTFN(1, ("ulptwrite: transfer %d bytes\n", n));
651 		err = usbd_bulk_transfer(xfer, sc->sc_out_pipe, USBD_NO_COPY,
652 			  USBD_NO_TIMEOUT, bufp, &n, "ulptwr");
653 		if (err) {
654 			DPRINTF(("ulptwrite: error=%d\n", err));
655 			error = EIO;
656 			break;
657 		}
658 	}
659 	usbd_free_xfer(xfer);
660 
661 	return (error);
662 }
663 
664 int
665 ulptwrite(dev_t dev, struct uio *uio, int flags)
666 {
667 	struct ulpt_softc *sc;
668 	int error;
669 
670 	USB_GET_SC(ulpt, ULPTUNIT(dev), sc);
671 
672 	if (sc->sc_dying)
673 		return (EIO);
674 
675 	sc->sc_refcnt++;
676 	error = ulpt_do_write(sc, uio, flags);
677 	if (--sc->sc_refcnt < 0)
678 		usb_detach_wakeup(USBDEV(sc->sc_dev));
679 	return (error);
680 }
681 
682 int
683 ulptioctl(dev_t dev, u_long cmd, caddr_t data, int flag, struct proc *p)
684 {
685 	int error = 0;
686 
687 	switch (cmd) {
688 	default:
689 		error = ENODEV;
690 	}
691 
692 	return (error);
693 }
694 
695 #if 0
696 /* XXX This does not belong here. */
697 /*
698  * Print select parts of a IEEE 1284 device ID.
699  */
700 void
701 ieee1284_print_id(char *str)
702 {
703 	char *p, *q;
704 
705 	for (p = str-1; p; p = strchr(p, ';')) {
706 		p++;		/* skip ';' */
707 		if (strncmp(p, "MFG:", 4) == 0 ||
708 		    strncmp(p, "MANUFACTURER:", 14) == 0 ||
709 		    strncmp(p, "MDL:", 4) == 0 ||
710 		    strncmp(p, "MODEL:", 6) == 0) {
711 			q = strchr(p, ';');
712 			if (q)
713 				printf("%.*s", (int)(q - p + 1), p);
714 		}
715 	}
716 }
717 #endif
718 
719 #if defined(__FreeBSD__)
720 DRIVER_MODULE(ulpt, uhub, ulpt_driver, ulpt_devclass, usbd_driver_load, 0);
721 #endif
722