1 /* $OpenBSD: ulpt.c,v 1.35 2008/10/09 01:07:02 deraadt 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 * http://www.usb.org/developers/devclass_docs/usbprint11.pdf 38 */ 39 40 #include <sys/param.h> 41 #include <sys/systm.h> 42 #include <sys/proc.h> 43 #include <sys/kernel.h> 44 #include <sys/device.h> 45 #include <sys/ioctl.h> 46 #include <sys/uio.h> 47 #include <sys/conf.h> 48 #include <sys/vnode.h> 49 #include <sys/syslog.h> 50 51 #include <dev/usb/usb.h> 52 #include <dev/usb/usbdi.h> 53 #include <dev/usb/usbdi_util.h> 54 #include <dev/usb/usbdevs.h> 55 #include <dev/usb/usb_quirks.h> 56 57 #define TIMEOUT hz*16 /* wait up to 16 seconds for a ready */ 58 #define STEP hz/4 59 60 #define LPTPRI (PZERO+8) 61 #define ULPT_BSIZE 16384 62 63 #ifdef ULPT_DEBUG 64 #define DPRINTF(x) do { if (ulptdebug) printf x; } while (0) 65 #define DPRINTFN(n,x) do { if (ulptdebug>(n)) printf x; } while (0) 66 int ulptdebug = 0; 67 #else 68 #define DPRINTF(x) 69 #define DPRINTFN(n,x) 70 #endif 71 72 #define UR_GET_DEVICE_ID 0 73 #define UR_GET_PORT_STATUS 1 74 #define UR_SOFT_RESET 2 75 76 #define LPS_NERR 0x08 /* printer no error */ 77 #define LPS_SELECT 0x10 /* printer selected */ 78 #define LPS_NOPAPER 0x20 /* printer out of paper */ 79 #define LPS_INVERT (LPS_SELECT|LPS_NERR) 80 #define LPS_MASK (LPS_SELECT|LPS_NERR|LPS_NOPAPER) 81 82 struct ulpt_softc { 83 struct device sc_dev; 84 usbd_device_handle sc_udev; /* device */ 85 usbd_interface_handle sc_iface; /* interface */ 86 int sc_ifaceno; 87 88 int sc_out; 89 usbd_pipe_handle sc_out_pipe; /* bulk out pipe */ 90 91 int sc_in; 92 usbd_pipe_handle sc_in_pipe; /* bulk in pipe */ 93 usbd_xfer_handle sc_in_xfer1; 94 usbd_xfer_handle sc_in_xfer2; 95 u_char sc_junk[64]; /* somewhere to dump input */ 96 97 u_char sc_state; 98 #define ULPT_OPEN 0x01 /* device is open */ 99 #define ULPT_OBUSY 0x02 /* printer is busy doing output */ 100 #define ULPT_INIT 0x04 /* waiting to initialize for open */ 101 u_char sc_flags; 102 #define ULPT_NOPRIME 0x40 /* don't prime on open */ 103 u_char sc_laststatus; 104 105 int sc_refcnt; 106 u_char sc_dying; 107 }; 108 109 void ulpt_disco(void *); 110 111 int ulpt_do_write(struct ulpt_softc *, struct uio *uio, int); 112 int ulpt_status(struct ulpt_softc *); 113 void ulpt_reset(struct ulpt_softc *); 114 int ulpt_statusmsg(u_char, struct ulpt_softc *); 115 116 #if 0 117 void ieee1284_print_id(char *); 118 #endif 119 120 #define ULPTUNIT(s) (minor(s) & 0x1f) 121 #define ULPTFLAGS(s) (minor(s) & 0xe0) 122 123 124 int ulpt_match(struct device *, void *, void *); 125 void ulpt_attach(struct device *, struct device *, void *); 126 int ulpt_detach(struct device *, int); 127 int ulpt_activate(struct device *, enum devact); 128 129 struct cfdriver ulpt_cd = { 130 NULL, "ulpt", DV_DULL 131 }; 132 133 const struct cfattach ulpt_ca = { 134 sizeof(struct ulpt_softc), 135 ulpt_match, 136 ulpt_attach, 137 ulpt_detach, 138 ulpt_activate, 139 }; 140 141 int 142 ulpt_match(struct device *parent, void *match, void *aux) 143 { 144 struct usb_attach_arg *uaa = aux; 145 usb_interface_descriptor_t *id; 146 147 DPRINTFN(10,("ulpt_match\n")); 148 if (uaa->iface == NULL) 149 return (UMATCH_NONE); 150 id = usbd_get_interface_descriptor(uaa->iface); 151 if (id != NULL && 152 id->bInterfaceClass == UICLASS_PRINTER && 153 id->bInterfaceSubClass == UISUBCLASS_PRINTER && 154 ((id->bInterfaceProtocol == UIPROTO_PRINTER_UNI) || 155 (id->bInterfaceProtocol == UIPROTO_PRINTER_BI) || 156 (id->bInterfaceProtocol == UIPROTO_PRINTER_1284))) 157 return (UMATCH_IFACECLASS_IFACESUBCLASS_IFACEPROTO); 158 return (UMATCH_NONE); 159 } 160 161 void 162 ulpt_attach(struct device *parent, struct device *self, void *aux) 163 { 164 struct ulpt_softc *sc = (struct ulpt_softc *)self; 165 struct usb_attach_arg *uaa = aux; 166 usbd_device_handle dev = uaa->device; 167 usbd_interface_handle iface = uaa->iface; 168 usb_interface_descriptor_t *ifcd = usbd_get_interface_descriptor(iface); 169 usb_interface_descriptor_t *id, *iend; 170 usb_config_descriptor_t *cdesc; 171 usbd_status err; 172 usb_endpoint_descriptor_t *ed; 173 u_int8_t epcount; 174 int i, altno; 175 176 DPRINTFN(10,("ulpt_attach: sc=%p\n", sc)); 177 178 //printf("%s: iclass %d/%d\n", sc->sc_dev.dv_xname, 179 // ifcd->bInterfaceClass, ifcd->bInterfaceSubClass); 180 181 /* XXX 182 * Stepping through the alternate settings needs to be abstracted out. 183 */ 184 cdesc = usbd_get_config_descriptor(dev); 185 if (cdesc == NULL) { 186 printf("%s: failed to get configuration descriptor\n", 187 sc->sc_dev.dv_xname); 188 return; 189 } 190 iend = (usb_interface_descriptor_t *) 191 ((char *)cdesc + UGETW(cdesc->wTotalLength)); 192 #ifdef DIAGNOSTIC 193 if (ifcd < (usb_interface_descriptor_t *)cdesc || 194 ifcd >= iend) 195 panic("ulpt: iface desc out of range"); 196 #endif 197 /* Step through all the descriptors looking for bidir mode */ 198 for (id = ifcd, altno = 0; 199 id < iend; 200 id = (void *)((char *)id + id->bLength)) { 201 if (id->bDescriptorType == UDESC_INTERFACE && 202 id->bInterfaceNumber == ifcd->bInterfaceNumber) { 203 if (id->bInterfaceClass == UICLASS_PRINTER && 204 id->bInterfaceSubClass == UISUBCLASS_PRINTER && 205 (id->bInterfaceProtocol == UIPROTO_PRINTER_BI /*|| 206 id->bInterfaceProtocol == UIPROTO_PRINTER_1284*/)) 207 goto found; 208 altno++; 209 } 210 } 211 id = ifcd; /* not found, use original */ 212 found: 213 if (id != ifcd) { 214 /* Found a new bidir setting */ 215 DPRINTF(("ulpt_attach: set altno = %d\n", altno)); 216 err = usbd_set_interface(iface, altno); 217 if (err) { 218 printf("%s: setting alternate interface failed\n", 219 sc->sc_dev.dv_xname); 220 sc->sc_dying = 1; 221 return; 222 } 223 } 224 225 epcount = 0; 226 (void)usbd_endpoint_count(iface, &epcount); 227 228 sc->sc_in = -1; 229 sc->sc_out = -1; 230 for (i = 0; i < epcount; i++) { 231 ed = usbd_interface2endpoint_descriptor(iface, i); 232 if (ed == NULL) { 233 printf("%s: couldn't get ep %d\n", 234 sc->sc_dev.dv_xname, i); 235 return; 236 } 237 if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_IN && 238 UE_GET_XFERTYPE(ed->bmAttributes) == UE_BULK) { 239 sc->sc_in = ed->bEndpointAddress; 240 } else if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_OUT && 241 UE_GET_XFERTYPE(ed->bmAttributes) == UE_BULK) { 242 sc->sc_out = ed->bEndpointAddress; 243 } 244 } 245 if (sc->sc_out == -1) { 246 printf("%s: could not find bulk out endpoint\n", 247 sc->sc_dev.dv_xname); 248 sc->sc_dying = 1; 249 return; 250 } 251 252 if (usbd_get_quirks(dev)->uq_flags & UQ_BROKEN_BIDIR) { 253 /* This device doesn't handle reading properly. */ 254 sc->sc_in = -1; 255 } 256 257 printf("%s: using %s-directional mode\n", sc->sc_dev.dv_xname, 258 sc->sc_in >= 0 ? "bi" : "uni"); 259 260 DPRINTFN(10, ("ulpt_attach: bulk=%d\n", sc->sc_out)); 261 262 sc->sc_iface = iface; 263 sc->sc_ifaceno = id->bInterfaceNumber; 264 sc->sc_udev = dev; 265 266 #if 0 267 /* 268 * This code is disabled because for some mysterious reason it causes 269 * printing not to work. But only sometimes, and mostly with 270 * UHCI and less often with OHCI. *sigh* 271 */ 272 { 273 usb_config_descriptor_t *cd = usbd_get_config_descriptor(dev); 274 usb_device_request_t req; 275 int len, alen; 276 277 req.bmRequestType = UT_READ_CLASS_INTERFACE; 278 req.bRequest = UR_GET_DEVICE_ID; 279 USETW(req.wValue, cd->bConfigurationValue); 280 USETW2(req.wIndex, id->bInterfaceNumber, id->bAlternateSetting); 281 USETW(req.wLength, DEVINFOSIZE - 1); 282 err = usbd_do_request_flags(dev, &req, devinfop, USBD_SHORT_XFER_OK, 283 &alen, USBD_DEFAULT_TIMEOUT); 284 if (err) { 285 printf("%s: cannot get device id\n", sc->sc_dev.dv_xname); 286 } else if (alen <= 2) { 287 printf("%s: empty device id, no printer connected?\n", 288 sc->sc_dev.dv_xname); 289 } else { 290 /* devinfop now contains an IEEE-1284 device ID */ 291 len = ((devinfop[0] & 0xff) << 8) | (devinfop[1] & 0xff); 292 if (len > DEVINFOSIZE - 3) 293 len = DEVINFOSIZE - 3; 294 devinfo[len] = 0; 295 printf("%s: device id <", sc->sc_dev.dv_xname); 296 ieee1284_print_id(devinfop+2); 297 printf(">\n"); 298 } 299 } 300 #endif 301 usbd_add_drv_event(USB_EVENT_DRIVER_ATTACH, sc->sc_udev, 302 &sc->sc_dev); 303 } 304 305 int 306 ulpt_activate(struct device *self, enum devact act) 307 { 308 struct ulpt_softc *sc = (struct ulpt_softc *)self; 309 310 switch (act) { 311 case DVACT_ACTIVATE: 312 break; 313 314 case DVACT_DEACTIVATE: 315 sc->sc_dying = 1; 316 break; 317 } 318 return (0); 319 } 320 321 int 322 ulpt_detach(struct device *self, int flags) 323 { 324 struct ulpt_softc *sc = (struct ulpt_softc *)self; 325 int s; 326 int maj, mn; 327 328 DPRINTF(("ulpt_detach: sc=%p\n", sc)); 329 330 sc->sc_dying = 1; 331 if (sc->sc_out_pipe != NULL) 332 usbd_abort_pipe(sc->sc_out_pipe); 333 if (sc->sc_in_pipe != NULL) 334 usbd_abort_pipe(sc->sc_in_pipe); 335 336 s = splusb(); 337 if (--sc->sc_refcnt >= 0) { 338 /* There is noone to wake, aborting the pipe is enough */ 339 /* Wait for processes to go away. */ 340 usb_detach_wait(&sc->sc_dev); 341 } 342 splx(s); 343 344 /* locate the major number */ 345 for (maj = 0; maj < nchrdev; maj++) 346 if (cdevsw[maj].d_open == ulptopen) 347 break; 348 349 /* Nuke the vnodes for any open instances (calls close). */ 350 mn = self->dv_unit; 351 vdevgone(maj, mn, mn, VCHR); 352 vdevgone(maj, mn | ULPT_NOPRIME , mn | ULPT_NOPRIME, VCHR); 353 354 usbd_add_drv_event(USB_EVENT_DRIVER_DETACH, sc->sc_udev, 355 &sc->sc_dev); 356 357 return (0); 358 } 359 360 int 361 ulpt_status(struct ulpt_softc *sc) 362 { 363 usb_device_request_t req; 364 usbd_status err; 365 u_char status; 366 367 req.bmRequestType = UT_READ_CLASS_INTERFACE; 368 req.bRequest = UR_GET_PORT_STATUS; 369 USETW(req.wValue, 0); 370 USETW(req.wIndex, sc->sc_ifaceno); 371 USETW(req.wLength, 1); 372 err = usbd_do_request(sc->sc_udev, &req, &status); 373 DPRINTFN(1, ("ulpt_status: status=0x%02x err=%d\n", status, err)); 374 if (!err) 375 return (status); 376 else 377 return (0); 378 } 379 380 void 381 ulpt_reset(struct ulpt_softc *sc) 382 { 383 usb_device_request_t req; 384 385 DPRINTFN(1, ("ulpt_reset\n")); 386 req.bRequest = UR_SOFT_RESET; 387 USETW(req.wValue, 0); 388 USETW(req.wIndex, sc->sc_ifaceno); 389 USETW(req.wLength, 0); 390 391 /* 392 * There was a mistake in the USB printer 1.0 spec that gave the 393 * request type as UT_WRITE_CLASS_OTHER; it should have been 394 * UT_WRITE_CLASS_INTERFACE. Many printers use the old one, 395 * so we try both. 396 */ 397 req.bmRequestType = UT_WRITE_CLASS_OTHER; 398 if (usbd_do_request(sc->sc_udev, &req, 0)) { /* 1.0 */ 399 req.bmRequestType = UT_WRITE_CLASS_INTERFACE; 400 (void)usbd_do_request(sc->sc_udev, &req, 0); /* 1.1 */ 401 } 402 } 403 404 static void 405 ulpt_input(usbd_xfer_handle xfer, usbd_private_handle priv, usbd_status status) 406 { 407 struct ulpt_softc *sc = priv; 408 409 DPRINTFN(2,("ulpt_input: got some data\n")); 410 /* Do it again. */ 411 if (xfer == sc->sc_in_xfer1) 412 usbd_transfer(sc->sc_in_xfer2); 413 else 414 usbd_transfer(sc->sc_in_xfer1); 415 } 416 417 int ulptusein = 1; 418 419 /* 420 * Reset the printer, then wait until it's selected and not busy. 421 */ 422 int 423 ulptopen(dev_t dev, int flag, int mode, struct proc *p) 424 { 425 u_char flags = ULPTFLAGS(dev); 426 struct ulpt_softc *sc; 427 usbd_status err; 428 int error; 429 430 if (ULPTUNIT(dev) >= ulpt_cd.cd_ndevs) 431 return (ENXIO); 432 sc = ulpt_cd.cd_devs[ULPTUNIT(dev)]; 433 if (sc == NULL) 434 return (ENXIO); 435 436 if (sc == NULL || sc->sc_iface == NULL || sc->sc_dying) 437 return (ENXIO); 438 439 if (sc->sc_state) 440 return (EBUSY); 441 442 sc->sc_state = ULPT_INIT; 443 sc->sc_flags = flags; 444 DPRINTF(("ulptopen: flags=0x%x\n", (unsigned)flags)); 445 446 error = 0; 447 sc->sc_refcnt++; 448 449 if ((flags & ULPT_NOPRIME) == 0) { 450 ulpt_reset(sc); 451 if (sc->sc_dying) { 452 error = ENXIO; 453 sc->sc_state = 0; 454 goto done; 455 } 456 } 457 458 err = usbd_open_pipe(sc->sc_iface, sc->sc_out, 0, &sc->sc_out_pipe); 459 if (err) { 460 sc->sc_state = 0; 461 error = EIO; 462 goto done; 463 } 464 if (ulptusein && sc->sc_in != -1) { 465 DPRINTF(("ulpt_open: open input pipe\n")); 466 err = usbd_open_pipe(sc->sc_iface, sc->sc_in,0,&sc->sc_in_pipe); 467 if (err) { 468 error = EIO; 469 usbd_close_pipe(sc->sc_out_pipe); 470 sc->sc_out_pipe = NULL; 471 sc->sc_state = 0; 472 goto done; 473 } 474 sc->sc_in_xfer1 = usbd_alloc_xfer(sc->sc_udev); 475 sc->sc_in_xfer2 = usbd_alloc_xfer(sc->sc_udev); 476 if (sc->sc_in_xfer1 == NULL || sc->sc_in_xfer2 == NULL) { 477 error = ENOMEM; 478 if (sc->sc_in_xfer1 != NULL) { 479 usbd_free_xfer(sc->sc_in_xfer1); 480 sc->sc_in_xfer1 = NULL; 481 } 482 if (sc->sc_in_xfer2 != NULL) { 483 usbd_free_xfer(sc->sc_in_xfer2); 484 sc->sc_in_xfer2 = NULL; 485 } 486 usbd_close_pipe(sc->sc_out_pipe); 487 sc->sc_out_pipe = NULL; 488 usbd_close_pipe(sc->sc_in_pipe); 489 sc->sc_in_pipe = NULL; 490 sc->sc_state = 0; 491 goto done; 492 } 493 usbd_setup_xfer(sc->sc_in_xfer1, sc->sc_in_pipe, sc, 494 sc->sc_junk, sizeof sc->sc_junk, USBD_SHORT_XFER_OK, 495 USBD_NO_TIMEOUT, ulpt_input); 496 usbd_setup_xfer(sc->sc_in_xfer2, sc->sc_in_pipe, sc, 497 sc->sc_junk, sizeof sc->sc_junk, USBD_SHORT_XFER_OK, 498 USBD_NO_TIMEOUT, ulpt_input); 499 usbd_transfer(sc->sc_in_xfer1); /* ignore failed start */ 500 } 501 502 sc->sc_state = ULPT_OPEN; 503 504 done: 505 if (--sc->sc_refcnt < 0) 506 usb_detach_wakeup(&sc->sc_dev); 507 508 DPRINTF(("ulptopen: done, error=%d\n", error)); 509 return (error); 510 } 511 512 int 513 ulpt_statusmsg(u_char status, struct ulpt_softc *sc) 514 { 515 u_char new; 516 517 status = (status ^ LPS_INVERT) & LPS_MASK; 518 new = status & ~sc->sc_laststatus; 519 sc->sc_laststatus = status; 520 521 if (new & LPS_SELECT) 522 log(LOG_NOTICE, "%s: offline\n", sc->sc_dev.dv_xname); 523 else if (new & LPS_NOPAPER) 524 log(LOG_NOTICE, "%s: out of paper\n", sc->sc_dev.dv_xname); 525 else if (new & LPS_NERR) 526 log(LOG_NOTICE, "%s: output error\n", sc->sc_dev.dv_xname); 527 528 return (status); 529 } 530 531 int 532 ulptclose(dev_t dev, int flag, int mode, struct proc *p) 533 { 534 struct ulpt_softc *sc; 535 536 sc = ulpt_cd.cd_devs[ULPTUNIT(dev)]; 537 538 if (sc->sc_state != ULPT_OPEN) 539 /* We are being forced to close before the open completed. */ 540 return (0); 541 542 if (sc->sc_out_pipe != NULL) { 543 usbd_close_pipe(sc->sc_out_pipe); 544 sc->sc_out_pipe = NULL; 545 } 546 if (sc->sc_in_pipe != NULL) { 547 usbd_abort_pipe(sc->sc_in_pipe); 548 usbd_close_pipe(sc->sc_in_pipe); 549 sc->sc_in_pipe = NULL; 550 if (sc->sc_in_xfer1 != NULL) { 551 usbd_free_xfer(sc->sc_in_xfer1); 552 sc->sc_in_xfer1 = NULL; 553 } 554 if (sc->sc_in_xfer2 != NULL) { 555 usbd_free_xfer(sc->sc_in_xfer2); 556 sc->sc_in_xfer2 = NULL; 557 } 558 } 559 560 sc->sc_state = 0; 561 562 DPRINTF(("ulptclose: closed\n")); 563 return (0); 564 } 565 566 int 567 ulpt_do_write(struct ulpt_softc *sc, struct uio *uio, int flags) 568 { 569 u_int32_t n; 570 int error = 0; 571 void *bufp; 572 usbd_xfer_handle xfer; 573 usbd_status err; 574 575 DPRINTF(("ulptwrite\n")); 576 xfer = usbd_alloc_xfer(sc->sc_udev); 577 if (xfer == NULL) 578 return (ENOMEM); 579 bufp = usbd_alloc_buffer(xfer, ULPT_BSIZE); 580 if (bufp == NULL) { 581 usbd_free_xfer(xfer); 582 return (ENOMEM); 583 } 584 while ((n = min(ULPT_BSIZE, uio->uio_resid)) != 0) { 585 ulpt_statusmsg(ulpt_status(sc), sc); 586 error = uiomove(bufp, n, uio); 587 if (error) 588 break; 589 DPRINTFN(1, ("ulptwrite: transfer %d bytes\n", n)); 590 err = usbd_bulk_transfer(xfer, sc->sc_out_pipe, USBD_NO_COPY, 591 USBD_NO_TIMEOUT, bufp, &n, "ulptwr"); 592 if (err) { 593 DPRINTF(("ulptwrite: error=%d\n", err)); 594 error = EIO; 595 break; 596 } 597 } 598 usbd_free_xfer(xfer); 599 600 return (error); 601 } 602 603 int 604 ulptwrite(dev_t dev, struct uio *uio, int flags) 605 { 606 struct ulpt_softc *sc; 607 int error; 608 609 sc = ulpt_cd.cd_devs[ULPTUNIT(dev)]; 610 611 if (sc->sc_dying) 612 return (EIO); 613 614 sc->sc_refcnt++; 615 error = ulpt_do_write(sc, uio, flags); 616 if (--sc->sc_refcnt < 0) 617 usb_detach_wakeup(&sc->sc_dev); 618 return (error); 619 } 620 621 int 622 ulptioctl(dev_t dev, u_long cmd, caddr_t data, int flag, struct proc *p) 623 { 624 int error = 0; 625 626 switch (cmd) { 627 default: 628 error = ENODEV; 629 } 630 631 return (error); 632 } 633 634 #if 0 635 /* XXX This does not belong here. */ 636 /* 637 * Print select parts of a IEEE 1284 device ID. 638 */ 639 void 640 ieee1284_print_id(char *str) 641 { 642 char *p, *q; 643 644 for (p = str-1; p; p = strchr(p, ';')) { 645 p++; /* skip ';' */ 646 if (strncmp(p, "MFG:", 4) == 0 || 647 strncmp(p, "MANUFACTURER:", 14) == 0 || 648 strncmp(p, "MDL:", 4) == 0 || 649 strncmp(p, "MODEL:", 6) == 0) { 650 q = strchr(p, ';'); 651 if (q) 652 printf("%.*s", (int)(q - p + 1), p); 653 } 654 } 655 } 656 #endif 657