1#include <sys/cdefs.h>
2/*	$NetBSD: ulpt.c,v 1.60 2003/10/04 21:19:50 augustss Exp $	*/
3
4/*-
5 * SPDX-License-Identifier: BSD-2-Clause
6 *
7 * Copyright (c) 1998, 2003 The NetBSD Foundation, Inc.
8 * All rights reserved.
9 *
10 * This code is derived from software contributed to The NetBSD Foundation
11 * by Lennart Augustsson (lennart@augustsson.net) at
12 * Carlstedt Research & Technology.
13 *
14 * Redistribution and use in source and binary forms, with or without
15 * modification, are permitted provided that the following conditions
16 * are met:
17 * 1. Redistributions of source code must retain the above copyright
18 *    notice, this list of conditions and the following disclaimer.
19 * 2. Redistributions in binary form must reproduce the above copyright
20 *    notice, this list of conditions and the following disclaimer in the
21 *    documentation and/or other materials provided with the distribution.
22 *
23 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
24 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
25 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
26 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
27 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
28 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
29 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
30 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
31 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
32 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
33 * POSSIBILITY OF SUCH DAMAGE.
34 */
35
36/*
37 * Printer Class spec: http://www.usb.org/developers/data/devclass/usbprint109.PDF
38 * Printer Class spec: http://www.usb.org/developers/devclass_docs/usbprint11.pdf
39 */
40
41#include <sys/stdint.h>
42#include <sys/stddef.h>
43#include <sys/param.h>
44#include <sys/queue.h>
45#include <sys/types.h>
46#include <sys/systm.h>
47#include <sys/kernel.h>
48#include <sys/bus.h>
49#include <sys/module.h>
50#include <sys/lock.h>
51#include <sys/mutex.h>
52#include <sys/condvar.h>
53#include <sys/sysctl.h>
54#include <sys/sx.h>
55#include <sys/unistd.h>
56#include <sys/callout.h>
57#include <sys/malloc.h>
58#include <sys/priv.h>
59#include <sys/syslog.h>
60#include <sys/selinfo.h>
61#include <sys/conf.h>
62#include <sys/fcntl.h>
63
64#include <dev/usb/usb.h>
65#include <dev/usb/usbdi.h>
66#include <dev/usb/usbdi_util.h>
67#include <dev/usb/usbhid.h>
68#include "usbdevs.h"
69
70#define	USB_DEBUG_VAR ulpt_debug
71#include <dev/usb/usb_debug.h>
72#include <dev/usb/usb_process.h>
73
74#ifdef USB_DEBUG
75static int ulpt_debug = 0;
76
77static SYSCTL_NODE(_hw_usb, OID_AUTO, ulpt, CTLFLAG_RW | CTLFLAG_MPSAFE, 0,
78    "USB ulpt");
79SYSCTL_INT(_hw_usb_ulpt, OID_AUTO, debug, CTLFLAG_RWTUN,
80    &ulpt_debug, 0, "Debug level");
81#endif
82
83#define	ULPT_BSIZE		(1<<15)	/* bytes */
84#define	ULPT_IFQ_MAXLEN         2	/* units */
85
86#define	UR_GET_DEVICE_ID        0x00
87#define	UR_GET_PORT_STATUS      0x01
88#define	UR_SOFT_RESET           0x02
89
90#define	LPS_NERR		0x08	/* printer no error */
91#define	LPS_SELECT		0x10	/* printer selected */
92#define	LPS_NOPAPER		0x20	/* printer out of paper */
93#define	LPS_INVERT      (LPS_SELECT|LPS_NERR)
94#define	LPS_MASK        (LPS_SELECT|LPS_NERR|LPS_NOPAPER)
95
96enum {
97	ULPT_BULK_DT_WR,
98	ULPT_BULK_DT_RD,
99	ULPT_INTR_DT_RD,
100	ULPT_N_TRANSFER,
101};
102
103struct ulpt_softc {
104	struct usb_fifo_sc sc_fifo;
105	struct usb_fifo_sc sc_fifo_noreset;
106	struct mtx sc_mtx;
107	struct usb_callout sc_watchdog;
108
109	device_t sc_dev;
110	struct usb_device *sc_udev;
111	struct usb_fifo *sc_fifo_open[2];
112	struct usb_xfer *sc_xfer[ULPT_N_TRANSFER];
113
114	int	sc_fflags;		/* current open flags, FREAD and
115					 * FWRITE */
116	uint8_t	sc_iface_no;
117	uint8_t	sc_last_status;
118	uint8_t	sc_zlps;		/* number of consequtive zero length
119					 * packets received */
120};
121
122/* prototypes */
123
124static device_probe_t ulpt_probe;
125static device_attach_t ulpt_attach;
126static device_detach_t ulpt_detach;
127
128static usb_callback_t ulpt_write_callback;
129static usb_callback_t ulpt_read_callback;
130static usb_callback_t ulpt_status_callback;
131
132static void	ulpt_reset(struct ulpt_softc *);
133static void	ulpt_watchdog(void *);
134
135static usb_fifo_close_t ulpt_close;
136static usb_fifo_cmd_t ulpt_start_read;
137static usb_fifo_cmd_t ulpt_start_write;
138static usb_fifo_cmd_t ulpt_stop_read;
139static usb_fifo_cmd_t ulpt_stop_write;
140static usb_fifo_ioctl_t ulpt_ioctl;
141static usb_fifo_open_t ulpt_open;
142static usb_fifo_open_t unlpt_open;
143
144static struct usb_fifo_methods ulpt_fifo_methods = {
145	.f_close = &ulpt_close,
146	.f_ioctl = &ulpt_ioctl,
147	.f_open = &ulpt_open,
148	.f_start_read = &ulpt_start_read,
149	.f_start_write = &ulpt_start_write,
150	.f_stop_read = &ulpt_stop_read,
151	.f_stop_write = &ulpt_stop_write,
152	.basename[0] = "ulpt",
153};
154
155static struct usb_fifo_methods unlpt_fifo_methods = {
156	.f_close = &ulpt_close,
157	.f_ioctl = &ulpt_ioctl,
158	.f_open = &unlpt_open,
159	.f_start_read = &ulpt_start_read,
160	.f_start_write = &ulpt_start_write,
161	.f_stop_read = &ulpt_stop_read,
162	.f_stop_write = &ulpt_stop_write,
163	.basename[0] = "unlpt",
164};
165
166static void
167ulpt_reset(struct ulpt_softc *sc)
168{
169	struct usb_device_request req;
170
171	DPRINTFN(2, "\n");
172
173	req.bRequest = UR_SOFT_RESET;
174	USETW(req.wValue, 0);
175	USETW(req.wIndex, sc->sc_iface_no);
176	USETW(req.wLength, 0);
177
178	/*
179	 * There was a mistake in the USB printer 1.0 spec that gave the
180	 * request type as UT_WRITE_CLASS_OTHER; it should have been
181	 * UT_WRITE_CLASS_INTERFACE.  Many printers use the old one,
182	 * so we try both.
183	 */
184
185	mtx_lock(&sc->sc_mtx);
186	req.bmRequestType = UT_WRITE_CLASS_OTHER;
187	if (usbd_do_request_flags(sc->sc_udev, &sc->sc_mtx,
188	    &req, NULL, 0, NULL, 2 * USB_MS_HZ)) {	/* 1.0 */
189		req.bmRequestType = UT_WRITE_CLASS_INTERFACE;
190		if (usbd_do_request_flags(sc->sc_udev, &sc->sc_mtx,
191		    &req, NULL, 0, NULL, 2 * USB_MS_HZ)) {	/* 1.1 */
192			/* ignore error */
193		}
194	}
195	mtx_unlock(&sc->sc_mtx);
196}
197
198static void
199ulpt_write_callback(struct usb_xfer *xfer, usb_error_t error)
200{
201	struct ulpt_softc *sc = usbd_xfer_softc(xfer);
202	struct usb_fifo *f = sc->sc_fifo_open[USB_FIFO_TX];
203	struct usb_page_cache *pc;
204	int actlen, max;
205
206	usbd_xfer_status(xfer, &actlen, NULL, NULL, NULL);
207
208	if (f == NULL) {
209		/* should not happen */
210		DPRINTF("no FIFO\n");
211		return;
212	}
213	DPRINTF("state=0x%x actlen=%d\n", USB_GET_STATE(xfer), actlen);
214
215	switch (USB_GET_STATE(xfer)) {
216	case USB_ST_TRANSFERRED:
217	case USB_ST_SETUP:
218tr_setup:
219		pc = usbd_xfer_get_frame(xfer, 0);
220		max = usbd_xfer_max_len(xfer);
221		if (usb_fifo_get_data(f, pc, 0, max, &actlen, 0)) {
222			usbd_xfer_set_frame_len(xfer, 0, actlen);
223			usbd_transfer_submit(xfer);
224		}
225		break;
226
227	default:			/* Error */
228		if (error != USB_ERR_CANCELLED) {
229			/* try to clear stall first */
230			usbd_xfer_set_stall(xfer);
231			goto tr_setup;
232		}
233		break;
234	}
235}
236
237static void
238ulpt_read_callback(struct usb_xfer *xfer, usb_error_t error)
239{
240	struct ulpt_softc *sc = usbd_xfer_softc(xfer);
241	struct usb_fifo *f = sc->sc_fifo_open[USB_FIFO_RX];
242	struct usb_page_cache *pc;
243	int actlen;
244
245	usbd_xfer_status(xfer, &actlen, NULL, NULL, NULL);
246
247	if (f == NULL) {
248		/* should not happen */
249		DPRINTF("no FIFO\n");
250		return;
251	}
252	DPRINTF("state=0x%x\n", USB_GET_STATE(xfer));
253
254	switch (USB_GET_STATE(xfer)) {
255	case USB_ST_TRANSFERRED:
256
257		if (actlen == 0) {
258			if (sc->sc_zlps == 4) {
259				/* enable BULK throttle */
260				usbd_xfer_set_interval(xfer, 500); /* ms */
261			} else {
262				sc->sc_zlps++;
263			}
264		} else {
265			/* disable BULK throttle */
266
267			usbd_xfer_set_interval(xfer, 0);
268			sc->sc_zlps = 0;
269		}
270
271		pc = usbd_xfer_get_frame(xfer, 0);
272		usb_fifo_put_data(f, pc, 0, actlen, 1);
273
274	case USB_ST_SETUP:
275tr_setup:
276		if (usb_fifo_put_bytes_max(f) != 0) {
277			usbd_xfer_set_frame_len(xfer, 0, usbd_xfer_max_len(xfer));
278			usbd_transfer_submit(xfer);
279		}
280		break;
281
282	default:			/* Error */
283		/* disable BULK throttle */
284		usbd_xfer_set_interval(xfer, 0);
285		sc->sc_zlps = 0;
286
287		if (error != USB_ERR_CANCELLED) {
288			/* try to clear stall first */
289			usbd_xfer_set_stall(xfer);
290			goto tr_setup;
291		}
292		break;
293	}
294}
295
296static void
297ulpt_status_callback(struct usb_xfer *xfer, usb_error_t error)
298{
299	struct ulpt_softc *sc = usbd_xfer_softc(xfer);
300	struct usb_device_request req;
301	struct usb_page_cache *pc;
302	uint8_t cur_status;
303	uint8_t new_status;
304
305	switch (USB_GET_STATE(xfer)) {
306	case USB_ST_TRANSFERRED:
307
308		pc = usbd_xfer_get_frame(xfer, 1);
309		usbd_copy_out(pc, 0, &cur_status, 1);
310
311		cur_status = (cur_status ^ LPS_INVERT) & LPS_MASK;
312		new_status = cur_status & ~sc->sc_last_status;
313		sc->sc_last_status = cur_status;
314
315		if (new_status & LPS_SELECT)
316			log(LOG_NOTICE, "%s: offline\n",
317			    device_get_nameunit(sc->sc_dev));
318		else if (new_status & LPS_NOPAPER)
319			log(LOG_NOTICE, "%s: out of paper\n",
320			    device_get_nameunit(sc->sc_dev));
321		else if (new_status & LPS_NERR)
322			log(LOG_NOTICE, "%s: output error\n",
323			    device_get_nameunit(sc->sc_dev));
324		break;
325
326	case USB_ST_SETUP:
327		req.bmRequestType = UT_READ_CLASS_INTERFACE;
328		req.bRequest = UR_GET_PORT_STATUS;
329		USETW(req.wValue, 0);
330		req.wIndex[0] = sc->sc_iface_no;
331		req.wIndex[1] = 0;
332		USETW(req.wLength, 1);
333
334		pc = usbd_xfer_get_frame(xfer, 0);
335		usbd_copy_in(pc, 0, &req, sizeof(req));
336
337		usbd_xfer_set_frame_len(xfer, 0, sizeof(req));
338		usbd_xfer_set_frame_len(xfer, 1, 1);
339		usbd_xfer_set_frames(xfer, 2);
340		usbd_transfer_submit(xfer);
341		break;
342
343	default:			/* Error */
344		DPRINTF("error=%s\n", usbd_errstr(error));
345		if (error != USB_ERR_CANCELLED) {
346			/* wait for next watchdog timeout */
347		}
348		break;
349	}
350}
351
352static const struct usb_config ulpt_config[ULPT_N_TRANSFER] = {
353	[ULPT_BULK_DT_WR] = {
354		.type = UE_BULK,
355		.endpoint = UE_ADDR_ANY,
356		.direction = UE_DIR_OUT,
357		.bufsize = ULPT_BSIZE,
358		.flags = {.pipe_bof = 1,.proxy_buffer = 1},
359		.callback = &ulpt_write_callback,
360	},
361
362	[ULPT_BULK_DT_RD] = {
363		.type = UE_BULK,
364		.endpoint = UE_ADDR_ANY,
365		.direction = UE_DIR_IN,
366		.bufsize = ULPT_BSIZE,
367		.flags = {.pipe_bof = 1,.short_xfer_ok = 1,.proxy_buffer = 1},
368		.callback = &ulpt_read_callback,
369	},
370
371	[ULPT_INTR_DT_RD] = {
372		.type = UE_CONTROL,
373		.endpoint = 0x00,	/* Control pipe */
374		.direction = UE_DIR_ANY,
375		.bufsize = sizeof(struct usb_device_request) + 1,
376		.callback = &ulpt_status_callback,
377		.timeout = 1000,	/* 1 second */
378	},
379};
380
381static void
382ulpt_start_read(struct usb_fifo *fifo)
383{
384	struct ulpt_softc *sc = usb_fifo_softc(fifo);
385
386	usbd_transfer_start(sc->sc_xfer[ULPT_BULK_DT_RD]);
387}
388
389static void
390ulpt_stop_read(struct usb_fifo *fifo)
391{
392	struct ulpt_softc *sc = usb_fifo_softc(fifo);
393
394	usbd_transfer_stop(sc->sc_xfer[ULPT_BULK_DT_RD]);
395}
396
397static void
398ulpt_start_write(struct usb_fifo *fifo)
399{
400	struct ulpt_softc *sc = usb_fifo_softc(fifo);
401
402	usbd_transfer_start(sc->sc_xfer[ULPT_BULK_DT_WR]);
403}
404
405static void
406ulpt_stop_write(struct usb_fifo *fifo)
407{
408	struct ulpt_softc *sc = usb_fifo_softc(fifo);
409
410	usbd_transfer_stop(sc->sc_xfer[ULPT_BULK_DT_WR]);
411}
412
413static int
414ulpt_open(struct usb_fifo *fifo, int fflags)
415{
416	struct ulpt_softc *sc = usb_fifo_softc(fifo);
417
418	/* we assume that open is a serial process */
419
420	if (sc->sc_fflags == 0) {
421		/* reset USB parallel port */
422
423		ulpt_reset(sc);
424	}
425	return (unlpt_open(fifo, fflags));
426}
427
428static int
429unlpt_open(struct usb_fifo *fifo, int fflags)
430{
431	struct ulpt_softc *sc = usb_fifo_softc(fifo);
432
433	if (sc->sc_fflags & fflags) {
434		return (EBUSY);
435	}
436	if (fflags & FREAD) {
437		/* clear stall first */
438		mtx_lock(&sc->sc_mtx);
439		usbd_xfer_set_stall(sc->sc_xfer[ULPT_BULK_DT_RD]);
440		mtx_unlock(&sc->sc_mtx);
441		if (usb_fifo_alloc_buffer(fifo,
442		    usbd_xfer_max_len(sc->sc_xfer[ULPT_BULK_DT_RD]),
443		    ULPT_IFQ_MAXLEN)) {
444			return (ENOMEM);
445		}
446		/* set which FIFO is opened */
447		sc->sc_fifo_open[USB_FIFO_RX] = fifo;
448	}
449	if (fflags & FWRITE) {
450		/* clear stall first */
451		mtx_lock(&sc->sc_mtx);
452		usbd_xfer_set_stall(sc->sc_xfer[ULPT_BULK_DT_WR]);
453		mtx_unlock(&sc->sc_mtx);
454		if (usb_fifo_alloc_buffer(fifo,
455		    usbd_xfer_max_len(sc->sc_xfer[ULPT_BULK_DT_WR]),
456		    ULPT_IFQ_MAXLEN)) {
457			return (ENOMEM);
458		}
459		/* set which FIFO is opened */
460		sc->sc_fifo_open[USB_FIFO_TX] = fifo;
461	}
462	sc->sc_fflags |= fflags & (FREAD | FWRITE);
463	return (0);
464}
465
466static void
467ulpt_close(struct usb_fifo *fifo, int fflags)
468{
469	struct ulpt_softc *sc = usb_fifo_softc(fifo);
470
471	sc->sc_fflags &= ~(fflags & (FREAD | FWRITE));
472
473	if (fflags & (FREAD | FWRITE)) {
474		usb_fifo_free_buffer(fifo);
475	}
476}
477
478static int
479ulpt_ioctl(struct usb_fifo *fifo, u_long cmd, void *data,
480    int fflags)
481{
482	return (ENODEV);
483}
484
485static const STRUCT_USB_HOST_ID ulpt_devs[] = {
486	/* Uni-directional USB printer */
487	{USB_IFACE_CLASS(UICLASS_PRINTER),
488	 USB_IFACE_SUBCLASS(UISUBCLASS_PRINTER),
489	 USB_IFACE_PROTOCOL(UIPROTO_PRINTER_UNI)},
490
491	/* Bi-directional USB printer */
492	{USB_IFACE_CLASS(UICLASS_PRINTER),
493	 USB_IFACE_SUBCLASS(UISUBCLASS_PRINTER),
494	 USB_IFACE_PROTOCOL(UIPROTO_PRINTER_BI)},
495
496	/* 1284 USB printer */
497	{USB_IFACE_CLASS(UICLASS_PRINTER),
498	 USB_IFACE_SUBCLASS(UISUBCLASS_PRINTER),
499	 USB_IFACE_PROTOCOL(UIPROTO_PRINTER_1284)},
500
501	/* Epson printer */
502	{USB_VENDOR(USB_VENDOR_EPSON),
503	 USB_PRODUCT(USB_PRODUCT_EPSON_TMU220B),
504	 USB_IFACE_CLASS(UICLASS_VENDOR),
505	 USB_IFACE_SUBCLASS(UISUBCLASS_VENDOR),
506	 USB_IFACE_PROTOCOL(UIPROTO_PRINTER_BI)},
507};
508
509static int
510ulpt_probe(device_t dev)
511{
512	struct usb_attach_arg *uaa = device_get_ivars(dev);
513	int error;
514
515	DPRINTFN(11, "\n");
516
517	if (uaa->usb_mode != USB_MODE_HOST)
518		return (ENXIO);
519
520	error = usbd_lookup_id_by_uaa(ulpt_devs, sizeof(ulpt_devs), uaa);
521	if (error)
522		return (error);
523
524	return (BUS_PROBE_GENERIC);
525}
526
527static int
528ulpt_attach(device_t dev)
529{
530	struct usb_attach_arg *uaa = device_get_ivars(dev);
531	struct ulpt_softc *sc = device_get_softc(dev);
532	struct usb_interface_descriptor *id;
533	int unit = device_get_unit(dev);
534	int error;
535	uint8_t iface_index = uaa->info.bIfaceIndex;
536	uint8_t alt_index;
537
538	DPRINTFN(11, "sc=%p\n", sc);
539
540	sc->sc_dev = dev;
541	sc->sc_udev = uaa->device;
542
543	device_set_usb_desc(dev);
544
545	mtx_init(&sc->sc_mtx, "ulpt lock", NULL, MTX_DEF | MTX_RECURSE);
546
547	usb_callout_init_mtx(&sc->sc_watchdog, &sc->sc_mtx, 0);
548
549	/* search through all the descriptors looking for bidir mode */
550
551	id = usbd_get_interface_descriptor(uaa->iface);
552	alt_index = 0xFF;
553	while (1) {
554		if (id == NULL) {
555			break;
556		}
557		if ((id->bDescriptorType == UDESC_INTERFACE) &&
558		    (id->bLength >= sizeof(*id))) {
559			if (id->bInterfaceNumber != uaa->info.bIfaceNum) {
560				break;
561			} else {
562				alt_index++;
563				if ((id->bInterfaceClass == UICLASS_PRINTER ||
564				     id->bInterfaceClass == UICLASS_VENDOR) &&
565				    (id->bInterfaceSubClass == UISUBCLASS_PRINTER ||
566				     id->bInterfaceSubClass == UISUBCLASS_VENDOR) &&
567				    (id->bInterfaceProtocol == UIPROTO_PRINTER_BI)) {
568					goto found;
569				}
570			}
571		}
572		id = (void *)usb_desc_foreach(
573		    usbd_get_config_descriptor(uaa->device), (void *)id);
574	}
575	goto detach;
576
577found:
578
579	DPRINTF("setting alternate "
580	    "config number: %d\n", alt_index);
581
582	if (alt_index) {
583		error = usbd_set_alt_interface_index
584		    (uaa->device, iface_index, alt_index);
585
586		if (error) {
587			DPRINTF("could not set alternate "
588			    "config, error=%s\n", usbd_errstr(error));
589			goto detach;
590		}
591	}
592	sc->sc_iface_no = id->bInterfaceNumber;
593
594	error = usbd_transfer_setup(uaa->device, &iface_index,
595	    sc->sc_xfer, ulpt_config, ULPT_N_TRANSFER,
596	    sc, &sc->sc_mtx);
597	if (error) {
598		DPRINTF("error=%s\n", usbd_errstr(error));
599		goto detach;
600	}
601	device_printf(sc->sc_dev, "using bi-directional mode\n");
602
603#if 0
604/*
605 * This code is disabled because for some mysterious reason it causes
606 * printing not to work.  But only sometimes, and mostly with
607 * UHCI and less often with OHCI.  *sigh*
608 */
609	{
610		struct usb_config_descriptor *cd = usbd_get_config_descriptor(dev);
611		struct usb_device_request req;
612		int len, alen;
613
614		req.bmRequestType = UT_READ_CLASS_INTERFACE;
615		req.bRequest = UR_GET_DEVICE_ID;
616		USETW(req.wValue, cd->bConfigurationValue);
617		USETW2(req.wIndex, id->bInterfaceNumber, id->bAlternateSetting);
618		USETW(req.wLength, sizeof devinfo - 1);
619		error = usbd_do_request_flags(dev, &req, devinfo, USB_SHORT_XFER_OK,
620		    &alen, USB_DEFAULT_TIMEOUT);
621		if (error) {
622			device_printf(sc->sc_dev, "cannot get device id\n");
623		} else if (alen <= 2) {
624			device_printf(sc->sc_dev, "empty device id, no "
625			    "printer connected?\n");
626		} else {
627			/* devinfo now contains an IEEE-1284 device ID */
628			len = ((devinfo[0] & 0xff) << 8) | (devinfo[1] & 0xff);
629			if (len > sizeof devinfo - 3)
630				len = sizeof devinfo - 3;
631			devinfo[len] = 0;
632			printf("%s: device id <", device_get_nameunit(sc->sc_dev));
633			ieee1284_print_id(devinfo + 2);
634			printf(">\n");
635		}
636	}
637#endif
638
639	error = usb_fifo_attach(uaa->device, sc, &sc->sc_mtx,
640	    &ulpt_fifo_methods, &sc->sc_fifo,
641	    unit, -1, uaa->info.bIfaceIndex,
642	    UID_ROOT, GID_OPERATOR, 0644);
643	if (error) {
644		goto detach;
645	}
646	error = usb_fifo_attach(uaa->device, sc, &sc->sc_mtx,
647	    &unlpt_fifo_methods, &sc->sc_fifo_noreset,
648	    unit, -1, uaa->info.bIfaceIndex,
649	    UID_ROOT, GID_OPERATOR, 0644);
650	if (error) {
651		goto detach;
652	}
653	/* start reading of status */
654
655	mtx_lock(&sc->sc_mtx);
656	ulpt_watchdog(sc);
657	mtx_unlock(&sc->sc_mtx);
658	return (0);
659
660detach:
661	ulpt_detach(dev);
662	return (ENOMEM);
663}
664
665static int
666ulpt_detach(device_t dev)
667{
668	struct ulpt_softc *sc = device_get_softc(dev);
669
670	DPRINTF("sc=%p\n", sc);
671
672	usb_fifo_detach(&sc->sc_fifo);
673	usb_fifo_detach(&sc->sc_fifo_noreset);
674
675	mtx_lock(&sc->sc_mtx);
676	usb_callout_stop(&sc->sc_watchdog);
677	mtx_unlock(&sc->sc_mtx);
678
679	usbd_transfer_unsetup(sc->sc_xfer, ULPT_N_TRANSFER);
680	usb_callout_drain(&sc->sc_watchdog);
681	mtx_destroy(&sc->sc_mtx);
682
683	return (0);
684}
685
686#if 0
687/* XXX This does not belong here. */
688
689/*
690 * Compare two strings until the second ends.
691 */
692
693static uint8_t
694ieee1284_compare(const char *a, const char *b)
695{
696	while (1) {
697		if (*b == 0) {
698			break;
699		}
700		if (*a != *b) {
701			return 1;
702		}
703		b++;
704		a++;
705	}
706	return 0;
707}
708
709/*
710 * Print select parts of an IEEE 1284 device ID.
711 */
712void
713ieee1284_print_id(char *str)
714{
715	char *p, *q;
716
717	for (p = str - 1; p; p = strchr(p, ';')) {
718		p++;			/* skip ';' */
719		if (ieee1284_compare(p, "MFG:") == 0 ||
720		    ieee1284_compare(p, "MANUFACTURER:") == 0 ||
721		    ieee1284_compare(p, "MDL:") == 0 ||
722		    ieee1284_compare(p, "MODEL:") == 0) {
723			q = strchr(p, ';');
724			if (q)
725				printf("%.*s", (int)(q - p + 1), p);
726		}
727	}
728}
729
730#endif
731
732static void
733ulpt_watchdog(void *arg)
734{
735	struct ulpt_softc *sc = arg;
736
737	mtx_assert(&sc->sc_mtx, MA_OWNED);
738
739	/*
740	 * Only read status while the device is not opened, due to
741	 * possible hardware or firmware bug in some printers.
742	 */
743	if (sc->sc_fflags == 0)
744		usbd_transfer_start(sc->sc_xfer[ULPT_INTR_DT_RD]);
745
746	usb_callout_reset(&sc->sc_watchdog,
747	    hz, &ulpt_watchdog, sc);
748}
749
750static device_method_t ulpt_methods[] = {
751	DEVMETHOD(device_probe, ulpt_probe),
752	DEVMETHOD(device_attach, ulpt_attach),
753	DEVMETHOD(device_detach, ulpt_detach),
754	DEVMETHOD_END
755};
756
757static driver_t ulpt_driver = {
758	.name = "ulpt",
759	.methods = ulpt_methods,
760	.size = sizeof(struct ulpt_softc),
761};
762
763DRIVER_MODULE(ulpt, uhub, ulpt_driver, NULL, NULL);
764MODULE_DEPEND(ulpt, usb, 1, 1, 1);
765MODULE_VERSION(ulpt, 1);
766USB_PNP_HOST_INFO(ulpt_devs);
767