Skip site navigation (1)Skip section navigation (2)
Date:      Tue, 5 Sep 2006 18:57:03 GMT
From:      Hans Petter Selasky <hselasky@FreeBSD.org>
To:        Perforce Change Reviews <perforce@FreeBSD.org>
Subject:   PERFORCE change 105688 for review
Message-ID:  <200609051857.k85Iv3dd094174@repoman.freebsd.org>

next in thread | raw e-mail | index | archive | help
http://perforce.freebsd.org/chv.cgi?CH=105688

Change 105688 by hselasky@hselasky_mini_itx on 2006/09/05 18:56:24

	Finished reworking uscanner. Initial version was 
	written by "Attilio Rao". Please test!

Affected files ...

.. //depot/projects/usb/src/sys/dev/usb/uscanner.c#4 edit

Differences ...

==== //depot/projects/usb/src/sys/dev/usb/uscanner.c#4 (text+ko) ====

@@ -1,0 +1,669 @@
+/*	$NetBSD: uscanner.c,v 1.30 2002/07/11 21:14:36 augustss Exp$	*/
+
+/* Also already merged from NetBSD:
+ *	$NetBSD: uscanner.c,v 1.33 2002/09/23 05:51:24 simonb Exp $
+ */
+
+/*-
+ * Copyright (c) 2000 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Lennart Augustsson (lennart@augustsson.net) at
+ * Carlstedt Research & Technology
+ * and Nick Hibma (n_hibma@qubesoft.com).
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *        This product includes software developed by the NetBSD
+ *        Foundation, Inc. and its contributors.
+ * 4. Neither the name of The NetBSD Foundation nor the names of its
+ *    contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/kernel.h>
+#include <sys/fcntl.h>
+
+#include <dev/usb/usb_port.h>
+#include <dev/usb/usb.h>
+#include <dev/usb/usb_subr.h>
+
+#include "usbdevs.h"
+
+__FBSDID("$FreeBSD: src/sys/dev/usb/uscanner.c,v 1.70 2006/04/11 10:44:31 flz Exp $");
+
+/*
+ * uscanner debugging statements.
+ */
+#ifdef	USB_DEBUG
+static int uscanner_debug = 0;
+SYSCTL_NODE(_hw_usb, OID_AUTO, uscanner, CTLFLAG_RW, 0, "USB uscanner");
+SYSCTL_INT(_hw_usb_uscanner, OID_AUTO, uscanner, CTLFLAG_RW, &uscanner_debug,
+	   0, "uscanner debug level");
+
+#define	DPRINTF(n, fmt, ...) do {		\
+	if (uscanner_debug > (n)) {		\
+	    printf("%s: " fmt, __FUNCTION__	\
+		   ,## __VA_ARGS__);		\
+	}					\
+  } while (0)
+#else
+#define	DPRINTF(...)
+#endif
+
+/*
+ * uscanner transfers macros definition.
+ */
+#define	USCANNER_BSIZE			(1 << 16)
+#define	USCANNER_IFQ_MAXLEN		2
+#define	USCANNER_N_TRANSFER		4
+
+/*
+ * Transfers stallings handling flags definition.
+ */
+#define	USCANNER_FLAG_READ_STALL	0x01
+#define	USCANNER_FLAG_WRITE_STALL	0x02
+
+/*
+ * uscanner_info flags definition.
+ */
+#define	USCANNER_FLAG_KEEP_OPEN		0x04
+
+ /*
+ * uscanner driver specific structures.
+ */
+struct uscanner_info {
+	struct usb_devno	devno;
+	uint8_t			flags;
+};
+
+struct uscanner_softc {
+	struct usb_cdev		sc_cdev;
+	struct mtx		sc_mtx;
+	struct usbd_memory_wait	sc_mem_wait;
+
+	device_t		sc_dev;
+	struct usbd_xfer *	sc_xfer[USCANNER_N_TRANSFER];
+
+	uint8_t			sc_flags;	/* Used to prevent stalls */
+};
+
+/*
+ * Prototypes for driver handling routines (sorted by use).
+ */
+static device_probe_t	uscanner_probe;
+static device_attach_t	uscanner_attach;
+static device_detach_t	uscanner_detach;
+
+/*
+ * Prototypes for xfer transfer callbacks.
+ */
+static void	uscanner_read_callback(struct usbd_xfer *xfer);
+static void	uscanner_read_clear_stall_callback(struct usbd_xfer *xfer);
+static void	uscanner_write_callback(struct usbd_xfer *xfer);
+static void	uscanner_write_clear_stall_callback(struct usbd_xfer *xfer);
+
+/*
+ * Prototypes for the character device handling routines.
+ */
+static int32_t	uscanner_open(struct usb_cdev *cdev, int32_t fflags,
+			      int32_t devtype, struct thread *td);
+static void	uscanner_start_read(struct usb_cdev *cdev);
+static void	uscanner_start_write(struct usb_cdev *cdev);
+static void	uscanner_stop_read(struct usb_cdev *cdev);
+static void	uscanner_stop_write(struct usb_cdev *cdev);
+
+/*
+ * xfer transfers array.  Resolve-stalling callbacks are marked as control
+ * transfers.
+ */
+static const struct usbd_config uscanner_config [USCANNER_N_TRANSFER] = {
+    [0] = { 
+      .type      = UE_BULK,
+      .endpoint  = -1, /* any */
+      .direction = UE_DIR_OUT,
+      .bufsize   = USCANNER_BSIZE,
+      .flags     = 0,
+      .callback  = &uscanner_write_callback,
+    },
+
+    [1] = {
+      .type      = UE_BULK,
+      .endpoint  = -1, /* any */
+      .direction = UE_DIR_IN,
+      .bufsize   = USCANNER_BSIZE,
+      .flags     = USBD_SHORT_XFER_OK,
+      .callback  = &uscanner_read_callback,
+    },
+
+    [2] = {
+      .type      = UE_CONTROL,
+      .endpoint  = 0x00, /* Control pipe */
+      .direction = -1,
+      .bufsize   = sizeof(usb_device_request_t),
+      .flags     = USBD_USE_DMA,
+      .callback  = &uscanner_write_clear_stall_callback,
+      .timeout   = 1000,
+    },
+
+    [3] = {
+      .type      = UE_CONTROL,
+      .endpoint  = 0x00,
+      .direction = -1,
+      .bufsize   = sizeof(usb_device_request_t),
+      .flags     = USBD_USE_DMA,
+      .callback  = &uscanner_read_clear_stall_callback,
+      .timeout   = 1000,
+    },
+};
+
+static devclass_t uscanner_devclass;
+
+static device_method_t uscanner_methods[] = {
+    DEVMETHOD(device_probe, uscanner_probe),
+    DEVMETHOD(device_attach, uscanner_attach),
+    DEVMETHOD(device_detach, uscanner_detach),
+    { 0, 0 }
+};
+
+static driver_t uscanner_driver = {
+    .name    = "uscanner",
+    .methods = uscanner_methods,
+    .size    = sizeof(struct uscanner_softc),
+};
+
+DRIVER_MODULE(uscanner, uhub, uscanner_driver, uscanner_devclass, usbd_driver_load, 0);
+MODULE_DEPEND(uscanner, usb, 1, 1, 1);
+
+/*
+ * USB scanners probing array.  It determines flags too.
+ */
+static const struct uscanner_info uscanner_devs[] = {
+		/* Acer */
+	{ { USB_VENDOR_ACERP, USB_PRODUCT_ACERP_ACERSCAN_320U }, 0 },
+	{ { USB_VENDOR_ACERP, USB_PRODUCT_ACERP_ACERSCAN_640U }, 0 },
+	{ { USB_VENDOR_ACERP, USB_PRODUCT_ACERP_ACERSCAN_640BT }, 0 },
+	{ { USB_VENDOR_ACERP, USB_PRODUCT_ACERP_ACERSCAN_620U }, 0 },
+	{ { USB_VENDOR_ACERP, USB_PRODUCT_ACERP_ACERSCAN_1240U }, 0 },
+	{ { USB_VENDOR_ACERP, USB_PRODUCT_ACERP_ACERSCAN_C310U }, 0 },
+		/* AGFA */
+	{ { USB_VENDOR_AGFA, USB_PRODUCT_AGFA_SNAPSCAN1236U }, 0 },
+	{ { USB_VENDOR_AGFA, USB_PRODUCT_AGFA_SNAPSCAN1212U }, 0 },
+	{ { USB_VENDOR_AGFA, USB_PRODUCT_AGFA_SNAPSCAN1212U2 }, 0 },
+	{ { USB_VENDOR_AGFA, USB_PRODUCT_AGFA_SNAPSCANTOUCH }, 0 },
+	{ { USB_VENDOR_AGFA, USB_PRODUCT_AGFA_SNAPSCANE40 }, 0 },
+	{ { USB_VENDOR_AGFA, USB_PRODUCT_AGFA_SNAPSCANE50 }, 0 },
+	{ { USB_VENDOR_AGFA, USB_PRODUCT_AGFA_SNAPSCANE20 }, 0 },
+	{ { USB_VENDOR_AGFA, USB_PRODUCT_AGFA_SNAPSCANE25 }, 0 },
+	{ { USB_VENDOR_AGFA, USB_PRODUCT_AGFA_SNAPSCANE26 }, 0 },
+	{ { USB_VENDOR_AGFA, USB_PRODUCT_AGFA_SNAPSCANE52 }, 0 },
+		/* Avision */
+	{ { USB_VENDOR_AVISION, USB_PRODUCT_AVISION_1200U }, 0 },
+		/* Canon */
+	{ { USB_VENDOR_CANON, USB_PRODUCT_CANON_N656U }, 0 },
+	{ { USB_VENDOR_CANON, USB_PRODUCT_CANON_N676U }, 0 },
+	{ { USB_VENDOR_CANON, USB_PRODUCT_CANON_N1220U }, 0 },
+	{ { USB_VENDOR_CANON, USB_PRODUCT_CANON_D660U }, 0 },
+	{ { USB_VENDOR_CANON, USB_PRODUCT_CANON_N1240U }, 0 },
+	{ { USB_VENDOR_CANON, USB_PRODUCT_CANON_LIDE25 }, 0 },
+		/* Epson */
+	{ { USB_VENDOR_EPSON, USB_PRODUCT_EPSON_636 }, 0 },
+	{ { USB_VENDOR_EPSON, USB_PRODUCT_EPSON_610 }, 0 },
+	{ { USB_VENDOR_EPSON, USB_PRODUCT_EPSON_1200 }, 0 },
+	{ { USB_VENDOR_EPSON, USB_PRODUCT_EPSON_1240 }, 0 },
+	{ { USB_VENDOR_EPSON, USB_PRODUCT_EPSON_1250 }, 0 },
+	{ { USB_VENDOR_EPSON, USB_PRODUCT_EPSON_1600 }, 0 },
+	{ { USB_VENDOR_EPSON, USB_PRODUCT_EPSON_1640 }, 0 },
+	{ { USB_VENDOR_EPSON, USB_PRODUCT_EPSON_640U }, 0 },
+	{ { USB_VENDOR_EPSON, USB_PRODUCT_EPSON_1650 }, 0 },
+	{ { USB_VENDOR_EPSON, USB_PRODUCT_EPSON_1660 }, 0 },
+	{ { USB_VENDOR_EPSON, USB_PRODUCT_EPSON_1670 }, 0 },
+	{ { USB_VENDOR_EPSON, USB_PRODUCT_EPSON_1260 }, 0 },
+	{ { USB_VENDOR_EPSON, USB_PRODUCT_EPSON_RX425 }, 0 },
+	{ { USB_VENDOR_EPSON, USB_PRODUCT_EPSON_3200 }, USCANNER_FLAG_KEEP_OPEN },
+	{ { USB_VENDOR_EPSON, USB_PRODUCT_EPSON_GT9700F }, USCANNER_FLAG_KEEP_OPEN },
+	{ { USB_VENDOR_EPSON, USB_PRODUCT_EPSON_GT9300UF }, 0 },
+	{ { USB_VENDOR_EPSON, USB_PRODUCT_EPSON_2480 }, 0 },
+		/* HP */
+	{ { USB_VENDOR_HP, USB_PRODUCT_HP_2200C }, 0 },
+	{ { USB_VENDOR_HP, USB_PRODUCT_HP_3300C }, 0 },
+	{ { USB_VENDOR_HP, USB_PRODUCT_HP_3400CSE }, 0 },
+	{ { USB_VENDOR_HP, USB_PRODUCT_HP_4100C }, 0 },
+	{ { USB_VENDOR_HP, USB_PRODUCT_HP_4200C }, 0 },
+	{ { USB_VENDOR_HP, USB_PRODUCT_HP_4300C }, 0 },
+	{ { USB_VENDOR_HP, USB_PRODUCT_HP_4670V }, 0 },
+	{ { USB_VENDOR_HP, USB_PRODUCT_HP_S20 }, 0 },
+	{ { USB_VENDOR_HP, USB_PRODUCT_HP_5200C }, 0 },
+	{ { USB_VENDOR_HP, USB_PRODUCT_HP_5300C }, 0 },
+	{ { USB_VENDOR_HP, USB_PRODUCT_HP_5400C }, 0 },
+	{ { USB_VENDOR_HP, USB_PRODUCT_HP_6200C }, 0 },
+	{ { USB_VENDOR_HP, USB_PRODUCT_HP_6300C }, 0 },
+	{ { USB_VENDOR_HP, USB_PRODUCT_HP_82x0C }, 0 },
+		/* Kye */
+	{ { USB_VENDOR_KYE, USB_PRODUCT_KYE_VIVIDPRO }, 0 },
+		/* Microtek */
+	{ { USB_VENDOR_MICROTEK, USB_PRODUCT_MICROTEK_X6U }, 0 },
+	{ { USB_VENDOR_MICROTEK, USB_PRODUCT_MICROTEK_336CX }, 0 },
+	{ { USB_VENDOR_MICROTEK, USB_PRODUCT_MICROTEK_336CX2 }, 0 },
+	{ { USB_VENDOR_MICROTEK, USB_PRODUCT_MICROTEK_C6 }, 0 },
+	{ { USB_VENDOR_MICROTEK, USB_PRODUCT_MICROTEK_V6USL }, 0 },
+	{ { USB_VENDOR_MICROTEK, USB_PRODUCT_MICROTEK_V6USL2 }, 0 },
+	{ { USB_VENDOR_MICROTEK, USB_PRODUCT_MICROTEK_V6UL }, 0 },
+		/* Minolta */
+	{ { USB_VENDOR_MINOLTA, USB_PRODUCT_MINOLTA_5400 }, 0 },
+		/* Mustek */
+	{ { USB_VENDOR_MUSTEK, USB_PRODUCT_MUSTEK_1200CU }, 0 },
+	{ { USB_VENDOR_MUSTEK, USB_PRODUCT_MUSTEK_BEARPAW1200F }, 0 },
+	{ { USB_VENDOR_MUSTEK, USB_PRODUCT_MUSTEK_BEARPAW1200TA }, 0 },
+	{ { USB_VENDOR_MUSTEK, USB_PRODUCT_MUSTEK_600USB }, 0 },
+	{ { USB_VENDOR_MUSTEK, USB_PRODUCT_MUSTEK_600CU }, 0 },
+	{ { USB_VENDOR_MUSTEK, USB_PRODUCT_MUSTEK_1200USB }, 0 },
+	{ { USB_VENDOR_MUSTEK, USB_PRODUCT_MUSTEK_1200UB }, 0 },
+	{ { USB_VENDOR_MUSTEK, USB_PRODUCT_MUSTEK_1200USBPLUS }, 0 },
+	{ { USB_VENDOR_MUSTEK, USB_PRODUCT_MUSTEK_1200CUPLUS }, 0 },
+		/* National */
+	{ { USB_VENDOR_NATIONAL, USB_PRODUCT_NATIONAL_BEARPAW1200 }, 0 },
+	{ { USB_VENDOR_NATIONAL, USB_PRODUCT_NATIONAL_BEARPAW2400 }, 0 },
+		/* Nikon */
+	{ { USB_VENDOR_NIKON, USB_PRODUCT_NIKON_LS40 }, 0 },
+		/* Primax */
+	{ { USB_VENDOR_PRIMAX, USB_PRODUCT_PRIMAX_G2X300 }, 0 },
+	{ { USB_VENDOR_PRIMAX, USB_PRODUCT_PRIMAX_G2E300 }, 0 },
+	{ { USB_VENDOR_PRIMAX, USB_PRODUCT_PRIMAX_G2300 }, 0 },
+	{ { USB_VENDOR_PRIMAX, USB_PRODUCT_PRIMAX_G2E3002 }, 0 },
+	{ { USB_VENDOR_PRIMAX, USB_PRODUCT_PRIMAX_9600 }, 0 },
+	{ { USB_VENDOR_PRIMAX, USB_PRODUCT_PRIMAX_600U }, 0 },
+	{ { USB_VENDOR_PRIMAX, USB_PRODUCT_PRIMAX_6200 }, 0 },
+	{ { USB_VENDOR_PRIMAX, USB_PRODUCT_PRIMAX_19200 }, 0 },
+	{ { USB_VENDOR_PRIMAX, USB_PRODUCT_PRIMAX_1200U }, 0 },
+	{ { USB_VENDOR_PRIMAX, USB_PRODUCT_PRIMAX_G600 }, 0 },
+	{ { USB_VENDOR_PRIMAX, USB_PRODUCT_PRIMAX_636I }, 0 },
+	{ { USB_VENDOR_PRIMAX, USB_PRODUCT_PRIMAX_G2600 }, 0 },
+	{ { USB_VENDOR_PRIMAX, USB_PRODUCT_PRIMAX_G2E600 }, 0 },
+		/* Scanlogic */
+	{ { USB_VENDOR_SCANLOGIC, USB_PRODUCT_SCANLOGIC_336CX }, 0 },
+		/* Ultima */
+	{ { USB_VENDOR_ULTIMA, USB_PRODUCT_ULTIMA_1200UBPLUS }, 0 },
+		/* UMAX */
+	{ { USB_VENDOR_UMAX, USB_PRODUCT_UMAX_ASTRA1220U }, 0 },
+	{ { USB_VENDOR_UMAX, USB_PRODUCT_UMAX_ASTRA1236U }, 0 },
+	{ { USB_VENDOR_UMAX, USB_PRODUCT_UMAX_ASTRA2000U }, 0 },
+	{ { USB_VENDOR_UMAX, USB_PRODUCT_UMAX_ASTRA2100U }, 0 },
+	{ { USB_VENDOR_UMAX, USB_PRODUCT_UMAX_ASTRA2200U }, 0 },
+	{ { USB_VENDOR_UMAX, USB_PRODUCT_UMAX_ASTRA3400 }, 0 },
+		/* Visioneer */
+	{ { USB_VENDOR_VISIONEER, USB_PRODUCT_VISIONEER_3000 }, 0 },
+	{ { USB_VENDOR_VISIONEER, USB_PRODUCT_VISIONEER_5300 }, 0 },
+	{ { USB_VENDOR_VISIONEER, USB_PRODUCT_VISIONEER_7600 }, 0 },
+	{ { USB_VENDOR_VISIONEER, USB_PRODUCT_VISIONEER_6100 }, 0 },
+	{ { USB_VENDOR_VISIONEER, USB_PRODUCT_VISIONEER_6200 }, 0 },
+	{ { USB_VENDOR_VISIONEER, USB_PRODUCT_VISIONEER_8100 }, 0 },
+	{ { USB_VENDOR_VISIONEER, USB_PRODUCT_VISIONEER_8600 }, 0 }
+};
+
+/*
+ * It returns vendor and product ids.
+ */
+static inline const struct uscanner_info *
+uscanner_lookup(uint16_t v, uint16_t p)
+{
+	return ((const struct uscanner_info *)usb_lookup(uscanner_devs, v, p));
+}
+
+/*
+ * uscanner device probing method.
+ */
+static int
+uscanner_probe(device_t dev)
+{
+	struct usb_attach_arg *uaa;
+
+	DPRINTF(10, "\n");
+
+	uaa = device_get_ivars(dev);
+	if (uaa->iface != NULL) {
+		return (UMATCH_NONE);
+	}
+
+	return ((uscanner_lookup(uaa->vendor, uaa->product) != NULL) ?
+	    UMATCH_VENDOR_PRODUCT : UMATCH_NONE);
+}
+
+/*
+ * uscanner device attaching method.
+ */
+static int
+uscanner_attach(device_t dev)
+{
+	struct usb_attach_arg *uaa;
+	struct uscanner_softc *sc;
+	struct usbd_device *udev;
+	const char *p_buf[2];
+	char buf[32];
+	int32_t unit;
+	int error;
+
+	uaa = device_get_ivars(dev);
+	sc = device_get_softc(dev);
+	unit = device_get_unit(dev);
+
+	/*
+	 * A first path softc structure filling.  sc_cdev, sc_mem_wait and
+	 * sc_xfer are filled later with appropriate functions.
+	 */
+	sc->sc_dev = dev;
+	sc->sc_flags = uscanner_lookup(uaa->vendor, uaa->product)->flags;
+	mtx_init(&(sc->sc_mtx), "uscanner mutex", NULL, MTX_DEF | MTX_RECURSE);
+
+	/*
+	 * Announce the device:
+	 */
+	usbd_set_desc(dev, uaa->device);
+
+	/*
+	 * Assume only one interface and check for this.
+	 */
+	udev = uaa->device;
+	if ((error = usbd_set_config_no(udev, 1, 1))) {
+		device_printf(dev, "could not set config number\n");
+		goto detach;
+	}
+
+	/*
+	 * Setup the transfer.
+	 */
+	if ((error = usbd_transfer_setup(udev, uaa->iface_index, sc->sc_xfer,
+	    uscanner_config, USCANNER_N_TRANSFER, sc, &(sc->sc_mtx),
+	    &(sc->sc_mem_wait)))) {
+		device_printf(dev, "could not setup transfers, "
+			      "error=%s\n", usbd_errstr(error));
+		goto detach;
+	}
+
+	/*
+	 * Setup the character device for USB scanner.
+	 */
+	snprintf(buf, sizeof(buf), "uscanner%u", unit);
+	p_buf[0] = buf;
+	p_buf[1] = NULL;
+
+	sc->sc_cdev.sc_start_read = &uscanner_start_read;
+	sc->sc_cdev.sc_stop_read = &uscanner_stop_read;
+	sc->sc_cdev.sc_start_write = &uscanner_start_write;
+	sc->sc_cdev.sc_stop_write = &uscanner_stop_write;
+	sc->sc_cdev.sc_open = &uscanner_open;
+	sc->sc_cdev.sc_flags |= (USB_CDEV_FLAG_FWD_SHORT|
+				 USB_CDEV_FLAG_WAKEUP_RD_IMMED |
+				 USB_CDEV_FLAG_WAKEUP_WR_IMMED);
+
+	if ((error = usb_cdev_attach(&(sc->sc_cdev), sc, &(sc->sc_mtx), p_buf,
+	    UID_ROOT, GID_OPERATOR, 0644, USCANNER_BSIZE, USCANNER_IFQ_MAXLEN,
+	    USCANNER_BSIZE, USCANNER_IFQ_MAXLEN))) {
+		device_printf(dev, "error setting the "
+			      "char device!\n");
+		goto detach;
+	}
+
+	return (0);
+
+detach:
+	uscanner_detach(dev);
+	return ENOMEM;
+}
+
+/*
+ * uscanner device detaching method.
+ */
+static int
+uscanner_detach(device_t dev)
+{
+	struct uscanner_softc *sc;
+
+	sc = device_get_softc(dev);
+
+	usb_cdev_detach(&(sc->sc_cdev));
+	usbd_transfer_unsetup(sc->sc_xfer, USCANNER_N_TRANSFER);
+	usbd_transfer_drain(&(sc->sc_mem_wait), &(sc->sc_mtx));
+	mtx_destroy(&(sc->sc_mtx));
+
+	return (0);
+}
+
+/*
+ * Reading callback.  Implemented as an "in" bulk transfer.
+ */
+static void
+uscanner_read_callback(struct usbd_xfer *xfer)
+{
+	struct uscanner_softc *sc;
+	struct usbd_mbuf *m;
+
+	sc = xfer->priv_sc;
+
+	USBD_CHECK_STATUS(xfer);
+
+tr_transferred:
+	usb_cdev_put_data(&(sc->sc_cdev), xfer->buffer, xfer->actlen, 1);
+
+tr_setup:
+	/*
+	 * If reading is in stall, just jump to clear stall callback and
+	 * solve the situation.
+	 */
+	if (sc->sc_flags & USCANNER_FLAG_READ_STALL) {
+		usbd_transfer_start(sc->sc_xfer[3]);
+		return;
+	}
+
+	USBD_IF_POLL(&(sc->sc_cdev).sc_rdq_free, m);
+	if (m) {
+		usbd_start_hardware(xfer);
+	}
+	return;
+
+tr_error:
+	if (xfer->error != USBD_CANCELLED) {
+		sc->sc_flags |= USCANNER_FLAG_READ_STALL;
+		usbd_transfer_start(sc->sc_xfer[3]);
+	}
+	return;
+}
+
+/*
+ * Removing stall on reading callback.
+ */
+static void
+uscanner_read_clear_stall_callback(struct usbd_xfer *xfer)
+{
+	struct uscanner_softc *sc;
+	struct usbd_xfer *xfer_other;
+
+	sc = xfer->priv_sc;
+	xfer_other = sc->sc_xfer[1];
+
+	USBD_CHECK_STATUS(xfer);
+
+tr_setup:
+	usbd_clear_stall_tr_setup(xfer, xfer_other);
+	return;
+
+tr_transferred:
+	usbd_clear_stall_tr_transferred(xfer, xfer_other);
+	sc->sc_flags &= ~USCANNER_FLAG_READ_STALL;
+	usbd_transfer_start(xfer_other);
+	return;
+
+tr_error:
+	sc->sc_flags &= ~USCANNER_FLAG_READ_STALL;
+	usb_cdev_put_data_error(&(sc->sc_cdev));
+	return;
+}
+
+/*
+ * Writing callback.  Implemented as an "out" bulk transfer.
+ */
+static void
+uscanner_write_callback(struct usbd_xfer *xfer)
+{
+	struct uscanner_softc *sc;
+	uint32_t actlen;
+
+	sc = xfer->priv_sc;
+
+	USBD_CHECK_STATUS(xfer);
+
+tr_setup:
+tr_transferred:
+	/*
+	 * If writing is in stall, just jump to clear stall callback and
+	 * solve the situation.
+	 */
+	if (sc->sc_flags & USCANNER_FLAG_WRITE_STALL) {
+		usbd_transfer_start(sc->sc_xfer[2]);
+		return;
+	}
+
+	/*
+	 * Write datas, setup and perform hardware transfer.
+	 */
+	if (usb_cdev_get_data(&(sc->sc_cdev), xfer->buffer, USCANNER_BSIZE,
+	    &actlen, 0)) {
+		xfer->length = actlen;
+		usbd_start_hardware(xfer);
+	}
+	return;
+
+tr_error:
+	if (xfer->error != USBD_CANCELLED) {
+		sc->sc_flags |= USCANNER_FLAG_WRITE_STALL;
+		usbd_transfer_start(sc->sc_xfer[2]);
+	}
+	return;
+}
+
+/*
+ * Removing stall on writing callback.
+ */
+static void
+uscanner_write_clear_stall_callback(struct usbd_xfer *xfer)
+{
+	struct uscanner_softc *sc;
+	struct usbd_xfer *xfer_other;
+
+	sc = xfer->priv_sc;
+	xfer_other = sc->sc_xfer[0];
+
+	USBD_CHECK_STATUS(xfer);
+
+tr_setup:
+	usbd_clear_stall_tr_setup(xfer, xfer_other);
+	return;
+
+tr_transferred:
+	usbd_clear_stall_tr_transferred(xfer, xfer_other);
+	sc->sc_flags &= ~USCANNER_FLAG_WRITE_STALL;
+	usbd_transfer_start(xfer_other);
+	return;
+
+tr_error:
+	sc->sc_flags &= ~USCANNER_FLAG_WRITE_STALL;
+	usb_cdev_get_data_error(&(sc->sc_cdev));
+	return;
+}
+
+/*
+ * uscanner character device opening method.
+ */
+static int32_t
+uscanner_open(struct usb_cdev *cdev, int32_t fflags, int32_t devtype,
+	      struct thread *td)
+{
+	struct uscanner_softc *sc;
+
+	sc = cdev->sc_priv_ptr;
+
+	if (!(sc->sc_flags & USCANNER_FLAG_KEEP_OPEN)) {
+	    if (fflags & FWRITE) {
+		sc->sc_flags |= USCANNER_FLAG_WRITE_STALL;
+	    }
+
+	    if (fflags & FREAD) {
+		sc->sc_flags |= USCANNER_FLAG_READ_STALL;
+	    }
+	}
+	return (0);
+}
+
+/*
+ * uscanner character device start reading method.
+ */
+static void
+uscanner_start_read(struct usb_cdev *cdev)
+{
+	struct uscanner_softc *sc;
+
+	sc = cdev->sc_priv_ptr;
+	usbd_transfer_start(sc->sc_xfer[1]);
+}
+
+/*
+ * uscanner character device start writing method.
+ */
+static void
+uscanner_start_write(struct usb_cdev *cdev)
+{
+	struct uscanner_softc *sc;
+
+	sc = cdev->sc_priv_ptr;
+	usbd_transfer_start(sc->sc_xfer[0]);
+}
+
+/*
+ * uscanner character device stop reading method.
+ */
+static void
+uscanner_stop_read(struct usb_cdev *cdev)
+{
+	struct uscanner_softc *sc;
+
+	sc = cdev->sc_priv_ptr;
+	usbd_transfer_stop(sc->sc_xfer[3]);
+	usbd_transfer_stop(sc->sc_xfer[1]);
+}
+
+/*
+ * uscanner character device stop writing method.
+ */
+static void
+uscanner_stop_write(struct usb_cdev *cdev)
+{
+	struct uscanner_softc *sc;
+
+	sc = cdev->sc_priv_ptr;
+	usbd_transfer_stop(sc->sc_xfer[2]);
+	usbd_transfer_stop(sc->sc_xfer[0]);
+}



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?200609051857.k85Iv3dd094174>