1 /* $OpenBSD: ulpt.c,v 1.39 2011/07/03 15:47:17 matthew 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 *, int); 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 } 302 303 int 304 ulpt_activate(struct device *self, int act) 305 { 306 struct ulpt_softc *sc = (struct ulpt_softc *)self; 307 308 switch (act) { 309 case DVACT_DEACTIVATE: 310 sc->sc_dying = 1; 311 break; 312 } 313 return (0); 314 } 315 316 int 317 ulpt_detach(struct device *self, int flags) 318 { 319 struct ulpt_softc *sc = (struct ulpt_softc *)self; 320 int s; 321 int maj, mn; 322 323 DPRINTF(("ulpt_detach: sc=%p\n", sc)); 324 325 if (sc->sc_out_pipe != NULL) 326 usbd_abort_pipe(sc->sc_out_pipe); 327 if (sc->sc_in_pipe != NULL) 328 usbd_abort_pipe(sc->sc_in_pipe); 329 330 s = splusb(); 331 if (--sc->sc_refcnt >= 0) { 332 /* There is noone to wake, aborting the pipe is enough */ 333 /* Wait for processes to go away. */ 334 usb_detach_wait(&sc->sc_dev); 335 } 336 splx(s); 337 338 /* locate the major number */ 339 for (maj = 0; maj < nchrdev; maj++) 340 if (cdevsw[maj].d_open == ulptopen) 341 break; 342 343 /* Nuke the vnodes for any open instances (calls close). */ 344 mn = self->dv_unit; 345 vdevgone(maj, mn, mn, VCHR); 346 vdevgone(maj, mn | ULPT_NOPRIME , mn | ULPT_NOPRIME, VCHR); 347 348 return (0); 349 } 350 351 int 352 ulpt_status(struct ulpt_softc *sc) 353 { 354 usb_device_request_t req; 355 usbd_status err; 356 u_char status; 357 358 req.bmRequestType = UT_READ_CLASS_INTERFACE; 359 req.bRequest = UR_GET_PORT_STATUS; 360 USETW(req.wValue, 0); 361 USETW(req.wIndex, sc->sc_ifaceno); 362 USETW(req.wLength, 1); 363 err = usbd_do_request(sc->sc_udev, &req, &status); 364 DPRINTFN(1, ("ulpt_status: status=0x%02x err=%d\n", status, err)); 365 if (!err) 366 return (status); 367 else 368 return (0); 369 } 370 371 void 372 ulpt_reset(struct ulpt_softc *sc) 373 { 374 usb_device_request_t req; 375 376 DPRINTFN(1, ("ulpt_reset\n")); 377 req.bRequest = UR_SOFT_RESET; 378 USETW(req.wValue, 0); 379 USETW(req.wIndex, sc->sc_ifaceno); 380 USETW(req.wLength, 0); 381 382 /* 383 * There was a mistake in the USB printer 1.0 spec that gave the 384 * request type as UT_WRITE_CLASS_OTHER; it should have been 385 * UT_WRITE_CLASS_INTERFACE. Many printers use the old one, 386 * so we try both. 387 */ 388 req.bmRequestType = UT_WRITE_CLASS_OTHER; 389 if (usbd_do_request(sc->sc_udev, &req, 0)) { /* 1.0 */ 390 req.bmRequestType = UT_WRITE_CLASS_INTERFACE; 391 (void)usbd_do_request(sc->sc_udev, &req, 0); /* 1.1 */ 392 } 393 } 394 395 static void 396 ulpt_input(usbd_xfer_handle xfer, usbd_private_handle priv, usbd_status status) 397 { 398 struct ulpt_softc *sc = priv; 399 400 DPRINTFN(2,("ulpt_input: got some data\n")); 401 /* Do it again. */ 402 if (xfer == sc->sc_in_xfer1) 403 usbd_transfer(sc->sc_in_xfer2); 404 else 405 usbd_transfer(sc->sc_in_xfer1); 406 } 407 408 int ulptusein = 1; 409 410 /* 411 * Reset the printer, then wait until it's selected and not busy. 412 */ 413 int 414 ulptopen(dev_t dev, int flag, int mode, struct proc *p) 415 { 416 u_char flags = ULPTFLAGS(dev); 417 struct ulpt_softc *sc; 418 usbd_status err; 419 int error; 420 421 if (ULPTUNIT(dev) >= ulpt_cd.cd_ndevs) 422 return (ENXIO); 423 sc = ulpt_cd.cd_devs[ULPTUNIT(dev)]; 424 if (sc == NULL) 425 return (ENXIO); 426 427 if (sc == NULL || sc->sc_iface == NULL || sc->sc_dying) 428 return (ENXIO); 429 430 if (sc->sc_state) 431 return (EBUSY); 432 433 sc->sc_state = ULPT_INIT; 434 sc->sc_flags = flags; 435 DPRINTF(("ulptopen: flags=0x%x\n", (unsigned)flags)); 436 437 error = 0; 438 sc->sc_refcnt++; 439 440 if ((flags & ULPT_NOPRIME) == 0) { 441 ulpt_reset(sc); 442 if (sc->sc_dying) { 443 error = ENXIO; 444 sc->sc_state = 0; 445 goto done; 446 } 447 } 448 449 err = usbd_open_pipe(sc->sc_iface, sc->sc_out, 0, &sc->sc_out_pipe); 450 if (err) { 451 sc->sc_state = 0; 452 error = EIO; 453 goto done; 454 } 455 if (ulptusein && sc->sc_in != -1) { 456 DPRINTF(("ulpt_open: open input pipe\n")); 457 err = usbd_open_pipe(sc->sc_iface, sc->sc_in,0,&sc->sc_in_pipe); 458 if (err) { 459 error = EIO; 460 usbd_close_pipe(sc->sc_out_pipe); 461 sc->sc_out_pipe = NULL; 462 sc->sc_state = 0; 463 goto done; 464 } 465 sc->sc_in_xfer1 = usbd_alloc_xfer(sc->sc_udev); 466 sc->sc_in_xfer2 = usbd_alloc_xfer(sc->sc_udev); 467 if (sc->sc_in_xfer1 == NULL || sc->sc_in_xfer2 == NULL) { 468 error = ENOMEM; 469 if (sc->sc_in_xfer1 != NULL) { 470 usbd_free_xfer(sc->sc_in_xfer1); 471 sc->sc_in_xfer1 = NULL; 472 } 473 if (sc->sc_in_xfer2 != NULL) { 474 usbd_free_xfer(sc->sc_in_xfer2); 475 sc->sc_in_xfer2 = NULL; 476 } 477 usbd_close_pipe(sc->sc_out_pipe); 478 sc->sc_out_pipe = NULL; 479 usbd_close_pipe(sc->sc_in_pipe); 480 sc->sc_in_pipe = NULL; 481 sc->sc_state = 0; 482 goto done; 483 } 484 usbd_setup_xfer(sc->sc_in_xfer1, sc->sc_in_pipe, sc, 485 sc->sc_junk, sizeof sc->sc_junk, USBD_SHORT_XFER_OK, 486 USBD_NO_TIMEOUT, ulpt_input); 487 usbd_setup_xfer(sc->sc_in_xfer2, sc->sc_in_pipe, sc, 488 sc->sc_junk, sizeof sc->sc_junk, USBD_SHORT_XFER_OK, 489 USBD_NO_TIMEOUT, ulpt_input); 490 usbd_transfer(sc->sc_in_xfer1); /* ignore failed start */ 491 } 492 493 sc->sc_state = ULPT_OPEN; 494 495 done: 496 if (--sc->sc_refcnt < 0) 497 usb_detach_wakeup(&sc->sc_dev); 498 499 DPRINTF(("ulptopen: done, error=%d\n", error)); 500 return (error); 501 } 502 503 int 504 ulpt_statusmsg(u_char status, struct ulpt_softc *sc) 505 { 506 u_char new; 507 508 status = (status ^ LPS_INVERT) & LPS_MASK; 509 new = status & ~sc->sc_laststatus; 510 sc->sc_laststatus = status; 511 512 if (new & LPS_SELECT) 513 log(LOG_NOTICE, "%s: offline\n", sc->sc_dev.dv_xname); 514 else if (new & LPS_NOPAPER) 515 log(LOG_NOTICE, "%s: out of paper\n", sc->sc_dev.dv_xname); 516 else if (new & LPS_NERR) 517 log(LOG_NOTICE, "%s: output error\n", sc->sc_dev.dv_xname); 518 519 return (status); 520 } 521 522 int 523 ulptclose(dev_t dev, int flag, int mode, struct proc *p) 524 { 525 struct ulpt_softc *sc; 526 527 sc = ulpt_cd.cd_devs[ULPTUNIT(dev)]; 528 529 if (sc->sc_state != ULPT_OPEN) 530 /* We are being forced to close before the open completed. */ 531 return (0); 532 533 if (sc->sc_out_pipe != NULL) { 534 usbd_close_pipe(sc->sc_out_pipe); 535 sc->sc_out_pipe = NULL; 536 } 537 if (sc->sc_in_pipe != NULL) { 538 usbd_abort_pipe(sc->sc_in_pipe); 539 usbd_close_pipe(sc->sc_in_pipe); 540 sc->sc_in_pipe = NULL; 541 if (sc->sc_in_xfer1 != NULL) { 542 usbd_free_xfer(sc->sc_in_xfer1); 543 sc->sc_in_xfer1 = NULL; 544 } 545 if (sc->sc_in_xfer2 != NULL) { 546 usbd_free_xfer(sc->sc_in_xfer2); 547 sc->sc_in_xfer2 = NULL; 548 } 549 } 550 551 sc->sc_state = 0; 552 553 DPRINTF(("ulptclose: closed\n")); 554 return (0); 555 } 556 557 int 558 ulpt_do_write(struct ulpt_softc *sc, struct uio *uio, int flags) 559 { 560 u_int32_t n; 561 int error = 0; 562 void *bufp; 563 usbd_xfer_handle xfer; 564 usbd_status err; 565 566 DPRINTF(("ulptwrite\n")); 567 xfer = usbd_alloc_xfer(sc->sc_udev); 568 if (xfer == NULL) 569 return (ENOMEM); 570 bufp = usbd_alloc_buffer(xfer, ULPT_BSIZE); 571 if (bufp == NULL) { 572 usbd_free_xfer(xfer); 573 return (ENOMEM); 574 } 575 while ((n = min(ULPT_BSIZE, uio->uio_resid)) != 0) { 576 ulpt_statusmsg(ulpt_status(sc), sc); 577 error = uiomove(bufp, n, uio); 578 if (error) 579 break; 580 DPRINTFN(1, ("ulptwrite: transfer %d bytes\n", n)); 581 err = usbd_bulk_transfer(xfer, sc->sc_out_pipe, USBD_NO_COPY, 582 USBD_NO_TIMEOUT, bufp, &n, "ulptwr"); 583 if (err) { 584 DPRINTF(("ulptwrite: error=%d\n", err)); 585 error = EIO; 586 break; 587 } 588 } 589 usbd_free_xfer(xfer); 590 591 return (error); 592 } 593 594 int 595 ulptwrite(dev_t dev, struct uio *uio, int flags) 596 { 597 struct ulpt_softc *sc; 598 int error; 599 600 sc = ulpt_cd.cd_devs[ULPTUNIT(dev)]; 601 602 if (sc->sc_dying) 603 return (EIO); 604 605 sc->sc_refcnt++; 606 error = ulpt_do_write(sc, uio, flags); 607 if (--sc->sc_refcnt < 0) 608 usb_detach_wakeup(&sc->sc_dev); 609 return (error); 610 } 611 612 int 613 ulptioctl(dev_t dev, u_long cmd, caddr_t data, int flag, struct proc *p) 614 { 615 int error = 0; 616 617 switch (cmd) { 618 default: 619 error = ENODEV; 620 } 621 622 return (error); 623 } 624 625 #if 0 626 /* XXX This does not belong here. */ 627 /* 628 * Print select parts of a IEEE 1284 device ID. 629 */ 630 void 631 ieee1284_print_id(char *str) 632 { 633 char *p, *q; 634 635 for (p = str-1; p; p = strchr(p, ';')) { 636 p++; /* skip ';' */ 637 if (strncmp(p, "MFG:", 4) == 0 || 638 strncmp(p, "MANUFACTURER:", 14) == 0 || 639 strncmp(p, "MDL:", 4) == 0 || 640 strncmp(p, "MODEL:", 6) == 0) { 641 q = strchr(p, ';'); 642 if (q) 643 printf("%.*s", (int)(q - p + 1), p); 644 } 645 } 646 } 647 #endif 648