Annotation of sys/dev/usb/uscanner.c, Revision 1.1
1.1 ! nbrk 1: /* $OpenBSD: uscanner.c,v 1.35 2007/06/14 10:11:16 mbalmer Exp $ */
! 2: /* $NetBSD: uscanner.c,v 1.40 2003/01/27 00:32:44 wiz Exp $ */
! 3:
! 4: /*
! 5: * Copyright (c) 2000 The NetBSD Foundation, Inc.
! 6: * All rights reserved.
! 7: *
! 8: * This code is derived from software contributed to The NetBSD Foundation
! 9: * by Lennart Augustsson (lennart@augustsson.net) at
! 10: * Carlstedt Research & Technology
! 11: * and Nick Hibma (n_hibma@qubesoft.com).
! 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: #include <sys/param.h>
! 44: #include <sys/systm.h>
! 45: #include <sys/kernel.h>
! 46: #include <sys/malloc.h>
! 47: #include <sys/device.h>
! 48: #include <sys/tty.h>
! 49: #include <sys/file.h>
! 50: #include <sys/selinfo.h>
! 51: #include <sys/proc.h>
! 52: #include <sys/vnode.h>
! 53: #include <sys/poll.h>
! 54: #include <sys/conf.h>
! 55:
! 56: #include <dev/usb/usb.h>
! 57: #include <dev/usb/usbdi.h>
! 58: #include <dev/usb/usbdi_util.h>
! 59:
! 60: #include <dev/usb/usbdevs.h>
! 61:
! 62: #ifdef USCANNER_DEBUG
! 63: #define DPRINTF(x) do { if (uscannerdebug) printf x; } while (0)
! 64: #define DPRINTFN(n,x) do { if (uscannerdebug>(n)) printf x; } while (0)
! 65: int uscannerdebug = 0;
! 66: #else
! 67: #define DPRINTF(x)
! 68: #define DPRINTFN(n,x)
! 69: #endif
! 70:
! 71: struct uscan_info {
! 72: struct usb_devno devno;
! 73: u_int flags;
! 74: #define USC_KEEP_OPEN 1
! 75: };
! 76:
! 77: /* Table of scanners that may work with this driver. */
! 78: static const struct uscan_info uscanner_devs[] = {
! 79: /* Acer Peripherals */
! 80: {{ USB_VENDOR_ACERP, USB_PRODUCT_ACERP_ACERSCAN_320U }, 0 },
! 81: {{ USB_VENDOR_ACERP, USB_PRODUCT_ACERP_ACERSCAN_640U }, 0 },
! 82: {{ USB_VENDOR_ACERP, USB_PRODUCT_ACERP_ACERSCAN_620U }, 0 },
! 83: {{ USB_VENDOR_ACERP, USB_PRODUCT_ACERP_ACERSCAN_C310U }, 0 },
! 84:
! 85: /* AGFA */
! 86: {{ USB_VENDOR_AGFA, USB_PRODUCT_AGFA_SNAPSCAN1236U }, 0 },
! 87: {{ USB_VENDOR_AGFA, USB_PRODUCT_AGFA_SNAPSCAN1212U }, 0 },
! 88: {{ USB_VENDOR_AGFA, USB_PRODUCT_AGFA_SNAPSCAN1212U2 }, 0 },
! 89: {{ USB_VENDOR_AGFA, USB_PRODUCT_AGFA_SNAPSCANTOUCH }, 0 },
! 90: {{ USB_VENDOR_AGFA, USB_PRODUCT_AGFA_SNAPSCANE40 }, 0 },
! 91: {{ USB_VENDOR_AGFA, USB_PRODUCT_AGFA_SNAPSCANE50 }, 0 },
! 92: {{ USB_VENDOR_AGFA, USB_PRODUCT_AGFA_SNAPSCANE20 }, 0 },
! 93: {{ USB_VENDOR_AGFA, USB_PRODUCT_AGFA_SNAPSCANE25 }, 0 },
! 94: {{ USB_VENDOR_AGFA, USB_PRODUCT_AGFA_SNAPSCANE26 }, 0 },
! 95: {{ USB_VENDOR_AGFA, USB_PRODUCT_AGFA_SNAPSCANE52 }, 0 },
! 96:
! 97: /* Avision */
! 98: {{ USB_VENDOR_AVISION, USB_PRODUCT_AVISION_1200U }, 0 },
! 99:
! 100: /* Canon */
! 101: {{ USB_VENDOR_CANON, USB_PRODUCT_CANON_N656U }, 0 },
! 102: {{ USB_VENDOR_CANON, USB_PRODUCT_CANON_N670U }, 0 },
! 103: {{ USB_VENDOR_CANON, USB_PRODUCT_CANON_N1220U }, 0 },
! 104: {{ USB_VENDOR_CANON, USB_PRODUCT_CANON_N1240U }, 0 },
! 105:
! 106: /* Kye */
! 107: {{ USB_VENDOR_KYE, USB_PRODUCT_KYE_VIVIDPRO }, 0 },
! 108:
! 109: /* HP */
! 110: {{ USB_VENDOR_HP, USB_PRODUCT_HP_2200C }, 0 },
! 111: {{ USB_VENDOR_HP, USB_PRODUCT_HP_3300C }, 0 },
! 112: {{ USB_VENDOR_HP, USB_PRODUCT_HP_3400CSE }, 0 },
! 113: {{ USB_VENDOR_HP, USB_PRODUCT_HP_4100C }, 0 },
! 114: {{ USB_VENDOR_HP, USB_PRODUCT_HP_4200C }, 0 },
! 115: {{ USB_VENDOR_HP, USB_PRODUCT_HP_4300C }, 0 },
! 116: {{ USB_VENDOR_HP, USB_PRODUCT_HP_S20 }, 0 },
! 117: {{ USB_VENDOR_HP, USB_PRODUCT_HP_5200C }, 0 },
! 118: #if 0
! 119: /* Handled by usscanner */
! 120: {{ USB_VENDOR_HP, USB_PRODUCT_HP_5300C }, 0 },
! 121: #endif
! 122: {{ USB_VENDOR_HP, USB_PRODUCT_HP_6200C }, 0 },
! 123: {{ USB_VENDOR_HP, USB_PRODUCT_HP_6300C }, 0 },
! 124:
! 125: #if 0
! 126: /* XXX Should be handled by usscanner */
! 127: /* Microtek */
! 128: {{ USB_VENDOR_SCANLOGIC, USB_PRODUCT_SCANLOGIC_336CX }, 0 },
! 129: {{ USB_VENDOR_MICROTEK, USB_PRODUCT_MICROTEK_X6U }, 0 },
! 130: {{ USB_VENDOR_MICROTEK, USB_PRODUCT_MICROTEK_336CX }, 0 },
! 131: {{ USB_VENDOR_MICROTEK, USB_PRODUCT_MICROTEK_336CX2 }, 0 },
! 132: {{ USB_VENDOR_MICROTEK, USB_PRODUCT_MICROTEK_C6 }, 0 },
! 133: {{ USB_VENDOR_MICROTEK, USB_PRODUCT_MICROTEK_V6USL }, 0 },
! 134: {{ USB_VENDOR_MICROTEK, USB_PRODUCT_MICROTEK_V6USL2 }, 0 },
! 135: {{ USB_VENDOR_MICROTEK, USB_PRODUCT_MICROTEK_V6UL }, 0 },
! 136: #endif
! 137:
! 138: /* Mustek */
! 139: {{ USB_VENDOR_MUSTEK, USB_PRODUCT_MUSTEK_1200CU }, 0 },
! 140: {{ USB_VENDOR_MUSTEK, USB_PRODUCT_MUSTEK_BEARPAW1200F }, 0 },
! 141: {{ USB_VENDOR_MUSTEK, USB_PRODUCT_MUSTEK_600USB }, 0 },
! 142: {{ USB_VENDOR_MUSTEK, USB_PRODUCT_MUSTEK_600CU }, 0 },
! 143: {{ USB_VENDOR_MUSTEK, USB_PRODUCT_MUSTEK_1200USB }, 0 },
! 144: {{ USB_VENDOR_MUSTEK, USB_PRODUCT_MUSTEK_1200UB }, 0 },
! 145: {{ USB_VENDOR_MUSTEK, USB_PRODUCT_MUSTEK_1200USBPLUS }, 0 },
! 146: {{ USB_VENDOR_MUSTEK, USB_PRODUCT_MUSTEK_1200CUPLUS }, 0 },
! 147:
! 148: /* National */
! 149: {{ USB_VENDOR_NATIONAL, USB_PRODUCT_NATIONAL_BEARPAW1200 }, 0 },
! 150: {{ USB_VENDOR_NATIONAL, USB_PRODUCT_NATIONAL_BEARPAW2400 }, 0 },
! 151:
! 152: /* Primax */
! 153: {{ USB_VENDOR_PRIMAX, USB_PRODUCT_PRIMAX_G2X300 }, 0 },
! 154: {{ USB_VENDOR_PRIMAX, USB_PRODUCT_PRIMAX_G2E300 }, 0 },
! 155: {{ USB_VENDOR_PRIMAX, USB_PRODUCT_PRIMAX_G2300 }, 0 },
! 156: {{ USB_VENDOR_PRIMAX, USB_PRODUCT_PRIMAX_G2E3002 }, 0 },
! 157: {{ USB_VENDOR_PRIMAX, USB_PRODUCT_PRIMAX_9600 }, 0 },
! 158: {{ USB_VENDOR_PRIMAX, USB_PRODUCT_PRIMAX_600U }, 0 },
! 159: {{ USB_VENDOR_PRIMAX, USB_PRODUCT_PRIMAX_6200 }, 0 },
! 160: {{ USB_VENDOR_PRIMAX, USB_PRODUCT_PRIMAX_19200 }, 0 },
! 161: {{ USB_VENDOR_PRIMAX, USB_PRODUCT_PRIMAX_1200U }, 0 },
! 162: {{ USB_VENDOR_PRIMAX, USB_PRODUCT_PRIMAX_G600 }, 0 },
! 163: {{ USB_VENDOR_PRIMAX, USB_PRODUCT_PRIMAX_636I }, 0 },
! 164: {{ USB_VENDOR_PRIMAX, USB_PRODUCT_PRIMAX_G2600 }, 0 },
! 165: {{ USB_VENDOR_PRIMAX, USB_PRODUCT_PRIMAX_G2E600 }, 0 },
! 166:
! 167: /* Epson */
! 168: {{ USB_VENDOR_EPSON, USB_PRODUCT_EPSON_636 }, 0 },
! 169: {{ USB_VENDOR_EPSON, USB_PRODUCT_EPSON_610 }, 0 },
! 170: {{ USB_VENDOR_EPSON, USB_PRODUCT_EPSON_1200 }, 0 },
! 171: {{ USB_VENDOR_EPSON, USB_PRODUCT_EPSON_1240 }, 0 },
! 172: {{ USB_VENDOR_EPSON, USB_PRODUCT_EPSON_1260 }, 0 },
! 173: {{ USB_VENDOR_EPSON, USB_PRODUCT_EPSON_1600 }, 0 },
! 174: {{ USB_VENDOR_EPSON, USB_PRODUCT_EPSON_1640 }, 0 },
! 175: {{ USB_VENDOR_EPSON, USB_PRODUCT_EPSON_1660 }, 0 },
! 176: {{ USB_VENDOR_EPSON, USB_PRODUCT_EPSON_640U }, 0 },
! 177: {{ USB_VENDOR_EPSON, USB_PRODUCT_EPSON_1650 }, 0 },
! 178: {{ USB_VENDOR_EPSON, USB_PRODUCT_EPSON_2400 }, 0 },
! 179: {{ USB_VENDOR_EPSON, USB_PRODUCT_EPSON_GT9700F }, USC_KEEP_OPEN },
! 180:
! 181: /* UMAX */
! 182: {{ USB_VENDOR_UMAX, USB_PRODUCT_UMAX_ASTRA1220U }, 0 },
! 183: {{ USB_VENDOR_UMAX, USB_PRODUCT_UMAX_ASTRA1236U }, 0 },
! 184: {{ USB_VENDOR_UMAX, USB_PRODUCT_UMAX_ASTRA2000U }, 0 },
! 185: {{ USB_VENDOR_UMAX, USB_PRODUCT_UMAX_ASTRA2200U }, 0 },
! 186: {{ USB_VENDOR_UMAX, USB_PRODUCT_UMAX_ASTRA3400 }, 0 },
! 187:
! 188: /* Visioneer */
! 189: {{ USB_VENDOR_VISIONEER, USB_PRODUCT_VISIONEER_3000 }, 0 },
! 190: {{ USB_VENDOR_VISIONEER, USB_PRODUCT_VISIONEER_5300 }, 0 },
! 191: {{ USB_VENDOR_VISIONEER, USB_PRODUCT_VISIONEER_7600 }, 0 },
! 192: {{ USB_VENDOR_VISIONEER, USB_PRODUCT_VISIONEER_6100 }, 0 },
! 193: {{ USB_VENDOR_VISIONEER, USB_PRODUCT_VISIONEER_6200 }, 0 },
! 194: {{ USB_VENDOR_VISIONEER, USB_PRODUCT_VISIONEER_8100 }, 0 },
! 195: {{ USB_VENDOR_VISIONEER, USB_PRODUCT_VISIONEER_8600 }, 0 },
! 196:
! 197: /* Ultima */
! 198: {{ USB_VENDOR_ULTIMA, USB_PRODUCT_ULTIMA_1200UBPLUS }, 0 },
! 199:
! 200: };
! 201: #define uscanner_lookup(v, p) ((const struct uscan_info *)usb_lookup(uscanner_devs, v, p))
! 202:
! 203: #define USCANNER_BUFFERSIZE 1024
! 204:
! 205: struct uscanner_softc {
! 206: struct device sc_dev; /* base device */
! 207: usbd_device_handle sc_udev;
! 208: usbd_interface_handle sc_iface;
! 209:
! 210: u_int sc_dev_flags;
! 211:
! 212: usbd_pipe_handle sc_bulkin_pipe;
! 213: int sc_bulkin;
! 214: usbd_xfer_handle sc_bulkin_xfer;
! 215: void *sc_bulkin_buffer;
! 216: int sc_bulkin_bufferlen;
! 217: int sc_bulkin_datalen;
! 218:
! 219: usbd_pipe_handle sc_bulkout_pipe;
! 220: int sc_bulkout;
! 221: usbd_xfer_handle sc_bulkout_xfer;
! 222: void *sc_bulkout_buffer;
! 223: int sc_bulkout_bufferlen;
! 224: int sc_bulkout_datalen;
! 225:
! 226: struct selinfo sc_selq;
! 227:
! 228: u_char sc_state;
! 229: #define USCANNER_OPEN 0x01 /* opened */
! 230:
! 231: int sc_refcnt;
! 232: u_char sc_dying;
! 233: };
! 234:
! 235: int uscanner_do_read(struct uscanner_softc *, struct uio *, int);
! 236: int uscanner_do_write(struct uscanner_softc *, struct uio *, int);
! 237: void uscanner_do_close(struct uscanner_softc *);
! 238:
! 239: #define USCANNERUNIT(n) (minor(n))
! 240:
! 241: int uscanner_match(struct device *, void *, void *);
! 242: void uscanner_attach(struct device *, struct device *, void *);
! 243: int uscanner_detach(struct device *, int);
! 244: int uscanner_activate(struct device *, enum devact);
! 245:
! 246: struct cfdriver uscanner_cd = {
! 247: NULL, "uscanner", DV_DULL
! 248: };
! 249:
! 250: const struct cfattach uscanner_ca = {
! 251: sizeof(struct uscanner_softc),
! 252: uscanner_match,
! 253: uscanner_attach,
! 254: uscanner_detach,
! 255: uscanner_activate,
! 256: };
! 257:
! 258: int
! 259: uscanner_match(struct device *parent, void *match, void *aux)
! 260: {
! 261: struct usb_attach_arg *uaa = aux;
! 262:
! 263: if (uaa->iface != NULL)
! 264: return UMATCH_NONE;
! 265:
! 266: return (uscanner_lookup(uaa->vendor, uaa->product) != NULL ?
! 267: UMATCH_VENDOR_PRODUCT : UMATCH_NONE);
! 268: }
! 269:
! 270: void
! 271: uscanner_attach(struct device *parent, struct device *self, void *aux)
! 272: {
! 273: struct uscanner_softc *sc = (struct uscanner_softc *)self;
! 274: struct usb_attach_arg *uaa = aux;
! 275: usb_interface_descriptor_t *id = 0;
! 276: usb_endpoint_descriptor_t *ed, *ed_bulkin = NULL, *ed_bulkout = NULL;
! 277: char *devinfop;
! 278: int i;
! 279: usbd_status err;
! 280:
! 281: devinfop = usbd_devinfo_alloc(uaa->device, 0);
! 282: printf("\n%s: %s\n", sc->sc_dev.dv_xname, devinfop);
! 283: usbd_devinfo_free(devinfop);
! 284:
! 285: sc->sc_dev_flags = uscanner_lookup(uaa->vendor, uaa->product)->flags;
! 286:
! 287: sc->sc_udev = uaa->device;
! 288:
! 289: err = usbd_set_config_no(uaa->device, 1, 1); /* XXX */
! 290: if (err) {
! 291: printf("%s: setting config no failed\n",
! 292: sc->sc_dev.dv_xname);
! 293: return;
! 294: }
! 295:
! 296: /* XXX We only check the first interface */
! 297: err = usbd_device2interface_handle(sc->sc_udev, 0, &sc->sc_iface);
! 298: if (!err && sc->sc_iface)
! 299: id = usbd_get_interface_descriptor(sc->sc_iface);
! 300: if (err || id == 0) {
! 301: printf("%s: could not get interface descriptor, err=%d,id=%p\n",
! 302: sc->sc_dev.dv_xname, err, id);
! 303: return;
! 304: }
! 305:
! 306: /* Find the two first bulk endpoints */
! 307: for (i = 0 ; i < id->bNumEndpoints; i++) {
! 308: ed = usbd_interface2endpoint_descriptor(sc->sc_iface, i);
! 309: if (ed == 0) {
! 310: printf("%s: could not read endpoint descriptor\n",
! 311: sc->sc_dev.dv_xname);
! 312: return;
! 313: }
! 314:
! 315: if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_IN
! 316: && (ed->bmAttributes & UE_XFERTYPE) == UE_BULK) {
! 317: ed_bulkin = ed;
! 318: } else if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_OUT
! 319: && (ed->bmAttributes & UE_XFERTYPE) == UE_BULK) {
! 320: ed_bulkout = ed;
! 321: }
! 322:
! 323: if (ed_bulkin && ed_bulkout) /* found all we need */
! 324: break;
! 325: }
! 326:
! 327: /* Verify that we goething sensible */
! 328: if (ed_bulkin == NULL || ed_bulkout == NULL) {
! 329: printf("%s: bulk-in and/or bulk-out endpoint not found\n",
! 330: sc->sc_dev.dv_xname);
! 331: return;
! 332: }
! 333:
! 334: sc->sc_bulkin = ed_bulkin->bEndpointAddress;
! 335: sc->sc_bulkout = ed_bulkout->bEndpointAddress;
! 336:
! 337: usbd_add_drv_event(USB_EVENT_DRIVER_ATTACH, sc->sc_udev,
! 338: &sc->sc_dev);
! 339: }
! 340:
! 341: int
! 342: uscanneropen(dev_t dev, int flag, int mode, struct proc *p)
! 343: {
! 344: struct uscanner_softc *sc;
! 345: int unit = USCANNERUNIT(dev);
! 346: usbd_status err;
! 347:
! 348: if (unit >= uscanner_cd.cd_ndevs)
! 349: return (ENXIO);
! 350: sc = uscanner_cd.cd_devs[unit];
! 351: if (sc == NULL)
! 352: return (ENXIO);
! 353:
! 354: DPRINTFN(5, ("uscanneropen: flag=%d, mode=%d, unit=%d\n",
! 355: flag, mode, unit));
! 356:
! 357: if (sc->sc_dying)
! 358: return (ENXIO);
! 359:
! 360: if (sc->sc_state & USCANNER_OPEN)
! 361: return (EBUSY);
! 362:
! 363: sc->sc_state |= USCANNER_OPEN;
! 364:
! 365: sc->sc_bulkin_buffer = malloc(USCANNER_BUFFERSIZE, M_USBDEV, M_WAITOK);
! 366: sc->sc_bulkout_buffer = malloc(USCANNER_BUFFERSIZE, M_USBDEV, M_WAITOK);
! 367: /* No need to check buffers for NULL since we have WAITOK */
! 368:
! 369: sc->sc_bulkin_bufferlen = USCANNER_BUFFERSIZE;
! 370: sc->sc_bulkout_bufferlen = USCANNER_BUFFERSIZE;
! 371:
! 372: /* We have decided on which endpoints to use, now open the pipes */
! 373: if (sc->sc_bulkin_pipe == NULL) {
! 374: err = usbd_open_pipe(sc->sc_iface, sc->sc_bulkin,
! 375: USBD_EXCLUSIVE_USE, &sc->sc_bulkin_pipe);
! 376: if (err) {
! 377: printf("%s: cannot open bulk-in pipe (addr %d)\n",
! 378: sc->sc_dev.dv_xname, sc->sc_bulkin);
! 379: uscanner_do_close(sc);
! 380: return (EIO);
! 381: }
! 382: }
! 383: if (sc->sc_bulkout_pipe == NULL) {
! 384: err = usbd_open_pipe(sc->sc_iface, sc->sc_bulkout,
! 385: USBD_EXCLUSIVE_USE, &sc->sc_bulkout_pipe);
! 386: if (err) {
! 387: printf("%s: cannot open bulk-out pipe (addr %d)\n",
! 388: sc->sc_dev.dv_xname, sc->sc_bulkout);
! 389: uscanner_do_close(sc);
! 390: return (EIO);
! 391: }
! 392: }
! 393:
! 394: sc->sc_bulkin_xfer = usbd_alloc_xfer(sc->sc_udev);
! 395: if (sc->sc_bulkin_xfer == NULL) {
! 396: uscanner_do_close(sc);
! 397: return (ENOMEM);
! 398: }
! 399: sc->sc_bulkout_xfer = usbd_alloc_xfer(sc->sc_udev);
! 400: if (sc->sc_bulkout_xfer == NULL) {
! 401: uscanner_do_close(sc);
! 402: return (ENOMEM);
! 403: }
! 404:
! 405: return (0); /* success */
! 406: }
! 407:
! 408: int
! 409: uscannerclose(dev_t dev, int flag, int mode, struct proc *p)
! 410: {
! 411: struct uscanner_softc *sc;
! 412:
! 413: sc = uscanner_cd.cd_devs[USCANNERUNIT(dev)];
! 414:
! 415: DPRINTFN(5, ("uscannerclose: flag=%d, mode=%d, unit=%d\n",
! 416: flag, mode, USCANNERUNIT(dev)));
! 417:
! 418: #ifdef DIAGNOSTIC
! 419: if (!(sc->sc_state & USCANNER_OPEN)) {
! 420: printf("uscannerclose: not open\n");
! 421: return (EINVAL);
! 422: }
! 423: #endif
! 424:
! 425: uscanner_do_close(sc);
! 426:
! 427: return (0);
! 428: }
! 429:
! 430: void
! 431: uscanner_do_close(struct uscanner_softc *sc)
! 432: {
! 433: if (sc->sc_bulkin_xfer) {
! 434: usbd_free_xfer(sc->sc_bulkin_xfer);
! 435: sc->sc_bulkin_xfer = NULL;
! 436: }
! 437: if (sc->sc_bulkout_xfer) {
! 438: usbd_free_xfer(sc->sc_bulkout_xfer);
! 439: sc->sc_bulkout_xfer = NULL;
! 440: }
! 441:
! 442: if (!(sc->sc_dev_flags & USC_KEEP_OPEN)) {
! 443: if (sc->sc_bulkin_pipe != NULL) {
! 444: usbd_abort_pipe(sc->sc_bulkin_pipe);
! 445: usbd_close_pipe(sc->sc_bulkin_pipe);
! 446: sc->sc_bulkin_pipe = NULL;
! 447: }
! 448: if (sc->sc_bulkout_pipe != NULL) {
! 449: usbd_abort_pipe(sc->sc_bulkout_pipe);
! 450: usbd_close_pipe(sc->sc_bulkout_pipe);
! 451: sc->sc_bulkout_pipe = NULL;
! 452: }
! 453: }
! 454:
! 455: if (sc->sc_bulkin_buffer) {
! 456: free(sc->sc_bulkin_buffer, M_USBDEV);
! 457: sc->sc_bulkin_buffer = NULL;
! 458: }
! 459: if (sc->sc_bulkout_buffer) {
! 460: free(sc->sc_bulkout_buffer, M_USBDEV);
! 461: sc->sc_bulkout_buffer = NULL;
! 462: }
! 463:
! 464: sc->sc_state &= ~USCANNER_OPEN;
! 465: }
! 466:
! 467: int
! 468: uscanner_do_read(struct uscanner_softc *sc, struct uio *uio, int flag)
! 469: {
! 470: u_int32_t n, tn;
! 471: usbd_status err;
! 472: int error = 0;
! 473:
! 474: DPRINTFN(5, ("%s: uscannerread\n", sc->sc_dev.dv_xname));
! 475:
! 476: if (sc->sc_dying)
! 477: return (EIO);
! 478:
! 479: while ((n = min(sc->sc_bulkin_bufferlen, uio->uio_resid)) != 0) {
! 480: DPRINTFN(1, ("uscannerread: start transfer %d bytes\n",n));
! 481: tn = n;
! 482:
! 483: err = usbd_bulk_transfer(
! 484: sc->sc_bulkin_xfer, sc->sc_bulkin_pipe,
! 485: USBD_SHORT_XFER_OK, USBD_NO_TIMEOUT,
! 486: sc->sc_bulkin_buffer, &tn,
! 487: "uscnrb");
! 488: if (err) {
! 489: if (err == USBD_INTERRUPTED)
! 490: error = EINTR;
! 491: else if (err == USBD_TIMEOUT)
! 492: error = ETIMEDOUT;
! 493: else
! 494: error = EIO;
! 495: break;
! 496: }
! 497: DPRINTFN(1, ("uscannerread: got %d bytes\n", tn));
! 498: error = uiomove(sc->sc_bulkin_buffer, tn, uio);
! 499: if (error || tn < n)
! 500: break;
! 501: }
! 502:
! 503: return (error);
! 504: }
! 505:
! 506: int
! 507: uscannerread(dev_t dev, struct uio *uio, int flag)
! 508: {
! 509: struct uscanner_softc *sc;
! 510: int error;
! 511:
! 512: sc = uscanner_cd.cd_devs[USCANNERUNIT(dev)];
! 513:
! 514: sc->sc_refcnt++;
! 515: error = uscanner_do_read(sc, uio, flag);
! 516: if (--sc->sc_refcnt < 0)
! 517: usb_detach_wakeup(&sc->sc_dev);
! 518:
! 519: return (error);
! 520: }
! 521:
! 522: int
! 523: uscanner_do_write(struct uscanner_softc *sc, struct uio *uio, int flag)
! 524: {
! 525: u_int32_t n;
! 526: int error = 0;
! 527: usbd_status err;
! 528:
! 529: DPRINTFN(5, ("%s: uscanner_do_write\n", sc->sc_dev.dv_xname));
! 530:
! 531: if (sc->sc_dying)
! 532: return (EIO);
! 533:
! 534: while ((n = min(sc->sc_bulkout_bufferlen, uio->uio_resid)) != 0) {
! 535: error = uiomove(sc->sc_bulkout_buffer, n, uio);
! 536: if (error)
! 537: break;
! 538: DPRINTFN(1, ("uscanner_do_write: transfer %d bytes\n", n));
! 539: err = usbd_bulk_transfer(
! 540: sc->sc_bulkout_xfer, sc->sc_bulkout_pipe,
! 541: 0, USBD_NO_TIMEOUT,
! 542: sc->sc_bulkout_buffer, &n,
! 543: "uscnwb");
! 544: if (err) {
! 545: if (err == USBD_INTERRUPTED)
! 546: error = EINTR;
! 547: else
! 548: error = EIO;
! 549: break;
! 550: }
! 551: }
! 552:
! 553: return (error);
! 554: }
! 555:
! 556: int
! 557: uscannerwrite(dev_t dev, struct uio *uio, int flag)
! 558: {
! 559: struct uscanner_softc *sc;
! 560: int error;
! 561:
! 562: sc = uscanner_cd.cd_devs[USCANNERUNIT(dev)];
! 563:
! 564: sc->sc_refcnt++;
! 565: error = uscanner_do_write(sc, uio, flag);
! 566: if (--sc->sc_refcnt < 0)
! 567: usb_detach_wakeup(&sc->sc_dev);
! 568: return (error);
! 569: }
! 570:
! 571: int
! 572: uscanner_activate(struct device *self, enum devact act)
! 573: {
! 574: struct uscanner_softc *sc = (struct uscanner_softc *)self;
! 575:
! 576: switch (act) {
! 577: case DVACT_ACTIVATE:
! 578: break;
! 579:
! 580: case DVACT_DEACTIVATE:
! 581: sc->sc_dying = 1;
! 582: break;
! 583: }
! 584: return (0);
! 585: }
! 586:
! 587: int
! 588: uscanner_detach(struct device *self, int flags)
! 589: {
! 590: struct uscanner_softc *sc = (struct uscanner_softc *)self;
! 591: int s;
! 592: int maj, mn;
! 593:
! 594: DPRINTF(("uscanner_detach: sc=%p flags=%d\n", sc, flags));
! 595:
! 596: sc->sc_dying = 1;
! 597: sc->sc_dev_flags = 0; /* make close really close device */
! 598:
! 599: /* Abort all pipes. Causes processes waiting for transfer to wake. */
! 600: if (sc->sc_bulkin_pipe != NULL)
! 601: usbd_abort_pipe(sc->sc_bulkin_pipe);
! 602: if (sc->sc_bulkout_pipe != NULL)
! 603: usbd_abort_pipe(sc->sc_bulkout_pipe);
! 604:
! 605: s = splusb();
! 606: if (--sc->sc_refcnt >= 0) {
! 607: /* Wait for processes to go away. */
! 608: usb_detach_wait(&sc->sc_dev);
! 609: }
! 610: splx(s);
! 611:
! 612: /* locate the major number */
! 613: for (maj = 0; maj < nchrdev; maj++)
! 614: if (cdevsw[maj].d_open == uscanneropen)
! 615: break;
! 616:
! 617: /* Nuke the vnodes for any open instances (calls close). */
! 618: mn = self->dv_unit * USB_MAX_ENDPOINTS;
! 619: vdevgone(maj, mn, mn + USB_MAX_ENDPOINTS - 1, VCHR);
! 620: usbd_add_drv_event(USB_EVENT_DRIVER_DETACH, sc->sc_udev,
! 621: &sc->sc_dev);
! 622:
! 623: return (0);
! 624: }
! 625:
! 626: int
! 627: uscannerpoll(dev_t dev, int events, struct proc *p)
! 628: {
! 629: struct uscanner_softc *sc;
! 630: int revents = 0;
! 631:
! 632: sc = uscanner_cd.cd_devs[USCANNERUNIT(dev)];
! 633:
! 634: if (sc->sc_dying)
! 635: return (POLLERR);
! 636:
! 637: /*
! 638: * We have no easy way of determining if a read will
! 639: * yield any data or a write will happen.
! 640: * Pretend they will.
! 641: */
! 642: revents |= events &
! 643: (POLLIN | POLLRDNORM | POLLOUT | POLLWRNORM);
! 644:
! 645: return (revents);
! 646: }
! 647:
! 648: int
! 649: uscannerioctl(dev_t dev, u_long cmd, caddr_t addr, int flag, struct proc *p)
! 650: {
! 651: return (EINVAL);
! 652: }
! 653:
! 654: void filt_uscannerdetach(struct knote *);
! 655: int uscannerkqfilter(dev_t, struct knote *);
! 656:
! 657: void
! 658: filt_uscannerdetach(struct knote *kn)
! 659: {
! 660: struct uscanner_softc *sc = (void *)kn->kn_hook;
! 661:
! 662: SLIST_REMOVE(&sc->sc_selq.si_note, kn, knote, kn_selnext);
! 663: }
! 664:
! 665: struct filterops uscanner_seltrue_filtops =
! 666: { 1, NULL, filt_uscannerdetach, filt_seltrue };
! 667:
! 668: int
! 669: uscannerkqfilter(dev_t dev, struct knote *kn)
! 670: {
! 671: struct uscanner_softc *sc;
! 672: struct klist *klist;
! 673:
! 674: sc = uscanner_cd.cd_devs[USCANNERUNIT(dev)];
! 675:
! 676: if (sc->sc_dying)
! 677: return (1);
! 678:
! 679: switch (kn->kn_filter) {
! 680: case EVFILT_READ:
! 681: case EVFILT_WRITE:
! 682: /*
! 683: * We have no easy way of determining if a read will
! 684: * yield any data or a write will happen.
! 685: * Pretend they will.
! 686: */
! 687: klist = &sc->sc_selq.si_note;
! 688: kn->kn_fop = &uscanner_seltrue_filtops;
! 689: break;
! 690:
! 691: default:
! 692: return (1);
! 693: }
! 694:
! 695: kn->kn_hook = (void *)sc;
! 696:
! 697: SLIST_INSERT_HEAD(klist, kn, kn_selnext);
! 698:
! 699: return (0);
! 700: }
CVSweb