xref: /openbsd-src/sys/dev/usb/ulpt.c (revision a0747c9f67a4ae71ccb71e62a28d1ea19e06a63c)
1 /*	$OpenBSD: ulpt.c,v 1.58 2021/01/29 17:12:19 sthen Exp $ */
2 /*	$NetBSD: ulpt.c,v 1.57 2003/01/05 10:19:42 scw 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  *
22  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
23  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
24  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
25  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
26  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
27  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
28  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
29  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
30  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
31  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
32  * POSSIBILITY OF SUCH DAMAGE.
33  */
34 
35 /*
36  * Printer Class spec:
37  *   https://www.usb.org/sites/default/files/usbprint11a021811.pdf
38  */
39 
40 #include <sys/param.h>
41 #include <sys/systm.h>
42 #include <sys/device.h>
43 #include <sys/uio.h>
44 #include <sys/conf.h>
45 #include <sys/vnode.h>
46 #include <sys/syslog.h>
47 #include <sys/malloc.h>
48 
49 #include <dev/usb/usb.h>
50 #include <dev/usb/usbdi.h>
51 #include <dev/usb/usbdi_util.h>
52 #include <dev/usb/usbdevs.h>
53 #include <dev/usb/usb_quirks.h>
54 
55 #define	LPTPRI		(PZERO+8)
56 #define	ULPT_BSIZE	16384
57 
58 #ifdef ULPT_DEBUG
59 #define DPRINTF(x)	do { if (ulptdebug) printf x; } while (0)
60 #define DPRINTFN(n,x)	do { if (ulptdebug>(n)) printf x; } while (0)
61 int	ulptdebug = 0;
62 #else
63 #define DPRINTF(x)
64 #define DPRINTFN(n,x)
65 #endif
66 
67 #define UR_GET_DEVICE_ID 0
68 #define UR_GET_PORT_STATUS 1
69 #define UR_SOFT_RESET 2
70 
71 #define	LPS_NERR		0x08	/* printer no error */
72 #define	LPS_SELECT		0x10	/* printer selected */
73 #define	LPS_NOPAPER		0x20	/* printer out of paper */
74 #define LPS_INVERT      (LPS_SELECT|LPS_NERR)
75 #define LPS_MASK        (LPS_SELECT|LPS_NERR|LPS_NOPAPER)
76 
77 struct ulpt_softc {
78 	struct device sc_dev;
79 	struct usbd_device *sc_udev;	/* device */
80 	struct usbd_interface *sc_iface;/* interface */
81 	int sc_ifaceno;
82 
83 	int sc_out;
84 	struct usbd_pipe *sc_out_pipe;	/* bulk out pipe */
85 
86 	int sc_in;
87 	struct usbd_pipe *sc_in_pipe;	/* bulk in pipe */
88 	struct usbd_xfer *sc_in_xfer1;
89 	struct usbd_xfer *sc_in_xfer2;
90 	u_char sc_junk[64];	/* somewhere to dump input */
91 
92 	u_char sc_state;
93 #define	ULPT_OPEN	0x01	/* device is open */
94 #define	ULPT_OBUSY	0x02	/* printer is busy doing output */
95 #define	ULPT_INIT	0x04	/* waiting to initialize for open */
96 	u_char sc_flags;
97 #define	ULPT_NOPRIME	0x40	/* don't prime on open */
98 #define	ULPT_EFIRMWARE	0x80	/* error loading firmware */
99 	u_char sc_laststatus;
100 
101 	int sc_refcnt;
102 
103 	struct ulpt_fwdev *sc_fwdev;
104 };
105 
106 void ulpt_disco(void *);
107 
108 int ulpt_do_write(struct ulpt_softc *, struct uio *uio, int);
109 int ulpt_status(struct ulpt_softc *);
110 void ulpt_reset(struct ulpt_softc *);
111 int ulpt_statusmsg(u_char, struct ulpt_softc *);
112 
113 /*
114  * Printers which need firmware uploads.
115  */
116 void ulpt_load_firmware(struct device *);
117 usbd_status ulpt_ucode_loader_hp(struct ulpt_softc *);
118 struct ulpt_fwdev {
119 	struct usb_devno	 uv_dev;
120 	char			*ucode_name;
121 	usbd_status		 (*ucode_loader)(struct ulpt_softc *);
122 } ulpt_fwdevs[] = {
123 	{
124 	    { USB_VENDOR_HP, USB_PRODUCT_HP_1000 },
125 	    "ulpt-hp1000",
126 	    ulpt_ucode_loader_hp
127 	},
128 	{
129 	    { USB_VENDOR_HP, USB_PRODUCT_HP_1005 },
130 	    "ulpt-hp1005",
131 	    ulpt_ucode_loader_hp
132 	},
133 	{
134 	    { USB_VENDOR_HP, USB_PRODUCT_HP_1018 },
135 	    "ulpt-hp1018",
136 	    ulpt_ucode_loader_hp
137 	},
138 	{
139 	    { USB_VENDOR_HP, USB_PRODUCT_HP_1020 },
140 	    "ulpt-hp1020",
141 	    ulpt_ucode_loader_hp
142 	},
143 };
144 
145 #if 0
146 void ieee1284_print_id(char *);
147 #endif
148 
149 #define	ULPTUNIT(s)	(minor(s) & 0x1f)
150 #define	ULPTFLAGS(s)	(minor(s) & 0xe0)
151 
152 
153 int ulpt_match(struct device *, void *, void *);
154 void ulpt_attach(struct device *, struct device *, void *);
155 int ulpt_detach(struct device *, int);
156 
157 struct cfdriver ulpt_cd = {
158 	NULL, "ulpt", DV_DULL
159 };
160 
161 const struct cfattach ulpt_ca = {
162 	sizeof(struct ulpt_softc), ulpt_match, ulpt_attach, ulpt_detach
163 };
164 
165 int
166 ulpt_match(struct device *parent, void *match, void *aux)
167 {
168 	struct usb_attach_arg *uaa = aux;
169 	usb_interface_descriptor_t *id;
170 
171 	DPRINTFN(10,("ulpt_match\n"));
172 	if (uaa->iface == NULL)
173 		return (UMATCH_NONE);
174 	id = usbd_get_interface_descriptor(uaa->iface);
175 	if (id != NULL &&
176 	    id->bInterfaceClass == UICLASS_PRINTER &&
177 	    id->bInterfaceSubClass == UISUBCLASS_PRINTER &&
178 	    ((id->bInterfaceProtocol == UIPROTO_PRINTER_UNI) ||
179 	     (id->bInterfaceProtocol == UIPROTO_PRINTER_BI) ||
180 	     (id->bInterfaceProtocol == UIPROTO_PRINTER_1284)))
181 		return (UMATCH_IFACECLASS_IFACESUBCLASS_IFACEPROTO);
182 	return (UMATCH_NONE);
183 }
184 
185 void
186 ulpt_load_firmware(struct device *self)
187 {
188 	struct ulpt_softc *sc = (struct ulpt_softc *)self;
189 	usbd_status err;
190 
191 	err = (sc->sc_fwdev->ucode_loader)(sc);
192 	if (err != USBD_NORMAL_COMPLETION) {
193 		sc->sc_flags |= ULPT_EFIRMWARE;
194 		printf("%s: could not load firmware '%s'\n",
195 		    sc->sc_dev.dv_xname, sc->sc_fwdev->ucode_name);
196 	} else
197 		sc->sc_flags &= ~ULPT_EFIRMWARE;
198 }
199 
200 #define ulpt_lookup(v, p) \
201 	((struct ulpt_fwdev *)usb_lookup(ulpt_fwdevs, v, p))
202 
203 void
204 ulpt_attach(struct device *parent, struct device *self, void *aux)
205 {
206 	struct ulpt_softc *sc = (struct ulpt_softc *)self;
207 	struct usb_attach_arg *uaa = aux;
208 	struct usbd_device *dev = uaa->device;
209 	struct usbd_interface *iface = uaa->iface;
210 	usb_interface_descriptor_t *ifcd = usbd_get_interface_descriptor(iface);
211 	usb_interface_descriptor_t *id, *iend;
212 	usb_config_descriptor_t *cdesc;
213 	usbd_status err;
214 	usb_endpoint_descriptor_t *ed;
215 	int i, altno;
216 
217 	DPRINTFN(10,("ulpt_attach: sc=%p\n", sc));
218 
219 	//printf("%s: iclass %d/%d\n", sc->sc_dev.dv_xname,
220 	//    ifcd->bInterfaceClass, ifcd->bInterfaceSubClass);
221 
222 	/* XXX
223 	 * Stepping through the alternate settings needs to be abstracted out.
224 	 */
225 	cdesc = usbd_get_config_descriptor(dev);
226 	if (cdesc == NULL) {
227 		printf("%s: failed to get configuration descriptor\n",
228 		       sc->sc_dev.dv_xname);
229 		return;
230 	}
231 	iend = (usb_interface_descriptor_t *)
232 		   ((char *)cdesc + UGETW(cdesc->wTotalLength));
233 #ifdef DIAGNOSTIC
234 	if (ifcd < (usb_interface_descriptor_t *)cdesc ||
235 	    ifcd >= iend)
236 		panic("ulpt: iface desc out of range");
237 #endif
238 	/* Step through all the descriptors looking for bidir mode */
239 	for (id = ifcd, altno = 0;
240 	     id < iend;
241 	     id = (void *)((char *)id + id->bLength)) {
242 		if (id->bDescriptorType == UDESC_INTERFACE &&
243 		    id->bInterfaceNumber == ifcd->bInterfaceNumber) {
244 			if (id->bInterfaceClass == UICLASS_PRINTER &&
245 			    id->bInterfaceSubClass == UISUBCLASS_PRINTER &&
246 			    (id->bInterfaceProtocol == UIPROTO_PRINTER_BI /*||
247 			     id->bInterfaceProtocol == UIPROTO_PRINTER_1284*/))
248 				goto found;
249 			altno++;
250 		}
251 	}
252 	id = ifcd;		/* not found, use original */
253  found:
254 	if (id != ifcd) {
255 		/* Found a new bidir setting */
256 		DPRINTF(("ulpt_attach: set altno = %d\n", altno));
257 		err = usbd_set_interface(iface, altno);
258 		if (err) {
259 			printf("%s: setting alternate interface failed\n",
260 			       sc->sc_dev.dv_xname);
261 			usbd_deactivate(sc->sc_udev);
262 			return;
263 		}
264 	}
265 
266 
267 	sc->sc_in = -1;
268 	sc->sc_out = -1;
269 
270 	id = usbd_get_interface_descriptor(iface);
271 	for (i = 0; i < id->bNumEndpoints; i++) {
272 		ed = usbd_interface2endpoint_descriptor(iface, i);
273 		if (ed == NULL) {
274 			printf("%s: couldn't get ep %d\n",
275 			    sc->sc_dev.dv_xname, i);
276 			return;
277 		}
278 		if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_IN &&
279 		    UE_GET_XFERTYPE(ed->bmAttributes) == UE_BULK) {
280 			sc->sc_in = ed->bEndpointAddress;
281 		} else if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_OUT &&
282 			   UE_GET_XFERTYPE(ed->bmAttributes) == UE_BULK) {
283 			sc->sc_out = ed->bEndpointAddress;
284 		}
285 	}
286 	if (sc->sc_out == -1) {
287 		printf("%s: could not find bulk out endpoint\n",
288 		    sc->sc_dev.dv_xname);
289 		usbd_deactivate(sc->sc_udev);
290 		return;
291 	}
292 
293 	if (usbd_get_quirks(dev)->uq_flags & UQ_BROKEN_BIDIR) {
294 		/* This device doesn't handle reading properly. */
295 		sc->sc_in = -1;
296 	}
297 
298 	printf("%s: using %s-directional mode\n", sc->sc_dev.dv_xname,
299 	       sc->sc_in >= 0 ? "bi" : "uni");
300 
301 	DPRINTFN(10, ("ulpt_attach: bulk=%d\n", sc->sc_out));
302 
303 	sc->sc_iface = iface;
304 	sc->sc_ifaceno = id->bInterfaceNumber;
305 	sc->sc_udev = dev;
306 
307 	/* maybe the device needs firmware */
308 	sc->sc_fwdev = ulpt_lookup(uaa->vendor, uaa->product);
309 	if (sc->sc_fwdev)
310 		config_mountroot(self, ulpt_load_firmware);
311 
312 #if 0
313 /*
314  * This code is disabled because for some mysterious reason it causes
315  * printing not to work.  But only sometimes, and mostly with
316  * UHCI and less often with OHCI.  *sigh*
317  */
318 	{
319 	usb_config_descriptor_t *cd = usbd_get_config_descriptor(dev);
320 	usb_device_request_t req;
321 	int len, alen;
322 
323 	req.bmRequestType = UT_READ_CLASS_INTERFACE;
324 	req.bRequest = UR_GET_DEVICE_ID;
325 	USETW(req.wValue, cd->bConfigurationValue);
326 	USETW2(req.wIndex, id->bInterfaceNumber, id->bAlternateSetting);
327 	USETW(req.wLength, DEVINFOSIZE - 1);
328 	err = usbd_do_request_flags(dev, &req, devinfop, USBD_SHORT_XFER_OK,
329 		  &alen, USBD_DEFAULT_TIMEOUT);
330 	if (err) {
331 		printf("%s: cannot get device id\n", sc->sc_dev.dv_xname);
332 	} else if (alen <= 2) {
333 		printf("%s: empty device id, no printer connected?\n",
334 		       sc->sc_dev.dv_xname);
335 	} else {
336 		/* devinfop now contains an IEEE-1284 device ID */
337 		len = ((devinfop[0] & 0xff) << 8) | (devinfop[1] & 0xff);
338 		if (len > DEVINFOSIZE - 3)
339 			len = DEVINFOSIZE - 3;
340 		devinfo[len] = 0;
341 		printf("%s: device id <", sc->sc_dev.dv_xname);
342 		ieee1284_print_id(devinfop+2);
343 		printf(">\n");
344 	}
345 	}
346 #endif
347 }
348 
349 int
350 ulpt_detach(struct device *self, int flags)
351 {
352 	struct ulpt_softc *sc = (struct ulpt_softc *)self;
353 	int s;
354 	int maj, mn;
355 
356 	DPRINTF(("ulpt_detach: sc=%p\n", sc));
357 
358 	if (sc->sc_out_pipe != NULL)
359 		usbd_abort_pipe(sc->sc_out_pipe);
360 	if (sc->sc_in_pipe != NULL)
361 		usbd_abort_pipe(sc->sc_in_pipe);
362 
363 	s = splusb();
364 	if (--sc->sc_refcnt >= 0) {
365 		/* There is noone to wake, aborting the pipe is enough */
366 		/* Wait for processes to go away. */
367 		usb_detach_wait(&sc->sc_dev);
368 	}
369 	splx(s);
370 
371 	/* locate the major number */
372 	for (maj = 0; maj < nchrdev; maj++)
373 		if (cdevsw[maj].d_open == ulptopen)
374 			break;
375 
376 	/* Nuke the vnodes for any open instances (calls close). */
377 	mn = self->dv_unit;
378 	vdevgone(maj, mn, mn, VCHR);
379 	vdevgone(maj, mn | ULPT_NOPRIME , mn | ULPT_NOPRIME, VCHR);
380 
381 	return (0);
382 }
383 
384 int
385 ulpt_status(struct ulpt_softc *sc)
386 {
387 	usb_device_request_t req;
388 	usbd_status err;
389 	u_char status;
390 
391 	req.bmRequestType = UT_READ_CLASS_INTERFACE;
392 	req.bRequest = UR_GET_PORT_STATUS;
393 	USETW(req.wValue, 0);
394 	USETW(req.wIndex, sc->sc_ifaceno);
395 	USETW(req.wLength, 1);
396 	err = usbd_do_request(sc->sc_udev, &req, &status);
397 	DPRINTFN(1, ("ulpt_status: status=0x%02x err=%d\n", status, err));
398 	if (!err)
399 		return (status);
400 	else
401 		return (0);
402 }
403 
404 void
405 ulpt_reset(struct ulpt_softc *sc)
406 {
407 	usb_device_request_t req;
408 
409 	DPRINTFN(1, ("ulpt_reset\n"));
410 	req.bRequest = UR_SOFT_RESET;
411 	USETW(req.wValue, 0);
412 	USETW(req.wIndex, sc->sc_ifaceno);
413 	USETW(req.wLength, 0);
414 
415 	/*
416 	 * There was a mistake in the USB printer 1.0 spec that gave the
417 	 * request type as UT_WRITE_CLASS_OTHER; it should have been
418 	 * UT_WRITE_CLASS_INTERFACE.  Many printers use the old one,
419 	 * so we try both.
420 	 */
421 	req.bmRequestType = UT_WRITE_CLASS_OTHER;
422 	if (usbd_do_request(sc->sc_udev, &req, 0)) {	/* 1.0 */
423 		req.bmRequestType = UT_WRITE_CLASS_INTERFACE;
424 		(void)usbd_do_request(sc->sc_udev, &req, 0); /* 1.1 */
425 	}
426 }
427 
428 static void
429 ulpt_input(struct usbd_xfer *xfer, void *priv, usbd_status status)
430 {
431 	struct ulpt_softc *sc = priv;
432 
433 	DPRINTFN(2,("ulpt_input: got some data\n"));
434 	/* Do it again. */
435 	if (xfer == sc->sc_in_xfer1)
436 		usbd_transfer(sc->sc_in_xfer2);
437 	else
438 		usbd_transfer(sc->sc_in_xfer1);
439 }
440 
441 int ulptusein = 1;
442 
443 /*
444  * Reset the printer, then wait until it's selected and not busy.
445  */
446 int
447 ulptopen(dev_t dev, int flag, int mode, struct proc *p)
448 {
449 	u_char flags = ULPTFLAGS(dev);
450 	struct ulpt_softc *sc;
451 	usbd_status err;
452 	int error;
453 
454 	if (ULPTUNIT(dev) >= ulpt_cd.cd_ndevs)
455 		return (ENXIO);
456 	sc = ulpt_cd.cd_devs[ULPTUNIT(dev)];
457 	if (sc == NULL)
458 		return (ENXIO);
459 
460 	if (sc == NULL || sc->sc_iface == NULL || usbd_is_dying(sc->sc_udev))
461 		return (ENXIO);
462 
463 	if (sc->sc_state)
464 		return (EBUSY);
465 
466 	/* If a previous attempt to load firmware failed, retry. */
467 	if (sc->sc_flags & ULPT_EFIRMWARE) {
468 		ulpt_load_firmware(&sc->sc_dev);
469 		if (sc->sc_flags & ULPT_EFIRMWARE)
470 			return (EIO);
471 	}
472 
473 	sc->sc_state = ULPT_INIT;
474 	sc->sc_flags = flags;
475 	DPRINTF(("ulptopen: flags=0x%x\n", (unsigned)flags));
476 
477 	error = 0;
478 	sc->sc_refcnt++;
479 
480 	if ((flags & ULPT_NOPRIME) == 0) {
481 		ulpt_reset(sc);
482 		if (usbd_is_dying(sc->sc_udev)) {
483 			error = ENXIO;
484 			sc->sc_state = 0;
485 			goto done;
486 		}
487 	}
488 
489 	err = usbd_open_pipe(sc->sc_iface, sc->sc_out, 0, &sc->sc_out_pipe);
490 	if (err) {
491 		sc->sc_state = 0;
492 		error = EIO;
493 		goto done;
494 	}
495 	if (ulptusein && sc->sc_in != -1) {
496 		DPRINTF(("ulpt_open: open input pipe\n"));
497 		err = usbd_open_pipe(sc->sc_iface, sc->sc_in,0,&sc->sc_in_pipe);
498 		if (err) {
499 			error = EIO;
500 			usbd_close_pipe(sc->sc_out_pipe);
501 			sc->sc_out_pipe = NULL;
502 			sc->sc_state = 0;
503 			goto done;
504 		}
505 		sc->sc_in_xfer1 = usbd_alloc_xfer(sc->sc_udev);
506 		sc->sc_in_xfer2 = usbd_alloc_xfer(sc->sc_udev);
507 		if (sc->sc_in_xfer1 == NULL || sc->sc_in_xfer2 == NULL) {
508 			error = ENOMEM;
509 			if (sc->sc_in_xfer1 != NULL) {
510 				usbd_free_xfer(sc->sc_in_xfer1);
511 				sc->sc_in_xfer1 = NULL;
512 			}
513 			if (sc->sc_in_xfer2 != NULL) {
514 				usbd_free_xfer(sc->sc_in_xfer2);
515 				sc->sc_in_xfer2 = NULL;
516 			}
517 			usbd_close_pipe(sc->sc_out_pipe);
518 			sc->sc_out_pipe = NULL;
519 			usbd_close_pipe(sc->sc_in_pipe);
520 			sc->sc_in_pipe = NULL;
521 			sc->sc_state = 0;
522 			goto done;
523 		}
524 		usbd_setup_xfer(sc->sc_in_xfer1, sc->sc_in_pipe, sc,
525 		    sc->sc_junk, sizeof sc->sc_junk, USBD_SHORT_XFER_OK,
526 		    USBD_NO_TIMEOUT, ulpt_input);
527 		usbd_setup_xfer(sc->sc_in_xfer2, sc->sc_in_pipe, sc,
528 		    sc->sc_junk, sizeof sc->sc_junk, USBD_SHORT_XFER_OK,
529 		    USBD_NO_TIMEOUT, ulpt_input);
530 		usbd_transfer(sc->sc_in_xfer1); /* ignore failed start */
531 	}
532 
533 	sc->sc_state = ULPT_OPEN;
534 
535  done:
536 	if (--sc->sc_refcnt < 0)
537 		usb_detach_wakeup(&sc->sc_dev);
538 
539 	DPRINTF(("ulptopen: done, error=%d\n", error));
540 	return (error);
541 }
542 
543 int
544 ulpt_statusmsg(u_char status, struct ulpt_softc *sc)
545 {
546 	u_char new;
547 
548 	status = (status ^ LPS_INVERT) & LPS_MASK;
549 	new = status & ~sc->sc_laststatus;
550 	sc->sc_laststatus = status;
551 
552 	if (new & LPS_SELECT)
553 		log(LOG_NOTICE, "%s: offline\n", sc->sc_dev.dv_xname);
554 	else if (new & LPS_NOPAPER)
555 		log(LOG_NOTICE, "%s: out of paper\n", sc->sc_dev.dv_xname);
556 	else if (new & LPS_NERR)
557 		log(LOG_NOTICE, "%s: output error\n", sc->sc_dev.dv_xname);
558 
559 	return (status);
560 }
561 
562 int
563 ulptclose(dev_t dev, int flag, int mode, struct proc *p)
564 {
565 	struct ulpt_softc *sc;
566 
567 	sc = ulpt_cd.cd_devs[ULPTUNIT(dev)];
568 
569 	if (sc->sc_state != ULPT_OPEN)
570 		/* We are being forced to close before the open completed. */
571 		return (0);
572 
573 	if (sc->sc_out_pipe != NULL) {
574 		usbd_close_pipe(sc->sc_out_pipe);
575 		sc->sc_out_pipe = NULL;
576 	}
577 	if (sc->sc_in_pipe != NULL) {
578 		usbd_close_pipe(sc->sc_in_pipe);
579 		sc->sc_in_pipe = NULL;
580 		if (sc->sc_in_xfer1 != NULL) {
581 			usbd_free_xfer(sc->sc_in_xfer1);
582 			sc->sc_in_xfer1 = NULL;
583 		}
584 		if (sc->sc_in_xfer2 != NULL) {
585 			usbd_free_xfer(sc->sc_in_xfer2);
586 			sc->sc_in_xfer2 = NULL;
587 		}
588 	}
589 
590 	sc->sc_state = 0;
591 
592 	DPRINTF(("ulptclose: closed\n"));
593 	return (0);
594 }
595 
596 int
597 ulpt_do_write(struct ulpt_softc *sc, struct uio *uio, int flags)
598 {
599 	size_t n;
600 	int error = 0;
601 	void *bufp;
602 	struct usbd_xfer *xfer;
603 	usbd_status err;
604 
605 	DPRINTF(("ulptwrite\n"));
606 	xfer = usbd_alloc_xfer(sc->sc_udev);
607 	if (xfer == NULL)
608 		return (ENOMEM);
609 	bufp = usbd_alloc_buffer(xfer, ULPT_BSIZE);
610 	if (bufp == NULL) {
611 		usbd_free_xfer(xfer);
612 		return (ENOMEM);
613 	}
614 	while ((n = ulmin(ULPT_BSIZE, uio->uio_resid)) != 0) {
615 		ulpt_statusmsg(ulpt_status(sc), sc);
616 		error = uiomove(bufp, n, uio);
617 		if (error)
618 			break;
619 		DPRINTFN(1, ("ulptwrite: transfer %zu bytes\n", n));
620 		usbd_setup_xfer(xfer, sc->sc_out_pipe, 0, bufp, n,
621 		    USBD_NO_COPY | USBD_SYNCHRONOUS | USBD_CATCH, 0, NULL);
622 		err = usbd_transfer(xfer);
623 		if (err) {
624 			usbd_clear_endpoint_stall(sc->sc_out_pipe);
625 			DPRINTF(("ulptwrite: error=%d\n", err));
626 			error = EIO;
627 			break;
628 		}
629 	}
630 	usbd_free_xfer(xfer);
631 
632 	return (error);
633 }
634 
635 int
636 ulptwrite(dev_t dev, struct uio *uio, int flags)
637 {
638 	struct ulpt_softc *sc;
639 	int error;
640 
641 	sc = ulpt_cd.cd_devs[ULPTUNIT(dev)];
642 
643 	if (usbd_is_dying(sc->sc_udev) || (sc->sc_flags & ULPT_EFIRMWARE))
644 		return (EIO);
645 
646 	sc->sc_refcnt++;
647 	error = ulpt_do_write(sc, uio, flags);
648 	if (--sc->sc_refcnt < 0)
649 		usb_detach_wakeup(&sc->sc_dev);
650 	return (error);
651 }
652 
653 usbd_status
654 ulpt_ucode_loader_hp(struct ulpt_softc *sc)
655 {
656 	usbd_status error;
657 	int load_error;
658 	uint8_t *ucode;
659 	uint32_t len;
660 	size_t ucode_size;
661 	const char *ucode_name = sc->sc_fwdev->ucode_name;
662 	int offset = 0, remain;
663 	struct usbd_xfer *xfer;
664 	void *bufp;
665 
666 	/* open microcode file */
667 	load_error = loadfirmware(ucode_name, &ucode, &ucode_size);
668 	if (load_error != 0) {
669 		printf("%s: failed loadfirmware of file %s (error %d)\n",
670 		    sc->sc_dev.dv_xname, ucode_name, load_error);
671 		return (USBD_INVAL);
672 	}
673 
674 	/* upload microcode */
675 	error = usbd_open_pipe(sc->sc_iface, sc->sc_out, 0, &sc->sc_out_pipe);
676 	if (error)
677 		goto free_ucode;
678 	xfer = usbd_alloc_xfer(sc->sc_udev);
679 	if (xfer == NULL)
680 		goto close_pipe;
681 	bufp = usbd_alloc_buffer(xfer, ULPT_BSIZE);
682 	if (bufp == NULL) {
683 		error = USBD_NOMEM;
684 		goto free_xfer;
685 	}
686 	remain = ucode_size;
687 	while (remain > 0) {
688 		len = min(remain, ULPT_BSIZE);
689 		memcpy(bufp, &ucode[offset], len);
690 		usbd_setup_xfer(xfer, sc->sc_out_pipe, 0, bufp, len,
691 		    USBD_NO_COPY | USBD_SYNCHRONOUS, 0, NULL);
692 		error = usbd_transfer(xfer);
693 		if (error != USBD_NORMAL_COMPLETION) {
694 			usbd_clear_endpoint_stall(sc->sc_out_pipe);
695 			printf("%s: ucode upload error=%s!\n",
696 			    sc->sc_dev.dv_xname, usbd_errstr(error));
697 			break;
698 		}
699 		DPRINTF(("%s: uploaded %d bytes ucode\n",
700 		    sc->sc_dev.dv_xname, len));
701 
702 		offset += len;
703 		remain -= len;
704 	}
705 free_xfer:
706 	usbd_free_xfer(xfer);
707 close_pipe:
708 	usbd_close_pipe(sc->sc_out_pipe);
709 	sc->sc_out_pipe = NULL;
710 free_ucode:
711 	free(ucode, M_DEVBUF, ucode_size);
712 
713 	return (error);
714 }
715 
716 #if 0
717 /* XXX This does not belong here. */
718 /*
719  * Print select parts of a IEEE 1284 device ID.
720  */
721 void
722 ieee1284_print_id(char *str)
723 {
724 	char *p, *q;
725 
726 	for (p = str-1; p; p = strchr(p, ';')) {
727 		p++;		/* skip ';' */
728 		if (strncmp(p, "MFG:", 4) == 0 ||
729 		    strncmp(p, "MANUFACTURER:", 14) == 0 ||
730 		    strncmp(p, "MDL:", 4) == 0 ||
731 		    strncmp(p, "MODEL:", 6) == 0) {
732 			q = strchr(p, ';');
733 			if (q)
734 				printf("%.*s", (int)(q - p + 1), p);
735 		}
736 	}
737 }
738 #endif
739